抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

任务管理

系统中任务运行调度方式

  1. 每个任务都是在独立的堆栈环境运行,运行的任务越多需要的堆栈空间越多。

  2. 任务之间的切换是基于抢占优先级的,高优先级抢占低优先级

  3. 任务切换的寻找方式

    • 基于链表,从高往低查,任务创建时已经完成排序
    • 计算前导零指令CLZ​,直接读出优先级任务(stm32​使用这种方式)
  4. 相同优先级任务则采用时间片轮转,无更高优先级任务情况下。

任务状态

创建的任务一般有四种状态

  1. 就绪态:新创建的任务处于该状态,等待调度器调度

  2. 运行态:正在运行的任务,运行的是最高优先级的就绪态任务

  3. 阻塞态:不在就绪态列表中,处于中断或等待

  4. 挂起态:

    • 挂起态任务调度器不可见
    • 使用vTaskSuspend()​进入挂起态
    • 使用vTaskResume()​或vTaskResumeFromISR()​从挂起态恢复
    • 和阻塞态的区别在于:挂起态用于长时间不处理的任务;阻塞态的任务系统需要判断是否超时

常见任务操作函数

  1. vTaskSuspend()​任务挂起:等效于该任务被“冻结”或者“休眠”

  2. vTaskSuspendAll()​全任务挂起

  3. vTaskResume()​任务恢复:将被挂起的任务恢复

  4. vTaskResumeFromISR()​中断专用任务恢复

    • 无论使用几次vTaskSuspend()​,只需要使用一次恢复函数即可恢复
    • 需要配置INCLUDE_vTaskResumeFromISR 1​的宏定义
  5. vTaskResumeAll()​全任务恢复

  6. vTaskDelete()​任务删除

  7. vTaskDelay()​任务延时,延时时间为Systick

  8. vTaskDelayUntil()​任务绝对延时

设计一个任务管理

通过2个Button​控制一个LED​灯任务的挂起和恢复,需要注意的是:按键检测最好设计成通用函数,保留GPIO​和Pin​让每个按键的检测尽量避免耦合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//按下状态,0为低有效道通,此处根据接线而定
#define KEY_ON 0
#define KEY_OFF 1

uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
/*检测是否有按键按下 */
if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )
{
/*等待按键释放 */
while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON );
return KEY_ON ;
}
else
return KEY_OFF;
}

建立一个按键检测的任务,根据按键检测来判断是否导通,然后其中一个按键用于挂起任务,另一个按键用于恢复任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static void KEY_Task(void *paramter)
{
while(1)
{
if( Key_Scan(GPIOB,GPIO_Pin_1) == 0 )
{
/* Button1 被按下 */
printf("按下开启键,LED0任务挂起\r\n");
vTaskSuspend(LED0_Task_Handle);/* 挂起LED任务 */
printf("挂起成功\r\n");
}
if( Key_Scan(GPIOB,GPIO_Pin_10) == 0 )
{
/* Button1 被按下 */
printf("按下关闭键,LED0任务恢复\r\n");
vTaskResume(LED0_Task_Handle);/* 恢复LED任务! */
printf("恢复成功\r\n");
}
vTaskDelay(20);

}
}