目录
- FreeRTOS学习第6篇--任务状态挂起恢复删除等操作
- 任务的状态
- 设计实验
- IRReceiver_Task任务相关代码片段
- 实验现象
- 本文中使用的测试工程
FreeRTOS学习第6篇–任务状态挂起恢复删除等操作
本文目标:学习与使用FreeRTOS中的几项操作,有挂起恢复删除等操作。
按照本文的描述,应该可以跑通实验并举一反三。
本文实验条件:拥有C语言基础,装有编译和集成的开发环境,比如:Keil uVision5
任务的状态
- 就绪态(Ready):任务已经准备好运行,只等待调度器分配CPU时间片给它。就绪态的任务按照优先级排列在就绪列表中,优先级越高的任务越靠前。
- 运行态(Running):任务正在执行,占用CPU资源。同一时刻,只有一个任务处于运行态,除非使用多核处理器。
- 阻塞态(Blocked):任务因为等待某个事件(如信号量、队列、延时等)而无法运行,被放入阻塞列表中。阻塞态的任务不会占用CPU资源,也不会参与调度。当等待的事件发生时,任务会从阻塞列表中移出,重新进入就绪列表,等待调度。比如:使用函数vTaskDelay()或vTaskDelayUntil()就是进入阻塞状态,或者xSemaphoreTake()等函数也是进阻塞状态。
- 挂起态(Suspended):任务被主动暂停,无论是否有事件发生,都不会运行,被放入挂起列表中。挂起态的任务不会占用CPU资源,也不会参与调度。只有当任务被主动恢复时,才会从挂起列表中移出,重新进入就绪列表,等待调度。比如:直接调用vTaskSuspend()函数。
- 删除态:任务被主动删除,不再存在于任何列表中,也不会再运行。删除态的任务的内存资源会被释放,不会占用任何资源。
设计实验
本次实验就是设计一个实验,来实现任务的一些操作,有删除任务,恢复任务。在本次实验中,将使用两个按键,一个按键用作删除任务,一个按键用作挂起和恢复。基于这个实验情况,我在我的硬件平台进行实验。
IRReceiver_Task任务相关代码片段
void IRReceiver_Task(void * pvParameters)
{
int bRunning;
uint8_t dev, data;
OLED_Init();
IRReceiver_Init();
while(1)
{
OLED_ShowString(0,0,"IR Receiver: ",16);
OLED_ShowString(0,16,"Device Data",16);
if (!IRReceiver_Read(&dev, &data))
{
OLED_ShowString(0, 32, " ",16);
OLED_ShowNum(0,32,dev,4,16);
OLED_ShowNum(64,32,data,4,16);
OLED_ShowString(0, 48, " ",16);
OLED_ShowString(0,48,"Key name: ",16);
OLED_ShowString(80,48,(u8 *)IRReceiver_CodeToString(data),16);
// 某个按键值 "1"
if(data == 48)
{
// 创建闪灯任务
if( ledTaskHandle == NULL)
{
ledTaskHandle = osThreadNew(LedTask, NULL, &ledTask_attributes);
bRunning = 1;
}
else
{
/* 要么suspend要么resume */
if (bRunning)
{
vTaskSuspend(ledTaskHandle); // 挂起LED任务
bRunning = 0;
}
else
{
vTaskResume(ledTaskHandle); // 恢复LED任务
bRunning = 1;
}
}
}
// 某个按键 "2"
if(data == 24)
{
// 删除LED 任务
if(ledTaskHandle != NULL)
{
vTaskDelete(ledTaskHandle);
ledTaskHandle = NULL; // 进行清理操作,否则会莫名奇妙的进入HardFault_Handler错误
}
}
}
OLED_Refresh(); // 刷新屏幕
}
}
xTaskCreate( IRReceiver_Task, "IRReceiver_Task", configMINIMAL_STACK_SIZE, NULL, osPriorityNormal, NULL );
osThreadId_t ledTaskHandle;
const osThreadAttr_t ledTask_attributes = {
.name = "ledTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
void LedTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
HAL_GPIO_TogglePin(LED3_GPIO_Port,LED3_Pin);
mdelay(100);
}
/* USER CODE END StartDefaultTask */
}
实验现象
下载代码到板子上,当我按下1号按钮时,会创建LedTask的任务,当我继续按下1号按钮时,会把LedTask进行挂起或恢复,如果是挂起的状态则进行恢复,如果是恢复的状态则进行挂起,当我按下2号按钮时会把LedTask的任务进行删除,通过这些代码片段就实现了我们本次设计的实验,完美的实现了挂起恢复删除等操作。