Arduino ESP32 FreeRTOS

基本多线程Arduino示例

在这里插入图片描述

配置

#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif

当FreeRTOS配置为单核模式时,ARDUINO_RUNNING_CORE宏被定义为0,表示应用程序在主核心上运行。而当FreeRTOS配置为双核模式时,ARDUINO_RUNNING_CORE宏被定义为1,表示应用程序在第二个核心上运行。

在ESP32上,可以使用两个独立的处理器核心来运行应用程序和操作系统。在双核模式下,一个核心运行FreeRTOS调度程序,另一个核心则可用于运行用户应用程序。这种方式可以提高系统性能和响应速度。

创建任务

#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

void task1(void *pvParameters) {
    while (1) {
        // 任务1的代码
        vTaskDelay(1000 / portTICK_PERIOD_MS);  // 延时1秒
    }
}

void task2(void *pvParameters) {
    while (1) {
        // 任务2的代码
        vTaskDelay(2000 / portTICK_PERIOD_MS);  // 延时2秒
    }
}

void setup() {
    // 初始化代码可以放在这里
    Serial.begin(115200);

    // 创建FreeRTOS任务
    xTaskCreate(task1, "task1", 4096, NULL, 1, NULL);
    xTaskCreate(task2, "task2", 4096, NULL, 2, NULL);
}

void loop() {
    // 由于FreeRTOS自行管理任务,loop()中一般不需要添加额外的代码
}
  • 例子中,setup()函数用于初始化代码,而loop()函数为空。FreeRTOS的任务(task1和task2)被创建在setup()函数中,因为它们会在整个程序运行期间持续执行。

  • 请注意,在ESP32上,FreeRTOS自身负责任务的调度,因此在loop()中通常不需要编写额外的代码。任务的具体实现应该在各自的任务函数中。这样设计的好处是能够更灵活地管理任务的执行和调度。

消息队列

#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>

QueueHandle_t xQueue;

void sender_task(void *pvParameters) {
    while (1) {
        // 生产数据
        int data = esp_random();
        xQueueSend(xQueue, &data, portMAX_DELAY);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void receiver_task(void *pvParameters) {
    while (1) {
        int data;
        xQueueReceive(xQueue, &data, portMAX_DELAY);
        
        // 处理接收到的数据
        Serial.println("Received data: " + String(data));
    }
}

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

    // 创建消息队列
    xQueue = xQueueCreate(5, sizeof(int));

    // 创建FreeRTOS任务
    xTaskCreate(sender_task, "sender", 4096, NULL, 1, NULL);
    xTaskCreate(receiver_task, "receiver", 4096, NULL, 2, NULL);
}

void loop() {
    // FreeRTOS任务的具体执行在各自的任务函数中,因此loop()中无需额外的代码
}
  • 例子中,sender_task任务负责产生随机数据并将其发送到消息队列中,而receiver_task任务则负责从消息队列中接收数据并进行处理。在setup()函数中,首先创建了一个消息队列 (xQueue = xQueueCreate(5, sizeof(int))😉,然后创建了两个FreeRTOS任务,分别执行sender_task和receiver_task。

  • 请注意,vTaskDelay函数用于任务之间的延时,以防止任务频繁执行。此外,在Arduino中使用Serial对象输出调试信息。

信号量

#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>

SemaphoreHandle_t xSemaphore;

void task1(void *pvParameters) {
    while (1) {
        // 任务1等待信号量
        if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
            // 共享资源的访问和操作
            Serial.println("Task 1 is running");
            
            // 释放信号量
            xSemaphoreGive(xSemaphore);
        }

        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void task2(void *pvParameters) {
    while (1) {
        // 任务2等待信号量
        if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
            // 共享资源的访问和操作
            Serial.println("Task 2 is running");
            
            // 释放信号量
            xSemaphoreGive(xSemaphore);
        }

        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}

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

    // 创建信号量
    xSemaphore = xSemaphoreCreateMutex();

    // 创建FreeRTOS任务
    xTaskCreate(task1, "task1", 4096, NULL, 1, NULL);
    xTaskCreate(task2, "task2", 4096, NULL, 2, NULL);
}

void loop() {
    // FreeRTOS任务的具体执行在各自的任务函数中,因此loop()中无需额外的代码
}
  • 例子中,task1和task2任务都尝试获取一个互斥信号量 (xSemaphore)。如果信号量可用,任务就会获得对共享资源的访问权限,执行一些操作,然后释放信号量。如果信号量当前被其他任务占用,任务将等待,直到信号量可用。

  • 请注意,在实际应用中,信号量可用于保护共享资源,以确保多个任务之间对资源的访问是同步的,避免竞态条件。

定时器

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/timers.h>

TimerHandle_t xTimer;

void timer_callback(TimerHandle_t xTimer) {
    // 定时器到期时的处理代码
}

void setup() {
    xTimer = xTimerCreate("MyTimer", pdMS_TO_TICKS(1000), pdTRUE, 0, timer_callback);
    xTimerStart(xTimer, 0);

    // 创建其他任务等
}

void loop() {
    // FreeRTOS任务的具体执行在各自的任务函数中,因此loop()中无需额外的代码
}
  • 定时器可以用于定时执行特定的任务或操作。

互拆量(Mutex)

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>

SemaphoreHandle_t xMutex;

void task1(void *pvParameters) {
    while (1) {
        xSemaphoreTake(xMutex, portMAX_DELAY);
        // 临界区的代码
        xSemaphoreGive(xMutex);

        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void task2(void *pvParameters) {
    while (1) {
        xSemaphoreTake(xMutex, portMAX_DELAY);
        // 临界区的代码
        xSemaphoreGive(xMutex);

        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}

void setup() {
    xMutex = xSemaphoreCreateMutex();

    xTaskCreate(task1, "task1", 4096, NULL, 1, NULL);
    xTaskCreate(task2, "task2", 4096, NULL, 2, NULL);
}

void loop() {
    // FreeRTOS任务的具体执行在各自的任务函数中,因此loop()中无需额外的代码
}
  • 互斥量用于保护共享资源,确保在任何时刻只有一个任务能够访问临界区的代码。

事件组(Event Group)

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/event_groups.h>

EventGroupHandle_t xEventGroup;

#define BIT_0 (1 << 0)
#define BIT_1 (1 << 1)

void task1(void *pvParameters) {
    while (1) {
        xEventGroupSetBits(xEventGroup, BIT_0);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void task2(void *pvParameters) {
    while (1) {
        if (xEventGroupWaitBits(xEventGroup, BIT_0, pdTRUE, pdTRUE, portMAX_DELAY)) {
            // 处理事件 BIT_0
            xEventGroupSetBits(xEventGroup, BIT_1);
        }

        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}

void setup() {
    xEventGroup = xEventGroupCreate();

    xTaskCreate(task1, "task1", 4096, NULL, 1, NULL);
    xTaskCreate(task2, "task2", 4096, NULL, 2, NULL);
}

void loop() {
    // FreeRTOS任务的具体执行在各自的任务函数中,因此loop()中无需额外的代码
}
  • 事件组允许任务等待和设置事件标志,用于任务间的同步和通信。
  • 9
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逢生博客

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值