启动ucosii之二PC_DOSSaveReturn()

来源:互联网 发布:网络工程师 知乎 编辑:程序博客网 时间:2024/05/16 15:11

以下函数原型来自PC.C

奋斗

void PC_DOSSaveReturn (void)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;//OS_CPU.H typedef unsigned short OS_CPU_SR; /* Define size of CPU status register (PSW = 16 bits) */
#endif   


    PC_ExitFlag  = FALSE;                                  /* Indicate that we are not exiting yet!    */
    OSTickDOSCtr =     1;                                  /* Initialize the DOS tick counter          */

//将PC系统原来自己的中断向量0x08H提取出来,转给用户自己定义的中断向量0x81H
//空出来的中断向量0x08H留给uCOSII安装时钟中断向量
    PC_TickISR   = PC_VectGet(VECT_TICK);                  /* Get MS-DOS's tick vector                 */
   
    PC_VectSet(VECT_DOS_CHAIN, PC_TickISR);                /* Store MS-DOS's tick to chain             */
   

   /*函数原型: int setjmp(jmp_buf envbuf);*/
    setjmp(PC_JumpBuf);//调用setjmp,用变量envbuf记录当前的位置.以备以后通过longjmp(jmp_buf envbuf,int val);返回到该处
    //可以看出,当在某个需要退出程序,回到DOS的地方,先设置PC_ExitFlag  = TRUE,然后调用longjmp即可到达该处执行下面代码
                                    /* Capture where we are in DOS              */


    if (PC_ExitFlag == TRUE) {                             /* See if we are exiting back to DOS        */
        OS_ENTER_CRITICAL();//OS_CPU.H
        PC_SetTickRate(18);                                /* Restore tick rate to 18.2 Hz             */
        OS_EXIT_CRITICAL();//OS_CPU.H
        PC_VectSet(VECT_TICK, PC_TickISR);                 /* Restore DOS's tick vector                */
        PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK);  /* Clear the display                        */
        exit(0);                                           /* Return to DOS                            */
    }
}

void PC_DOSReturn (void)//返回DOS函数
{
     //先设置PC_ExitFlag  = TRUE
 PC_ExitFlag = TRUE;                                    /* Indicate we are returning to DOS         */
 //然后调用longjmp跳转至函数PC_DOSSaveReturn (void)中setjmp保存的地方开始执行
 //第2个参数其实是setjmp的返回值.setjmp初次设置返回0,执行完longjmp后,setjmp返回longjmp的第2个参数
     longjmp(PC_JumpBuf, 1);                                /* Jump back to saved environment           */
}

 

//pc.c中定义#define  VECT_TICK  0x08
//pc.c中定义#define  VECT_DOS_CHAIN  0x81
//该函数从中断向量表中取出指定中断类型号的中断服务函数的地址,赋给一个函数指针
void *PC_VectGet (INT8U vect)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif   
    INT16U    *pvect;
    INT16U     off;
    INT16U     seg;
   
/*
函数名: MK_FP
函数原型: #define MK_FP( seg,ofs )( (void _seg * )( seg ) +( void near * )( ofs ))
函数位置: dos.h
函数说明: MK_FP()不是一个函数,只是一个宏.功能是做段基址加上偏移地址的运算,也就是取实际地址.
*/   
    pvect = (INT16U *)MK_FP(0x0000, vect * 4);        /* Point into IVT at desired vector location     */
    OS_ENTER_CRITICAL();
    off   = *pvect++;                                 /* Obtain the vector's OFFSET                    */
    seg   = *pvect;                                   /* Obtain the vector's SEGMENT                   */
    OS_EXIT_CRITICAL();
    return (MK_FP(seg, off));
}


/*
中断向量是指中断服务程序入口地址的偏移量与段基值,一个中断向量占据4字节空间.
中断向量表是8088系统内存中最低端0x0000h开始的1K字节空间,它的作用就是按照中断类型号从小到大的顺序存储对应的中断向量,总共存储256个中断向量.
在中断响应过程中,CPU通过从接口电路获取的中断类型号(中断向量号)计算对应中断向量在表中的位置,并从中断向量表中获取中断向量,将程序流程转向中断服务程序的入口地址
*/
//vect向量号,一个内部中断(软中断)向量号
//参数2-中断处理函数.
void PC_VectSet (INT8U vect, void (*isr)(void))
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif   
    INT16U    *pvect;
       
    pvect    = (INT16U *)MK_FP(0x0000, vect * 4);     /* Point into IVT at desired vector location     */
    OS_ENTER_CRITICAL();
/*
函数名: FP_OFF
功  能: 获取远地址偏移量
用  法: unsigned FP_OFF(void far *farptr);
函数位置: dos.h
*/
    *pvect++ = (INT16U)FP_OFF(isr);                   /* Store ISR offset                              */
/*
函数名: FP_SEG
功  能: 获取远地址段值
用  法: unsigned FP_SEG(void far *farptr);
函数位置: dos.h
*/
    *pvect   = (INT16U)FP_SEG(isr);                   /* Store ISR segment                             */
    OS_EXIT_CRITICAL();
}

 

/*
uCOS-II定义频率,以改变钟节拍的速率.
在DOS下,每秒产生18.20648次时钟节拍,或每隔54.925ms一次.这是因为82C54定时器芯片没有初始化,而使用默认值65535的结果.
如果初始化为58659,那么时钟节拍的速率就会精确地为20.000Hz
*/
void PC_SetTickRate (INT16U freq)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif   
    INT16U     count;

//1.193Mhz/65536 ≈ 18.2HZ每秒18次中断
    if (freq == 18) {                            /* See if we need to restore the DOS frequency        */
        count = 0;
    } else if (freq > 0) {                       
                                                 /* Compute 8254 counts for desired frequency and ...  */
                                                 /* ... round to nearest count                         */

//设置计数count=1.193Mhz/f + 0.5
        count = (INT16U)(((INT32U)2386360L / freq + 1) >> 1);
    } else {
        count = 0;
    }
    OS_ENTER_CRITICAL();
//控制字设置为通道0; 先读低字节,再读高字节; mode3-方波信号发生器; 计数器使用二进制.
    outp(TICK_T0_8254_CWR,  TICK_T0_8254_CTR0_MODE3); /* Load the 8254 with desired frequency          */ 
    outp(TICK_T0_8254_CTR0, count & 0xFF);            /* Low  byte                                     */
    outp(TICK_T0_8254_CTR0, (count >> 8) & 0xFF);     /* High byte                                     */
    OS_EXIT_CRITICAL();
}


BOOLEAN PC_GetKey (INT16S *c)
{
    if (kbhit()) {                                         /* See if a key has been pressed            */
        *c = (INT16S)getch();                              /* Get key pressed                          */
        return (TRUE);
    } else {
        *c = 0x00;                                         /* No key pressed                           */
        return (FALSE);
    }
}