一、引言
在嵌入式实时操作系统(RTOS)领域,μC/OS和FreeRTOS是最具代表性的两大开源内核。两者都遵循RTOS的核心设计原则------确定性调度、低延迟中断响应、可抢占式多任务,但在实现理念、功能特性、生态授权等方面存在显著差异。本文将从内核架构、API设计、同步机制、内存管理、授权模式等维度进行系统对比,帮助开发者做出技术选型决策。
二、项目背景与定位
2.1 发展历史
| 维度 |
μC/OS (Micrium OS) |
FreeRTOS |
| 创始人 |
Jean J. Labrosse (1992) |
Richard Barry (2003) |
| 当前维护 |
Silicon Labs (收购) |
Amazon Web Services (收购) |
| 最新版本 |
μC/OS-III v3.08+ |
FreeRTOS v10.4+ / Kernel v11.x |
| 代码规模 |
~15,000行 (III) |
~4,000-9,000行 (依配置) |
| 设计目标 |
商业级可靠性、可认证性 |
极致轻量、广泛兼容 |
| 认证支持 |
DO-178C, IEC 61508, ISO 26262 |
通过SafeRTOS商业版提供 |
2.2 核心定位差异
复制代码
┌─────────────────────────────────────────────────────────────┐
│ μC/OS 定位:商业级、可认证、功能完备的企业级RTOS │
├─────────────────────────────────────────────────────────────┤
│ • 航空电子 (DO-178C) │
│ • 汽车电子 (ISO 26262) │
│ • 工业控制 (IEC 61508) │
│ • 医疗仪器 (IEC 62304) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ FreeRTOS 定位:开源免费、极致轻量、生态广泛的通用RTOS │
├─────────────────────────────────────────────────────────────┤
│ • 物联网终端设备 │
│ • 消费电子产品 │
│ • 教育学习与原型开发 │
│ • 快速产品迭代 │
└─────────────────────────────────────────────────────────────┘
三、内核架构对比
3.1 调度器设计
μC/OS-III:固定优先级 + 时间片轮转
复制代码
// μC/OS-III 调度器特性演示
#include "os.h"
#define TASK_HIGH_PRIO 5u
#define TASK_MED_PRIO 6u // 同优先级,启用时间片
#define TASK_LOW_PRIO 7u
OS_TCB TCB_High, TCB_Med1, TCB_Med2, TCB_Low;
CPU_STK Stk_High[512], Stk_Med1[512], Stk_Med2[512], Stk_Low[512];
void TaskHigh(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while (1) {
// 最高优先级,一旦就绪立即抢占
HAL_GPIO_TogglePin(LED_HIGH_GPIO_Port, LED_HIGH_Pin);
OSTimeDly(50u, OS_OPT_TIME_DLY, &err);
}
}
void TaskMed(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while (1) {
// 同优先级任务按时间片轮流执行
HAL_GPIO_TogglePin(LED_MED_GPIO_Port, LED_MED_Pin);
OSTimeDly(1u, OS_OPT_TIME_DLY, &err); // 主动让出
}
}
void SystemInit(void)
{
OS_ERR err;
OSInit(&err);
// 创建同优先级任务,启用时间片轮转
OSTaskCreate(&TCB_High, "TaskHigh", TaskHigh, 0, TASK_HIGH_PRIO,
Stk_High, 50, 512, 0, 10, 0, // time_quanta = 10 ticks
OS_OPT_TASK_STK_CHK, &err);
OSTaskCreate(&TCB_Med1, "TaskMed1", TaskMed, 0, TASK_MED_PRIO,
Stk_Med1, 50, 512, 0, 10, 0,
OS_OPT_TASK_STK_CHK, &err);
OSTaskCreate(&TCB_Med2, "TaskMed2", TaskMed, 0, TASK_MED_PRIO,
Stk_Med2, 50, 512, 0, 10, 0,
OS_OPT_TASK_STK_CHK, &err);
OSStart(&err);
}
FreeRTOS:灵活配置调度策略
复制代码
// FreeRTOS 调度器特性演示
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#define TASK_HIGH_PRIO (configMAX_PRIORITIES - 2)
#define TASK_MED_PRIO (configMAX_PRIORITIES - 3)
#define TASK_LOW_PRIO (configMAX_PRIORITIES - 4)
// 堆栈大小以字为单位(非字节!)
#define STACK_SIZE 128
void vTaskHigh(void *pvParameters)
{
(void)pvParameters;
while (1) {
HAL_GPIO_TogglePin(LED_HIGH_GPIO_Port, LED_HIGH_Pin);
vTaskDelay(pdMS_TO_TICKS(500)); // 500ms延时
}
}
void vTaskMed(void *pvParameters)
{
(void)pvParameters;
while (1) {
HAL_GPIO_TogglePin(LED_MED_GPIO_Port, LED_MED_Pin);
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void SystemInit(void)
{
// FreeRTOS 配置通过 FreeRTOSConfig.h 进行
xTaskCreate(vTaskHigh, "TaskHigh", STACK_SIZE, NULL,
TASK_HIGH_PRIO, NULL);
xTaskCreate(vTaskMed, "TaskMed1", STACK_SIZE, NULL,
TASK_MED_PRIO, NULL);
xTaskCreate(vTaskMed, "TaskMed2", STACK_SIZE, NULL,
TASK_MED_PRIO, NULL);
// 同优先级时间片在 FreeRTOSConfig.h 中配置:
// #define configUSE_TIME_SLICING 1
vTaskStartScheduler(); // 永不返回
}
// 可选:协程支持(Co-routines,已较少使用)
// 可选:对称多处理 SMP 支持(FreeRTOS v10+)
3.2 调度器特性对比
| 特性 |
μC/OS-III |
FreeRTOS |
| 调度算法 |
固定优先级抢占式 + 可选时间片 |
固定优先级抢占式 + 可选时间片 |
| 同优先级调度 |
时间片轮转(可配置) |
时间片轮转(可配置) |
| 空闲任务 |
内置,可配置钩子 |
内置,可配置钩子 |
| ** tickless 模式** |
支持 |
✅ 原生支持(低功耗) |
| 多核SMP |
❌ 不支持 |
✅ v10.4+ 支持 |
| 对称多处理 |
单核设计 |
✅ 支持多核均衡负载 |
| 调度点 |
系统调用返回、中断退出 |
系统调用返回、中断退出 |
四、任务与同步机制对比
4.1 任务管理
μC/OS-III:显式TCB管理
复制代码
#include "os.h"
// μC/OS-III:用户声明所有内核对象
OS_TCB AppTaskTCB;
CPU_STK AppTaskStk[512];
void AppTask(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while (1) {
// 任务内建信号量/消息队列
OSTaskSemPend(0, OS_OPT_PEND_BLOCKING, NULL, &err);
// ...
}
}
void CreateTask(void)
{
OS_ERR err;
OSTaskCreate(&AppTaskTCB,
"AppTask", // 任务名(调试可见)
AppTask,
(void *)0,
5u, // 优先级
&AppTaskStk[0],
50u, // 栈限制(水线)
512u, // 栈大小
0u, // 消息队列大小
0u, // 时间片
(void *)0, // 扩展
OS_OPT_TASK_STK_CHK,
&err);
}
FreeRTOS:动态/静态可选
复制代码
#include "FreeRTOS.h"
#include "task.h"
// 方式1:动态分配(默认)
void CreateTaskDynamic(void)
{
TaskHandle_t xHandle = NULL;
xTaskCreate(
vTaskFunction, // 任务函数
"TaskName", // 任务名
STACK_SIZE, // 栈深度(字)
(void *)param, // 参数
tskIDLE_PRIORITY + 1, // 优先级
&xHandle // 任务句柄
);
}
// 方式2:静态分配(无需堆内存,适合安全关键系统)
static StaticTask_t xTaskBuffer;
static StackType_t xStack[STACK_SIZE];
void CreateTaskStatic(void)
{
TaskHandle_t xHandle = xTaskCreateStatic(
vTaskFunction,
"StaticTask",
STACK_SIZE,
(void *)param,
tskIDLE_PRIORITY + 1,
xStack, // 预分配栈
&xTaskBuffer // 预分配TCB
);
}
4.2 同步机制对比
| 机制 |
μC/OS-III |
FreeRTOS |
说明 |
| 二进制信号量 |
OSSem |
xSemaphoreCreateBinary |
任务同步 |
| 计数信号量 |
OSSem |
xSemaphoreCreateCounting |
资源计数 |
| 互斥锁 |
OSMutex(优先级继承) |
xSemaphoreCreateMutex(优先级继承) |
互斥访问 |
| 递归互斥锁 |
❌ 不支持 |
xSemaphoreCreateRecursiveMutex |
递归锁定 |
| 事件标志组 |
OSFlagGrp(原生) |
xEventGroup |
多条件等待 |
| 消息队列 |
OSQ |
xQueue |
消息传递 |
| 流缓冲区 |
❌ 不支持 |
xStreamBuffer |
字节流通信 |
| 消息缓冲区 |
❌ 不支持 |
xMessageBuffer |
变长消息 |
| 任务通知 |
OSTaskSem/OSTaskQ |
xTaskNotify |
轻量级同步 |
| 软件定时器 |
OS_TMR(原生) |
TimerHandle_t |
回调定时器 |
4.3 同步代码对比
互斥锁使用
复制代码
// ========== μC/OS-III ==========
#include "os.h"
OS_MUTEX g_sensorMutex;
SensorData_t g_sensorData;
void SensorTask(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
OSMutexCreate(&g_sensorMutex, "SensorMutex", &err);
while (1) {
OSMutexPend(&g_sensorMutex, 0, OS_OPT_PEND_BLOCKING, 0, &err);
// 读取传感器...
g_sensorData.temperature = ReadTemp();
OSMutexPost(&g_sensorMutex, OS_OPT_POST_NONE, &err);
OSTimeDly(100, OS_OPT_TIME_DLY, &err);
}
}
// ========== FreeRTOS ==========
#include "FreeRTOS.h"
#include "semphr.h"
SemaphoreHandle_t g_sensorMutex;
SensorData_t g_sensorData;
void SensorTask(void *pvParameters)
{
(void)pvParameters;
g_sensorMutex = xSemaphoreCreateMutex();
configASSERT(g_sensorMutex != NULL);
while (1) {
if (xSemaphoreTake(g_sensorMutex, portMAX_DELAY) == pdTRUE) {
// 读取传感器...
g_sensorData.temperature = ReadTemp();
xSemaphoreGive(g_sensorMutex);
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
事件标志组使用
复制代码
// ========== μC/OS-III ==========
#include "os.h"
OS_FLAG_GRP g_eventFlags;
#define EVT_WIFI_CONNECTED 0x01
#define EVT_SERVER_READY 0x02
#define EVT_DATA_RECEIVED 0x04
void InitEvents(void)
{
OS_ERR err;
OSFlagCreate(&g_eventFlags, "NetEvents", 0, &err);
}
void NetworkTask(void *p_arg)
{
OS_ERR err;
OS_FLAGS flags;
p_arg = p_arg;
while (1) {
// 等待多个事件:WiFi连接 且 服务器就绪
flags = OSFlagPend(&g_eventFlags,
EVT_WIFI_CONNECTED | EVT_SERVER_READY,
0,
OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_FLAG_CONSUME,
NULL,
&err);
if (err == OS_ERR_NONE) {
// 网络就绪,开始传输
}
}
}
void WifiCallback(void)
{
OS_ERR err;
OSFlagPost(&g_eventFlags, EVT_WIFI_CONNECTED, OS_OPT_POST_FLAG_SET, &err);
}
// ========== FreeRTOS ==========
#include "FreeRTOS.h"
#include "event_groups.h"
EventGroupHandle_t g_eventFlags;
#define EVT_WIFI_CONNECTED (1 << 0)
#define EVT_SERVER_READY (1 << 1)
#define EVT_DATA_RECEIVED (1 << 2)
void InitEvents(void)
{
g_eventFlags = xEventGroupCreate();
configASSERT(g_eventFlags != NULL);
}
void NetworkTask(void *pvParameters)
{
(void)pvParameters;
EventBits_t flags;
while (1) {
// 等待多个事件
flags = xEventGroupWaitBits(
g_eventFlags,
EVT_WIFI_CONNECTED | EVT_SERVER_READY,
pdTRUE, // 清除位
pdTRUE, // 等待所有位
portMAX_DELAY);
if ((flags & (EVT_WIFI_CONNECTED | EVT_SERVER_READY))
== (EVT_WIFI_CONNECTED | EVT_SERVER_READY)) {
// 网络就绪
}
}
}
void WifiCallback(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xEventGroupSetBitsFromISR(g_eventFlags, EVT_WIFI_CONNECTED,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
五、内存管理对比
5.1 μC/OS-III:固定分区 + 静态分配
复制代码
#include "os.h"
// 方案1:固定大小内存分区(推荐)
OS_MEM g_memPartition;
CPU_INT08U g_memPool[10][256]; // 10个256字节块
void InitMemory(void)
{
OS_ERR err;
OSMemCreate(&g_memPartition,
"MemPool",
&g_memPool[0][0],
10u,
256u,
&err);
}
void* AllocateBlock(void)
{
OS_ERR err;
return OSMemGet(&g_memPartition, &err);
}
void FreeBlock(void *p_blk)
{
OS_ERR err;
OSMemPut(&g_memPartition, p_blk, &err);
}
// 方案2:完全静态分配(安全关键系统)
// μC/OS-III 所有对象均可静态声明,无需堆
5.2 FreeRTOS:多种堆算法可选
复制代码
#include "FreeRTOS.h"
// FreeRTOS 提供5种堆实现(heap_1.c ~ heap_5.c):
// heap_1.c: 只分配不释放(最简单,无碎片)
// heap_2.c: 最佳匹配算法(有碎片)
// heap_3.c: 包装标准库 malloc/free(线程安全)
// heap_4.c: 首次匹配算法 + 合并相邻空闲块(推荐)
// heap_5.c: heap_4 + 跨多个非连续内存区域
// 配置选择:FreeRTOSConfig.h
// #define configUSE_HEAP_SCHEME 4
// 使用示例
void* pvBuffer = pvPortMalloc(256); // 使用FreeRTOS堆
vPortFree(pvBuffer);
// 静态分配(无需堆)
static StaticTask_t xTaskBuffer;
static StackType_t xStack[128];
TaskHandle_t xHandle = xTaskCreateStatic(...);
// 静态队列
static StaticQueue_t xQueueBuffer;
static uint8_t ucQueueStorage[10 * sizeof(MyMsg)];
QueueHandle_t xQueue = xQueueCreateStatic(10, sizeof(MyMsg),
ucQueueStorage, &xQueueBuffer);
5.3 内存管理对比
| 特性 |
μC/OS-III |
FreeRTOS |
| 固定分区 |
✅ 原生支持 |
❌ 需自行实现 |
| 动态分配 |
有限支持 |
✅ 5种堆算法可选 |
| 静态分配 |
✅ 完全支持 |
✅ 完全支持 |
| 内存碎片处理 |
无(固定大小无碎片) |
heap_4/5合并相邻块 |
| 跨RAM区域 |
❌ 不支持 |
✅ heap_5支持 |
| 内存保护 |
❌ 无MPU支持 |
✅ FreeRTOS-MPU |
| 堆溢出检测 |
栈检查 |
configCHECK_FOR_STACK_OVERFLOW |
六、中断与低功耗
6.1 中断处理模型
μC/OS-III:传统中断嵌套
复制代码
// μC/OS-III 中断处理
#include "os.h"
void TIM2_IRQHandler(void)
{
OS_ERR err;
OSIntEnter(&err); // 进入中断
// 清除中断标志
TIM2->SR &= ~TIM_SR_UIF;
// 发布信号量
OSSemPost(&g_timSem, OS_OPT_POST_NONE, &err);
OSIntExit(&err); // 退出中断,可能触发调度
}
FreeRTOS:更灵活的中断安全API
复制代码
// FreeRTOS 中断处理
#include "FreeRTOS.h"
#include "task.h"
void TIM2_IRQHandler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// 清除中断标志
TIM2->SR &= ~TIM_SR_UIF;
// 从中断安全地释放信号量
xSemaphoreGiveFromISR(g_timSem, &xHigherPriorityTaskWoken);
// 上下文切换(如果使用portYIELD_FROM_ISR)
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
6.2 Tickless 低功耗模式
复制代码
// ========== FreeRTOS 原生支持 Tickless ==========
// FreeRTOSConfig.h
#define configUSE_TICKLESS_IDLE 1
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
// 可选:自定义低功耗实现
void vApplicationSleep(TickType_t xExpectedIdleTime)
{
// 进入MCU低功耗模式
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}
// ========== μC/OS-III 需自行实现 ==========
// 无原生tickless支持,需通过钩子实现
void App_OS_IdleTaskHook(void)
{
// 检测空闲时间,手动进入低功耗
if (SystemIdleTime() > MIN_SLEEP_TIME) {
EnterLowPowerMode();
}
}
6.3 中断与功耗对比
| 特性 |
μC/OS-III |
FreeRTOS |
| 中断嵌套 |
支持 |
支持 |
| 中断安全API |
*Post函数 |
*FromISR后缀函数 |
| 延迟中断处理 |
直接发布 |
xHigherPriorityTaskWoken机制 |
| Tickless低功耗 |
❌ 需自行实现 |
✅ 原生支持 |
| 低功耗钩子 |
空闲任务钩子 |
vApplicationSleep |
| 中断延迟 |
~12-25个时钟周期 |
~12-20个时钟周期 |
七、调试与诊断
7.1 μC/OS-III:内置统计与追踪
复制代码
#include "os.h"
// μC/OS-III 内置丰富的统计功能
void InitDiagnostics(void)
{
OS_ERR err;
// 启用统计任务(计算CPU使用率)
OSStatTaskCPUUsageInit(&err);
}
void PrintStats(void)
{
OS_ERR err;
// 获取CPU使用率
CPU_USAGE usage = OSStatTaskCPUUsage;
// 获取中断禁用时间
CPU_TS int_dis_time = OSIntDisTimeMax;
// 获取调度锁定时间
CPU_TS sched_lock_time = OSSchedLockTimeMax;
// 遍历所有任务,打印状态
OS_TCB *p_tcb;
OS_ERR err_local;
p_tcb = OSTCBList; // 任务链表头
while (p_tcb != (OS_TCB *)0) {
printf("Task: %s, Prio: %d, CPU%%: %d, StkUsed: %d\n",
p_tcb->NamePtr,
p_tcb->Prio,
p_tcb->CPUUsage,
p_tcb->StkUsed);
p_tcb = p_tcb->NextPtr;
}
}
// 内置内核感知调试支持
// 兼容IAR、Keil、Segger等调试器的RTOS插件
7.2 FreeRTOS:可配置追踪
复制代码
#include "FreeRTOS.h"
#include "task.h"
// FreeRTOS 通过配置启用统计
// FreeRTOSConfig.h
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configGENERATE_RUN_TIME_STATS 1
// 提供时间基准
volatile uint32_t ulHighFrequencyTimerTicks;
void ConfigureTimerForRunTimeStats(void)
{
// 初始化高精度定时器
}
uint32_t GetRunTimeCounterValue(void)
{
return ulHighFrequencyTimerTicks;
}
void PrintTaskStats(void)
{
// 分配缓冲区
static char pcWriteBuffer[512];
// 获取任务状态表
vTaskList(pcWriteBuffer);
printf("Task Name\tState\tPrio\tStack\tNum\n%s", pcWriteBuffer);
// 获取CPU使用率
vTaskGetRunTimeStats(pcWriteBuffer);
printf("Runtime Stats:\n%s", pcWriteBuffer);
}
// 第三方追踪:FreeRTOS+Trace, SystemView
// 商业方案:Percepio Tracealyzer
7.3 调试能力对比
| 特性 |
μC/OS-III |
FreeRTOS |
| 任务状态查看 |
内置链表遍历 |
vTaskList() |
| CPU使用率统计 |
内置统计任务 |
需配置运行时统计 |
| 栈溢出检测 |
OS_OPT_TASK_STK_CHK |
configCHECK_FOR_STACK_OVERFLOW |
| 中断禁用时间 |
自动测量 |
需自行实现 |
| 内核感知调试 |
原生支持主流IDE |
需插件/配置 |
| 第三方追踪工具 |
Micrium工具链 |
Tracealyzer, SystemView |
| 断言机制 |
OS_ASSERT |
configASSERT |
八、授权模式与商业生态
8.1 许可证对比
| 维度 |
μC/OS (Micrium OS) |
FreeRTOS |
| 开源许可证 |
Apache 2.0 (2016年后) |
MIT |
| 商业授权 |
需购买(旧版本) |
无需 |
| 闭源使用 |
✅ 允许 |
✅ 允许 |
| 修改后分发 |
✅ 允许 |
✅ 允许 |
| 专利授权 |
Apache 2.0明确授予 |
MIT隐含 |
| 安全认证版 |
包含在授权中 |
SafeRTOS需单独购买 |
8.2 生态与中间件
复制代码
┌─────────────────────────────────────────────────────────────┐
│ μC/OS 生态(Silicon Labs) │
├─────────────────────────────────────────────────────────────┤
│ 内核:μC/OS-III / Micrium OS │
│ 文件系统:μC/FS(FAT/exFAT) │
│ 网络协议:μC/TCP-IP(IPv4/IPv6) │
│ USB协议:μC/USB-Host/Device/OTG │
│ GUI:μC/GUI(emWin) │
│ 安全:μC/Crypto, μC/SSL-TLS │
│ 认证:DO-178C, IEC 61508, ISO 26262(完整包) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ FreeRTOS 生态(AWS) │
├─────────────────────────────────────────────────────────────┤
│ 内核:FreeRTOS Kernel │
│ 库:FreeRTOS-Plus(TCP, FAT, CLI, Trace) │
│ AWS集成:AWS IoT, AWS OTA, AWS Jobs │
│ 安全:AWS IoT Device Defender, mbedTLS │
│ 认证:SafeRTOS(WITTENSTEIN,单独购买) │
│ 社区:极其活跃的GitHub社区,大量第三方库 │
└─────────────────────────────────────────────────────────────┘
九、完整应用示例对比
9.1 传感器数据采集系统
μC/OS-III 实现
复制代码
// sensor_system_ucos.c
#include "os.h"
#include "bsp.h"
#define TASK_SENSOR_PRIO 5u
#define TASK_FILTER_PRIO 6u
#define TASK_UPLOAD_PRIO 7u
#define TASK_MONITOR_PRIO 8u
// 内核对象声明
OS_TCB TCB_Sensor, TCB_Filter, TCB_Upload, TCB_Monitor;
CPU_STK Stk_Sensor[512], Stk_Filter[512], Stk_Upload[512], Stk_Monitor[256];
OS_MUTEX g_dataMutex;
OS_Q g_rawQueue;
OS_FLAG_GRP g_sysFlags;
OS_TMR g_sampleTmr;
#define EVT_SAMPLE_READY 0x01
#define EVT_NETWORK_OK 0x02
#define EVT_ERROR_FLAG 0x04
typedef struct {
uint32_t timestamp;
float temperature;
float humidity;
float pressure;
} SensorData_t;
void *g_msgPool[16]; // 消息队列缓冲区
// 采样定时器回调
void SampleTimerCallback(void *p_tmr, void *p_arg)
{
OS_ERR err;
(void)p_tmr; (void)p_arg;
// 触发采样任务
OSFlagPost(&g_sysFlags, EVT_SAMPLE_READY, OS_OPT_POST_FLAG_SET, &err);
}
void TaskSensor(void *p_arg)
{
OS_ERR err;
OS_FLAGS flags;
SensorData_t *p_data;
p_arg = p_arg;
while (1) {
// 等待采样信号
flags = OSFlagPend(&g_sysFlags,
EVT_SAMPLE_READY,
0,
OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_FLAG_CONSUME,
NULL,
&err);
// 从内存池分配
p_data = OSMemGet(&g_memPool, &err);
if (err != OS_ERR_NONE) continue;
// 读取传感器
p_data->timestamp = OSTimeGet(&err);
p_data->temperature = BSP_TempRead();
p_data->humidity = BSP_HumiRead();
p_data->pressure = BSP_PresRead();
// 发送到处理队列
OSQPost(&g_rawQueue,
(void *)p_data,
sizeof(SensorData_t),
OS_OPT_POST_FIFO,
&err);
}
}
void TaskFilter(void *p_arg)
{
OS_ERR err;
OS_MSG_SIZE msg_size;
CPU_TS ts;
SensorData_t *p_data;
p_arg = p_arg;
while (1) {
p_data = (SensorData_t *)OSQPend(&g_rawQueue,
0,
OS_OPT_PEND_BLOCKING,
&msg_size,
&ts,
&err);
// 卡尔曼滤波处理
OSMutexPend(&g_dataMutex, 0, OS_OPT_PEND_BLOCKING, 0, &err);
KalmanFilter(p_data);
OSMutexPost(&g_dataMutex, OS_OPT_POST_NONE, &err);
// 通知上传任务
OSTaskSemPost(&TCB_Upload, OS_OPT_POST_NONE, &err);
}
}
void SystemInit(void)
{
OS_ERR err;
OSInit(&err);
BSP_Init();
// 创建同步对象
OSMutexCreate(&g_dataMutex, "DataMutex", &err);
OSQCreate(&g_rawQueue, "RawQueue", 16, &err);
OSFlagCreate(&g_sysFlags, "SysFlags", 0, &err);
OSMemCreate(&g_memPool, "DataPool", g_memBuf, 16, sizeof(SensorData_t), &err);
// 创建定时器:100ms周期采样
OSTmrCreate(&g_sampleTmr, "SampleTmr", 10, 10,
OS_TMR_OPT_PERIODIC, SampleTimerCallback, 0, &err);
// 创建任务
OSTaskCreate(&TCB_Sensor, "Sensor", TaskSensor, 0,
TASK_SENSOR_PRIO, Stk_Sensor, 50, 512, 0, 0, 0,
OS_OPT_TASK_STK_CHK, &err);
// ... 其他任务
OSTmrStart(&g_sampleTmr, &err);
OSStart(&err);
}
FreeRTOS 实现
复制代码
// sensor_system_freertos.c
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"
#include "timers.h"
#define TASK_SENSOR_PRIO (configMAX_PRIORITIES - 2)
#define TASK_FILTER_PRIO (configMAX_PRIORITIES - 3)
#define TASK_UPLOAD_PRIO (configMAX_PRIORITIES - 4)
#define EVT_SAMPLE_READY (1 << 0)
#define EVT_NETWORK_OK (1 << 1)
typedef struct {
uint32_t timestamp;
float temperature;
float humidity;
float pressure;
} SensorData_t;
// 静态分配所有对象
static StaticTask_t xSensorTCB, xFilterTCB, xUploadTCB;
static StackType_t xSensorStk[128], xFilterStk[128], xUploadStk[128];
static StaticSemaphore_t xMutexBuffer;
static StaticQueue_t xQueueBuffer;
static StaticEventGroup_t xEventBuffer;
static StaticTimer_t xTimerBuffer;
static uint8_t ucQueueStorage[16 * sizeof(SensorData_t)];
SemaphoreHandle_t xDataMutex;
QueueHandle_t xRawQueue;
EventGroupHandle_t xSysEvents;
TimerHandle_t xSampleTimer;
// 采样定时器回调
void vSampleTimerCallback(TimerHandle_t xTimer)
{
(void)xTimer;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xEventGroupSetBitsFromISR(xSysEvents, EVT_SAMPLE_READY,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void vTaskSensor(void *pvParameters)
{
(void)pvParameters;
EventBits_t xBits;
SensorData_t xData;
while (1) {
xBits = xEventGroupWaitBits(xSysEvents,
EVT_SAMPLE_READY,
pdTRUE, // 清除位
pdFALSE, // 等待任意
portMAX_DELAY);
if (xBits & EVT_SAMPLE_READY) {
xData.timestamp = xTaskGetTickCount();
xData.temperature = BSP_TempRead();
xData.humidity = BSP_HumiRead();
xData.pressure = BSP_PresRead();
// 发送到队列(复制数据)
xQueueSend(xRawQueue, &xData, portMAX_DELAY);
}
}
}
void vTaskFilter(void *pvParameters)
{
(void)pvParameters;
SensorData_t xData;
while (1) {
if (xQueueReceive(xRawQueue, &xData, portMAX_DELAY) == pdTRUE) {
xSemaphoreTake(xDataMutex, portMAX_DELAY);
KalmanFilter(&xData);
xSemaphoreGive(xDataMutex);
// 通知上传任务
xTaskNotifyGive(xUploadHandle);
}
}
}
void SystemInit(void)
{
// 静态创建所有对象(无需堆)
xDataMutex = xSemaphoreCreateMutexStatic(&xMutexBuffer);
xRawQueue = xQueueCreateStatic(16, sizeof(SensorData_t),
ucQueueStorage, &xQueueBuffer);
xSysEvents = xEventGroupCreateStatic(&xEventBuffer);
xSampleTimer = xTimerCreateStatic("SampleTmr",
pdMS_TO_TICKS(100),
pdTRUE,
NULL,
vSampleTimerCallback,
&xTimerBuffer);
// 静态创建任务
xTaskCreateStatic(vTaskSensor, "Sensor", 128, NULL,
TASK_SENSOR_PRIO, xSensorStk, &xSensorTCB);
xTaskCreateStatic(vTaskFilter, "Filter", 128, NULL,
TASK_FILTER_PRIO, xFilterStk, &xFilterTCB);
// ... 其他任务
xTimerStart(xSampleTimer, 0);
vTaskStartScheduler();
}
十、选型决策指南
10.1 选择 μC/OS 的场景
| 场景 |
理由 |
| 航空/汽车/医疗认证 |
原生支持DO-178C、ISO 26262、IEC 61508 |
| 严格确定性要求 |
内核行为更可预测,适合硬实时系统 |
| 商业技术支持 |
Silicon Labs提供专业技术支持 |
| 完整中间件栈 |
文件系统、网络、USB、GUI一体化 |
| 团队熟悉度 |
已有μC/OS开发经验和代码积累 |
10.2 选择 FreeRTOS 的场景
| 场景 |
理由 |
| 成本敏感项目 |
MIT许可证,完全免费商用 |
| 极致资源受限 |
最小内核仅需4-9KB ROM |
| 多核处理器 |
原生SMP支持 |
| 低功耗物联网 |
原生Tickless,AWS IoT深度集成 |
| 快速原型开发 |
社区庞大,示例丰富,移植简单 |
| 需要动态内存 |
多种堆算法,支持跨RAM区域分配 |
10.3 快速决策流程图
复制代码
┌─────────────────┐
│ 开始RTOS选型 │
└────────┬────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌──────────┐
│需要安全 │ │资源极度 │ │需要多核 │
│认证? │ │受限? │ │SMP? │
└────┬────┘ └────┬─────┘ └────┬─────┘
│ │ │
是│ 是│ 是│
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌──────────┐
│ μC/OS │ │FreeRTOS │ │FreeRTOS │
│ + 认证包 │ │最小配置 │ │SMP版本 │
└─────────┘ └──────────┘ └──────────┘
│ │ │
└─────────────┴──────────────┘
│
▼
┌─────────────────┐
│ 需要完整中间件? │
└────────┬────────┘
│
┌────────┴────────┐
▼ ▼
是 否
│ │
▼ ▼
┌─────────┐ ┌──────────┐
│ μC/OS │ │ FreeRTOS │
│ 全家桶 │ │ + 社区库 │
└─────────┘ └──────────┘
十一、总结
| 对比维度 |
μC/OS-III |
FreeRTOS |
| 代码体积 |
较大(功能丰富) |
较小(可裁剪) |
| RAM占用 |
较高 |
较低 |
| 功能完备性 |
⭐⭐⭐⭐⭐ |
⭐⭐⭐⭐ |
| 类型安全 |
强(显式错误码) |
中等(返回码检查) |
| 静态分配支持 |
完全 |
完全 |
| 动态分配 |
有限 |
丰富 |
| 低功耗 |
需自行实现 |
原生Tickless |
| 多核支持 |
❌ |
✅ SMP |
| 安全认证 |
✅ 原生 |
需SafeRTOS |
| 授权成本 |
免费(Apache 2.0) |
免费(MIT) |
| 社区活跃度 |
中等 |
⭐⭐⭐⭐⭐ |
| 学习曲线 |
较陡 |
平缓 |
| 调试工具 |
专业级 |
丰富多样 |
最终建议:
-
新项目、通用嵌入式 :优先评估 FreeRTOS,生态活跃,社区支持好
-
安全关键、认证项目 :选择 μC/OS + 认证包,确定性更强
-
资源极度受限(<8KB Flash) :FreeRTOS 最小配置
-
需要完整中间件栈 :μC/OS 全家桶或 FreeRTOS + 第三方库