STM32——FreeRTOS - 任务创建和删除 ~ 静态方法

STM32------FreeRTOS - 任务创建和删除*

三、任务创建和删除(静态方法)

静态任务创建流程

删除任务、prvAddNewTaskToReadyList、prvInitialiseNewTask 参考:

STM32------FreeRTOS - 任务创建和删除 ~ 动态方法-CSDN博客https://blog.csdn.net/PinnsiR/article/details/159357638?sharetype=blogdetail&sharerId=159357638&sharerefer=PC&sharesource=PinnsiR&spm=1011.2480.3001.8118xTaskCreateStatic 与xTaskCreate 的差别主要在内存分配上,以及会返回一个 TCB任务控制块句柄,其余逻辑看源码即可。

静态配置运行分析

FreeRTOSConfig.h

cpp 复制代码
FreeRTOSConfig.h
#define configSUPPORT_STATIC_ALLOCATION  1    /* 1: 支持静态申请内存, 默认: 0 */

#define configMINIMAL_STACK_SIZE         128  /* 定义空闲任务的栈空间大小, 单位: Word, 无默认需定义 */
#define configTIMER_TASK_STACK_DEPTH    ( configMINIMAL_STACK_SIZE * 2) /* 定义软件定时器任务的栈空间大小, 无默认configUSE_TIMERS为1时需定义 */

开启静态申请内存宏后,配置所有任务创建的函数会被宏编译调用。

那么,任务开启调度器(vTaskStartScheduler)里 自动 创建的 空闲任务(IdleTask)\定时器任务(TimerTask),需要

  1. 手动分配空闲任务内存空间(任务堆栈内存和大小)。

  2. vApplicationGetIdleTaskMemory函数体实现

  3. vApplicationGetTimerTaskMemory函数体实现

函数启动调简易图:

main() ->

vTaskStartScheduler -》

-> vApplicationGetIdleTaskMemory

-> xTaskCreateStatic( prvIdleTask,

-> xTimerCreateTimerTask

-> vApplicationGetTimerTaskMemory

-> xTaskCreateStatic( prvTimerTask

vTaskStartScheduler()
cpp 复制代码
void vTaskStartScheduler( void )
{
    BaseType_t xReturn;

    /* Add the idle task at the lowest priority. */
    #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
        {
            StaticTask_t * pxIdleTaskTCBBuffer = NULL;
            StackType_t * pxIdleTaskStackBuffer = NULL;
            uint32_t ulIdleTaskStackSize;

            /* The Idle task is created using user provided RAM - obtain the
             * address of the RAM then create the idle task. */
            vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
            xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
                                                 configIDLE_TASK_NAME,
                                                 ulIdleTaskStackSize,
                                                 ( void * ) NULL,       /*lint !e961.  The cast is not redundant for all compilers. */
                                                 portPRIVILEGE_BIT,     /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                                 pxIdleTaskStackBuffer,
                                                 pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
  
        ...... ......

    #if ( configUSE_TIMERS == 1 )
        {
            if( xReturn == pdPASS )
            {
                xReturn = xTimerCreateTimerTask();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
    #endif /* configUSE_TIMERS */

    #endif

}
xTimerCreateTimerTask()
cpp 复制代码
BaseType_t xTimerCreateTimerTask( void )
{
    BaseType_t xReturn = pdFAIL;

    /* This function is called when the scheduler is started if
        * configUSE_TIMERS is set to 1.  Check that the infrastructure used by the
        * timer service task has been created/initialised.  If timers have already
        * been created then the initialisation will already have been performed. */
    prvCheckForValidListAndQueue();

    if( xTimerQueue != NULL )
    {
        #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
            {
                StaticTask_t * pxTimerTaskTCBBuffer = NULL;
                StackType_t * pxTimerTaskStackBuffer = NULL;
                uint32_t ulTimerTaskStackSize;

                vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
                xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
                                                        configTIMER_SERVICE_TASK_NAME,
                                                        ulTimerTaskStackSize,
                                                        NULL,
                                                        ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
                                                        pxTimerTaskStackBuffer,
                                                        pxTimerTaskTCBBuffer );
    
    ...... ......
    return xReturn;
}
/*-----------------------------------------------------------*/
vApplication xxx Memory()
cpp 复制代码
static StackType_t  IdleTaskStack[configMINIMAL_STACK_SIZE];        /* 空闲任务任务堆栈 */
static StaticTask_t IdleTaskTCB;                                    /* 空闲任务控制块 */
static StackType_t  TimerTaskStack[configTIMER_TASK_STACK_DEPTH];   /* 定时器服务任务堆栈 */
static StaticTask_t TimerTaskTCB;                                   /* 定时器服务任务控制块 */

、/**
 * @brief       获取空闲任务地任务堆栈和任务控制块内存,因为本例程使用的
                静态内存,因此空闲任务的任务堆栈和任务控制块的内存就应该
                有用户来提供,FreeRTOS提供了接口函数vApplicationGetIdleTaskMemory()
                实现此函数即可。
 * @param       ppxIdleTaskTCBBuffer:任务控制块内存
                ppxIdleTaskStackBuffer:任务堆栈内存
                pulIdleTaskStackSize:任务堆栈大小
 * @retval      无
 */
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
                                   StackType_t  **ppxIdleTaskStackBuffer, 
                                   uint32_t     *pulIdleTaskStackSize)
{
    *ppxIdleTaskTCBBuffer   = &IdleTaskTCB;
    *ppxIdleTaskStackBuffer = IdleTaskStack;
    *pulIdleTaskStackSize   = configMINIMAL_STACK_SIZE;
}


/**
 * @brief       获取定时器服务任务的任务堆栈和任务控制块内存
 * @param       ppxTimerTaskTCBBuffer:任务控制块内存
                ppxTimerTaskStackBuffer:任务堆栈内存
                pulTimerTaskStackSize:任务堆栈大小
 * @retval      无
 */
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
                                    StackType_t  **ppxTimerTaskStackBuffer,
                                    uint32_t     *pulTimerTaskStackSize)
{
    *ppxTimerTaskTCBBuffer  = &TimerTaskTCB;
    *ppxTimerTaskStackBuffer= TimerTaskStack;
    *pulTimerTaskStackSize  = configTIMER_TASK_STACK_DEPTH;
}
demo:
cpp 复制代码
#include "freertos_demo.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"

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

static StackType_t  IdleTaskStack[configMINIMAL_STACK_SIZE];        /* 空闲任务任务堆栈 */
static StaticTask_t IdleTaskTCB;                                    /* 空闲任务控制块 */
static StackType_t  TimerTaskStack[configTIMER_TASK_STACK_DEPTH];   /* 定时器服务任务堆栈 */
static StaticTask_t TimerTaskTCB;                                   /* 定时器服务任务控制块 */

/**
 * @brief       获取空闲任务地任务堆栈和任务控制块内存,因为本例程使用的
                静态内存,因此空闲任务的任务堆栈和任务控制块的内存就应该
                有用户来提供,FreeRTOS提供了接口函数vApplicationGetIdleTaskMemory()
                实现此函数即可。
 * @param       ppxIdleTaskTCBBuffer:任务控制块内存
                ppxIdleTaskStackBuffer:任务堆栈内存
                pulIdleTaskStackSize:任务堆栈大小
 * @retval      无
 */
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
                                   StackType_t  **ppxIdleTaskStackBuffer, 
                                   uint32_t     *pulIdleTaskStackSize)
{
    *ppxIdleTaskTCBBuffer   = &IdleTaskTCB;
    *ppxIdleTaskStackBuffer = IdleTaskStack;
    *pulIdleTaskStackSize   = configMINIMAL_STACK_SIZE;
}

/**
 * @brief       获取定时器服务任务的任务堆栈和任务控制块内存
 * @param       ppxTimerTaskTCBBuffer:任务控制块内存
                ppxTimerTaskStackBuffer:任务堆栈内存
                pulTimerTaskStackSize:任务堆栈大小
 * @retval      无
 */
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
                                    StackType_t  **ppxTimerTaskStackBuffer,
                                    uint32_t     *pulTimerTaskStackSize)
{
    *ppxTimerTaskTCBBuffer  = &TimerTaskTCB;
    *ppxTimerTaskStackBuffer= TimerTaskStack;
    *pulTimerTaskStackSize  = configTIMER_TASK_STACK_DEPTH;
}

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

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

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

/* TASK3 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK3_PRIO      4                   /* 任务优先级 */
#define TASK3_STK_SIZE  128                 /* 任务堆栈大小 */
StackType_t Task3TaskStack[TASK3_STK_SIZE]; /* 任务堆栈 */
StaticTask_t            Task3TaskTCB;       /* 任务控制块 */
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 Create & Del", 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);
    
    StartTask_Handler = xTaskCreateStatic((TaskFunction_t   )start_task,        /* 任务函数 */
                                          (const char*      )"start_task",      /* 任务名称 */
                                          (uint32_t         )START_STK_SIZE,    /* 任务堆栈大小 */
                                          (void*            )NULL,              /* 传递给任务函数的参数 */
                                          (UBaseType_t      )START_TASK_PRIO,   /* 任务优先级 */
                                          (StackType_t*     )StartTaskStack,    /* 任务堆栈 */
                                          (StaticTask_t*    )&StartTaskTCB);    /* 任务控制块 */
    vTaskStartScheduler();
}

/**
 * @brief       start_task
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           /* 进入临界区 */
    /* 创建任务1 */
    Task1Task_Handler = xTaskCreateStatic((TaskFunction_t   )task1,         /* 任务函数 */
                                          (const char*      )"task1",       /* 任务名称 */
                                          (uint32_t         )TASK1_STK_SIZE,/* 任务堆栈大小 */
                                          (void*            )NULL,          /* 传递给任务函数的参数 */
                                          (UBaseType_t      )TASK1_PRIO,    /* 任务优先级 */
                                          (StackType_t*     )Task1TaskStack,/* 任务堆栈 */
                                          (StaticTask_t*    )&Task1TaskTCB);/* 任务控制块 */
    /* 创建任务2 */
    Task2Task_Handler = xTaskCreateStatic((TaskFunction_t   )task2,         /* 任务函数 */
                                          (const char*      )"task2",       /* 任务名称 */
                                          (uint32_t         )TASK2_STK_SIZE,/* 任务堆栈大小 */
                                          (void*            )NULL,          /* 传递给任务函数的参数 */
                                          (UBaseType_t      )TASK2_PRIO,    /* 任务优先级 */
                                          (StackType_t*     )Task2TaskStack,/* 任务堆栈 */
                                          (StaticTask_t*    )&Task2TaskTCB);/* 任务控制块 */
    /* 创建任务3 */
    Task3Task_Handler = xTaskCreateStatic((TaskFunction_t   )task3,         /* 任务函数 */
                                          (const char*      )"task3",       /* 任务名称 */
                                          (uint32_t         )TASK3_STK_SIZE,/* 任务堆栈大小 */
                                          (void*            )NULL,          /* 传递给任务函数的参数 */
                                          (UBaseType_t      )TASK3_PRIO,    /* 任务优先级 */
                                          (StackType_t*     )Task3TaskStack,/* 任务堆栈 */
                                          (StaticTask_t*    )&Task3TaskTCB);/* 任务控制块 */
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
    taskEXIT_CRITICAL();            /* 退出临界区 */
}

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

/**
 * @brief       task2
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task2(void *pvParameters)
{
    uint32_t task2_num = 0;
    
    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);
        
        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 */
            {
                if (Task1Task_Handler != NULL)
                {
                    vTaskDelete(Task1Task_Handler);
                    Task1Task_Handler = NULL;
                }
                break;
            }
            case KEY1_PRES:                     /* 删除任务2 */
            {
                if (Task2Task_Handler != NULL)
                {
                    vTaskDelete(Task2Task_Handler);
                    Task2Task_Handler = NULL;
                }
                break;
            }
            default:
            {
                break;
            }
        }
        
        vTaskDelay(10);
    }
}

"动态更方便,静态给高手极限压榨内存的"

相关推荐
蒙塔基的钢蛋儿2 小时前
告别内存泄露与空指针:用C#与.NET 10开启STM32H7高性能单片机开发新纪元
stm32·c#·.net
悠哉悠哉愿意3 小时前
【单片机学习笔记】第十一届省赛复盘
笔记·单片机·嵌入式硬件·学习
学嵌入式的小杨同学3 小时前
STM32 进阶封神之路(二十七):MQTT 深度解析 —— 从协议原理到 OneNET 云平台接入(底层逻辑 + AT 指令开发)
stm32·单片机·嵌入式硬件·mcu·硬件架构·pcb·嵌入式实时数据库
DLGXY3 小时前
STM32(二十九)——读写、擦除FLASH
前端·stm32·嵌入式硬件
風清掦3 小时前
【江科大STM32学习笔记-09】USART串口协议 - 9.2 USART串口数据包
笔记·stm32·单片机·嵌入式硬件·学习
【 STM32开发 】3 小时前
【STM32 + CubeMX】低功耗 -- Standby 待机模式
单片机·嵌入式硬件
广药门徒3 小时前
PADS 改变飞线方向 改变同网络既定路径规划 改变VIRTUAL HOLE连接路径 修复差分信号自动规划飞线错误问题的办法
嵌入式硬件
猪猪童鞋4 小时前
PADS安装包资源分享
嵌入式硬件
Zarek枫煜4 小时前
zig与c3的算法 -- 静态队列
开发语言·stm32·单片机·嵌入式硬件·算法·51单片机