RTOS 选型与架构
FreeRTOS 核心概念
任务管理
c
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
// 任务优先级定义(数字越大优先级越高)
#define PRIORITY_MODBUS_POLL 5 // 高优先级:实时采集
#define PRIORITY_DATA_PROCESS 4 // 中优先级:数据处理
#define PRIORITY_MQTT_SEND 3 // 中优先级:数据上报
#define PRIORITY_HEARTBEAT 2 // 低优先级:心跳
#define PRIORITY_IDLE 1 // 最低:空闲任务
// 任务栈大小(字,1字=4字节)
#define STACK_MODBUS 512
#define STACK_MQTT 1024
#define STACK_PROCESS 512
// 任务句柄
TaskHandle_t xModbusTask = NULL;
TaskHandle_t xMQTTTask = NULL;
// Modbus 采集任务
void vModbusPollTask(void *pvParameters) {
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xPeriod = pdMS_TO_TICKS(1000); // 1秒周期
for (;;) {
// 精确周期执行(补偿执行时间)
vTaskDelayUntil(&xLastWakeTime, xPeriod);
// 读取 Modbus 数据
ModbusData_t data;
if (Modbus_ReadRegisters(&data) == MODBUS_OK) {
// 发送到处理队列
xQueueSend(xDataQueue, &data, 0); // 不等待,丢弃旧数据
}
}
}
// 创建任务
void vCreateTasks(void) {
xTaskCreate(
vModbusPollTask, // 任务函数
"ModbusPoll", // 任务名称(调试用)
STACK_MODBUS, // 栈大小
NULL, // 参数
PRIORITY_MODBUS_POLL, // 优先级
&xModbusTask // 任务句柄
);
}队列通信
c
// 定义数据结构
typedef struct {
uint32_t timestamp;
float voltage;
float current;
float soc;
uint16_t alarm_flags;
} ModbusData_t;
// 创建队列(10个元素的缓冲)
QueueHandle_t xDataQueue;
void vInitQueues(void) {
xDataQueue = xQueueCreate(10, sizeof(ModbusData_t));
configASSERT(xDataQueue != NULL);
}
// 生产者:Modbus 采集任务
void vProducerTask(void *pvParameters) {
ModbusData_t data;
for (;;) {
if (Modbus_ReadData(&data) == MODBUS_OK) {
// 发送到队列,等待最多 10ms
if (xQueueSend(xDataQueue, &data, pdMS_TO_TICKS(10)) != pdPASS) {
// 队列满,记录丢弃事件
xDropCount++;
}
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// 消费者:数据处理任务
void vConsumerTask(void *pvParameters) {
ModbusData_t data;
for (;;) {
// 等待队列数据(最多 5 秒)
if (xQueueReceive(xDataQueue, &data, pdMS_TO_TICKS(5000)) == pdPASS) {
ProcessData(&data);
PublishToMQTT(&data);
} else {
// 超时,检查设备连接状态
HandleCommTimeout();
}
}
}互斥锁与信号量
c
// 互斥锁保护共享资源(串口)
SemaphoreHandle_t xUARTMutex;
void vInitMutex(void) {
xUARTMutex = xSemaphoreCreateMutex();
}
// 安全的串口发送
BaseType_t UART_SendSafe(const uint8_t *data, size_t len) {
// 获取互斥锁(最多等待 100ms)
if (xSemaphoreTake(xUARTMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
HAL_UART_Transmit(&huart1, data, len, 1000);
xSemaphoreGive(xUARTMutex);
return pdTRUE;
}
return pdFALSE; // 获取锁超时
}
// 二值信号量:中断通知任务
SemaphoreHandle_t xDataReadySemaphore;
// 中断服务程序(ISR)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// 从 ISR 中释放信号量
xSemaphoreGiveFromISR(xDataReadySemaphore, &xHigherPriorityTaskWoken);
// 如果有更高优先级任务被唤醒,请求上下文切换
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
// 等待数据就绪的任务
void vDataReceiveTask(void *pvParameters) {
for (;;) {
if (xSemaphoreTake(xDataReadySemaphore, pdMS_TO_TICKS(1000)) == pdTRUE) {
ProcessReceivedData();
}
}
}内存管理
c
// FreeRTOS 内存分配方案选择:
// heap_1: 只分配不释放(最简单,确定性)
// heap_2: 可释放,但有碎片(不推荐)
// heap_3: 封装 malloc/free(依赖 C 库)
// heap_4: 合并相邻空闲块(推荐)
// heap_5: 跨多个内存区域(大型系统)
// 推荐:heap_4,在 FreeRTOSConfig.h 中配置
#define configTOTAL_HEAP_SIZE ((size_t)(64 * 1024)) // 64KB 堆
// 监控堆使用情况
void vPrintHeapStats(void) {
HeapStats_t stats;
vPortGetHeapStats(&stats);
printf("Heap: free=%d, min_ever_free=%d, largest_block=%d\n",
stats.xAvailableHeapSpaceInBytes,
stats.xMinimumEverFreeBytesRemaining,
stats.xSizeOfLargestFreeBlockInBytes);
}
// 监控任务栈使用情况
void vCheckStackUsage(void) {
UBaseType_t watermark = uxTaskGetStackHighWaterMark(xModbusTask);
if (watermark < 50) { // 剩余不足 50 字(200字节)
printf("WARNING: ModbusTask stack low! Watermark=%d words\n", watermark);
}
}RT-Thread 架构
c
// RT-Thread 线程创建(国产 RTOS,API 类似 POSIX)
#include <rtthread.h>
#define THREAD_PRIORITY 5
#define THREAD_STACK_SIZE 1024
#define THREAD_TIMESLICE 10
static rt_thread_t modbus_thread = RT_NULL;
static void modbus_thread_entry(void *parameter) {
while (1) {
// 采集数据
modbus_poll();
// 延时 1 秒
rt_thread_mdelay(1000);
}
}
int modbus_init(void) {
modbus_thread = rt_thread_create(
"modbus",
modbus_thread_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY,
THREAD_TIMESLICE
);
if (modbus_thread != RT_NULL) {
rt_thread_startup(modbus_thread);
}
return RT_EOK;
}
// RT-Thread 消息队列
static rt_mq_t data_mq = RT_NULL;
void init_message_queue(void) {
data_mq = rt_mq_create("data_mq",
sizeof(ModbusData_t), // 消息大小
20, // 最大消息数
RT_IPC_FLAG_FIFO);
}
// 发送消息
rt_mq_send(data_mq, &data, sizeof(ModbusData_t));
// 接收消息(等待 1 秒)
rt_mq_recv(data_mq, &data, sizeof(ModbusData_t), RT_TICK_PER_SECOND);实时性保证
c
// 关键实时任务设计原则
// 1. 避免在高优先级任务中使用动态内存分配
// 错误:
void vHighPriorityTask(void *pvParameters) {
char *buf = malloc(256); // 可能阻塞!
// ...
free(buf);
}
// 正确:使用静态分配
void vHighPriorityTask(void *pvParameters) {
static char buf[256]; // 静态分配,无阻塞
// ...
}
// 2. 使用 configASSERT 检测错误
#define configASSERT(x) if((x) == 0) { taskDISABLE_INTERRUPTS(); for(;;); }
// 3. 看门狗集成
void vWatchdogTask(void *pvParameters) {
for (;;) {
// 喂狗
HAL_IWDG_Refresh(&hiwdg);
vTaskDelay(pdMS_TO_TICKS(500)); // 每 500ms 喂一次
}
}
// 4. 任务运行时间统计(调试用)
// FreeRTOSConfig.h:
// #define configGENERATE_RUN_TIME_STATS 1
// #define configUSE_TRACE_FACILITY 1
void vPrintTaskStats(void) {
char buf[1024];
vTaskGetRunTimeStats(buf);
printf("Task\t\tTime\t\t%%\n%s\n", buf);
}OTA 升级方案
c
// 双分区 OTA 升级(Bootloader + App A + App B)
// Flash 分区布局:
// 0x08000000 - 0x0800FFFF: Bootloader (64KB)
// 0x08010000 - 0x0807FFFF: App A (448KB) ← 当前运行
// 0x08080000 - 0x080EFFFF: App B (448KB) ← 待升级
// 0x080F0000 - 0x080FFFFF: 升级标志 (64KB)
typedef struct {
uint32_t magic; // 0xDEADBEEF
uint32_t version;
uint32_t new_app_addr;
uint32_t new_app_size;
uint32_t crc32;
uint8_t upgrade_flag; // 0=无升级, 1=待升级, 2=升级成功
} OTA_Flag_t;
// 应用层:接收固件并写入备用分区
void OTA_WriteChunk(uint32_t offset, const uint8_t *data, uint32_t len) {
uint32_t target_addr = APP_B_START + offset;
// 擦除(按扇区)
if (offset == 0) {
FLASH_EraseInitTypeDef erase = {
.TypeErase = FLASH_TYPEERASE_SECTORS,
.Sector = FLASH_SECTOR_APP_B,
.NbSectors = APP_B_SECTORS,
.VoltageRange = FLASH_VOLTAGE_RANGE_3
};
uint32_t error;
HAL_FLASHEx_Erase(&erase, &error);
}
// 写入
HAL_FLASH_Unlock();
for (uint32_t i = 0; i < len; i += 4) {
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
target_addr + i,
*(uint32_t*)(data + i));
}
HAL_FLASH_Lock();
}
// 升级完成,设置标志并重启
void OTA_Commit(uint32_t version, uint32_t crc) {
OTA_Flag_t flag = {
.magic = 0xDEADBEEF,
.version = version,
.new_app_addr = APP_B_START,
.crc32 = crc,
.upgrade_flag = 1
};
// 写入标志区
WriteOTAFlag(&flag);
// 重启,Bootloader 将验证并切换
NVIC_SystemReset();
}