以下函数原型来自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);
}
}