Freertos任务的管理
提示:文章来自正点原子和野火
文章目录
- Freertos任务的管理
- 前言
- 一、任务的四种状态
- 二、 四种状态的关系图
- 三、函数
- vTaskSuspend();挂起
- vTaskResume() ;解挂函数
- 四、代码示例
- 总结
前言
使用Freertos,创建任务,运行任务,必须知道怎么配置任务的状态,并将其修改运行的状态,做到想让哪个任务保证必须优先的情况下,也能保证其他任务的实时性。所有要知道任务有几种运行状态
,还要知道怎么修改任务的状态。
`
一、任务的四种状态
FreeRTOS 系统中的每一任务都有多种运行状态。系统初始化完成后,创建的任务就可
以在系统中竞争一定的资源,由内核进行调度。
任务状态通常分为以下四种:
- 运行态
如果一个任务得到 CPU 的使用权,即任务被实际执行时,那么这个任务处于运行态。如果
运行 RTOS 的 MCU 只有一个处理器核心,那么在任务时刻,都只能有一个任务处理运行态。 - 就绪态
如果一个任务已经能够被执行(不处于阻塞态后挂起态),但当前还未被执行(具有相同优
先级或更高优先级的任务正持有 CPU 使用权),那么这个任务就处于就绪态。 - 阻塞态
如果一个任务因延时一段时间或等待外部事件发生,那么这个任务就处理阻塞态。例如任
务调用了函数 vTaskDelay(),进行一段时间的延时,那么在延时超时之前,这个任务就处理阻塞
态。任务也可以处于阻塞态以等待队列、信号量、事件组、通知或信号量等外部事件。通常情
况下,处于阻塞态的任务都有一个阻塞的超时时间,在任务阻塞达到或超过这个超时时间后,
即使任务等待的外部事件还没有发生,任务的阻塞态也会被解除。
要注意的是,处于阻塞态的任务是无法被运行的。 - 挂起态
任务一般通过函数 vTaskSuspend()和函数 vTaskResums()进入和退出挂起态与阻塞态一样,
处于挂起态的任务也无法被运行。
二、 四种状态的关系图
三、函数
vTaskSuspend();挂起
FreeRTOS 中的任务也可以进入暂停状态,唯一的方法是通过 vTaskSuspend 函数。函数原型如下:void vTaskSuspend( TaskHandle_t xTaskToSuspend );
vTaskResume() ;解挂函数
挂起态→就绪态 : 把 一 个 挂 起 状态 的 任 务 恢复的 唯 一 途 径 就 是
调 用 vTaskResume()
或 vTaskResumeFromISR()
API 函数,
四、代码示例
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
void task1( void * pvParameters );
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
void task2( void * pvParameters );
/* TASK3 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK3_PRIO 4
#define TASK3_STACK_SIZE 128
TaskHandle_t task3_handler;
void task3( void * pvParameters );
/******************************************************************************************************/
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
xTaskCreate((TaskFunction_t ) start_task,
(char * ) "start_task",
(configSTACK_DEPTH_TYPE ) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(TaskHandle_t * ) &start_task_handler );
vTaskStartScheduler();
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL(); /* 进入临界区 */
xTaskCreate((TaskFunction_t ) task1,
(char * ) "task1",
(configSTACK_DEPTH_TYPE ) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &task1_handler );
xTaskCreate((TaskFunction_t ) task2,
(char * ) "task2",
(configSTACK_DEPTH_TYPE ) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(TaskHandle_t * ) &task2_handler );
xTaskCreate((TaskFunction_t ) task3,
(char * ) "task3",
(configSTACK_DEPTH_TYPE ) TASK3_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK3_PRIO,
(TaskHandle_t * ) &task3_handler );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
uint32_t task1_num = 0;
while(1)
{
printf("task1_num:%d\r\n",++task1_num);
LED0_TOGGLE();
vTaskDelay(500);
}
}
/* 任务二,实现LED1每500ms翻转一次 */
void task2( void * pvParameters )
{
uint32_t task2_num = 0;
while(1)
{
printf("task2_num:%d\r\n",++task2_num);
LED1_TOGGLE();
vTaskDelay(500);
}
}
/* 任务三,判断按键KEY0,按下KEY0删除task1 */
void task3( void * pvParameters )
{
uint8_t key = 0;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES)
{
printf("挂起task1\r\n");
vTaskSuspend(task1_handler);
}else if(key == KEY1_PRES)
{
printf("在任务中恢复task1\r\n");
vTaskResume(task1_handler);
}
vTaskDelay(10);
}
}
总结
看图可以明白他们其中的关系,但不使用挂起函数的时候就不会有挂起态,任务只运行在其中的三种状态之中。