当前位置: 首页 > web >正文

第六章:6.1 ESP32教学:多任务处理与FreeRTOS实战

一、FreeRTOS简介

ESP32内置了FreeRTOS实时操作系统内核,这是一个专为嵌入式系统设计的开源实时操作系统。它支持:

  • 多任务并行处理

  • 任务优先级管理

  • 内存管理

  • 任务间通信

  • 定时器管理

二、任务创建与管理

1. 任务创建(xTaskCreate)

BaseType_t xTaskCreate(TaskFunction_t pvTaskCode,    // 任务函数指针const char * const pcName,    // 任务名称configSTACK_DEPTH_TYPE usStackDepth, // 堆栈大小void *pvParameters,          // 任务参数UBaseType_t uxPriority,      // 任务优先级TaskHandle_t *pxCreatedTask  // 任务句柄指针
);
void setup() {Serial.begin(115200);// 创建两个任务xTaskCreate(task1,          // 任务函数"Task1",         // 任务名称2048,            // 堆栈大小(字节)NULL,            // 任务参数1,               // 优先级(0-24)NULL             // 任务句柄);xTaskCreate(task2, "Task2", 2048, NULL, 2, NULL);
}void task1(void * parameter) {while(1) {Serial.println("Task1正在运行");vTaskDelay(1000 / portTICK_PERIOD_MS);  // 延时1秒}
}void task2(void * parameter) {while(1) {Serial.println("Task2正在执行高优先级任务");vTaskDelay(500 / portTICK_PERIOD_MS);  // 延时500ms}
}void loop() {}  // Arduino主循环留空

2. 关键函数解析

  • vTaskDelay():非阻塞延时void vTaskDelay(const TickType_t xTicksToDelay);
    参数使用pdMS_TO_TICKS()宏转换时间,例如:vTaskDelay(pdMS_TO_TICKS(100));  // 精确延时100ms
    vTaskDelete():删除任务void vTaskDelete(TaskHandle_t xTaskToDelete);
     

三、任务间通信

1. 队列(Queue)

队列是先进先出(FIFO)的数据结构,用于任务间安全传递数据。

创建队列:

QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength,  // 队列长度UBaseType_t uxItemSize      // 单个元素大小(字节)
);

完整示例:

QueueHandle_t dataQueue;void setup() {Serial.begin(115200);// 创建能存储10个int的队列dataQueue = xQueueCreate(10, sizeof(int));xTaskCreate(producerTask, "Producer", 2048, NULL, 1, NULL);xTaskCreate(consumerTask, "Consumer", 2048, NULL, 2, NULL);
}// 生产者任务
void producerTask(void * parameter) {int counter = 0;while(1) {xQueueSend(dataQueue, &counter, portMAX_DELAY);Serial.printf("生产数据:%d\n", counter);counter++;vTaskDelay(800 / portTICK_PERIOD_MS);}
}// 消费者任务
void consumerTask(void * parameter) {int receivedData;while(1) {if(xQueueReceive(dataQueue, &receivedData, 1000 / portTICK_PERIOD_MS)){Serial.printf("消费数据:%d\n", receivedData);}}
}void loop() {}

2. 信号量(Semaphore)

用于任务同步和资源共享控制

二进制信号量示例:

SemaphoreHandle_t binSemaphore;void setup() {Serial.begin(115200);binSemaphore = xSemaphoreCreateBinary();xSemaphoreGive(binSemaphore);  // 初始可用xTaskCreate(taskA, "TaskA", 2048, NULL, 2, NULL);xTaskCreate(taskB, "TaskB", 2048, NULL, 1, NULL);
}void taskA(void * parameter) {while(1) {if(xSemaphoreTake(binSemaphore, portMAX_DELAY)){Serial.println("TaskA获得信号量");vTaskDelay(1000 / portTICK_PERIOD_MS);xSemaphoreGive(binSemaphore);}}
}void taskB(void * parameter) {while(1) {if(xSemaphoreTake(binSemaphore, portMAX_DELAY)){Serial.println("TaskB获得信号量");vTaskDelay(500 / portTICK_PERIOD_MS);xSemaphoreGive(binSemaphore);}}
}void loop() {}

四、最佳实践建议

  1. 堆栈大小设置原则:

    • 简单任务:1-2KB

    • 复杂任务(涉及字符串处理):4KB+

    • 使用uxTaskGetStackHighWaterMark()监控堆栈使用

  2. 优先级管理

    • 0(最低)~24(最高)

    • 避免"优先级反转"问题

  3. 队列使用技巧

    • 大数据建议传递指针

    • 使用xQueueSendToFront()实现紧急消息插队

    • 超时设置避免死锁

五、常见问题排查

  1. 任务无法启动

    • 检查堆栈是否过小

    • 确认任务函数为无限循环

  2. 队列数据丢失

    • 增加队列长度

    • 检查生产者速度是否过快

  3. 系统崩溃

    • 使用ESP32异常解码工具

    • 检查内存越界访问

六、综合应用案例

实现温湿度传感器数据采集与网络上传的协同工作:

#include <WiFi.h>
#include <DHT.h>#define DHTPIN 4
#define DHTTYPE DHT22DHT dht(DHTPIN, DHTTYPE);
QueueHandle_t sensorQueue;
SemaphoreHandle_t wifiSemaphore;void setup() {Serial.begin(115200);dht.begin();sensorQueue = xQueueCreate(5, sizeof(float[2]));wifiSemaphore = xSemaphoreCreateBinary();xTaskCreate(readSensorTask, "Sensor", 4096, NULL, 2, NULL);xTaskCreate(uploadTask, "Upload", 4096, NULL, 1, NULL);WiFi.begin("SSID", "password");while(WiFi.status() != WL_CONNECTED){vTaskDelay(500 / portTICK_PERIOD_MS);}xSemaphoreGive(wifiSemaphore);
}void readSensorTask(void * parameter) {float data[2];while(1) {data[0] = dht.readTemperature();data[1] = dht.readHumidity();if(!isnan(data[0]) && !isnan(data[1])){xQueueSend(sensorQueue, data, 0);}vTaskDelay(2000 / portTICK_PERIOD_MS);}
}void uploadTask(void * parameter) {float receivedData[2];while(1) {if(xSemaphoreTake(wifiSemaphore, 1000 / portTICK_PERIOD_MS)){if(xQueueReceive(sensorQueue, receivedData, 0)){// 模拟网络上传Serial.printf("上传数据:温度%.1f℃ 湿度%.1f%%\n", receivedData[0], receivedData[1]);}xSemaphoreGive(wifiSemaphore);}vTaskDelay(1000 / portTICK_PERIOD_MS);}
}void loop() {}

总结

通过合理使用FreeRTOS的多任务功能,可以充分发挥ESP32的双核优势。

http://www.xdnf.cn/news/4077.html

相关文章:

  • 谷歌SMR测试环境搭建
  • Spring 框架中 @Configuration 注解详解
  • Springboot循环依赖
  • FOC算法开环控制基础
  • Java开发者面试实录:微服务架构与Spring Cloud的应用
  • 学习黑客Nmap 原理
  • 什么是外联模板(extern template)?
  • 【阿里云大模型高级工程师ACP学习笔记】2.9 大模型应用生产实践 (下篇)
  • C++竞赛指南
  • 搜索速度迅猛,能在0.001秒内迅速找到文件,但遗憾的是,该软件已经停止更新
  • 前端- ElementPlus入门
  • yolov11 epoch100轮 训练笔记5 kaggle comet
  • Android学习总结之GetX库篇(优缺点)
  • 进程的程序替换——exec系列函数的使用
  • 效整理文件信息!一键生成文件夹目录的工具
  • 8.渐入佳境 -- 域名及网络地址
  • Unity:Surface Effector 2D(表面效应器 2D)
  • OSE2.【Linux】练习:查找项目的main函数入口
  • 开元类双端互动组件部署实战全流程教程(第3部分:UI资源加载机制与界面逻辑全面解析
  • 事务隔离(MySQL)
  • FTP(文件传输协议)
  • 15.日志分析入门
  • LeetCode算法题 (反转链表)Day17!!!C/C++
  • Cookie与Session
  • JookDB:一款国产的通用数据库开发工具
  • 期末代码Python
  • 【数据结构】第八章:排序
  • 【言语理解】片段阅读之标题拟定(5)
  • ABC 404
  • TCP协议(三次握手、流量控制、拥塞控制)