十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FreeRTOS任务创建与删除(动态编码)

FreeRTOS任务创建与删除(动态编码) 1.任务创建和删除的API函数任务创建的本质就是调用FreeRTOS的API函数下面是有关描述FreeRTOS提供两种创建任务函数的形式一种是动态创建任务另一种是静态创建任务。动态创建任务任务的任务控制块以及任务的栈空间所需的内存均由 FreeRTOS 从 FreeRTOS 管理的堆中分配。静态创建任务任务的任务控制块以及任务的栈空间所需的内存需用户分配提供。API函数描述xTaskCreate()动态方式创建任务xTaskCreateStatic()静态方式创建任务vTaskDelete()删除任务1.1动态创建任务函数函数说明BaseType_txTaskCreate(TaskFunction_tpxTaskCode,/* 指向任务函数的指针 */constchar*constpcName,/* 任务名字最大长度configMAX_TASK_NAME_LEN */constconfigSTACK_DEPTH_TYPEusStackDepth,/* 任务堆栈大小默认最小128单位4字节*/void*constpvParameters,/* 传递给任务函数的参数 */UBaseType_tuxPriority,/* 任务优先级范围0 ~ configMAX_PRIORITIES - 1 */TaskHandle_t*constpxCreatedTask/* 任务句柄就是任务的任务控制块 */)返回值说明如下pdPASS任务创建成功。errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY任务创建失败。备注pxTaskCode存放的是任务函数名pcName存放的是任务别名一般直接与任务函数名一致usStackDepth和uxPriority分别是任务堆栈大小和任务优先级可以通过宏定义的方式进行方便后续修改参数pxCreatedTask2.实验目标通过 xTaskCreate( ) 和 vTaskDelete( ) 的使用来实现下面功能start_task用来创建其他的三个任务。task1实现LED1每500ms闪烁一次。task2实现LED2每500ms闪烁一次。task3判断按键KEY1是否按下按下则删掉task1。3.实验准备过程在core/Src文件夹下新建一个.c文件用于存放本次任务。同时在core/Inc文件夹下创建一个同名的.h文件。这里我们命名为freertos_demo.c和freertos_demo.h。同时点击品字图标将freertos_demo.c路径进行添加。4.代码编写4.1freertos_demo.c文件代码编写1)任务设置#include freertos_demo.h//FreeRTOS相关的头文件必须的#include stdio.h#include FreeRTOS.h#include task.h//需要用到的其他头文件#include LED.h#include Key.h//启动任务的配置#define START_TASK_STACK 128#define START_TASK_PRIORITY 1TaskHandle_t start_task_handle;void start_task(void * pvParameters);//任务1的配置#define TASK1_STACK 128#define TASK1_PRIORITY 2TaskHandle_t task1_handle;void task1(void * pvParameters);//任务2的配置#define TASK2_STACK 128#define TASK2_PRIORITY 3TaskHandle_t task2_handle;void task2(void * pvParameters);//任务3的配置#define TASK3_STACK 128#define TASK3_PRIORITY 4TaskHandle_t task3_handle;void task3(void * pvParameters);2入口函数//启动FreeRTOSvoid freertos_start(void){/*1.创建一个启动任务*/xTaskCreate((TaskFunction_t) start_task, //任务函数的地址(char *) start_task, //任务名(configSTACK_DEPTH_TYPE) START_TASK_STACK, //任务堆栈大小默认最小128单位4字节(void *) NULL , //传递给任务的参数(UBaseType_t) START_TASK_PRIORITY, //任务优先级(TaskHandle_t *) start_task_handle); //任务句柄的地址/*2.启动调度器:会自动创建空闲任务*/vTaskStartScheduler();}3启动任务函数//启动任务用来创建其他任务void start_task(void * pvParameters){//进入临界区 临界区:保护临界区里面的代码不会被打断taskENTER_CRITICAL();//创建三个任务xTaskCreate((TaskFunction_t) task1, //任务函数的地址(char *) task1, //任务名(configSTACK_DEPTH_TYPE) TASK1_STACK, //任务堆栈大小默认最小128单位4字节(void *) NULL , //传递给任务的参数(UBaseType_t) TASK1_PRIORITY, //任务优先级(TaskHandle_t *) task1_handle); //任务句柄的地址xTaskCreate((TaskFunction_t) task2, //任务函数的地址(char *) task2, //任务名(configSTACK_DEPTH_TYPE) TASK2_STACK, //任务堆栈大小默认最小128单位4字节(void *) NULL , //传递给任务的参数(UBaseType_t) TASK2_PRIORITY, //任务优先级(TaskHandle_t *) task2_handle); //任务句柄的地址xTaskCreate((TaskFunction_t) task3, //任务函数的地址(char *) task3, //任务名(configSTACK_DEPTH_TYPE) TASK3_STACK, //任务堆栈大小默认最小128单位4字节(void *) NULL , //传递给任务的参数(UBaseType_t) TASK3_PRIORITY, //任务优先级(TaskHandle_t *) task3_handle); //任务句柄的地址//退出临界区后再删除启动任务避免屏蔽FreeRTOS时钟节拍taskEXIT_CRITICAL();//启动任务只需要执行一次即可创建完就删除vTaskDelete(NULL);}4)Task任务函数//任务一实现LED1每500ms闪烁一次void task1(void * pvParameters){while(1){printf(task1运行...\r\n);LED_Toggle(LED1_Pin);vTaskDelay(500);}}//任务二实现LED2每500ms闪烁一次void task2(void * pvParameters){while(1){printf(task2运行...\r\n);LED_Toggle(LED2_Pin);vTaskDelay(500);}}//任务三判断按键KEY1是否按下按下则删除task1void task3(void * pvParameters){uint8_t key0;while(1){printf(task3运行...\r\n);keyKey_Detect();if(keyKEY1_PRESS){//判断是否已经删过避免重复删除if(task1_handle !NULL ){printf(执行删除Task1...\r\n);//key1按下了删除task1vTaskDelete(task1_handle);task1_handleNULL;}}vTaskDelay(500);}}下面来解释一下代码实际运行时内部是如何发生变化的。task3优先级4最高task2优先级3task1优先级2启动任务优先级1空闲任务优先级0所以启动任务在临界区创建三个任务时它们的状态是task3就绪态task2就绪态task1就绪态启动任务运行态因为处于临界区task3暂时不能抢占启动任务等到临界区退出后调度过程如下第一步task3由就绪态变成运行态因为task3的优先级最高执行以下代码printf(task3运行...\r\n);key Key_Detect();vTaskDelay(500);第二步调用延时后task3由运行态转变为阻塞态。task2目前优先级最高同时处于就绪态所以执行task2的任务执行以下代码printf(task2运行...\r\n);LED_Toggle(LED2_Pin);vTaskDelay(500);第三步调用延时后task2由运行态转变为阻塞态。task1目前优先级最高同时处于就绪态所以执行task1的任务执行以下代码printf(task1运行...\r\n);LED_Toggle(LED1_Pin);vTaskDelay(500);第四步三个任务都进入阻塞态后启动任务执行vTaskDelete(NULL);删除自身。备注如果task3的500ms延时还没到系统会如何执行如果task3的500ms延时没到那么可能task1已经进入阻塞态同时启动任务也删除了自身FreeRTOS会运行系统自动创建的空闲任务Idle Task优先级0。因此CPU不会停止调度器也没有停止。系统状态是空闲任务运行态task1/2/3阻塞态。空闲任务主要做回收已删除任务的动态内存。维持系统始终至少有一个可运行任务。执行 Idle Hook当前工程已经关闭该 Hook。如果启用低功耗功能可以在空闲阶段进入休眠。当前没有开启 Tickless Idle所以CPU通常会一直执行空闲任务循环。同时每1ms仍然会发生 FreeRTOS SysTick 中断。SysTick不断检查延时任务是否到期。task3的500ms到期时task3阻塞态 → 就绪态。因为它的优先级4高于空闲任务的0所以立即抢占空闲任务空闲任务运行态 → 就绪态task3就绪态 → 运行态。
返回列表