STM32 基于开源 RTOS(FreeRTOS):嵌入式项目多任务(传感器采集 / 数据发送)调度开发
·
STM32基于FreeRTOS的多任务调度开发(传感器采集/数据发送)
1. 系统架构设计
采用生产者-消费者模型实现任务解耦:
- 生产者任务:传感器数据采集(周期性执行)
- 消费者任务:数据打包发送(事件驱动)
- 通信机制:使用队列传递数据,实现任务同步
graph LR
A[传感器采集任务] -->|写入队列| B[数据队列]
B -->|读取数据| C[数据发送任务]
2. 关键组件实现
(1)队列创建(main.c)
#include "FreeRTOS.h"
#include "queue.h"
#define QUEUE_LENGTH 10
#define ITEM_SIZE sizeof(SensorData)
QueueHandle_t xDataQueue;
int main(void) {
HAL_Init();
SystemClock_Config();
// 创建数据队列
xDataQueue = xQueueCreate(QUEUE_LENGTH, ITEM_SIZE);
// 创建任务
xTaskCreate(vSensorTask, "Sensor", 128, NULL, 3, NULL);
xTaskCreate(vSendTask, "Sender", 128, NULL, 2, NULL);
vTaskStartScheduler();
while(1);
}
(2)传感器采集任务(周期性)
void vSensorTask(void *pvParameters) {
SensorData data;
const TickType_t xDelay = pdMS_TO_TICKS(100); // 100ms周期
for(;;) {
// 1. 读取传感器(示例)
data.timestamp = xTaskGetTickCount();
data.value = read_adc(ADC_CHANNEL);
// 2. 写入队列(阻塞式)
if(xQueueSend(xDataQueue, &data, portMAX_DELAY) != pdPASS) {
// 错误处理
}
// 3. 精确周期延迟
vTaskDelayUntil(&xLastWakeTime, xDelay);
}
}
(3)数据发送任务(事件驱动)
void vSendTask(void *pvParameters) {
SensorData rxData;
for(;;) {
// 1. 阻塞等待队列数据
if(xQueueReceive(xDataQueue, &rxData, portMAX_DELAY) == pdPASS) {
// 2. 数据处理(示例)
uint8_t buffer[20];
int len = snprintf(buffer, sizeof(buffer), "T:%lu V:%d",
rxData.timestamp, rxData.value);
// 3. 通过UART发送
HAL_UART_Transmit(&huart1, buffer, len, HAL_MAX_DELAY);
}
}
}
3. 关键配置参数
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 采集任务优先级 | 3 (较高) | 保证实时性 |
| 发送任务优先级 | 2 (中等) | 低于采集任务 |
| 队列长度 | 10-20 | 根据数据速率调整 |
| 采集周期 | 50-200ms | 取决于传感器特性 |
| 任务堆栈大小 | 128-256字 | 根据函数调用深度调整 |
4. 优化策略
-
双缓冲技术:
// 在采集任务中 static SensorData buffer[2]; static uint8_t activeBuf = 0; // 采集周期结束时切换缓冲区 xQueueSend(xDataQueue, &buffer[activeBuf], 0); activeBuf ^= 1; // 切换缓冲区 -
带超时的队列接收:
// 在发送任务中 if(xQueueReceive(xDataQueue, &data, pdMS_TO_TICKS(50)) == pdPASS) { // 处理数据 } else { // 发送心跳包维持连接 } -
优先级反转预防:
- 使用互斥锁保护共享资源
- 考虑优先级继承机制:
SemaphoreHandle_t xUartMutex = xSemaphoreCreateMutex(); // 发送前获取互斥锁 if(xSemaphoreTake(xUartMutex, portMAX_DELAY) == pdTRUE) { HAL_UART_Transmit(...); xSemaphoreGive(xUartMutex); }
5. 调试技巧
- 使用FreeRTOS的
uxTaskGetStackHighWaterMark()监控堆栈使用 - 通过
vTaskList()获取任务状态信息 - 利用STM32的硬件定时器验证任务执行周期精度
- 在队列操作前后添加调试引脚电平变化,用示波器观察时序
注意事项:
- 避免在中断服务程序(ISR)中直接调用
xQueueSend(),应使用xQueueSendFromISR()- 任务优先级设置需确保传感器采集不被阻塞
- 使用
configASSERT()验证RTOS API调用结果- 低功耗设计时,合理使用
eTaskStateGet()管理任务状态
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)