第3章 μC/OS-Ⅱ的中断和时钟
3.1 μC/OS-Ⅱ的中断过程
☆μC/OS-Ⅱ的中断过程:系统接收到中断请求后,如果这时CPU处于中断允许状态(即中断开放),系统会中止正在运行的当前任务,而按照中断向量的指向转而去运行中断服务子程序;当中断服务子程序的运行结束后,系统将会根据情况返回到被中止的任务继续运行,或者转向运行另一个具有更高优先级别的就绪任务。
☆可剥夺的μC/OS-Ⅱ内核,中断服务子程序运行结束后,系统根据情况进行任务调度,去运行优先级别最高的就绪任务,并不一定是被中断的任务。
☆幢系统允许中断嵌套,即高优先级别的中断请求可中断低优先级别的中断服务程序的运行。全局变量OSIntNeating记录中断嵌套的层数。
☆μC/OS-Ⅱ响应中断的过程示意图:
☆中断服务函数OSIntEnter()(把全局变量OSIntNesting加1,用以记录中断嵌套的层数),在中断服务程序保护被中断任务的断点数据之后,运行用户中断服务代码之前来调用:
void OSIntEnter(void)
{
if(OSRunning == TRUE)
{
if(OSIntNesting < 255)
{
OSIntNesting++; //中断嵌套层数计数器加1
}
}
}
☆退出中断服务函数OSIntExit()
流程图:
在中断嵌套层数计数器为0,调度器未被锁定且从任务就绪表中查找到的最高级就绪任务又不是被中断的任务的条件下将要进行任务切换,否则就返回被中断的服务子程序。
源代码:
void OSIntExit(void)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
if(OSRunning == TRUE)
{
OS_ENTER_CRITICAL();
if(OSIntNesting > 0)
{
OSIntNesting--; //中断嵌套层数计数器减1
}
if((OSIntNesting == 0) && (OSLockNesting == 0))
{
OSIntExitY = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
if(OSPrioHighRdy != OSPrioCur)
{
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OSIntCtxSw();
}
}
OS_EXIT_CRITICAL();
}
}
☆一个中断服务程序的流程:
☆中断级任务切换函数(函数在中断嵌套层数计数器为0,调度器未被锁定且从任务就绪表中查找到的最高级就绪任务又不是被中断的任务的条件下,将要运行任务切换,中断级任务切换函数就是中断服务程序中调用的负责任务切换工作的函数)
中断级任务切换函数OSIntCtxSw()示意代码如下:
OSIntCtxSw()
{
OSTCBCur = OSTCBHighRdy; //任务控制块的切换
OSPrioCur = OSPrioHighRdy;
SP = OSTCBHighRdy -> OSTCBStkPtr; //使SP指向待运行任务堆栈
用出栈指令把R1、R2、…弹入CPU的通用寄存器中;
RETI; //中断返回,使PC指向待运行任务
}
☆应用程序中的临界段:
临界段:在应用程序中不受任何干扰地连续运行的代码。为了在运行时不受中断所打断,在临界代码前必须用关中断指令使CPU屏蔽中断请求,而在临界段代码后必须开中断指令解除屏蔽,使得CPU可以响应中断请求。
☆为了增强μC/OS-Ⅱ的可移植性,μC/OS-Ⅱ用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()这两个宏来实现中断的开放和关闭,把系统硬件相关的关中断和开中断的指令分别封装在这两个宏中。
☆宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()的实现方法:
1.直接使用处理器的中断和关中断指令来实现,需令常数OS_CRITICAL_METHOD = 1。
代码如下:
#define OS_ENTER_CRITICAL() \
asm(“DI”) //关中断
#define OS_EXIT_CRITICAL() \
asm(“EI”) //开中断
2.在宏OS_ENTER_CRITICAL()中,把CPU的允许中断标志保存在堆栈中,然后再关闭中断,这样在临界段结束时,即在调用宏OS_EXIT_CRITICAL()时,只要把堆栈中保存的CPU允许中断状态恢复即可,可以保证CPU中断允许标志的状态在临界段前和后不发生变化。
代码如下:
#define OS_ENTER_CRITICAL() \
asm(“PUSH PSW”) \ //通过保存程序状态字来保存中断允许标志
asm(“DI”) //关中断
#define OS_EXIT_CRITICAL() \
asm(“POP PSW”) //恢复中断允许标志
3.(前提:用户使用的C编译器只有扩展功能)用户可获得程序状态字的值,把该值保存在C语言函数的局部变量中,不必压到堆栈里。
代码如下:
#define OS_ENTER_CRITICAL() \
cpu_sr = get_processor_psw(); \ //通过保存程序状态字在全局变量sr中
disable_interrupts(); //关中断
#define OS_EXIT_CRITICAL() \
set_processor_psw(cpu_sr); //用sr恢复程序状态字
需令常数OS_CRITICAL_METHOD = 3。
|