3、FreeRTOS - 任务的创建、删除

目录

前言

动态创建任务

动态创建任务的使用流程

程序示例

静态创建任务

静态创建任务的使用流程

程序示例

任务删除函数

删除任务的流程


前言

声明:学习笔记是看正点原子视频教学+个人理解总结的,仅供学习交流!!


FreeRTOS 的使用过程可以简单的总结成以下几点:

1)系统初始化:如时钟、中断控制器、外设等等。

2)创建任务(本章重点):在 FreeRTOS 中,任务是最小的调度单位,使用 FreeRTOS 时需要先创建一个或多个任务,为任务分配堆栈空间和优先级。

3)启动任务调度器:任务创建后,需要调用 vTaskStartScheduler() 函数启动 FreeRTOS 的任务调度器,这样任务才能根据优先级或时间片进行调度切换。

4)多任务调度:创建有多个任务,又开启了任务调度器,FreeRTOS 任务调度器就会根据优先级和调度策略进行任务切换,以实现多任务并发执行。当一个任务被抢占时,调度器会保存当前任务的上下文(即保存当前任务的执行数据,保证下次切换回来后能继续当前的进度),并恢复下一个任务的上下文。


动态创建任务

创建函数

BaseType_t xTaskCreate

(
        TaskFunction_t    pxTaskCode,        /* 指向任务函数的指针 */                                
        const char * const    pcName,          /* 任务名字,最大长度configMAX_TASK_NAME_LEN */

        const  configSTACK_DEPTH_TYPE    usStackDepth,         /* 任务堆栈大小,注意字为单位 */

        void * const    pvParameters,           /* 传递给任务函数的参数 */

        UBaseType_t    uxPriority,                /* 任务优先级,范围:0 ~ configMAX_PRIORITIES - 1 */

        TaskHandle_t * const    pxCreatedTask            /* 任务句柄,就是任务的任务控制块 */

)

返回值

任务创建成功,返回 pdPASS

任务创建失败,返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY

任务控制块的结构体成员介绍:

typedef  struct  tskTaskControlBlock      

{

            volatile StackType_t * pxTopOfStack;       /* 任务栈栈顶,必须为TCB的第一个成员 */

            ListItem_t                     xStateListItem;      /* 任务状态列表项 */     

            ListItem_t                     xEventListItem;     /* 任务事件列表项 */    

            UBaseType_t               uxPriority;              /* 任务优先级,数值越大,优先级越大 */

            StackType_t              * pxStack;                /* 任务栈起始地址 */

            char     pcTaskName[ configMAX_TASK_NAME_LEN ];         /* 任务名字 */                

            …

        (省略很多条件编译的成员)

}   tskTCB;

任务栈栈顶,在任务切换时的任务上下文保存、任务恢复息息相关。

注意:每个任务都有属于自己的任务控制块,类似身份证。

1、动态创建任务函数的内部具体实现做了什么?

申请堆栈内存和任务控制块内存

        ↓

对 TCB 结构体成员进行赋值

        ↓

添加新任务到就绪列表中

2、动态创建任务的使用流程

1)将宏 configSUPPORT_DYNAMIC_ALLOCATION 配置为 1(表示允许动态申请内存。宏在 FreeRTOSConfig.h 文件内)

2)先再函数外定义动态创建任务函数的参数,然后再调用动态创建任务函数

3)编写任务函数 (是动态创建任务函数的第一个参数指向的函数)

此函数创建的任务会立刻进入就绪态,之后由任务调度器调度运行。

3、程序示例

需实现内容如下:

创建四个任务:start_task、task1、task2、task3。

start_task 任务负责用来创建另外的三个任务 task1~task3,

task1 实现 LED0 每 500ms 闪烁一次,

task2 实现 LED1 每 500ms 闪烁一次,

task3 实现判断按键KEY0是否按下,按下则删掉task1

1)main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/SDRAM/sdram.h"
#include "./MALLOC/malloc.h"
#include "freertos_demo.h"

int main(void)
{
/************************裸机外设初始化*************************************/
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(360, 25, 2, 8);        /* 设置时钟,180Mhz */
    delay_init(180);                            /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    led_init();                                 /* 初始化LED */
    key_init();                                 /* 初始化按键 */
    sdram_init();                               /* SRAM初始化 */
    lcd_init();                                 /* 初始化LCD */
    my_mem_init(SRAMIN);                        /* 初始化内部内存池 */
    my_mem_init(SRAMEX);                        /* 初始化外部内存池 */
    my_mem_init(SRAMCCM);                       /* 初始化CCM内存池 */
    
/************************FreeRTOS的使用***********************************/
    freertos_demo();
}

2)freertos_demo.h

#ifndef __FREERTOS_DEMO_H
#define __FREERTOS_DEMO_H

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"

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

void freertos_demo(void);

#endif

3)freertos_demo.c

#include "freertos_demo.h"

/* 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 );


/* FreeRTOS例程的入口函数,这个只是让main.c文件的代码看起来更简洁 */
void freertos_demo(void)
{    
/* 动态创建任务函数:创建 start_task 任务 */
    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();               /* 进入临界区:会关闭所有中断,防止任务调度,保证下面程序完整执行 */
	
/* 动态创建任务函数:创建 task1 任务 */
    xTaskCreate((TaskFunction_t         )   task1,
                (char *                 )   "task1",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &task1_handler );
/* 动态创建任务函数:创建 task2 任务 */            
    xTaskCreate((TaskFunction_t         )   task2,
                (char *                 )   "task2",
                (configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK2_PRIO,
                (TaskHandle_t *         )   &task2_handler );
/* 动态创建任务函数:创建 task3 任务 */            
    xTaskCreate((TaskFunction_t         )   task3,
                (char *                 )   "task3",
                (configSTACK_DEPTH_TYPE )   TASK3_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK3_PRIO,
                (TaskHandle_t *         )   &task3_handler );
    
    vTaskDelete(NULL);                  /* 删除当前任务,即 start_task */
								
    taskEXIT_CRITICAL();                /* 退出临界区:恢复中断,恢复正常的任务调度功能 */
}

/* task1,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
    while(1)
    {
        printf("task1正在运行!!!\r\n");
        LED0_TOGGLE();
        vTaskDelay(500);
    }
}

/* task2,实现LED1每500ms翻转一次 */
void task2( void * pvParameters )
{
    while(1)
    {
        printf("task2正在运行!!!\r\n");
        LED1_TOGGLE();
        vTaskDelay(500);
    }
}

/* task3,判断按键KEY0,按下KEY0删除task1 */
void task3( void * pvParameters )
{
    uint8_t key = 0;
    while(1)
    {
        printf("task3正在运行!!!\r\n");
        key = key_scan(0);
        if(key == KEY0_PRES)
        {
            if(task1_handler != NULL)
            {
                printf("删除task1任务\r\n");
                vTaskDelete(task1_handler);
                task1_handler = NULL;
            }

        }
        vTaskDelay(10);
    }
}

静态创建任务

创建函数

TaskHandle_t xTaskCreateStatic

(

            TaskFunction_t                pxTaskCode,                       /* 指向任务函数的指针 */

            const char * const            pcName,                             /* 任务函数名 */

            const uint32_t                  ulStackDepth,                     /* 任务堆栈大小注意字为单位 */

            void * const                      pvParameters,                   /* 传递的任务函数参数 */

            UBaseType_t                   uxPriority,                           /* 任务优先级 */

            StackType_t * const         puxStackBuffer,                 /* 任务堆栈,一般为数组,由用户分配 */

            StaticTask_t * const         pxTaskBuffer               /* 任务控制块指针,由用户分配 */

);         

返回值

任务创建成功,返回 任务句柄

任务创建失败(用户没有给静态任务分配内存),返回 NULL

1、静态创建任务函数的内部具体做了什么?

对 TCB 结构体成员进行赋值

        ↓

添加新任务到就绪列表中

2、静态创建任务的使用流程

1)将宏 configSUPPORT_STATIC_ALLOCATION 配置为 1。

2)调用如下函数:

vApplicationGetIdleTaskMemory( ):给空闲任务的分配一个堆栈内存,并创建相关的 TCB。

vApplicationGetTimerTaskMemory( ):给定时器任务的分配一个堆栈内存,并创建相关的 TCB。

静态创建需要用户自己分配堆栈内存给任务,而动态是由系统自己分配。

3)先在函数外定义静态创建任务函数的参数,然后再调用静态创建任务函数。

4)编写任务函数 (是静态创建任务函数的第一个参数指向的函数)

此函数创建的任务会立刻进入就绪态,之后由任务调度器调度运行。

3、程序示例

需实现内容如下:

创建四个任务:start_task、task1、task2、task3。

start_task 任务负责用来创建另外的三个任务 task1~task3,

task1 实现 LED0 每 500ms 闪烁一次,

task2 实现 LED1 每 500ms 闪烁一次,

task3 实现判断按键KEY0是否按下,按下则删掉task1

 1)main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/SDRAM/sdram.h"
#include "./MALLOC/malloc.h"
#include "freertos_demo.h"

int main(void)
{
/************************裸机外设初始化*************************************/
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(360, 25, 2, 8);        /* 设置时钟,180Mhz */
    delay_init(180);                            /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    led_init();                                 /* 初始化LED */
    key_init();                                 /* 初始化按键 */
    sdram_init();                               /* SRAM初始化 */
    lcd_init();                                 /* 初始化LCD */
    my_mem_init(SRAMIN);                        /* 初始化内部内存池 */
    my_mem_init(SRAMEX);                        /* 初始化外部内存池 */
    my_mem_init(SRAMCCM);                       /* 初始化CCM内存池 */
    
/************************FreeRTOS的使用***********************************/
    freertos_demo();
}

2)freertos_demo.h

#ifndef __FREERTOS_DEMO_H
#define __FREERTOS_DEMO_H

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"

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

void freertos_demo(void);

#endif

3)freertos_demo.c

#include "freertos_demo.h"

/* FreeRTOS 任务配置如下 */

/* START_TASK 任务的参数定义。包括: 任务句柄 任务优先级 堆栈大小 创建任务 */
    #define START_TASK_PRIO         1
    #define START_TASK_STACK_SIZE   128
    TaskHandle_t    start_task_handler;
    StackType_t     start_task_stack[START_TASK_STACK_SIZE];
    StaticTask_t    start_task_tcb;
    void start_task( void * pvParameters );

/* TASK1 任务的参数定义。包括: 任务句柄 任务优先级 堆栈大小 创建任务 */
    #define TASK1_PRIO         2
    #define TASK1_STACK_SIZE   128
    TaskHandle_t    task1_handler;
    StackType_t     task1_stack[TASK1_STACK_SIZE];
    StaticTask_t    task1_tcb;
    void task1( void * pvParameters );

/* TASK2 任务的参数定义。包括: 任务句柄 任务优先级 堆栈大小 创建任务 */
    #define TASK2_PRIO         3
    #define TASK2_STACK_SIZE   128
    TaskHandle_t    task2_handler;
    StackType_t     task2_stack[TASK2_STACK_SIZE];
    StaticTask_t    task2_tcb;
    void task2( void * pvParameters );

/* TASK3 任务的参数定义。包括: 任务句柄 任务优先级 堆栈大小 创建任务 */
    #define TASK3_PRIO         4
    #define TASK3_STACK_SIZE   128
    TaskHandle_t    task3_handler;
    StackType_t     task3_stack[TASK3_STACK_SIZE];
    StaticTask_t    task3_tcb;
    void task3( void * pvParameters );


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

/* 软件定时器任务配置 */
    StaticTask_t timer_task_tcb;
    StackType_t  timer_task_stack[configTIMER_TASK_STACK_DEPTH];

/* 空闲任务内存分配 */
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
    * ppxIdleTaskTCBBuffer = &idle_task_tcb;
    * ppxIdleTaskStackBuffer = idle_task_stack;
    * pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

/* 软件定时器内存分配 */
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
                                     StackType_t ** ppxTimerTaskStackBuffer,
                                     uint32_t * pulTimerTaskStackSize )
{
    * ppxTimerTaskTCBBuffer = &timer_task_tcb;
    * ppxTimerTaskStackBuffer = timer_task_stack;
    * pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
    
/* FreeRTOS例程入口函数,这个只是让代码看起来更简洁 */
void freertos_demo(void)
{    
/* 静态创建任务函数:创建 start_task 任务 */
    start_task_handler = xTaskCreateStatic( (TaskFunction_t )   start_task,
                                            (char *         )   "start_task", 
                                            (uint32_t       )   START_TASK_STACK_SIZE,
                                            (void *         )   NULL,
                                            (UBaseType_t    )   START_TASK_PRIO,
                                            (StackType_t *  )   start_task_stack,
                                            (StaticTask_t * )   &start_task_tcb );
																						
    vTaskStartScheduler();              /* 开启任务调度器:开启后就会根据任务的优先级进行调度 */
}

/* start_task:实现创建任务 task1~task3 */
void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();               /* 进入临界区:会关闭所有中断,防止任务调度,保证下面程序完整执行 */

/* 静态创建任务函数:创建 task1 任务 */
    task1_handler = xTaskCreateStatic(  (TaskFunction_t )   task1,
                                        (char *         )   "task1", 
                                        (uint32_t       )   TASK1_STACK_SIZE,
                                        (void *         )   NULL,
                                        (UBaseType_t    )   TASK1_PRIO,
                                        (StackType_t *  )   task1_stack,
                                        (StaticTask_t * )   &task1_tcb );

/* 静态创建任务函数:创建 task2 任务 */                
    task2_handler = xTaskCreateStatic(  (TaskFunction_t )   task2,
                                        (char *         )   "task2", 
                                        (uint32_t       )   TASK2_STACK_SIZE,
                                        (void *         )   NULL,
                                        (UBaseType_t    )   TASK2_PRIO,
                                        (StackType_t *  )   task2_stack,
                                        (StaticTask_t * )   &task2_tcb );

/* 静态创建任务函数:创建 task3 任务 */                     
    task3_handler = xTaskCreateStatic(  (TaskFunction_t )   task3,
                                        (char *         )   "task3", 
                                        (uint32_t       )   TASK3_STACK_SIZE,
                                        (void *         )   NULL,
                                        (UBaseType_t    )   TASK3_PRIO,
                                        (StackType_t *  )   task3_stack,
                                        (StaticTask_t * )   &task3_tcb );
    
    vTaskDelete(start_task_handler);    /* 删除任务 start_task  */
																				
    taskEXIT_CRITICAL();                /* 退出临界区:恢复中断,恢复正常的任务调度功能 */
}

/* task1:实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
    while(1)
    {
        printf("task1正在运行!!!\r\n");
        LED0_TOGGLE();
        vTaskDelay(500);
    }
}

/* task2:实现LED1每500ms翻转一次 */
void task2( void * pvParameters )
{
    while(1)
    {
        printf("task2正在运行!!!\r\n");
        LED1_TOGGLE();
        vTaskDelay(500);
    }
}

/* task3:判断按键KEY0,按下KEY0删除task1 */
void task3( void * pvParameters )
{
    uint8_t key = 0;
    while(1)
    {
        printf("task3正在运行!!!\r\n");
        key = key_scan(0);
        if(key == KEY0_PRES)
        {
            if(task1_handler != NULL)
            {
                printf("删除task1任务\r\n");
                vTaskDelete(task1_handler);
                task1_handler = NULL;
            }
        }
        vTaskDelay(10);
    }
}

任务删除函数

函数

void  vTaskDelete (TaskHandle_t  xTaskToDelete)

形参

xTaskToDelete:待删除任务的任务句柄。如果为 NULL,则删除当前正在运行的任务自身,即调用该函数的任务

功能

用于删除已被创建的任务。被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除。

空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存, 则需要由用户在任务被删除前提前释放,否则将导致内存泄露 。

1、任务删除函数的内部具体做了什么?

获取所要删除任务的控制块:通过传入的任务句柄,判断所需要删除哪个任务,NULL 代表删除任务自身。

        ↓

将被删除的任务从所在列表中移除:将该任务从所在的列表中移除,包括就绪列表、阻塞列表、挂起列表、事件列表等

        ↓

判断需要删除的任务:如果是删除任务自身,需先添加到等待删除列表,空闲任务执行内存释放。如果是删除其他任务,释放内存,任务数量减一。

        ↓

更新下一个任务的阻塞时间:更新下一个任务的阻塞超时时间,防止被删除的任务就是下一个阻塞超时的任务

2、删除任务的流程

1)使用删除任务函数之前,需要将宏 INCLUDE_vTaskDelete 配置为 1

2)函数的参数写入要删除任务的任务句柄 handle,如果写入 NULL 代表删除调用者本身

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值