Freertos系统(任务挂起和恢复)
如果不想看的可以直接使用git把我的代码下载出来,里面工程挺全的,后期会慢慢的补注释之类的
码云地址:stm32学习笔记: stm32学习笔记源码
如果不会使用git快速下载可以选择直接下载压缩包或者去看看git的使用
Git入门教程-CSDN博客
目录
一 函数讲解
函数说明:本章3个函数,挂起、恢复、在中断中恢复任务
1.1 挂起函数
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
需要开启宏:INCLUDE_vTaskSuspend 配置为 1
之后使用方法就是传入句柄,删除自己就传入NULL
1.2 恢复函数
vTaskResume()
传入句柄即可:需要打开宏:INCLUDE_vTaskSuspend
1.3 恢复函数(中断中恢复)
xTaskResumeFromISR()
开启宏:INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1
二 任务测试
2.1 挂起函数
我们先测试一下使用函数挂起任务2:PS框架在创建任务中有可以去看看
void KEY1_IRQHandler(void)
{//确保是否产生了EXTI Line中断if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {taskENTER_CRITICAL();vTaskSuspend(task2_handler);taskEXIT_CRITICAL();//清除中断标志位EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE); }
}void task1( void * pvParameters )
{while (1){printf("task 1\r\n");vTaskDelay(pdMS_TO_TICKS(500));}
}void task2( void * pvParameters )
{while (1){printf("task 2\r\n"); vTaskDelay(pdMS_TO_TICKS(500));}
}
按下按键后,task2被挂起了。测试成功
2.2 任务恢复函数
2.2.1 普通恢复函数
普通任务恢复函数,这里我直接拿vTaskResume()来在中断中给大家测试删除:这里应该是会引起程序崩溃的,最后给大家说原因
void KEY1_IRQHandler(void)
{//确保是否产生了EXTI Line中断if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {taskENTER_CRITICAL();vTaskSuspend(task2_handler);taskEXIT_CRITICAL();//清除中断标志位EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE); }
}void KEY2_IRQHandler(void)
{//确保是否产生了EXTI Line中断if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {vTaskResume(task2_handler);//清除中断标志位EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE); }
}
结果
= =没有被卡死,应该是我手动中断太慢,或者一直amr架构保护之类的。但是切记不能把这个释放函数用在中断里面
2.2.2 恢复函数(中断中恢复)
任务恢复函数:xTaskResumeFromISR() 在中断里面使用这个函数靠谱一点
void KEY2_IRQHandler(void)
{// 声明变量记录是否需要触发调度BaseType_t xHigherPriorityTaskWoken = pdFALSE;// 确保是否产生了EXTI Line中断if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) {// 调用中断版恢复函数,并获取返回值if (xTaskResumeFromISR(task2_handler) == pdTRUE) {// 若返回pdTRUE,说明被恢复的任务优先级高于当前运行任务xHigherPriorityTaskWoken = pdTRUE;}portYIELD_FROM_ISR(xHigherPriorityTaskWoken);// 清除中断标志位EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);}
}
关键补充说明
-
xHigherPriorityTaskWoken
变量:
用于标记 “被恢复的任务优先级是否高于当前正在运行的任务”。当xTaskResumeFromISR()
返回pdTRUE
时,说明被恢复的task2
优先级更高,需要立即调度它运行。 -
portYIELD_FROM_ISR()
调度触发:
这是中断专用的调度触发函数,作用是在中断退出前完成任务切换。如果缺少这一步,即使task2
优先级更高,也需要等待当前任务时间片耗尽才能运行,可能导致实时性下降。 -
句柄有效性检查:
为了更健壮,可增加句柄非空判断,避免恢复无效任务: -
这样可以确保被恢复的任务在优先级更高时能立即执行,同时避免内核数据结构冲突,保证系统稳定性。
我这里按下按键1后,task2被挂起了,之后按下按键2,task2正常恢复了
2.3 两个函数的区别总结
- 任务上下文:内核会自动处理数据结构的保护(如通过调度器锁),因此
vTaskResume()
无需额外操作即可安全修改任务状态。 - 中断上下文:中断优先级高于所有任务,直接修改内核数据可能导致冲突(如任务列表正在被修改时被中断打断)。
xTaskResumeFromISR()
内部通过特殊的原子操作实现安全访问,且需要手动触发调度(portYIELD_FROM_ISR()
),避免中断嵌套导致的状态混乱。
2.4 错误使用的后果
- 在中断中调用
vTaskResume()
:会导致内核数据结构损坏,可能引发系统崩溃(HardFault)或任务调度异常。 - 在任务中调用
xTaskResumeFromISR()
:虽然不会报错,但属于冗余操作(返回值处理和手动调度逻辑多余),不符合编程规范。
三 总结
vTaskResume()
:任务中使用,简单恢复被挂起任务,自动处理调度。xTaskResumeFromISR()
:中断中使用,安全恢复任务,需手动触发调度,返回值指示是否需要切换任务。