【FreeRTOS#5】任务挂起与恢复实例
问题纠正
在上一节中讲述了关于任务创建和删除的例程,在代码中有一个任务优先级的问题没有解决
我们给启动任务的优先级是最低的,其实这样有一定风险
#define START_TASK_STACK 128
#define STACK_TASK_PRIORITY 1
void start_task(void * pvParameters);
TaskHandle_t start_task_handle;
潜在风险:如果其他高优先级任务给的阻塞时间不够,可能任务创建后启动任务根本来不及删除自己的任务控制块,导致内存泄漏。
这里给出两个解决方案:
1. 在创建完其他任务后,临时把自己的优先级拉到最高(不一定能解决)
2. 初始化配置时就把启动任务优先级配置为最高
一、API函数
任务挂起与恢复功能实现的API有:
vTaskSuspend(); 挂起任务
vTaskResume(); 恢复任务
xTaskResumeFromISR; 中断中恢复被挂起的任务
(1) 任务挂起函数
原型:
void xTaskSuspend(TaskHandle_t xTasktoSuspend)
xTaskToSuspend: 待挂起任务的任务句柄,为NULL表示挂起正在运行的任务自身
使用此函数需要改变config.h中的宏
#define INCLUDE_vTaskSuspend 1
(2)任务恢复函数
void vTaskResume(TaskHandle_t xTasktoResume);
xTasktoResume: 无论任务被重复挂起多少次,Resume一次就能恢复就绪态
使用此函数需要改变config中的宏
#define INCLUDE_vTaskSuspend 1
(3) 中断中任务恢复
BaseType_t xTaskResumeFromISR(TaskHandle_t xTasktoResume)
返回值为:pdTRUE: 任务恢复后需要进行任务切换
pdFALSE: 任务恢复后不需要进行任务切换
在嵌入式系统中,低优先级中断不能打断高优先级,所以,在使用ISR任务恢复时,ISR本身的中断优先级不能高于FreeRTOS的最高中断优先级。
此外,以下两个配置宏需要置为1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xTaskResumeFromISR 1
(4) 任务挂起与恢复
vTaskSuspendALL():挂起任务调度器,调度器停止任务切换,当前任务一直运行下去
xTaskResumeALL () : 恢复任务调度器,调度器继续任务切换
(5)查看任务状态
需要提前使能task跟踪
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
预先开辟一个内存足够的字符串,并将首地址赋给函数
void vTaskList( uint8_t * pcWriteBuffer )
输出结果一般为
名称 状态 优先级 堆栈使用 任务编号
'X'(运行) 'B'(阻塞)、'R'(就绪)、'S'(暂停)或 'D'(删除)。
我们可以使用静态预估法计算需要的内存长度
总长度 = 表头长度 + (每行长度 × 任务数) + 安全余量
任务总数可以通过uxTaskGetNumberOfTasks()获取
二、挂起恢复实验
start_task:用来创建其他的三个任务。
task1:实现LED1每500ms闪烁一次。
task2:实现LED2每500ms闪烁一次。
task3:判断按键按下逻辑,KEY1按下,挂起task1,按下KEY2在任务中恢复task1,KEY3按下,挂起调度器,KEY4按下,恢复调度器,并打印任务的状态。
我们直接从上一节的例程修改,任务1和2没有区别,只要修改3就可以
1. 使能相关配置宏
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 )
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xResumeFromISR 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY 255
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. *//* This is the value being used as per the ST library which permits 16
priority values, 0 to 15. This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define INCLUDE_xTaskGetSchedulerState 1#endif /* FREERTOS_CONFIG_H */
2. 修改任务3内容
void task3(void * pvParameters){while(1){printf("Task 3 Running \r\n");if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0){HAL_Delay(40);if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0){switch(status_key1){case 0: vTaskSuspend(start_task1_handle);status_key1 = 1;break;case 1: vTaskResume(start_task1_handle);status_key1 = 0;break;}
// vTaskDelete(start_task1_handle);
// start_task1_handle=NULL;}}if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==0){HAL_Delay(40);if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==0){switch(status_key0){case 0: vTaskSuspend(start_task2_handle);status_key0 = 1;break;case 1: vTaskResume(start_task2_handle);status_key0 = 0;break;}
// vTaskDelete(start_task1_handle);
// start_task1_handle=NULL;}}vTaskList(pcBuffer);printf("%s\r\n",pcBuffer);vTaskDelay(200);}
}
现象
(1)任务2挂起
(2)任务1挂起