FreeRTOS 任务的挂起与恢复 任务状态查询

1. 任务挂起与恢复

1.1 任务的挂起与恢复的 API 函数

API 函数描述
vTaskSuspend()挂起任务, 类似暂停,可恢复
vTaskResume()恢复被挂起的任务
xTaskResumeFromISR()在中断中恢复被挂起的任务

1.1.1 任务挂起函数原型

void vTaskSuspend( TaskHandle_t xTaskToSuspend );

  • 需要定义宏来启动任务挂起函数

     #define INCLUDE_vTaskSuspend       1    /* 启用挂起任务的API */
    
  • xTaskToSuspend:待挂起任务的任务句柄 TCB ,为 NULL 表示挂起任务自身

1.1.2 任务恢复函数原型

void vTaskResume( TaskHandle_t xTaskToResume )

  • 需要定义宏来启动任务挂起函数

     #define INCLUDE_vTaskSuspend       1    /* 启用挂起任务的API */
    
  • 不论任务被使用 vTaskSuspend() 挂起多少次,只需调用 vTaskResume() 一次,即可使其继续执行。被恢复的任务会重新进入就绪状态。

1.1.2 任务恢复函数(中断中恢复 FromISR )

BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )

  • pdTRUE:任务恢复后需要进行任务切换。
  • pdFALSE:任务恢复后不需要进行任务切换。
  • 需要定义宏来启动任务恢复函数

    #define INCLUDE_vTaskSuspend       1    /* 启用挂起任务的API */
    #define INCLUDE_xTaskResumeFromISR 1	/* 启用任务恢复的API */
    
  • 在中断服务程序中调用 FreeRTOS 的 API 函数时,中断的优先级不能高于FreeRTOS 所管理的最高中断优先级

1.2 挂起与恢复调度器

  • vTaskSuspendAll():挂起任务调度器,调度器不会进行任务切换,当前任务一直运行,但允许中断。
  • xTaskResumeAll():恢复任务调度器,调度器继续任务切换。

通常搭配使用俩者,用于执行一段关键代码,防止任务切换。

1.3 查看任务状态

函数原型:

void vTaskList( char * pcWriteBuffer ) // 存放任务信息的字符数组,需要足够大以容纳所有任务信息

需要启动宏来开启跟踪任务状态信息

#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1

vTaskList() 典型输出示例

vTaskList() 以固定格式输出任务信息,列的含义如下:

任务名称       状态  优先级  堆栈使用  任务编号
--------------------------------------------
task3         X      4       68      5
IDLE          R      0      111      2
task1         B      2       68      3
task2         S      3       60      4
字段示例值含义
任务名称(Task Name)task3任务名称(xTaskCreate() 设定的)
状态(State)X任务当前的运行状态
优先级(Priority)4任务优先级,数值越大优先级越高
堆栈使用(Stack Usage)68任务运行时最小剩余堆栈大小(单位:字节)
任务编号(Task Number)5任务的唯一标识符

vTaskList() 输出中,状态字段表示任务的当前状态:

状态字符含义
X (Running)正在运行的任务(当前占用 CPU 的任务)
R (Ready)就绪状态(等待调度运行的任务)
B (Blocked)阻塞状态(任务在等待某个事件,如信号量、队列等)
S (Suspended)暂停状态(调用 vTaskSuspend() 暂停)
D (Deleted)已删除(任务被 vTaskDelete() 删除)

1.4 实践操作

start_task:用来创建其他的三个任务。
task1:实现 LED1 每 1000ms 闪烁一次。
task2:实现 LED2 每 100ms 闪烁一次。
task3:判断按键按下逻辑,KEY1 按下,挂起 task2,按下 KEY2 恢复 task2,KEY3 按下,挂起调度器,KEY4 按下,恢复调度器,KEY5按下,打印任务的状态。

1 ) FreeRTOSConfig.h

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

extern uint32_t SystemCoreClock;

/*-----------------------------------------------------------
 * 应用程序特定的定义。
 *
 * 这些定义应该根据您的硬件和应用程序需求进行调整。
 *
 * 这些参数在FreeRTOS API文档的“配置”部分中有详细描述。
 *
 * 请参阅:http://www.freertos.org/a00110.html
 *----------------------------------------------------------*/

#define configUSE_PREEMPTION		1      /* 1: 抢占式调度器, 0: 协程式调度器, 无默认需定义 */
#define configUSE_IDLE_HOOK			0      /* 禁用空闲钩子 */
#define configUSE_TICK_HOOK			0      /* 禁用滴答钩子 */
#define configCPU_CLOCK_HZ			( ( unsigned long ) 72000000 )    /* CPU时钟频率,72 MHz */
#define configTICK_RATE_HZ			( ( TickType_t ) 1000 )   /* 时钟节拍频率,每秒1000次 */
#define configMAX_PRIORITIES		( 5 )    /* 最大优先级数 */
#define configMINIMAL_STACK_SIZE	( ( unsigned short ) 128 )   /* 最小栈大小 */
#define configTOTAL_HEAP_SIZE		( ( size_t ) ( 8 * 1024 ) )   /* 堆大小,17KB */
#define configMAX_TASK_NAME_LEN		( 16 )    /* 任务名称最大长度 */
#define configUSE_16_BIT_TICKS		0      /* 禁用16位滴答 */
#define configIDLE_SHOULD_YIELD		1      /* 空闲任务应让出CPU */

 
/* 设置以下定义为1以包含API函数,或设置为0以排除API函数 */

#define INCLUDE_vTaskPrioritySet		1      /* 启用设置任务优先级的API */
#define INCLUDE_uxTaskPriorityGet		1      /* 启用获取任务优先级的API */
#define INCLUDE_vTaskDelete				1      /* 启用删除任务的API */
#define INCLUDE_vTaskCleanUpResources	0      /* 禁用清理任务资源的API */
#define INCLUDE_vTaskSuspend			1      /* 启用挂起任务的API */
#define INCLUDE_vTaskDelayUntil			1      /* 启用延迟直到的API */
#define INCLUDE_vTaskDelay				1      /* 启用延迟的API */

/* 这是Cortex-M3 NVIC的原始值。值的范围为255(最低)到0(最高)。 */
#define configKERNEL_INTERRUPT_PRIORITY 		255    /* 内核中断优先级 */

/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY 不能设置为零 !!!!
请参阅 http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html。 */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	191    /* 等价于0xb0,或优先级11 */ /*  如果 ISR 优先级高于该值,则可能打断 FreeRTOS 内核关键代码,破坏任务调度、数据同步 */

/* 这是根据ST库使用的值,允许16个优先级值,0到15。
这必须与configKERNEL_INTERRUPT_PRIORITY设置相匹配。
此处15对应最低的NVIC值255。 */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY	15     /* 库内核中断优先级 */

/* 由于 stm32 和 FreeRTOS 对变量命名的不同,我们进行宏定义 */
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler

/* 开启任务调度器API,允许查询 FreeRTOS 调度器的状态 */
#define INCLUDE_xTaskGetSchedulerState 1

// #define configSUPPORT_DYNAMIC_ALLOCATION 1

/* 启用静态创建任务 */
#define configSUPPORT_STATIC_ALLOCATION 1

/* 启用中断中任务恢复的API */
#define INCLUDE_xTaskResumeFromISR 1

/* 开启跟踪 task 信息 */
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1

#endif /* FREERTOS_CONFIG_H */

2 ) 任务函数

/* 启动任务配置 */
#define TASK_START_STACK_SIZE 128
#define TASK_START_PRIORITY 1
TaskHandle_t Task_start_Handle; // 如果后续不需要操作这个任务(删除,挂起等),可以省略这句
StackType_t start_task_stack[TASK_START_STACK_SIZE];
StaticTask_t start_task_tcb;
void task_start(void *pvParameters);

/* 任务1配置 */
#define TASK1_STACK_SIZE 128
#define TASK1_PRIORITY 2
TaskHandle_t Task1_Handler;
void task1(void *pvParameters);

/* 任务2配置 */
#define TASK2_STACK_SIZE 128
#define TASK2_PRIORITY 3
TaskHandle_t Task2_Handler;
void task2(void *pvParameters);

/* 任务3配置 */
#define TASK3_STACK_SIZE 128
#define TASK3_PRIORITY 4
TaskHandle_t Task3_Handler;
void task3(void *pvParameters);

/* 空闲任务配置 */
#define IDLE_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
StaticTask_t idle_task_tcb;
StackType_t idle_task_stack[IDLE_TASK_STACK_SIZE];

/* 空闲任务内存申请函数 */
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
                                   StackType_t **ppxIdleTaskStackBuffer,
                                   uint32_t *pulIdleTaskStackSize)
{
    *ppxIdleTaskTCBBuffer = &idle_task_tcb;
    *ppxIdleTaskStackBuffer = idle_task_stack;
    *pulIdleTaskStackSize = IDLE_TASK_STACK_SIZE;
}

/**
 * @brief : FreeRTOS 入口函数:创建任务函数并开始调度
 *
 */
void FreeRTOS_start()
{
    Task_start_Handle = xTaskCreateStatic((TaskFunction_t)task_start,                    // 任务函数指针
                                          (char *)"task_start",                          // 任务名称
                                          (configSTACK_DEPTH_TYPE)TASK_START_STACK_SIZE, // 任务栈大小
                                          (void *)NULL,                                  // 传递给任务函数的参数
                                          (UBaseType_t)TASK_START_PRIORITY,              // 任务优先级
                                          (StackType_t *)start_task_stack,               // 任务栈指针(用户手动分配)
                                          (StaticTask_t *)&start_task_tcb);              // 任务控制块(TCB)指针(用户手动分配)

    /* 启动任务调度器:自动创建空闲任务 */
    vTaskStartScheduler();
}

/**
 * @brief : 启动任务函数,创建三个任务,并删除自己
 *
 * @param pvParameters
 */
void task_start(void *pvParameters)
{
    /* 进入临界区:保护临界区里的代码不会被打断 */
    taskENTER_CRITICAL();

    /* 创建三个任务 */
    xTaskCreate((TaskFunction_t)task1,
                (char *)"task1",
                (configSTACK_DEPTH_TYPE)TASK1_STACK_SIZE,
                (void *)NULL,
                (UBaseType_t)TASK1_PRIORITY,
                (TaskHandle_t *)&Task1_Handler);
    xTaskCreate((TaskFunction_t)task2,
                (char *)"task2",
                (configSTACK_DEPTH_TYPE)TASK2_STACK_SIZE,
                (void *)NULL,
                (UBaseType_t)TASK2_PRIORITY,
                (TaskHandle_t *)&Task2_Handler);
    xTaskCreate((TaskFunction_t)task3,
                (char *)"task3",
                (configSTACK_DEPTH_TYPE)TASK3_STACK_SIZE,
                (void *)NULL,
                (UBaseType_t)TASK3_PRIORITY,
                (TaskHandle_t *)&Task3_Handler);

    /* 启动任务只需要执行一次即可,用完就删除自己 */
    vTaskDelete(NULL);

    /* 退出临界区 */
    taskEXIT_CRITICAL();
}

/**
 * @brief : 任务1函数,每隔1s翻转一次LED
 *
 * @param pvParameters
 */
void task1(void *pvParameters)
{
    while (1)
    {
        led[0].state = !led[0].state;
        printf("task1 runing...\r\n");
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, (GPIO_PinState)led[0].state);
        vTaskDelay(1000);
    }
}

/**
 * @brief : 任务2函数,每隔100ms翻转一次LED
 *
 * @param pvParameters
 */
void task2(void *pvParameters)
{
    while (1)
    {
        led[1].state = !led[1].state;
        printf("task2 runing...\r\n");
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, (GPIO_PinState)led[1].state);
        vTaskDelay(100);
    }
}

/**
 * @brief : 任务3函数,每隔100ms检测一次按键
 *
 * @param pvParameters
 */
char taskInfo[512];
void task3(void *pvParameters)
{
    while (1)
    {
        for (int i = 0; i < 16; i++)
        {
            if (key[i].flag == 1)
            {
                if (i == 0)
                {
                    printf("task2 suspend...\r\n");
                    vTaskSuspend(Task2_Handler);
                }
                else if (i == 1)
                {
                    printf("task2 resume...\r\n");
                    vTaskResume(Task2_Handler);
                }
                else if (i == 2)
                {
                    printf("task schduler suspend...\r\n");
                    vTaskSuspendAll();
                }
                else if (i == 3)
                {
                    printf("task schduler resume...\r\n");
                    xTaskResumeAll();
                }
                else if (i == 4)
                {
                    vTaskList(taskInfo);
                    printf("\r\ntask list:\r\n%s\r\n", taskInfo);
                }
                sprintf((char *)text, " key%d pressed ", i + 1);
                OLED_ShowString(1, 0, (char *)text);
                key[i].flag = 0;
            }
        }
        vTaskDelay(1000);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值