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();
    }
}

优点:代码直观、资源占用极低、无上下文切换开销;缺点:主循环中任意阻塞操作都会影响响应,难维护多任务逻辑。

配置步骤

  1. 规划全局事件标志(bitmask);
  2. 在ISR中只做最简操作(置位、保存数据);
  3. 主循环中依次检查标志并调用对应处理函数;
  4. 确保所有处理函数非阻塞,必要时拆分成状态机。

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;
    }
}

配置步骤

  1. 定义状态枚举和事件枚举;
  2. 为每个状态编写处理函数或switch-case分支;
  3. 在事件产生地方(中断、超时、轮询)调用迁移函数;
  4. 使用状态表(二维数组)替代大型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();
}

配置步骤

  1. 移植RTOS或使用IDE内置组件;
  2. 配置堆栈大小、时钟节拍;
  3. 拆分任务,分配优先级(就绪、阻塞、延时);
  4. 用队列或信号量进行任务间通信;
  5. 处理中断绑定(如portYIELD_FROM_ISR)。

优点:并行化开发、实时性强、支持超时等待;缺点:额外RAM/ROM开销,存在优先级反转、死锁等风险,调试更复杂。

4. 如何选型?

没有最好的架构,只有最合适的架构。请根据项目实际情况决策:

  • 任务数量:少于5个简单周期性任务→前后台+状态机足够;多于5个且存在互相等待→考虑RTOS。
  • 实时性要求:事件响应时延要求苛刻(微秒级)→优先中断+裸机;毫秒级可接受→RTOS。
  • 资源限制:RAM不足8KB、Flash不足64KB的深嵌入式→首选前后台或状态机。
  • 开发维护:多人协作、长期迭代→RTOS的抽象接口更利于分工;个人小项目→状态机更灵活。

| 架构 | 资源开销 | 实时性 | 可维护性 | 适用场景 | |------|----------|--------|----------|----------| | 前后台 | 极低 | 中 | 低 | 简单控制、传感采集 | | 状态机 | 低 | 高(无嵌套) | 中高 | 按键、通信协议、UI | | RTOS | 中高 | 高(抢占) | 高 | 多任务、复杂产品 |

5. 注意事项

  • 中断自律:无论何种架构,ISR必须短小精悍,不做耗时操作;若RTOS中可使用ISR-safe API。
  • 共享资源保护:前后台下用volatile或关中断;RTOS下使用互斥量,防止竞态。
  • 状态机拆解:复杂状态机务必画状态迁移图,避免非法跳转和“饿死”状态。
  • RTOS配置:不要盲目使用vTaskDelay替代硬件定时器,高精度场景仍需外设定时器。
  • 测试覆盖:架构切换后,需重点验证时序变化,如中断响应时间、任务抖动量。

总结

前后台、状态机与RTOS并非非此即彼,它们可以组合——比如用RTOS管理多任务,而复杂交互逻辑仍用状态机实现。选择的核心依据是任务复杂度与资源约束。理解每一种架构的本质,才能真正做出符合产品需求的最佳设计。