版本: V1.0
数据流:信号从哪来,经过哪些中断、任务、缓冲区,输出到什么硬件、存了什么,时序和掉电是否安全
用户体验: 实时、可靠、低功耗、可诊断、可维护、断电可恢复
抽象概念:硬件隔离是否正确,并发模型是否匹配,状态机是否清晰,组件是否可替换且开销可接受
概念展开
数据如何在系统中流动
数据大致可以分为 信号链、控制链、通信链
输入从哪来:传感器、ADC、GPIO、编码器、按键、总线(I2C、SPI、UART、CAN、以太网等等)、定时器、中断
怎么流动:中断服务程序 -> DMA -> RTOS队列/信号量 -> 任务 -> 控制算法/状态机 -> 协议栈
输出了什么:PWM、DAC、GPIO、继电器、电机、显示屏、通信报文、日志、故障信号
存储了什么:RAM里的栈、堆、全局变量、DMA缓冲;FLASH里的代码、参数、校准值、日志、OTA分区、EEPROM/FRAM里的掉电保存数据
数据流的关键问题
时间: 中断延迟多少? 任务最坏执行时间多少? 抖动多大? 有没有错过采样?
并发: 中断和任务共享数据怎么保护? 选择队列还是共享内存? 原子性怎么保证
缓冲区所有权: 谁分配 谁释放 谁修改? DMA和CPU会不会同时访问(尤其是带有Cache的芯片)
掉电与恢复: 写FLASH时断电怎么办? 参数是否CRC校验? 能否回滚
一致性: 字节序, 对齐, volatile, 内存屏障, 缓存一致性
常见错误: 在中断里做浮点运算, 动态分配, 阻塞调用; 把volatile当同步;DMA缓冲区被任务提前释放;共享变量不加保护;看门狗喂狗路径被阻塞
用户体验:不只是界面,而是系统行为
嵌入式里的“用户”是多重的:最终用户、操作员、维护人员、上层系统、被控对象。所以体验包括:
实时性:按键响应、控制环周期、通信超时、故障保护动作是否及时。
可靠性:看门狗、复位原因、故障安全、冗余、CRC/ECC、断电恢复。
功耗:睡眠模式、唤醒源、外设时钟、泄漏电流、电池寿命。
可维护性:日志、诊断接口、错误码、版本号、OTA 是否可靠、会不会变砖。
物理交互:按钮去抖、LED 指示、蜂鸣器、屏幕、振动反馈。
一致性:同样操作是否同样结果;错误码是否统一;多任务下行为是否稳定。
嵌入式体验的“漏洞”往往是:栈溢出、堆碎片、优先级反转、死锁、竞态、中断丢失、采样溢出、未初始化变量、看门狗误复位、OTA 断电变砖、通信协议状态不一致。
性能也不只是快慢,而是:CPU 占用率、内存占用、中断延迟、最坏执行时间、功耗、启动时间。一个功能“能跑”不够,还要“在最坏情况下也能跑”。
3. 基本抽象概念:硬件隔离、并发模型、状态机
嵌入式抽象的核心是:
HAL/BSP:把寄存器操作、外设初始化、读写接口封起来。
驱动:设备模型、中断处理、DMA、缓冲区管理。
RTOS 抽象:任务、队列、信号量、互斥量、事件组、内存池。
业务抽象:状态机、控制环、协议、故障管理、配置管理。
可抽换结构:硬件相关与平台无关分离;驱动可替换;RTOS 可替换;协议栈分层;用函数指针、弱符号、配置表做板级适配。
常见误用:
把中断当线程, 在里面做耗时操作。
把
volatile当原子操作或同步机制。用全局变量做任务间通信。
在实时路径里动态分配内存。
把硬件寄存器当普通内存,忽略读写副作用。
把“延时”当“定时”,把“看门狗”当复位工具。
抽象层太厚,带来额外拷贝、虚函数、内存开销,反而破坏实时性。
嵌入式里的抽象要“薄、可裁剪、可测试”。不是不能抽象,而是抽象必须考虑资源成本和实时性。
如何区分“大问题”和“小问题”
影响信号链时序、控制周期、中断延迟的,是大问题。
影响内存安全、栈/堆、硬件状态、安全保护的,是大问题。
破坏硬件抽象边界、并发模型、状态机一致性的,是大问题。
导致看门狗复位、OTA 变砖、断电丢参数的,是大问题。
只是某个模块代码冗长、命名不好、局部小 Bug,但隔离良好、不影响时序和内存,才可能是小问题。