1. 前后台架构(裸机轮询)
前后台架构是最基础的嵌入式软件框架,由“后台”主循环和“前台”中断服务程序组成。主循环不断轮询标志位或传感器值,中断负责捕获实时事件并置位标志或缓存数据。
// 典型前后台架构
volatile uint8_t flag = 0;
void EXTI_IRQHandler(void) {
flag = 1; // 置位事件标志
}
int main(void) {
while (1) {
if (flag) {
flag = 0;
process_event(); // 后台处理
}
poll_button();
poll_sensor();
}
}
优点:代码直观、资源占用极低、无上下文切换开销;缺点:主循环中任意阻塞操作都会影响响应,难维护多任务逻辑。
配置步骤:
- 规划全局事件标志(bitmask);
- 在ISR中只做最简操作(置位、保存数据);
- 主循环中依次检查标志并调用对应处理函数;
- 确保所有处理函数非阻塞,必要时拆分成状态机。
2. 状态机架构
状态机(State Machine)将程序行为分解为有限个状态,通过事件触发状态迁移,适合处理复杂协议、按键扫描、菜单导航等逻辑。其核心是“当前状态+事件→动作+下一个状态”。
// 状态枚举
typedef enum { LED_OFF, LED_ON, LED_BLINK } LEDState;
void led_process(LEDEvent evt) {
static LEDState state = LED_OFF;
switch (state) {
case LED_OFF:
if (evt == EVT_BUTTON_SINGLE) {
LED_SetOn();
state = LED_ON;
}
break;
case LED_ON:
if (evt == EVT_BUTTON_SINGLE) {
LED_SetOff();
state = LED_OFF;
} else if (evt == EVT_TIMER) {
LED_SetBlink();
state = LED_BLINK;
}
break;
case LED_BLINK:
// ...
break;
}
}
配置步骤:
- 定义状态枚举和事件枚举;
- 为每个状态编写处理函数或switch-case分支;
- 在事件产生地方(中断、超时、轮询)调用迁移函数;
- 使用状态表(二维数组)替代大型switch更易维护。
优点:逻辑清晰、无递归、可预测性强;缺点:若状态太多,代码量增长较快,且不适合CPU密集型计算并行场景。
3. RTOS架构
RTOS(实时操作系统)引入任务、调度器、信号量和消息队列等抽象,使多任务并行开发成为可能。以FreeRTOS为例,任务以线程方式独立运行,由优先级抢占式调度。
// FreeRTOS任务创建示例
void vTaskSensor(void *arg) {
while (1) {
int data = read_sensor();
xQueueSend(qSensor, &data, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void vTaskLog(void *arg) {
int data;
while (1) {
if (xQueueReceive(qSensor, &data, 100) == pdPASS) {
log_data(data); // 可能阻塞在UART上
}
}
}
int main(void) {
xQueueCreate(10, sizeof(int));
xTaskCreate(vTaskSensor, "sensor", 128, NULL, 2, NULL);
xTaskCreate(vTaskLog, "log", 128, NULL, 1, NULL);
vTaskStartScheduler();
}
配置步骤:
- 移植RTOS或使用IDE内置组件;
- 配置堆栈大小、时钟节拍;
- 拆分任务,分配优先级(就绪、阻塞、延时);
- 用队列或信号量进行任务间通信;
- 处理中断绑定(如
portYIELD_FROM_ISR)。
优点:并行化开发、实时性强、支持超时等待;缺点:额外RAM/ROM开销,存在优先级反转、死锁等风险,调试更复杂。
4. 如何选型?
没有最好的架构,只有最合适的架构。请根据项目实际情况决策:
- 任务数量:少于5个简单周期性任务→前后台+状态机足够;多于5个且存在互相等待→考虑RTOS。
- 实时性要求:事件响应时延要求苛刻(微秒级)→优先中断+裸机;毫秒级可接受→RTOS。
- 资源限制:RAM不足8KB、Flash不足64KB的深嵌入式→首选前后台或状态机。
- 开发维护:多人协作、长期迭代→RTOS的抽象接口更利于分工;个人小项目→状态机更灵活。
| 架构 | 资源开销 | 实时性 | 可维护性 | 适用场景 | |------|----------|--------|----------|----------| | 前后台 | 极低 | 中 | 低 | 简单控制、传感采集 | | 状态机 | 低 | 高(无嵌套) | 中高 | 按键、通信协议、UI | | RTOS | 中高 | 高(抢占) | 高 | 多任务、复杂产品 |
5. 注意事项
-
中断自律:无论何种架构,ISR必须短小精悍,不做耗时操作;若RTOS中可使用
ISR-safeAPI。 -
共享资源保护:前后台下用
volatile或关中断;RTOS下使用互斥量,防止竞态。 - 状态机拆解:复杂状态机务必画状态迁移图,避免非法跳转和“饿死”状态。
-
RTOS配置:不要盲目使用
vTaskDelay替代硬件定时器,高精度场景仍需外设定时器。 - 测试覆盖:架构切换后,需重点验证时序变化,如中断响应时间、任务抖动量。
总结
前后台、状态机与RTOS并非非此即彼,它们可以组合——比如用RTOS管理多任务,而复杂交互逻辑仍用状态机实现。选择的核心依据是任务复杂度与资源约束。理解每一种架构的本质,才能真正做出符合产品需求的最佳设计。