1.中断管理和中断服务程序的结构
3.1.1中断响应过程
UC/OS-II系统响应中断的过程是:系统接收到中断请求时,如果这时CPU处于中断允许状态,即中断时开放的,系统就会终止正在运行的当前任务,而按照中断向量的指向转而去运行服务子程序。需要特别注意的是对于可剥夺形的UC/OS-II内核来说,中断子程序运行结束之后,系统将会根据情况进行一次任务调度去运行优先级别最高的就绪任务,并不一定接着运行被中断的任务。同时中断是可以嵌套的,即高优先级别的中断源的中断请求可以中断低优先级别的中断服务程序的运行。为了记录中断嵌套的层数,UC/OS-II定义了一个全局变量OSIntNesting
以及2个重要函数
void OSIntEnter (void)
{
if (OSRunning == OS_TRUE) {
if (OSIntNesting < 255u) {
OSIntNesting++; /* Increment ISR nesting level */
}
}
}
OSIntEnter()的调用通常发生在中断服务程序保护了被中断任务的断点之后运行用户中断服务代码之前。
另一个函数是OSIntExt(),在改函数中会将变量OSIntNesting减1,OSIntExt()的源码如下
void OSIntExit (void)
{
#if OS_CRITICAL_METHOD == 3
/* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
if (OSRunning == OS_TRUE) {
OS_ENTER_CRITICAL();
if (OSIntNesting > 0) {
/* Prevent OSIntNesting from wrapping */
OSIntNesting--;
}
if (OSIntNesting == 0)
{
/* Reschedule only if all ISRs complete ... */
if (OSLockNesting == 0)
{
/* ... and not locked. */
OS_SchedNew();
if (OSPrioHighRdy != OSPrioCur)
{
/* No Ctx Sw if current task is highest rdy */
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
OSTCBHighRdy->OSTCBCtxSwCtr++;
/* Inc. # of context switches to this task */
#endif
OSCtxSwCtr++;
/* Keep track of the number of ctx switches */
OSIntCtxSw(); /* Perform interrupt level ctx switch */
}
}
}
OS_EXIT_CRITICAL();
}
}
3.1.2中断级任务切换
void OSIntCtxSw()
{
DWORD n = 0;
if(!(SS_SP->Exit)) {
n = SuspendThread(SS_SP->Handle);
}
OSTaskSwHook();
OSTrace( OBJ_SW, PT_SW_INT, OSTCBHighRdy, 0, O SPrioCur,OSPrioHighRdy,0 );
OSTCBCur = OSTCBHighRdy;
OSPrioCur = OSPrioHighRdy;
SS_SP = (OS_EMU_STK*) OSTCBHighRdy->OSTCBStkPtr;
ResumeThread(SS_SP->Handle);
}
3.1.3
1.临界段:不受任务干扰连续运行的代码段
1. 同样是通过关中断来保护临界区,OS_ENTER_CRITICAL/OS_EXIT_CRITICAL一共实现了三种实现方式,如下所示:
#if OS_CRITICAL_METHOD == 1
#define OS_ENTER_CRITICAL() __asm__("cli")
#define OS_EXIT_CRITICAL() __asm__("sti")
#endif
#if OS_CRITICAL_METHOD == 2
#define OS_ENTER_CRITICAL() __asm__("pushf \n\t cli")
#define OS_EXIT_CRITICAL() __asm__("popf")
#endif
#if OS_CRITICAL_METHOD == 3
#define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR())
#define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr))
#endif
第一种方式,OS_ENTER_CRITICAL()简单地关中断,OS_EXIT_CRITICAL()简单地开中断
第二种方式,OS_ENTER_CRITICAL()会在关中断前保存之前的标志寄存器内容到堆栈中,OS_EXIT_CRITICAL()从堆栈中恢复之前保存的状态
第三种,在关中断前,使用局部变量保存中断状态
3.2 UC/OS-II 时钟
1.UC/OS-II用硬件定时器产生一个毫秒级的周期性中断来实现系统时钟,最小的时钟单位就是两次中断之间的间隔时间,这个最小时钟单位就叫做时钟节拍。硬件定时器以时钟节拍为周期定时的产生中断,该中断的中断服务程序叫做OSTickISR(),中断服务程序通过调用函数OSTimeTick()来完成系统在每个时钟节拍时需要做的工作。
UC/OS-II在每次响应定时中断时调用OSTimeTick()做了两件事,一是给计数器OSTime加1,二是了解每个任务的延时状态,使其中已经到延时时限的非挂起任务进入就绪状态。
void OSTimeTick (void)
{
OS_TCB *ptcb;
#if OS_TICK_STEP_EN > 0
BOOLEAN step;
#endif
#if OS_CRITICAL_METHOD == 3
/* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
#if OS_TIME_TICK_HOOK_EN > 0
OSTimeTickHook();
/* Call user definable hook */
#endif
#if OS_TIME_GET_SET_EN > 0
OS_ENTER_CRITICAL();
/* Update the 32-bit tick counter */
OSTime++;
OS_EXIT_CRITICAL();
#endif
if (OSRunning == OS_TRUE) {
#if OS_TICK_STEP_EN > 0
switch (OSTickStepState) {
/* Determine whether we need to process a tick */
case OS_TICK_STEP_DIS:
/* Yes, stepping is disabled */
step = OS_TRUE;
break;
case OS_TICK_STEP_WAIT:
/* No, waiting for uC/OS-View to set ... */
step = OS_FALSE;
/* .. OSTickStepState to OS_TICK_STEP_ONCE */
break;
case OS_TICK_STEP_ONCE:
/* Yes, process tick once and wait for next ... */
step = OS_TRUE;
/* ... step command from uC/OS-View */
OSTickStepState = OS_TICK_STEP_WAIT;
break;
default:
/* Invalid case, correct situation */
step = OS_TRUE;
OSTickStepState = OS_TICK_STEP_DIS;
break;
}
if (step == OS_FALSE) {
/* Return if waiting for step command */
return;
}
#endif
ptcb = OSTCBList;
/* Point at first TCB in TCB list */
while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) { /* Go through all TCBs in TCB list */
OS_ENTER_CRITICAL();
if (ptcb->OSTCBDly != 0) {
/* No, Delayed or waiting for event with TO */
if (--ptcb->OSTCBDly == 0) {
/* Decrement nbr of ticks to end of delay */
/* Check for timeout */
if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
ptcb->OSTCBStat &= ~OS_STAT_PEND_ANY; /* Yes, Clear status flag */
ptcb->OSTCBPendTO = OS_TRUE; /* Indicate PEND timeout */
} else {
ptcb->OSTCBPendTO = OS_FALSE;
}
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */
OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make ready */
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
}
}
ptcb = ptcb->OSTCBNext;
/* Point at next TCB in TCB list */
OS_EXIT_CRITICAL();
}
}
}
3.3时间管理
1.任务延时
void OSTimeDly (INT16U ticks)
{
INT8U y;
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
if (ticks > 0) { /* 0 means no delay! */
OS_ENTER_CRITICAL();
y = OSTCBCur->OSTCBY; /* Delay current task */
OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next task to run! */
}
}
用时,分,秒,微妙为参数的延时任务OSTimeDlyHMSM(),其函数原型如下:
#if OS_TIME_DLY_HMSM_EN > 0
INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli)
{
INT32U ticks;
INT16U loops;
#if OS_ARG_CHK_EN > 0
if (hours == 0) {
if (minutes == 0) {
if (seconds == 0) {
if (milli == 0) {
return (OS_TIME_ZERO_DLY);
}
}
}
}
if (minutes > 59) {
return (OS_TIME_INVALID_MINUTES); /* Validate arguments to be within range */
}
if (seconds > 59) {
return (OS_TIME_INVALID_SECONDS);
}
if (milli > 999) {
return (OS_TIME_INVALID_MILLI);
}
#endif
/* Compute the total number of clock ticks required.. */
/* .. (rounded to the nearest tick) */
ticks = ((INT32U)hours * 3600L + (INT32U)minutes * 60L + (INT32U)seconds) * OS_TICKS_PER_SEC
+ OS_TICKS_PER_SEC * ((INT32U)milli + 500L / OS_TICKS_PER_SEC) / 1000L;
loops = (INT16U)(ticks / 65536L); /* Compute the integral number of 65536 tick delays */
ticks = ticks % 65536L; /* Obtain the fractional number of ticks */
OSTimeDly((INT16U)ticks);
while (loops > 0) {
OSTimeDly((INT16U)32768u);
OSTimeDly((INT16U)32768u);
loops--;
}
return (OS_NO_ERR);
}
调用延时函数,当规定的延时时间期满,或者有其他任务通过调用函数OSTimeDlyResume()取消延时时,他会立即进入就绪状态。如果任务比正在运行的任务优先级别高,则立即引发一次任务调度
3.3.2取消任务延时
INT8U OSTimeDlyResume(INT8U prio)
3.3.3 获取和设置系统时间
INT32U OSTimeGet(void)
每发生1个时钟节拍,OSTime的值加1,OSTimeGet()可获取OSTime的值