核心目标:解耦。让不同功能的代码在各自的平行时空中运行,不再相互掣肘。
1. 裸机时代的痛:超级循环 (Super Loop)
在裸机开发中,我们的 main 函数通常长这样
void main(void) {
Init();
while (1) {
Scan_Keys(); // 1. 扫按键 (快)
Read_Sensors(); // 2. 读传感器 (中)
PID_Compute(); // 3. 算控制量 (快)
Update_Display(); // 4. 刷屏幕 (慢,极慢!)
Report_UART(); // 5. 报数据 (慢)
}
}
逻辑死结: Update_Display() 是个“耗时大户”。假设刷新整个屏幕需要 30ms(对于 SPI 屏很正常)。 这意味着,你的 Scan_Keys() 和 PID_Compute() 也就是每 30ms 才能执行一次。
-
按键体验:可能会觉得肉肉的,不灵敏。
-
PID 控制:控制周期不稳定,甚至太长导致系统震荡。
为了解决这个问题,裸机高手会把按键和 PID 放到定时器中断里。但中断里不能干太多事,否则主循环又跑不动了。这就是耦合 (Coupling) —— 一个模块的性能瓶颈,拖累了整个系统。
2. RTOS 拆分原则:各司其职
在 RTOS 中,我们将上述逻辑拆解为独立的任务 (Task)。每个任务都有自己的 while(1),自己的栈空间,以及最重要的——优先级。
实战拆分案例:智能温控器
我们至少应该拆分为 3 个任务:
任务 A:交互任务 (Task_HMI)
-
职责:负责按键扫描、旋钮读取。
-
优先级:高 (High)。
-
逻辑:人的操作是最需要即时反馈的。无论 CPU 在干什么,只要用户按了键,系统必须立刻响应(比如置个标志位或发个信号)。
任务 B:控制任务 (Task_Control)
-
职责:读取传感器、跑 PID 算法、控制继电器/电机。
-
优先级:中 (Medium) 或 高 (High)。
-
逻辑:这是产品的核心业务,必须保证稳定的采样和计算周期(例如严格的 10ms)。可以使用
vTaskDelayUntil来保证绝对周期。
任务 C:显示任务 (Task_Display)
-
职责:刷新 LCD 界面、打印串口日志。
-
优先级:低 (Low)。
-
逻辑:这是最耗时且最不紧急的工作。屏幕每秒刷 10 帧还是 20 帧,对功能没影响。只有当按键没按下、PID 也没在算的时候,CPU 才会来刷屏。
3. 代码形态的对比
RTOS 下的代码结构:
// 1. 显示任务 (低优先级)
void Task_Display(void *pvParam) {
while(1) {
// 慢慢刷,不用担心阻塞别人
LCD_DrawString("Temp: 25.5");
vTaskDelay(100); // 10FPS 足够了
}
}
// 2. 控制任务 (高优先级)
void Task_Control(void *pvParam) {
TickType_t xLastWakeTime = xTaskGetTickCount();
while(1) {
// 严格每 10ms 执行一次
float temp = Read_ADC();
float out = PID_Calc(temp);
Motor_Set(out);
// 绝对延时
vTaskDelayUntil(&xLastWakeTime, 10);
}
}
神奇的效果: 当 Task_Display 正在努力画图(执行那几千行 SPI 传输代码)时,如果 10ms 时间到了,RTOS 会强行打断画图任务,切换到 Task_Control 去算 PID。算完后,再切回来继续画图。
-
PID 工程师:我的算法周期稳如泰山。
-
UI 工程师:我终于可以用复杂的动画效果了,不用担心卡死按键。
这就是抢占式调度 (Preemptive Scheduling) 的魅力。
4. 警惕反模式:上帝任务 (God Task)
新手常犯的一个错误是:虽然用了 RTOS,但只创建了一个任务,然后把原来的裸机 while(1) 代码原封不动地拷进去。
// 错误示范:上帝任务
void Task_App(void *pvParam) {
while(1) {
Scan_Keys();
PID();
Display();
vTaskDelay(10);
}
}
这就失去了 RTOS 的所有意义。如果你发现你的某个任务代码行数超过了 500 行,或者它既管硬件又管界面还管算法,请立刻把它拆分。
关键点总结
-
解耦:将快任务(按键、控制)与慢任务(显示、日志)分离。
-
优先级:紧急的给高优先级,耗时的给低优先级。
-
各扫门前雪:每个任务只关注自己的逻辑,不用再担心“我这一行代码会不会卡死整个系统”。
/******************************************************
* 本文为作者《嵌入式开发基础与工程实践》系列文章之一。
* 关注即可订阅后续内容更新,采用异步推送机制,无需主动轮询。
* 转发本文可视为一次网络广播,有助于更多节点接收该信息。
******************************************************/
58

被折叠的 条评论
为什么被折叠?



