1.UCOSIII 中断处理过程
UCOSIII 是支持中断嵌套的, 既高优先级的中断可以打断低优先级的中断,在 UCOSIII 中使用 OSIntNestingCtr 来记录中断嵌套次数,最大支持 250 级的中断嵌套,每进入一次中断服务函数 OSIntNestingCtr 就会加 1,当退出中断服务函数的时候 OSIntNestingCtr 就会减 1。
编写
UCOSIII
的中断服务程序的时候需要使用到两个函数
OSIntEnter()
和
OSIntExit()
,
OSIntExit()
函数是中断级任务调度器,
OSIntEnter()
的函数代
码如下:
void OSIntEnter (void)
{
if (OSRunning != OS_STATE_OS_RUNNING) { // 判断 UCOSIII 是否运行,
return;
}
if (OSIntNestingCtr >= (OS_NESTING_CTR)250u) { // 判断中断嵌套次数是否大于 250
return;
}
OSIntNestingCtr++; // 中断嵌套次数加 1
}
码如下:
void OSIntEnter (void)
{
if (OSRunning != OS_STATE_OS_RUNNING) { // 判断 UCOSIII 是否运行,
return;
}
if (OSIntNestingCtr >= (OS_NESTING_CTR)250u) { // 判断中断嵌套次数是否大于 250
return;
}
OSIntNestingCtr++; // 中断嵌套次数加 1
}
OSIntEnter()
函数其实就是将
OSIntNestingCtr
进行简单的加一操作,用来中断嵌套的次数而已。
中断服务函数:
void XXX_Handler(void) (1)
{
OSIntEnter(); // 进入中断 (2)
用户自行编写的中断服务程序; // 这部分就是我们的中断服务程序 (3)
OSIntExit(); // 触发任务切换软中断 (4)
}
(1) 中断服务程序, XXX 为不同中断源的中断函数名字。
(2) 首先调用 OSIntEnter() 函数来标记进入中断服务函数,并且记录中断嵌套次数。
(3) 这部分就是我们需要自行编写的中断服务程序了,也就是我们平时不使用 UCOSIII 时
的中断服务程序。
(4) 退出中断服务函数的时候调用 OSIntExit() ,发起一次中断级任务切换。
中断服务函数:
void XXX_Handler(void) (1)
{
OSIntEnter(); // 进入中断 (2)
用户自行编写的中断服务程序; // 这部分就是我们的中断服务程序 (3)
OSIntExit(); // 触发任务切换软中断 (4)
}
(1) 中断服务程序, XXX 为不同中断源的中断函数名字。
(2) 首先调用 OSIntEnter() 函数来标记进入中断服务函数,并且记录中断嵌套次数。
(3) 这部分就是我们需要自行编写的中断服务程序了,也就是我们平时不使用 UCOSIII 时
的中断服务程序。
(4) 退出中断服务函数的时候调用 OSIntExit() ,发起一次中断级任务切换。
2.
直接发布和延迟发布
UCOSIII
对从中断发布消息或者信号的处理有两种模式:直接发布和延迟发布两种方式。
通过宏
OS_CFG_ISR_POST_DEFERRED_EN
来选择使用直接发布还是延迟发布。宏
OS_CFG_ISR_POST_DEFERRED_EN
在
os_cfg.h
文件中有定义, 当定义为
0
时
使用直接发布模式,定义为 1 的时候使用延迟发布模式。
使用直接发布模式,定义为 1 的时候使用延迟发布模式。
使用直接发布模式的话,
UCOSIII
会对临界段代码采用关闭中断的保护措施,这样就会延长中断的响应时间。
延迟发布:
通过给任务调度器上锁的方法来保护临界段代码,在延迟发布模式下基本不存在关闭中断的情况 。
中断服务程序通过调用系统的发布服务函数向任务发布消息或信号,在延迟发布模式下,这个过程不是直接进行发布操作,而是将这个发布函数调用和相应的参数写入到专用队列中,该队列称为中断队列。然后使中断队列处理任务进入就绪态
,
这个任务是
UCOSIII
的内部任务,并且具有最高优先级
(0)
。
中断服务程序处理结束时,
UCOSIII
切换执行中断队列处理任务, 该任务从中断队列中提取出发布函数调用信息,此时仍需要关闭中断以防止中断服务程序同时对中断队列进行访问。中断队列处理任务提取出发布函数调用的信息后重新开中断,锁定任务调度器,然后进行发布函数调用,相当于发布函数调用一直是在任务级代码中进行的,这样本来应该在临界段中处理的代码就被放到了任务级完成。
中断队列处理任务将中断队列处理完,将自身挂起,并重新启动任务调度来运行处于最高优先级的就绪任务。如果原先被中断的任务仍然是最高优先级的就绪任务,则
UCOSIII
恢复运行这个任务。
由于中断队列处理任务的发布操作使得更重要的任务进入就绪态,内核将切换到更高优先级的任务运行。
在使用延迟发布模式额外增加的操作都是为了避免使用关中断来保护临界段代码。这些额外增加的操作仅包括将发布调用及其参数复制到中断队列中、从中断队列提取发布调用和相关参数以及一次额外的任务切换。
3.
OSTimeTick()
函数
钟,在 Systick 的中断服务程序中就必须调用 OSTimeTick() ,
进入临界段代码的时候使用宏 OS_CRITICAL_ENTER() ,退出临界区的时候使用宏 OS_CRITICAL_EXIT() 或者 OS_CRITICAL_EXIT_NO_SCHED() 。
当宏 OS_CFG_ISR_POST_DEFERRED_EN 定义为 0 的时候,进入临界区的时候 UCOSIII 会使用关中断的方式,退出临界区以后重新打开中断。当 OS_CFG_ISR_POST_DEFERRED_EN 定义为 1 的时候进入临界区前是给调度器上锁,并在退出临界区的时候给调度器解锁。
两个宏
CPU_CRITICAL_ENTER
和
CPU_CRITICAL_EXIT
,这两个宏最终调用的还是函数
CPU_SR_Save()
和
CPU_SR_Restore()
,这两个函数我们前面介绍
过,就是使用汇编实现的关闭和打开中断。
过,就是使用汇编实现的关闭和打开中断。