一、架构与调度模式
这是嵌入式系统的骨架,决定了程序执行流程。
1.前后台模式
这个是最基础、最常用的裸机模式。
-
原理:
- 后台:一个无限循环(while(1)),负责处理对实时性要求不高的任务(如LCD显示、数据处理)。
- 前台:中断服务程序,负责处理实时性要求高的事件(如按钮检测,ADC采集,串口接收)。
-
适用场景: 逻辑简单、低成本、无需RTOS的中小型MCU项目。
-
代码结构:
void main() { Init(); while(1) { if (flag_10ms) { Task_10ms(); flag_10ms = 0; } // 后台 if (flag_process_data) { ProcessData(); flag_process_data = 0; } } } void ISR_Timer() { flag_10ms = 1; }
2.时间触发模式
- 原理: 基于定时器构建一个简单的调度器。将任务划分为不同周期(如10ms,100ms,1s),在定时中断中计数,在主循环中按时间片轮询执行。
- 优点: 执行时序确定性强,会比单纯的Super Loop更有条理。
- 缺点: 如果某个任务执行时间过长,会阻塞后续任务,导致“抖动”。
3.分层架构模式
为了解决移植性差的问题,必须将硬件与业务逻辑剥离。
-
结构:
- 硬件层:MCU、外设。
- 驱动层:直接寄存器操作,提供API(如Create,Read,Write)。
- 中间件/功能模块层:协议层、文件系统、算法库(与硬件无关)。
- 应用层:具体的业务逻辑。
-
核心思想:上层调用下层,下层不依赖上层(通过回调函数除外)。
二、状态管理模式
嵌入式设备本质时状态机(如:待机、运行、故障、设置)。
1.有限状态机
-
实现方式A:Switch-Case法
- 最简单,适用于状态比较少的情况。
- 缺点:随着状态增加,代码变成“面条代码”,难以维护。
-
实现方式B:函数指针/查表法
-
原理:定义状态枚举和事件枚举,建立一个二位数组(或结构体数组),存储当前状态、事件-> 下一个状态 & 执行动作。
-
优点:逻辑清晰,增加状态只需要修改表格,O(1)查找效率。
-
代码示例:
typedef struct { State_t nextState; void (*action)(void); } StateTrans_t; StateTrans_t stateTable[MAX_STATES][MAX_EVENTS]; void HandleEvent(Event_t evt) { StateTrans_t *trans = &stateTable[currentState][evt]; if (trans->action) trans->action(); currentState = trans->nexState; }
-
三、数据处理与通信模式
1.生产者-消费者模式
- 核心组件:环形缓冲区。
- 场景:UART接收中断(生产者)高速写入数据,主循环解析任务(消费者)低速读取数据。
- 作用:解决速率不匹配问题,解耦中断和主线程,防止数据丢失。
- 注意:需要处理读写指针的原子性(尤其是在裸机中断中)。
2.观察者模式
-
场景:一个传感器数据(如温度)更新后,需要通知:屏幕显示模块、日志存储模块、网络上传模块。
-
传统写法:在温度采集函数里直接调用
Display_Update(),Log_Write(),Net_Send()。耦合度高。 -
模式写法:
- 定义一个“主题”。
- 各模块注册回调函数到主题列表。
- 数据更新时,便利列表调用回调。
-
优点:增加新的接收模块时,不需要修改采集模块的代码。
四、C语言面向对象模式
C语言虽然不是面向对象语言,但在嵌入式驱动开发中,模拟OOP时非常高级且常用的技巧。
1.结构体封装与堕胎
-
场景:系统中有3个不同的传感器(I2C接口、SPI接口、ADC接口),但上层应用只想调用
Sensor_Read()。 -
实现:
// 定义接口(基类) typedef struct { uint8_t (*init)(void); uint16_t (*read)(void); } sensor_driver_t; // 具体实现(子类) uint16_t temp_sensor_read() {/* I2C mode */} uint16_t light_sensor_read() {/* ADC mode */} // 实例化 sensor_driver_t temp_driver = {.read = temp_sensor_read}; sensor_driver_t light_driver = {.read = light_sensor_read}; // 多态调用 void app_read(sensor_driver_t *driver) { uint16_t val = driver->read(); }
2.单例模式
- 场景:硬件资源是唯一的(例如MCU只有一个LCD控制器或一个配置管理器)。
- 实现:在C语言中,通常通过结构体实例设为static并仅提供get_instance()接口,或者直接隐藏数据结构,只暴露操作API来实现。
五、可靠性与安全模式
1.哨兵模式/看门狗
-
策略:不要在中断中喂狗,也不要在主循环的一个地方喂狗。
-
任务流监控模式:
- 每个关键任务执行完成后设置一个标志位。
- 仅当所有标志位都置位是,才真正喂硬件看门狗。
- 这能检测“程序没死机,但某个传感器任务卡死”的情况。
2.双缓冲模式
-
场景:DMA数据传输(如音频播放、高速ADC采样)
-
原理:适用两个buffer(A和B)。
- DMA正在向buffer A写入数据。
- CPU同时处理buffer B的数据。
- A写满后,DMA自动切换写B,CPU开始处理A。
-
作用:提高吞吐量,实现无缝连续的数据流处理。