当前位置:   article > 正文

1.在ESP32 Arduino框架上实验FreeRTOS:多任务操作系统的简介与应用_arduino freertos

arduino freertos

FreeRTOS

介绍


实时操作系统(RTOS):

实时操作系统是一种专为实时应用程序设计的操作系统。实时应用程序对任务的响应时间有严格的要求,因此实时操作系统必须能够在预定的时间内完成任务的调度和执行。这与通用操作系统(如Windows、Linux)的设计目标有所不同,通用操作系统更注重用户体验和各种应用程序的同时运行。

实时操作系统通常用于嵌入式系统、航空航天、医疗设备、汽车控制系统等领域,这些领域对系统的响应时间和可靠性要求非常高。

FreeRTOS:

FreeRTOS(Real-Time Operating System)是一个开源的实时操作系统内核,它是由英国公司Real Time Engineers Ltd.创建并维护的。FreeRTOS提供了一个轻量级、可移植的内核,适用于多种嵌入式平台。

以下是FreeRTOS的一些特点和功能:

  1. 多任务管理: FreeRTOS支持多任务,允许在同一系统中运行多个任务。每个任务都有自己的堆栈和优先级,任务之间可以共享资源。

  2. 任务调度: FreeRTOS使用抢占式任务调度,任务按照优先级进行调度,高优先级任务可以打断低优先级任务的执行。

  3. 内存管理: FreeRTOS提供内存管理机制,可以灵活地配置和管理任务堆栈、消息队列等资源。

  4. 互斥锁和信号量: 用于实现任务之间的同步和互斥,防止资源冲突。

  5. 定时器和中断处理: FreeRTOS提供了软件定时器和硬件定时器的支持,以及灵活的中断处理机制。

  6. 可移植性: FreeRTOS的内核设计使其能够轻松地移植到不同的嵌入式平台上,支持多种处理器架构。

  7. 开源和社区支持: 作为开源项目,FreeRTOS得到了广泛的社区支持,用户可以方便地获取源代码、文档和社区帮助。

在使用FreeRTOS时,可以通过创建任务、使用信号量和队列等机制,以一种结构化和可维护的方式设计和实现复杂的嵌入式系统。

第一个FreeRTOS程序


创建多任务

在FreeRTOS中,创建多任务可以使用 xTaskCreate 函数。该函数的原型如下:

BaseType_t xTaskCreate(
    TaskFunction_t pvTaskCode,
    const char * const pcName,
    const uint32_t usStackDepth,
    void * const pvParameters,
    UBaseType_t uxPriority,
    TaskHandle_t * const pxCreatedTask
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这个函数用于创建一个新的任务。下面是各个参数的解释:

  • TaskFunction_t pvTaskCode: 这是任务函数的指针,该函数将在任务被创建时运行。任务函数的原型应为 void taskFunction(void *pvParameters),其中 pvParameters 是传递给任务的参数。

  • const char * const pcName: 这是任务的名称,用于识别任务。这个参数是一个字符串。

  • const uint32_t usStackDepth: 这是任务堆栈的深度,以字为单位。堆栈的深度取决于任务的要求和系统的限制。

  • void * const pvParameters: 这是传递给任务函数的参数,可以是一个结构体、整数或其他任何类型。

  • UBaseType_t uxPriority: 这是任务的优先级。优先级越高的任务将更早得到执行。通常,0是最低优先级,数字越大优先级越高

  • TaskHandle_t * const pxCreatedTask: 这是一个指向任务句柄的指针,用于接收任务的句柄。如果不需要任务句柄,可以将此参数设置为 NULL

下面是一个简单的例子,演示如何创建两个任务:

#include <Arduino.h>

void task1(void *pvParameters) {
  while (1) {
    Serial.println("Task 1 is running...");
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}

void task2(void *pvParameters) {
  while (1) {
    Serial.println("Task 2 is running...");
    vTaskDelay(2000 / portTICK_PERIOD_MS);
  }
}

void setup() {
  Serial.begin(115200);

  xTaskCreate(task1, "Task1", 1024, NULL, 1, NULL);
  xTaskCreate(task2, "Task2", 1024, NULL, 1, NULL);
}

void loop() {
  // 什么都不做
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在这个例子中,task1task2 是两个简单的任务函数,分别以不同的频率输出消息。通过 xTaskCreate 函数创建这两个任务,并在 setup 函数中启动它们。这样,两个任务将并行运行,形成多任务系统。

给任务函数传参

在FreeRTOS中,可以通过 pvParameters 参数将参数传递给任务函数。当使用 xTaskCreate 函数创建任务时,你可以将参数作为最后一个参数传递给该函数。这个参数是一个 void * 类型的指针,可以指向任何类型的数据。

以下是一个简单的例子:

#include <Arduino.h>


// 定义结构体作为参数
typedef struct {
  int ledPin;
  int delayTime;
} TaskParameters;

// 任务函数
void blinkTask(void *pvParameters) {
  TaskParameters *params = (TaskParameters *)pvParameters;

  pinMode(params->ledPin, OUTPUT);

  while (1) {
    digitalWrite(params->ledPin, !digitalRead(params->ledPin));
    vTaskDelay(params->delayTime / portTICK_PERIOD_MS);
  }
}

void setup() {
  Serial.begin(115200);

  // 设置LED1任务参数
  TaskParameters params1 = {21, 1000};
  // 创建LED1任务
  xTaskCreate(blinkTask, "BlinkTask1", 1024, (void *)&params1, 1, NULL);

  // 设置LED2任务参数
  TaskParameters params2 = {23, 2000};
  // 创建LED2任务
  xTaskCreate(blinkTask, "BlinkTask2", 1024, (void *)&params2, 1, NULL);
}

void loop() {
  // 什么都不做
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

在这个例子中,我们定义了一个结构体 TaskParameters 来存储任务的参数,其中包括LED引脚号和LED闪烁间隔时间。然后,我们分别为两个LED创建了两个任务,将不同的参数传递给它们。在任务函数 blinkTask 中,通过类型转换将 pvParameters 转换为 TaskParameters 类型,然后就可以访问传递的参数了。

FreeRTOS多任务点灯

掌握了创建多任务以及向任务传参的方法,我们就可以完成第一个FreeRTOS项目了

项目任务:
通过两个任务,分别控制两个LED的闪烁。每个LED由一个独立的任务来处理,通过在任务中控制LED的状态,实现两LED的闪烁间隔时间不同。
在这里插入图片描述

以下是这个项目的基本流程:

  1. 结构体定义:

    typedef struct {
      byte pin;
      int DelayTime;
    } LEDFLASH;
    
    • 1
    • 2
    • 3
    • 4

    定义了一个结构体 LEDFLASH,其中包含了 LED 的引脚号和闪烁的时间间隔。

  2. 任务函数定义:

    void task(void *pt) {
      LEDFLASH *ptLedFlash = (LEDFLASH *)pt;
    
      pinMode(ptLedFlash->pin, OUTPUT);
      while (1) {
        digitalWrite(ptLedFlash->pin, !digitalRead(ptLedFlash->pin));
        vTaskDelay(ptLedFlash->DelayTime); // 通过 FreeRTOS 的延迟函数实现 LED 闪烁
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    定义了一个任务函数 task,该函数通过类型转换获取 LED 结构体指针,然后在一个无限循环中控制 LED 的状态并通过 vTaskDelay 实现 LED 的闪烁效果。

  3. 任务创建:

    void setup() {
      LEDFLASH ledFlash1 = {21, 1000}; // 第一个LED,引脚21,每秒一次
      LEDFLASH ledFlash2 = {23, 3000}; // 第二个LED,引脚23,每三秒一次
    
      xTaskCreate(task, "Blink 21", 1024, (void *)&ledFlash1, 1, NULL);
      xTaskCreate(task, "Blink 23", 1024, (void *)&ledFlash2, 1, NULL);
    
      Serial.begin(115200);
      Serial.println(portTICK_PERIOD_MS); // 打印一个 tick 的时间
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    setup 函数中,创建了两个任务,分别用于控制两个 LED。每个任务都独立运行,控制不同 LED 的状态。

  4. 串口初始化:

    Serial.begin(115200);
    
    • 1

    初始化串口通信,用于在串口监视器上输出信息。

  5. 主循环:

    void loop() {
      // 什么都不做
    }
    
    • 1
    • 2
    • 3

    由于任务在 FreeRTOS 中进行管理和调度,因此 loop 函数为空。

通过 FreeRTOS 实现多任务处理,通过两个任务控制两个 LED 的独立闪烁,展示了 FreeRTOS 在 ESP32 上实时操作系统的应用。源码点击查看

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/825855
推荐阅读
相关标签
  

闽ICP备14008679号