上一篇博文介绍了内核是怎么在时钟节拍到来是更新节拍列表的,本文介绍任务插入节拍列表的实现过程,在调用延时函数时也会涉及到这个过程。
ucosiii中的任务是一个无限循环并且还是一个抢占式内核,为了使高优先级的任务不至于独占CPU,可以给其他优先级较低的任务获取CPU的使用权,ucosiii除空闲任务外的所有任务必须在合适的位置调用系统提供的延时函数或者任务调度函数,让当前的任务暂停运行一段时间并进行一个任务切换。
从串口打印出来的结果来看,精度还是相当高的,延时时间都是偏少的。存在些许误差的原因主要是在插入的时候可能在两个节拍的任何时刻,退出延时时,一定是在节拍到来处理节拍任务的时候。如图所示,虽然设置延时节拍个数是5个,但是的节拍比大部分都会小于5个,途中的小黑块表示节拍任务的处理。
延时函数的使用:延时函数是用来阻塞任务,调用这个函数之后任务会让出CPU,OS执行调度,执行就绪列表中优先级最高的任务。这个函数和平时写的延时函数不一样,它不会占用CPU。同OSTimeDlyHMSM函数一样,OSTimeDly函数也可以用来延时,但是OSTimeDly函数设置延时的单位是节拍数,当我们设置时钟节拍频率为1000HZ的时候,一个节拍数就是1ms。
取消任务延时: 延时任务可通过在其他任务中调用函数OSTimeDlyResume()取消延时而进入就绪状态,此函数的结尾会引发一次任务调度。
临界区:
临界段代码也叫临界区,是指那些必须连续运行,不可被打断的代码段,当访问这些临界区代码的时候需要对这些临界段代码进行保护。
宏OS_CFG_ISR_POST_DEFFERED_EN:
0:ucosiii使用关中断的方式来保护临界段代码。
1:采用给调度器上锁的方式来保护临界段代码。
如果OSTimeDly()函数调用OS_TickInsert()函数将当前任务插入节拍列表成功的话,就会调用OS_RdyListRemove()函数将当前任务从任务就绪列表中删除,并将系统切换至其他任务。
OSTimeGet()函数用于或许当前的时钟节拍的计数值
OSTimeSet()函数用于设置当前的时钟节拍计数值(最好不要使用)
总结:本文讲解了延时函数的使用,调用延时函数的本质就是,先将任务插入节拍列表,再进行任务切换让其他任务运行;接着节拍列表就会在时钟节拍到来的时候管理这些任务,并快速处理到期的任务。处理的时候还要检查任务的状态是否跟延时有关,如果任务单纯只是延时状态,那么直接将任务脱离节拍列表后就可以就绪;如果任务不只是延时状态,还有挂起状态,脱离节拍列表后还需要处于挂起状态。任务脱离和插入节拍列表其实是一个双向链表的插入和脱离过程,这个过程用到了哈希算法。可以通过调用函数OSTimeDlyResume解除任务的延时状态。