UCOS操作系统——中断和时间管理(七)

UCOS操作系统

前言

在 STM32 中是支持中断的,中断是一个硬件机制,主要用来向 CPU 通知一个异步事件发生了,这时 CPU 就会将当前 CPU 寄存器值入栈,然后转而执行中断服务程序,在 CPU 执行中断服务程序的时候有可能有更高优先级的任务就绪,那么当退出中断服务程序的时候,CPU 就会直接执行这个高优先级的任务。

一、UCOS中断

我们学习的重点就是—如何在UCOSIII下编写中断服务函数!

void XXX_Handler(void) (1)
{
    
     
OSIntEnter(); //进入中断 (2)
 
用户自行编写的中断服务程序; //这部分就是我们的中断服务程序 (3)
 
 OSIntExit(); //触发任务切换软中断 (4)
} 

(1) 中断服务程序,XXX 为不同中断源的中断函数名字。
(2) 首先调用 OSIntEnter()函数来标记进入中断服务函数,并且记录中断嵌套次数。
(3) 这部分就是我们需要自行编写的中断服务程序了,也就是我们平时不使用 UCOSIII 时
的中断服务程序。
(4) 退出中断服务函数的时候调用 OSIntExit(),发起一次中断级任务切换。

void OSIntEnter (void)
{
    
    
if (OSRunning != OS_STATE_OS_RUNNING) {
    
     //判断 UCOSIII 是否运行,
return; 
 }
if (OSIntNestingCtr >= (OS_NESTING_CTR)250u) {
    
     //判断中断嵌套次数是否大于 250
 return; 
 }
 OSIntNestingCtr++; //中断嵌套次数加 1 }

从上面代码中我们可以看出 OSIntEnter()函数其实就是将 OSIntNestingCtr 进行简单的加1操作,用来中断嵌套的次数而已。

二、临界段代码保护

临界段代码也叫做临界区,是指那些必须完整连续运行,不可被打断的代码段。当访问这些临界段代码的时候需要对这些临界段代码进行保护。
当宏OS_CFG_ISR_POST_DEFERRED_EN为0时,UCOSIII使用关中断的方式来保护临界段代码,当设置为1的时候就会采用给调度器上锁的方式来保护临界段代码。
UCOSIII定义了一个进入临界段代码的宏:OS_CRITICAL_ENTER(),定义了两个退出临界段代码的宏:OS_CRITICAL_EXIT和OS_CRITICAL_EXIT_NO_SCHED()。
在这里插入图片描述
在这里插入图片描述
进入临界段代码保护一定要调用这个函数

CPU_SR_ALLOC();

三、时间管理

UCOSIII中的任务是一个无限循环并且还是一个抢占式内核,为了使高优先级的任务不至于独占CPU,可以给其他优先级较低任务获取CPU使用权的机会,UCOSIII中除空闲任务外的所有任务必须在合适的位置调用系统提供的延时函数,让当前的任务暂停运行一段时间并进行一个任务切换。

延时函数有两种,OSTimeDly()和OSTimeDlyHMSM()。
OSTimeDly()函数有三种工作模式:相对模式、周期模式和绝对模式。
OSTimeDlyHMSM()函数仅在相对模式下工作。
在UCOS操作系统种,为了不让一些高优先级的独占CPU,可以用延迟函数来给低优先级函数运行的机会,也不是只有延时函数,只要能发生任务调度就可以。

1. OSTimeDly()函数

void OSTimeDly (OS_TICK dly,OS_OPT opt,OS_ERR *p_err)

dly: 指定延时的时间长度,这里单位为时间节拍数。
opt: 指定延迟使用的选项,有四种选项。
OS_OPT_TIME_DLY 相对模式
OS_OPT_TIME_TIMEOUT 和 OS_OPT_TIME_DLY 一样
OS_OPT_TIME_MATCH 绝对模式
OS_OPT_TIME_PERIODIC 周期模式
p_err: 指向调用该函数后返回的错误码

“相对模式”在系统负荷较重时有可能延时会少一个节拍,甚至偶尔差多个节拍,在周期
模式下,任务仍然可能会被推迟执行,但它总会和预期的“匹配值”同步。因此,推荐使用“周期模式”来实现长时间运行的周期性延时。
“绝对模式”可以用来在上电后指定的时间执行具体的动作,比如可以规定,上电 N 秒后
关闭某个外设。
绝对延迟和相对延时可以看我之前FreeRTOS学习时的博客,那篇博客更加详细。
总结一下,就是相对延迟是可以被打断的,也就是你想延迟3秒执行但是中间发生了一个事耽误了一秒,他就会4秒钟执行,但是绝对延迟的意思是,中间有个任务耽误了一秒,执行的时候两秒钟后就会执行那个任务,不会等你3秒的,规定的时间维度就是3秒,就算有事情打断了,耽误的时间就直接丢掉。

扫描二维码关注公众号,回复: 13758217 查看本文章

2.OSTimeDlyHMSM()函数

我们也可调用 OSTimeDlyHMSM() 函数来更加直观的来对某个任务延时,
OSTimeDlyHMSM()函数原型如下:

void OSTimeDlyHMSM (CPU_INT16U hours, //需要延时的小时数
 CPU_INT16U minutes, //需要延时的分钟数
 CPU_INT16U seconds, //需要延时的秒数
 CPU_INT32U milli, //需要延时的毫秒数
 OS_OPT opt, //选项
 OS_ERR *p_err)

hours、minutes、seconds、milli: 前面这四个参数用来设置需要延时的时间,使用的是:小时、分钟、秒和毫秒这种格式,这个就比较直观了,这个延时最小单位和我们设置的时钟节拍频率有关,比如我们设置时钟节拍频率 OS_CFG_TICK_RATE_HZ 为 200 的话,那么最小延时单位就是 5ms。
opt: 相比 OSTimeDly()函数多了两个选项 OS_OPT_TIME_HMSM_STRICT 和
OS_OPT_TIME_HMSM_NON_STRICT,其他四个选项都一样的。
使用 OS_OPT_TIME_HMSM_NON_STRICT 选项的话将会检查延时参数,
hours 的范围应该是 0~99,minutes 的范围应该是 0~59,seconds 的范围为 0~59,
milli的范围为 0~999。
使用 OS_OPT_TIME_HMSM_NON_STRICT 选项的话,hours 的范围为 0~999,
minutes 的范围为 0~9999,seconds 的范围为 0~65535,mili 的范围为 0~4294967259。
p_err: 调用此函数后返回的错误码

3.OSTimeDlyResume()函数

OSTimeDlyResume()函数取消任务延时
延时任务任务可通过在其他任务中调用函数OSTimeDlyResume()取消延时而进入就绪状态,此函数最后会引发一次任务调度。

void OSTimeDlyResume (OS_TCB *p_tcb,OS_ERR *p_err)

p_tcb: 需要恢复的任务的任务控制块。
p_err: 指向调用这个函数后返回的错误码。

4.OSTimeGet()和 OSTimeSet()函数

OSTimeGet()函数用来获取当前时钟节拍计数器的值。OSTimeSet()函数可以设置当前时钟
节拍计数器的值,这个函数谨慎使用。

猜你喜欢

转载自blog.csdn.net/qq_51963216/article/details/123900129