参考教程:【正点原子】手把手教你学UCOS-III实时操作系统_哔哩哔哩_bilibili
一、任务的挂起与恢复的API函数
1、概述
(1)任务挂起和恢复的本质就是调用µCOS-III的API函数。
API函数 | 描述 |
OSTaskSuspend() | 挂起任务 |
OSTaskResume() | 恢复任务 |
(2)挂起任务类似暂停任务,它可重新恢复,但删除任务则是将任务永远删除,除非是重新创建任务(任务也会重头开始执行),否则任务将永远消失。
(3)这两个函数不允许在中断中调用,且不能挂起空闲任务。
2、任务挂起函数
(1)任务挂起函数的接口定义:
void OSTaskSuspend
(
OS_TCB* p_tcb, //指向任务控制块的指针
OS_ERR* p_err //指向接收错误代码变量的指针
)
(2)此函数用于无条件地挂起任务,被挂起的任务不会参与任务调度,如果被挂起的任务是当前正在运行的任务,那么就会发起任务调度,将CPU的使用权交给另一个任务。
(3)无论优先级如何,被挂起的任务都将不再被执行(即将任务从就绪列表中暂时移除),直到任务被恢复。
(4)当传入的任务控制块的指针为NULL(或者0),则代表挂起任务自身,也即当前正在运行的任务。
3、任务恢复函数
(1)任务恢复函数的接口定义:
void OSTaskResume
(
OS_TCB* p_tcb, //指向任务控制块的指针
OS_ERR* p_err //指向接收错误代码变量的指针
)
(2)此函数用于恢复被函数OSTaskSuspend挂起的任务,并且只有该函数才能恢复被函数OSTaskSuspend挂起的任务。
(3)可调用多次OSTaskSuspend挂起同一个任务,相应地,解挂时需调用同样次数的OSTaskResume才可恢复任务。
(4)恢复即把任务从新插入到就绪列表,继续运行。
二、任务挂起与恢复实验
1、原理图与实验目标
(1)原理图:
(2)实验目标:
①设计4个任务——start_task、task1、task2、task3:
[1]start_task:用于初始化CPU库、配置Systick中断及优先级,并创建其它三个任务,然后删除自身。
[2]task1:实现LED1状态反转。
[3]task2:实现LED2状态反转。
[4]task3:按下按键1,若task1非挂起,则挂起task1,否则恢复task1;按下按键2,若task2非挂起,则挂起task2,否则恢复task2。
②预期实验现象:
[1]程序下载到板子上后,两个LED灯闪烁。
[2]按下一次按键1后,LED1停止闪烁,接着再按下按键1,LED1恢复闪烁。
[3]按下一次按键2后,LED2停止闪烁,接着再按下按键2,LED2恢复闪烁。
2、实验步骤
(1)将上一章中“任务创建和删除实验”的工程文件夹复制一份,在拷贝版中进行实验。
(2)修改task3的函数实现,并增加两个全局变量用作记录task1和task2的挂起状态。
char task1_state = 0; //记录task1挂起状态(0为非挂起,1为挂起)
char task2_state = 0; //记录task2挂起状态(0为非挂起,1为挂起)
void task3(void)
{
OS_ERR err;
uint8_t key = 0;
while(1)
{
key = Key_GetNum(); //读取按键键值
if(key == 1){
if(task1_state == 0) //若task1非挂起
{
OSTaskSuspend(&task1_tcb, &err); //挂起task1
task1_state = 1; //更改其状态为挂起
}
else if(task1_state == 1) //若task1挂起
{
OSTaskResume(&task1_tcb, &err); //恢复task1
task1_state = 0; //更改其状态为非挂起
}
}
if(key == 2){
if(task2_state == 0) //若task2非挂起
{
OSTaskSuspend(&task2_tcb, &err); //挂起task2
task2_state = 1; //更改其状态为挂起
}
else if(task2_state == 1) //若task2挂起
{
OSTaskResume(&task2_tcb, &err); //恢复task2
task2_state = 0; //更改其状态为非挂起
}
}
OSTimeDly(10, OS_OPT_TIME_DLY, &err); //自我阻塞10ms
}
}
(3)程序完善好后点击“编译”,然后将程序下载到开发板上。
3、程序执行流程
(1)main函数全流程:
①初始化LED模块、按键模块。
②调用UCOS_Test函数。
(2)测试函数全流程:
①创建任务start_task。
②开启任务调度器。
(3)多任务调度执行阶段(发生在开启任务调度器以后):
①start_task任务函数首先进入临界区,在临界区中start_task任务不会被其它任务打断(否则创建task1后,由于task1的优先级较高,start_task任务会被打断),接着start_task任务依次创建任务task1、task2、task3,然后删除自身,接着退出临界区,让出CPU资源。
②三个任务中task3的优先级最高,故优先执行task3,假设先不按下任何按键,task3未接收到任何键码,不做出其它行为,直接自我阻塞10ms,此时task2的优先级最高(除开已阻塞的task3),故执行task2,LED2的状态翻转后,task2自我阻塞500ms,此时未阻塞的就绪任务仅剩task1,故执行task1,LED1的状态翻转后,task1自我阻塞500ms。待task3的自我阻塞时间结束,task3重新抢占CPU,task3自我阻塞后,待task2的自我阻塞时间结束,task2重新抢占CPU,待task1的自我阻塞时间结束,task1重新抢占CPU,以此往复,实现双LED灯闪烁。
③在某次执行task3时,若task1和task2均未挂起,按下按键1,task1将会被挂起。(按下按键1的过程中因为按键消抖使用了OSTimeDly函数,task3会进行短暂的自我阻塞,图中未示出,不过由于task3的优先级最高,阻塞时间结束后task3可重新抢占CPU)
④在某次执行task3时,若task1挂起、task2未挂起,按下按键1,task1将会被恢复。(按下按键1的过程中因为按键消抖使用了OSTimeDly函数,task3会进行短暂的自我阻塞,图中未示出,不过由于task3的优先级最高,阻塞时间结束后task3可重新抢占CPU)
⑤在某次执行task3时,若task1和task2均未挂起,按下按键2,task2将会被挂起。(按下按键2的过程中因为按键消抖使用了OSTimeDly函数,task3会进行短暂的自我阻塞,图中未示出,不过由于task3的优先级最高,阻塞时间结束后task3可重新抢占CPU)
⑥在某次执行task3时,若task2挂起、task1未挂起,按下按键2,task2将会被恢复。(按下按键2的过程中因为按键消抖使用了OSTimeDly函数,task3会进行短暂的自我阻塞,图中未示出,不过由于task3的优先级最高,阻塞时间结束后task3可重新抢占CPU)