FreeRTOS study notes (2)-task management

One, the header file

#include "FreeRTOS.h"
#include "task.h"

2. Task creation and start

2.1 Related API description

2.1.1 TaskHandle_t

Task handle. For example, xTaskCreatethe call to returns. Can be used as a parameter to vTaskDeletedelete tasks.

/**
 * task. h
 *
 * Type by which tasks are referenced.  For example, a call to xTaskCreate
 * returns (via a pointer parameter) an TaskHandle_t variable that can then
 * be used as a parameter to vTaskDelete to delete the task.
 *
 * \defgroup TaskHandle_t TaskHandle_t
 * \ingroup Tasks
 */
typedef void * TaskHandle_t;

2.1.2 xTaskCreate

Use dynamic memory to create a task.

function BaseType_t xTaskCreate
( TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
parameter pxTaskCode: task entry function, the name of the task function, need to be customized and implemented

pcName: task name, string form, task name should be consistent with the task entry function name, easy to debug

usStackDepth: task stack size, the unit is word, in 32-bit processor (STM32), one word is equal to 4 bytes, if 512 is passed in, the task size is 512*4 bytes

pvParameters: task entry function formal parameters, when not in use, configure it to 0 or NULL

uxPriority: task’s Priority. In FreeRTOS, the larger the value, the higher the priority. 0 represents the lowest priority.

pxCreatedTask: used to return a handle (ID), which can be used to refer to the task after the task is created
return value pdPASS: The task is successfully created

errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: Due to insufficient memory heap space, FreeRTOS cannot allocate enough space to save the task structure data and task stack, so the task cannot be created

2.1.3 vTaskDelete

Delete yourself or other tasks. After the task is deleted, it no longer exists and will not enter the running state.

function void vTaskDelete( TaskHandle_t xTaskToDelete )
parameter xTaskToDelete: The handle of the deleted task (target task). If it is to delete itself, the formal parameter is NULL
return value no

To use this function must be FreeRTOSConfig.hin the INCLUDE_vTaskDeletedefined to be enabled.

2.1.4 vTaskStartScheduler

When the task is created, we need to turn on the scheduler, because the creation is only to add the task to the system, it has not been really scheduled, and the idle task has not been implemented, and the timer task has not been implemented. These are all opening the scheduling function. Implemented in vTaskStartScheduler(). Why idle tasks? Because once FreeRTOS is started, it is necessary to ensure that there is a task in the running state (Runing) at all times in the system, and idle tasks cannot be suspended or deleted. The priority of idle tasks is the lowest so that other tasks in the system Tasks can seize the CPU usage rights of idle tasks at any time.

function void vTaskStartScheduler( void )
parameter no
return value no

2.2 Example

#include "FreeRTOS.h"
#include "task.h"

#include "bsp_led.h"
#include "bsp_usart.h"

/****************** 任务句柄 ******************/
/* 
 * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
 * 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
 * 这个句柄可以为NULL。
 */
 /* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED1 任务句柄 */ 
static TaskHandle_t LED1_Task_Handle = NULL; 
/* LED2 任务句柄 */ 
static TaskHandle_t LED2_Task_Handle = NULL;

/*
*************************************************************************
* 函数声明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于创建任务 */
 
static void LED1_Task(void* pvParameters);/* LED1_Task 任务实现 */ 
static void LED2_Task(void* pvParameters);/* LED2_Task 任务实现 */

/*****************************************************************
* @brief 主函数
* @param 无
* @retval 无
* @note 第一步:开发板硬件初始化
        第二步:创建 APP 应用任务
        第三步:启动 FreeRTOS,开始多任务调度
****************************************************************/
int main(void)
{
    
    
    BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */

    /* 开发板硬件初始化 */
    BSP_Init();
    /* 创建 AppTaskCreate 任务 */
    xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */
                            (const char* )"AppTaskCreate",/* 任务名字 */
                            (uint16_t )512, /* 任务栈大小 */
                            (void* )NULL,/* 任务入口函数参数 */
                            (UBaseType_t )1, /* 任务的优先级 */
                            (TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指针 */
    /* 启动任务调度 */
    if (pdPASS == xReturn)
    {
    
    
        vTaskStartScheduler(); /* 启动任务,开启调度 */
    }
    else
    {
    
    
        return -1;
    }

    while (1); /* 正常不会执行到这里 */
}

/***********************************************************************
* @ 函数名 : AppTaskCreate
* @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
* @ 参数 : 无
* @ 返回值 : 无
**********************************************************************/
static void AppTaskCreate(void)
{
    
    
    BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */

    taskENTER_CRITICAL(); //进入临界区

    /* 创建 LED_Task 任务 */ 
    xReturn = xTaskCreate((TaskFunction_t )LED1_Task, /* 任务入口函数 */ 
                            (const char* )"LED1_Task",/* 任务名字 */ 
                            (uint16_t )512, /* 任务栈大小 */ 
                            (void* )NULL, /* 任务入口函数参数 */ 
                            (UBaseType_t )2, /* 任务的优先级 */ 
                            (TaskHandle_t* )&LED1_Task_Handle);/* 任务控制块指针 */ 
    if (pdPASS == xReturn) 
    {
    
    
        printf("创建 LED1_Task 任务成功!\r\n"); 
    }

    /* 创建 LED_Task 任务 */ 
    xReturn = xTaskCreate((TaskFunction_t )LED2_Task, /* 任务入口函数 */ 
                            (const char* )"LED2_Task",/* 任务名字 */ 
                            (uint16_t )512, /* 任务栈大小 */ 
                            (void* )NULL, /* 任务入口函数参数 */ 
                            (UBaseType_t )3, /* 任务的优先级 */ 
                            (TaskHandle_t* )&LED2_Task_Handle);/* 任务控制块指针 */ 
    if (pdPASS == xReturn) 
    {
    
    
        printf("创建 LED2_Task 任务成功!\r\n"); 
    }

    vTaskDelete(AppTaskCreate_Handle); //删除 AppTaskCreate 任务

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

/**********************************************************************
* @ 函数名 : LED1_Task
* @ 功能说明: LED1_Task 任务主体
* @ 参数 :
* @ 返回值 : 无
********************************************************************/
static void LED1_Task(void* parameter) 
{
    
     
    while (1) 
    {
    
     
        LED1_ON; 
        vTaskDelay(500); /* 延时 500 个 tick */ 
        printf("led1_task running,LED1_ON\r\n"); 

        LED1_OFF; 
        vTaskDelay(500); /* 延时 500 个 tick */ 
        printf("led1_task running,LED1_OFF\r\n"); 
    } 
} 

/**********************************************************************
* @ 函数名 : LED2_Task
* @ 功能说明: LED2_Task 任务主体
* @ 参数 :
* @ 返回值 : 无
********************************************************************/
static void LED2_Task(void* parameter) 
{
    
     
    while (1) 
    {
    
     
        LED2_ON; 
        vTaskDelay(1000); /* 延时 500 个 tick */ 
        printf("led1_task running,LED2_ON\r\n"); 
 
        LED2_OFF; 
        vTaskDelay(1000); /* 延时 500 个 tick */ 
        printf("led1_task running,LED2_OFF\r\n"); 
    } 
}

/***********************************************************************
* @ 函数名 : BSP_Init
* @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
* @ 参数 :
* @ 返回值 : 无
*********************************************************************/
static void BSP_Init(void)
{
    
    
    /*
    * STM32 中断优先级分组为 4,即 4bit 都用来表示抢占优先级,范围为:0~15
    * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
    * 都统一用这个优先级分组,千万不要再分组,切忌。
    */
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

    /* LED 初始化 */
    LED_GPIO_Config();

    /* 串口初始化*/
    USART_Config();
}

Three, task delay

3.1 Related API description

3.1.1 vTaskDelay

Relative delay function. Used for blocking delay. After calling this function, the task will enter the blocking state, and the task that enters the blocking state will give up CPU resources

function void vTaskDelay( const TickType_t xTicksToDelay )
parameter xTicksToDelay: The unit is the system tick period. For example, the system clock tick period is 1ms, then the delay time of calling vTaskDelay(1) is 1ms
return value no

To use this function must be FreeRTOSConfig.hin the INCLUDE_vTaskDelaydefined to be enabled.

3.1.2 vTaskDelayUntil

Absolute delay function. It is often used for more precise periodic running tasks. For example, I have a task and I hope it will be executed regularly at a fixed frequency without external influence. The time interval from the last run to the next run is absolute, not relatively

function void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
parameter pxPreviousWakeTime: The last time the task left the blocking state (was awakened). This moment is used as a reference point to calculate the next time the task leaves the blocked state

xTimeIncrement: used to implement a certain task periodically at a fixed frequency-this frequency is specified by xTimeIncrement. The unit is the heartbeat period, you can use the constant portTICK_RATE_MS to convert milliseconds to the heartbeat period
return value no

To use this function must be FreeRTOSConfig.hin the INCLUDE_vTaskDelayUntildefined to be enabled.

3.2 Example

3.2.1 Relative delay

void vTaskA( void * pvParameters )
{
    
    
    while (1) 
    {
    
    
        // ...
        // 这里为任务主体代码
        // ...

        /* 调用相对延时函数,阻塞 1000 个 tick */ 
        vTaskDelay( 1000 ); 
    }
}

3.2.2 Absolute delay

Note: When using, the delay time should be converted into system beats, and the delay function should be called before the task body.

void vTaskA( void * pvParameters ) 
{
    
    
    /* 用于保存上次时间。调用后系统自动更新 */ 
    static portTickType PreviousWakeTime; 
    /* 设置延时时间,将时间转为节拍数 */ 
    const portTickType TimeIncrement = pdMS_TO_TICKS(1000); 

    /* 获取当前系统时间 */ 
    PreviousWakeTime = xTaskGetTickCount(); 

    while (1)
    {
    
    
        /* 调用绝对延时函数,任务时间间隔为 1000 个 tick */ 
        vTaskDelayUntil( &PreviousWakeTime,TimeIncrement ); 
 
        // ...
        // 这里为任务主体代码 
        // ...
 
    }
}

Fourth, task suspension and resume

4.1 Related API description

4.1.1 vTaskSuspend

Suspend the specified task. A suspended task will never get the right to use the CPU, no matter what priority the task has.

function void vTaskSuspend( TaskHandle_t xTaskToSuspend )
parameter xTaskToSuspend: Suspend the task handle of the specified task. The task must be a created task. You can suspend the task itself by passing NULL
return value no

To use this function must be FreeRTOSConfig.hin the INCLUDE_vTaskSuspenddefined to be enabled.

4.1.2 vTaskSuspendAll

Suspend all tasks.

function void vTaskSuspendAll( void )
parameter no
return value no

4.1.3 vTaskResume

Let the suspended task enter the ready state again, and the restored task will retain the state information before the suspension, and continue to run according to the suspended state when it is resumed. If the restored task is the first in the highest priority list among all ready tasks, the system will switch the task context.

function void vTaskResume( TaskHandle_t xTaskToResume )
parameter xTaskToResume: restore the task handle of the specified task
return value no

4.1.4 xTaskResumeFromISR

xTaskResumeFromISR() 与 vTaskResume() 一样都是用于恢复被挂起的任务,不一样的是 xTaskResumeFromISR() 专门用在中断服务程序中 。

函数 void vTaskResume( TaskHandle_t xTaskToResume )
参数 xTaskToResume: 恢复指定任务的任务句柄
返回值

要想使用该函数必须在 FreeRTOSConfig.h 中把 INCLUDE_vTaskSuspendINCLUDE_vTaskResumeFromISR 定义为 1 来使能。

4.1.5 xTaskResumeAll

将所有的任务都挂起。

函数 void xTaskResumeAll( void )
参数
返回值

4.2 示例

4.2.1 挂起

/**************************** 任务句柄 ********************************/
/*
* 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
* 这个句柄可以为 NULL。
*/
static TaskHandle_t LED_Task_Handle = NULL;/* LED 任务句柄 */ 

static void KEY_Task(void* parameter)
{
    
    
    while (1) 
    {
    
    
        if ( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON ) 
        {
    
    
            /* K1 被按下 */
            printf("挂起 LED 任务!\n");
            vTaskSuspend(LED_Task_Handle);/* 挂起 LED 任务 */ 
        }
        vTaskDelay(20);/* 延时 20 个 tick */
    }
}

4.2.2 恢复

/**************************** 任务句柄 ********************************/
/*
* 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
* 这个句柄可以为 NULL。
*/
static TaskHandle_t LED_Task_Handle = NULL;/* LED 任务句柄 */ 

static void KEY_Task(void* parameter)
{
    
    
    while (1) 
    {
    
    
        if ( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON ) 
        {
    
    
            /* K2 被按下 */
            printf("恢复 LED 任务!\n");
            vTaskResume(LED_Task_Handle);/* 恢复 LED 任务! */ 
        }
        vTaskDelay(20);/* 延时 20 个 tick */
    }
}

4.2.3 中断服务中恢复

使用 xTaskResumeFromISR()的时候有几个需要注意的地方:

  1. 当函数的返回值为 pdTRUE 时:恢复运行的任务的优先级等于或高于正在运行的任务,表明在中断服务函数退出后必 须进行一次上下文切换 , 使用 portYIELD_FROM_ISR() 进行上下文切换。当函数的返回值为 pdFALSE 时:恢复运行的任务的优先级低于当前正在运行的任务,表明在中断服务函数退出后不需 要进行上下文切换。
  2. xTaskResumeFromISR() 通常被认为是一个危险的函数,因为它的调用并非是固定的,中断可能随时来来临。所以 xTaskResumeFromISR()不能用于任务和中断间的同步,如果中断恰巧在任务被挂起之前到达,这就会导致一次中断丢失(任务还没有挂起,调用 xTaskResumeFromISR()函数是没有意义的,只能等下一次中断)。这种情况下,可以使用信号量或者任务通知来同步就可以避免这种情况。
void vAnExampleISR( void )
{
    
    
    BaseType_t xYieldRequired;

    /* 恢复被挂起的任务 */ 
    xYieldRequired = xTaskResumeFromISR( xHandle ); 

    if ( xYieldRequired == pdTRUE ) 
    {
    
     
        /* 执行上下文切换, ISR 返回的时候将运行另外一个任务 */ 
        portYIELD_FROM_ISR(); 
    } 
}

4.2.4 全部恢复

xTaskResumeAll 函数的使用方法很简单,但是要注意,调用了多少次 vTaskSuspendAll() 函数就必须同样调用多少次 xTaskResumeAll() 函数。

void vDemoFunction( void )
{
    
    
    vTaskSuspendAll();
    /* 处理 xxx 代码 */
    vTaskSuspendAll();
    /* 处理 xxx 代码 */
    vTaskSuspendAll();
    /* 处理 xxx 代码 */
 
    xTaskResumeAll(); 
    xTaskResumeAll(); 
    xTaskResumeAll(); 
}

五、获取任务状态

5.1 相关API说明

5.1.1 eTaskGetState

获取任务当前状态。

函数 eTaskState eTaskGetState( TaskHandle_t xTask )
参数 xTask: 任务句柄
返回值 以下值
/* Task states returned by eTaskGetState. */
typedef enum
{
    
    
    eRunning = 0,     /* A task is querying the state of itself, so must be running. */
    eReady,           /* The task being queried is in a read or pending ready list. */
    eBlocked,         /* The task being queried is in the Blocked state. */
    eSuspended,       /* The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */
    eDeleted,         /* The task being queried has been deleted, but its TCB has not yet been freed. */
    eInvalid          /* Used as an 'invalid state' value. */
} eTaskState;

• 由 Leung 写于 2020 年 10 月 30 日

• 参考:野火FreeRTOS视频与PDF教程

Guess you like

Origin blog.csdn.net/qq_36347513/article/details/109381405