FreeRTOS的任务创建/删除(详解,很简单)

什么是FreeRTOS的任务?

        在FreeRTOS中,任务(Task)是系统中执行的基本单元。任务是一段具有独立执行流的代码,它可以在系统中独立运行。每个任务都有自己的栈空间和程序计数器(Program Counter),使得它能够保持自己的上下文并独立于其他任务运行。

        在FreeRTOS中,任务的创建和调度由内核负责。任务可以具有不同的优先级,高优先级的任务将在低优先级任务之前执行。FreeRTOS使用抢占式调度(Preemptive Scheduling),这意味着如果有更高优先级的任务准备好运行,它可以抢占当前正在运行的任务。

        任务的创建和管理是使用FreeRTOS提供的API函数完成的。以下是一些常见的任务管理函数:

        xTaskCreate(): 用于创建任务。

        vTaskDelete(): 用于删除任务。

        vTaskDelay(): 用于使任务延迟一段时间。

        vTaskSuspend()和vTaskResume(): 用于挂起和恢复任务的执行。

        vTaskPrioritySet(): 用于设置任务的优先级。

        任务可以通过调用vTaskDelay()来使自己暂停一段时间,也可以通过调用vTaskSuspend()挂起自己的执行,然后通过vTaskResume()来恢复执行。

        在FreeRTOS中,任务是多线程的基本单位,通过任务的创建、删除、挂起、恢复等操作,可以实现多任务协同工作,提高系统的实时性和并发性。

        在FreeRTOS中,任务就是一个函数,原型如下:

void ATaskFunction(void *pvParameters);

要注意的是:

1、这个函数不能返回

2、同一个函数,可以用来创建多个任务;换句话说,多个任务可以运行同一个函数;

3、函数内部,尽量使用局部变量:

        1)每个任务都有自己的栈

        2)每个任务运行这个函数时

                (1)任务A的局部变量放在任务A的栈里、任务B的局部变量放在任务B的栈里

                (2)不同任务的局部变量,有自己的副本

        3)函数使用全局变量、静态变量的话

                (1)只有一个副本:多个任务使用的是同一个副本

                (2)要防止冲突(后续会讲)

示例:

void ATaskFunction( void *pvParameters )
{
    /* 对于不同的任务,局部变量放在任务的栈里,有各自的副本 */
       int32_t lVariableExample = 0;

    /* 任务函数通常实现为一个无限循环 */
       for( ;; )
       {
              /* 任务的代码 */
       }

    /* 如果程序从循环中退出,一定要使用vTaskDelete删除自己
     * NULL表示删除的是自己
     */

       vTaskDelete( NULL );
    /* 程序不会执行到这里, 如果执行到这里就出错了 */
}

任务的创建

创建任务时使用的函数如下:

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
                        const char * const pcName, // 任务的名字
                        const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节
                        void * const pvParameters, // 调用任务函数时传入的参数
                        UBaseType_t uxPriority,    // 优先级
                        TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务

参数说明:

参数 描述
pvTaskCode

函数指针,可以简单地认为任务就是一个C函数。

它稍微特殊一点:永远不退出,或者退出时要调用"vTaskDelete(NULL)"

pcName

任务的名字,FreeRTOS内部不使用它,仅仅起调试作用。

长度为:configMAX_TASK_NAME_LEN

usStackDepth

每个任务都有自己的栈,这里指定栈大小。

单位是word,比如传入100,表示栈大小为100 word,也就是400字节。

最大值为uint16_t的最大值。

怎么确定栈的大小,并不容易,很多时候是估计。

精确的办法是看反汇编码。

pvParameters 调用pvTaskCode函数指针时用到:pvTaskCode(pvParameters)
uxPriority

优先级范围:0~(configMAX_PRIORITIES – 1)

数值越小优先级越低,

如果传入过大的值,xTaskCreate会把它调整为(configMAX_PRIORITIES – 1)

pxCreatedTask

用来保存xTaskCreate的输出结果:task handle。

以后如果想操作这个任务,比如修改它的优先级,就需要这个handle。

如果不想使用该handle,可以传入NULL。

返回值

成功:pdPASS;

失败:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(失败原因只有内存不足)

注意:文档里都说失败时返回值是pdFAIL,这不对。

pdFAIL是0,errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY是-1。

创建任务的例子

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


// 函数原型
void SystemClock_Config(void);
static void MX_GPIO_Init(void);

// 任务函数
void vTask1(void *pvParameters) {
    while (1) {
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 切换LED状态
        vTaskDelay(1000 / portTICK_PERIOD_MS); // 每隔1秒执行一次
    }
}

void vTask2(void *pvParameters) {
    while (1) {
        // 任务2的处理逻辑
        vTaskDelay(2000 / portTICK_PERIOD_MS); // 每隔2秒执行一次
    }
}

void vTask3(void *pvParameters) {
    while (1) {
        // 任务3的处理逻辑
        vTaskDelay(3000 / portTICK_PERIOD_MS); // 每隔3秒执行一次
    }
}

int main(void) {
    // 硬件初始化
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    // 创建任务
    xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
    xTaskCreate(vTask3, "Task3", configMINIMAL_STACK_SIZE, NULL, 3, NULL);

    // 启动调度器
    vTaskStartScheduler();

    // 代码不应该运行到这里,如果运行到这里说明发生了错误
    while (1) {
        // 处理错误
    }
}

任务的删除

删除任务时使用的函数如下:

void vTaskDelete( TaskHandle_t xTaskToDelete );

参数说明:

参数 描述
pvTaskCode

任务句柄,使用xTaskCreate创建任务时可以得到一个句柄。

也可传入NULL,这表示删除自己。

 

怎么删除任务?举个不好的例子(例子来自韦东山):

        自杀:vTaskDelete(NULL)

        被杀:别的任务执行vTaskDelete(pvTaskCode),pvTaskCode是自己的句柄

        杀人:执行vTaskDelete(pvTaskCode),pvTaskCode是别的任务的句柄

删除任务的例子

        在FreeRTOS中,任务的删除通常是在任务自身的函数中通过调用vTaskDelete()来完成的。其中演示了如何在任务中删除其他任务:

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

// 函数原型
void SystemClock_Config(void);
static void MX_GPIO_Init(void);

// 任务函数
TaskHandle_t Task1_Handle, Task2_Handle, Task3_Handle;

void vTask1(void *pvParameters) {
    while (1) {
        // 任务1的处理逻辑
        vTaskDelay(1000 / portTICK_PERIOD_MS); // 每隔1秒执行一次
    }
}

void vTask2(void *pvParameters) {
    while (1) {
        // 任务2的处理逻辑
        vTaskDelay(2000 / portTICK_PERIOD_MS); // 每隔2秒执行一次

        // 删除任务1
        vTaskDelete(Task1_Handle);
    }
}

void vTask3(void *pvParameters) {
    while (1) {
        // 任务3的处理逻辑
        vTaskDelay(3000 / portTICK_PERIOD_MS); // 每隔3秒执行一次

        // 删除任务2
        vTaskDelete(Task2_Handle);
    }
}

int main(void) {

    // 硬件初始化
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    // 创建任务1
    xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, &Task1_Handle);

    // 创建任务2
    xTaskCreate(vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, &Task2_Handle);

    // 创建任务3
    xTaskCreate(vTask3, "Task3", configMINIMAL_STACK_SIZE, NULL, 3, &Task3_Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 代码不应该运行到这里,如果运行到这里说明发生了错误
    while (1) {
        // 处理错误
    }
}

// 系统时钟配置
void SystemClock_Config(void) {
    // 与前述代码相同,这里省略
}

// GPIO初始化
static void MX_GPIO_Init(void) {
    // 与前述代码相同,这里省略
}

        在这个例子中,任务2和任务3中分别使用了vTaskDelete()函数删除了任务1和任务2。请注意,在FreeRTOS中,任务只能删除自己或优先级较低的任务,因此任务2可以删除任务1,而任务3可以删除任务2。任务的删除是一种谨慎操作,需要确保被删除的任务没有在其他地方被引用或使用。

相关推荐

  1. 【2】STM32·FreeRTOS·任务创建删除

    2023-12-10 17:40:04       6 阅读
  2. FreeRTOS创建任务保存以及任务堆栈大小记录

    2023-12-10 17:40:04       36 阅读
  3. FreeRTOS】堆栈管理:任务执行基石

    2023-12-10 17:40:04       32 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-10 17:40:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-10 17:40:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-10 17:40:04       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-10 17:40:04       20 阅读

热门阅读

  1. springboot——helloworld入门

    2023-12-10 17:40:04       27 阅读
  2. Python3 基本数据类型 ----20231209

    2023-12-10 17:40:04       31 阅读
  3. mysql中information_schema.tables字段说明

    2023-12-10 17:40:04       41 阅读
  4. GO设计模式——1、简单工厂模式(创建型)

    2023-12-10 17:40:04       39 阅读
  5. 开源软件:JumpServer、DataEase、MeterSphere

    2023-12-10 17:40:04       44 阅读
  6. 【周报2023.12.09】

    2023-12-10 17:40:04       43 阅读
  7. c++ 类和对象-封装意义一

    2023-12-10 17:40:04       39 阅读
  8. 用格里高利公式求给定精度的PI值

    2023-12-10 17:40:04       43 阅读
  9. Vue笔记(一)基础

    2023-12-10 17:40:04       43 阅读