FreeRTOS (2)----task management

First, the basic concept of the task

FreeRTOS is an operating system that supports multitasking. Multiple tasks can share a priority. When the task configUSE_TIME_SLICING is 1, the processor can be shared by time scheduling.

In short, a freertos task is a collection of tasks.

Second, the task scheduler

Only one task can be run at any time. What task to run is determined by the scheduler. Macroscopically, it seems that a bunch of tasks are being executed together, but in fact the tasks are executed alternately. When tasks are switched in and out At this time, the current execution environment is saved through TCB, and when the task is executed again, it can continue to execute where it stopped.

The task scheduler provided by freertos is preemptive scheduling, that is, tasks with higher priority are executed first and tasks with lower priority can be preempted, and 0 is an idle task

When the following statement is enabled, the priority is generally limited to a maximum of 32.

#define configUSE_PORT_OPTIMISED_TASK_SELECTION         1                       /* 1: 使用硬件计算下一个要运行的任务, 0: 使用软件算法计算下一个要运行的任务, 默认: 0 */

When there are multiple tasks in a system, the selection of the next ready task is also an important issue. freertos provides two methods for finding the highest priority task

Method 1: Perform sequential queries in the ready list, because when creating tasks, the priority is sorted from high to low, and then find the TCB of the corresponding task.

Method 2: Calculate the leading zero instruction CLZ, and directly calculate the highest priority task [stm32 can be used]

3. Task state transition

The previous article has explained the four states of the freertos task, but the switching between each task also needs to be well understood

1. Create a task---->ready state: When the task is successfully created, it will enter the ready state, indicating that the task is ready and waiting for the scheduling of the task scheduler.

2. Ready state---->Running state: When the task is switched, the task with the highest priority in the ready list will be executed, thus entering the running state.

3. Running state---->Ready state: When a higher-level task is created or returned from, task scheduling will occur, the task with the highest priority will enter the running state, and the originally running task will become ready. The priority task was preempted].

4. Running state---->blocking state: If the running task is blocked, it will be deleted from the ready list, the task will become blocked, and then the task will be switched to the highest priority task for execution.

5. Blocked state---->ready state: When the blocked task is restored, the restored task is added to the ready queue, changing from blocked state to ready state. When the priority of the restored task is higher than that of the currently executing task, A task switch will occur, from the ready state to the running state.

6. Change to suspended state: suspend tasks in any state through the vTaskSuspend() API function, the suspended task will not get the right to use the cpu, and will not participate in scheduling unless it is released from the suspended state.

7. Unsuspend state: call vTaskResume(), if the priority of the resumed task is higher than that of the currently executing task, a task switch will occur, from the ready state to the running state.

4. Explanation of common task functions

1. Task suspend function vTaskSuSpend()

A suspended task cannot get the right to use the CPU. Regardless of the priority of the current task, the task is suspended through the vTaskSuSpend() function. Unless it is released from the suspended state, it cannot participate in scheduling.

2.vTaskSuspendAll()

This function suspends all tasks, which is equivalent to suspending the task scheduler. When the scheduler is suspended, the interrupt will still be enabled. If the interrupt needs to switch the context, the task will be suspended. When the task scheduler After the server recovers, the execution task will be switched.

3. Task recovery function vTaskResume()

If the suspended task wants to release the suspended state, this function is needed. Task recovery is to make the suspended task re-enter the ready state. The restored task maintains the state before the suspension, and then continues to run. In the ready queue, priority The task with the highest level will be executed first, and the task also needs to be context switched [Because the priority is different, the highest priority in the ready queue is preempted by the higher priority task that is unsuspended, so the CPU will Save the previous content and load all the information of the new task]

4.xTaskResumeFromISR()

The task suspended by the vTaskSuspend() function only needs to call xTaskResumeFromISR() once.
is xTaskResumeFromISR()
xTaskResumeFromISR() and vTaskResume() are both used to resume suspended tasks, different
Specifically used in interrupt service routines. Either by calling once or multiple times
The function can be unlinked. To use this function, you must put INCLUDE_vTaskSuspend and
INCLUDE_vTaskResumeFromISR is defined as 1 to be valid. When the task is not in the pending state, call
The xTaskResumeFromISR() function is meaningless.
5. Task delete function vTaskDelete()

 Used to delete a task. When a task deletes another task, the formal parameter is the task handle returned when the task to be deleted is created; if it is to delete itself, the formal parameter is NULL. If you want to use this function, you must define INCLUDE_vTaskDelete as 1 in FreeRTOSConfig.h, and the deleted task will be deleted from all ready, blocked, pending and event lists.
The delay time is determined by the formal parameter xTicksToDelay , and the unit is the system tick period. For example, if the system clock tick period is 1ms , then the delay time for calling vTaskDelay(1) is 1ms .

6. Task relative delay function vTaskDelete()

 Freertos will run multiple tasks at the same time, and each task is an infinite loop, so it needs to be blocked to let the low-priority tasks execute, and then it needs to be enabled
#define INCLUDE_vTaskDelay                              1                       /* 任务延时 */

7. Absolute delay function vTaskDelayUntil()

This function allows each task to execute for a fixed time without external influence, and the time from the start of the task to the next start is absolutely unchanged.

code show as below:

/**
 ****************************************************************************************************
 * @file        freertos.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.4
 * @date        2022-01-04
 * @brief       FreeRTOS 任务挂起与恢复实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 精英F103开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#include "freertos_demo.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"

/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 */

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 */

/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO      3                   /* 任务优先级 */
#define TASK2_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task2Task_Handler;  /* 任务句柄 */
void task2(void *pvParameters);             /* 任务函数 */

/* TASK3 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK3_PRIO      4                   /* 任务优先级 */
#define TASK3_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task3Task_Handler;  /* 任务句柄 */
void task3(void *pvParameters);             /* 任务函数 */

/******************************************************************************************************/

/* LCD刷屏时使用的颜色 */
uint16_t lcd_discolor[11] = {WHITE, BLACK, BLUE, RED,
                             MAGENTA, GREEN, CYAN, YELLOW,
                             BROWN, BRRED, GRAY};

/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{
    lcd_show_string(10, 10, 220, 32, 32, "STM32", RED);
    lcd_show_string(10, 47, 220, 24, 24, "Task Susp & Resum", RED);
    lcd_show_string(10, 76, 220, 16, 16, "ATOM@ALIENTEK", RED);
    
    lcd_draw_rectangle(5, 110, 115, 314, BLACK);
    lcd_draw_rectangle(125, 110, 234, 314, BLACK);
    lcd_draw_line(5, 130, 115, 130, BLACK);
    lcd_draw_line(125, 130, 234, 130, BLACK);
    lcd_show_string(15, 111, 110, 16, 16, "Task1: 000", BLUE);
    lcd_show_string(135, 111, 110, 16, 16, "Task2: 000", BLUE);
    
    xTaskCreate((TaskFunction_t )start_task,            /* 任务函数 */
                (const char*    )"start_task",          /* 任务名称 */
                (uint16_t       )START_STK_SIZE,        /* 任务堆栈大小 */
                (void*          )NULL,                  /* 传入给任务函数的参数 */
                (UBaseType_t    )START_TASK_PRIO,       /* 任务优先级 */
                (TaskHandle_t*  )&StartTask_Handler);   /* 任务句柄 */
    vTaskStartScheduler();
}

/**
 * @brief       start_task
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           /* 进入临界区 */
    /* 创建任务1 */
    xTaskCreate((TaskFunction_t )task1,
                (const char*    )"task1",
                (uint16_t       )TASK1_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK1_PRIO,
                (TaskHandle_t*  )&Task1Task_Handler);
    /* 创建任务2 */
    xTaskCreate((TaskFunction_t )task2,
                (const char*    )"task2",
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler);
    /* 创建任务3 */
    xTaskCreate((TaskFunction_t )task3,
                (const char*    )"task3",
                (uint16_t       )TASK3_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK3_PRIO,
                (TaskHandle_t*  )&Task3Task_Handler);
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
    taskEXIT_CRITICAL();            /* 退出临界区 */
}

/**
 * @brief       task1
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task1(void *pvParameters)
{
    uint32_t task1_num = 0;
    printf("进入任务1\r\n");
    while (1)
    {
        lcd_fill(6, 131, 114, 313, lcd_discolor[++task1_num % 11]);
        lcd_show_xnum(71, 111, task1_num, 3, 16, 0x80, BLUE);
			  printf("lalala\r\n");
        vTaskDelay(500);
    }
}

/**
 * @brief       task2
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task2(void *pvParameters)
{
    uint32_t task2_num = 0;
    printf("进入任务2\r\n");
    while (1)
    {
        lcd_fill(126, 131, 233, 313, lcd_discolor[11 - (++task2_num % 11)]);
        lcd_show_xnum(191, 111, task2_num, 3, 16, 0x80, BLUE);
        printf("nenene\r\n");
        vTaskDelay(500);
    }
}

/**
 * @brief       task3
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task3(void *pvParameters)
{
    uint8_t key = 0;
    
    while (1)
    {
        key = key_scan(0);
        
        switch (key)
        {
            case KEY0_PRES:                     /* 挂起任务1 */
            {
                vTaskSuspend(Task2Task_Handler);
							  printf("任务2挂起\r\n");
                break;
            }
            case WKUP_PRES:                     /* 恢复任务1 */
            {
                vTaskResume(Task2Task_Handler);
							printf("任务2恢复\r\n");
                break;
            }
            default:
            {
                break;
            }
        }
        
        vTaskDelay(10);
    }
}

Guess you like

Origin blog.csdn.net/weixin_63032791/article/details/130695064