FreeRTOS 任务的四种状态

FreeRTOS主要分为运行状态(Running State)和非运行状态(Not-Running State)。
其中,非运行状态又分为就绪状态(Ready State)、阻塞状态(Blocked State)、暂停状态(Suspened State)。

状态含义
运行状态被调度器选中,正在由单片机的CPU执行它的任务代码
就绪状态等待被执行
阻塞状态因等待先决条件(等待超时或等待事件)而主动放弃执行权
暂停状态调用vTaskSuspend()使其不能被调度器选中

调用vTaskDelay()实际上是通过让当前任务进入阻塞状态来实现的,下面分析闪灯程序各个任务的状态变化。

1234567891011
//LED的任务代码static void prvLEDTask(void *pvParameters){	for(;;)	{		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);		vTaskDelay(pdMS_TO_TICKS(100));	}}//创建LED任务xTaskCreate( prvLEDTask, "LED", 128, NULL, 1, NULL );

时序图为:
时序图
任务执行vTaskDelay后,进入阻塞状态,放弃执行权。程序只有2个程序,此时,空闲任务运行。

为什么要使用vTaskDelay()?

过去使用HAL_Delay(),现在使用vTaskDelay()延迟。

vTaskDelay()是通过让调用它的任务进入阻塞状态来实现延迟的,调度器会在任务和空闲之间不断切换

HAL_Delay()是通过不断执行一个while循环,此时CPU会一直执行while循环,更低优先级的任务不会得到执行的机会。

例:使用HAL_Delay延迟来实现2个LED闪烁,并设置为不同优先级,LED1设置为1,LED2设置为2,观察现象,分析原因。

12345678910111213141516171819202122232425262728293031
/* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 *///LED1的任务代码static void prvLED1Task(void *pvParameters){for(;;){HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);HAL_Delay(100);HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);HAL_Delay(100);}}//LED2的任务代码static void prvLED2Task(void *pvParameters){for(;;){HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);HAL_Delay(100);HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);HAL_Delay(100);}}/* USER CODE END 0 */ /* USER CODE BEGIN 2 */xTaskCreate( prvLED1Task, "LED1", 128, NULL, 1, NULL );xTaskCreate( prvLED2Task, "LED2", 128, NULL, 2, NULL );vTaskStartScheduler();//启用调度器/* USER CODE END 2 */

代码现象是只有LED2闪烁,LED1不闪烁。
因为HAL_Delay的本质是不断在调用while循环,因此LED2一直有代码在执行,始终处于运行状态。LED1任务没有执行的机会,因此看不到LED1闪烁。

🔍 ×