1. 课程导论与分层思想:为什么需要分层架构?

大家好,我是你们这门课的老朋友。做了十几年单片机开发,踩过的坑比吃过的盐还多。今天咱们开篇第一讲,不急着上代码,先聊聊一个根本问题——为什么你的代码总是写着写着就成了一团乱麻?

说白了,就是“面条代码”在作祟。我刚入行那会儿,写一个温控器项目,所有逻辑全塞在一个 main.c 里。按键扫描、温度读取、PID计算、LCD显示……全搅在一起。结果呢?客户要改个显示格式,我改了三天,还引入三个新bug。那滋味,真不好受。

核心观点:分层架构不是花架子,它是让你从“能跑就行”进化到“好改、好测、好复用”的必经之路。

1.1 从“面条代码”说起

什么是面条代码?你想想看,一个函数里既有硬件寄存器操作,又有业务逻辑判断,还夹杂着延时等待。就像一碗面条,你夹起一根,带出一整碗。改一处,全盘都得动。

我见过最夸张的项目,一个 while(1) 循环里写了 2000 多行。没有函数,没有模块,全靠全局变量传参。后来换了个新人接手,直接崩溃——不是人崩溃,是代码崩溃,编译都过不了。

特征 面条代码 模块化代码
函数长度 几百上千行 几十行,职责单一
耦合度 高,改一处动全身 低,接口清晰
可测试性 几乎无法单元测试 可以 mock 硬件做测试
复用性 复制粘贴改参数 直接调用接口
维护成本 指数级增长 线性增长
避坑指南:我曾经接手过一个项目,所有外设驱动都写在中断服务函数里。中断里做浮点运算、调 printf、甚至跑延时循环。结果系统一跑就死,查了三天才发现是中断嵌套把栈撑爆了。记住:中断里只做最轻量的事。

1.2 分层架构的核心思想

分层架构,说白了就是“各司其职,各管一摊”。我们把代码按职责切分成几个层次,每一层只关心自己的事,通过定义好的接口跟上下层打交道。

我个人习惯把单片机软件分成三层:

  • 硬件抽象层(HAL):直接跟寄存器、外设打交道。比如 GPIO 置高置低、SPI 收发一个字节。
  • 中间层(Middleware):封装一些通用功能。比如按键消抖、环形缓冲区、协议解析。
  • 应用层(Application):业务逻辑。比如“温度超过 50 度就打开风扇”。

这样做的好处很明显:硬件换了,只改 HAL 层;业务逻辑变了,只改应用层。中间层几乎不用动。

单片机软件分层架构 应用层 (Application) 业务逻辑:状态机、任务调度、用户交互 中间层 (Middleware) 协议解析、按键管理、环形缓冲区、FIFO 硬件抽象层 (HAL) GPIO、SPI、I2C、UART、定时器寄存器操作 每一层只通过接口与相邻层通信,禁止跨层调用
我的习惯:在 HAL 层,我会把所有外设操作封装成 HAL_XXX_Read() / HAL_XXX_Write() 的形式。应用层永远不直接操作寄存器。这样即使换 MCU,应用层代码一行都不用改。

1.3 接口抽象:让代码“活”起来

分层只是第一步。真正让代码灵活的是接口抽象。什么意思呢?就是定义一套通用的操作接口,底层具体怎么实现,上层不关心。

举个例子。你有一个温湿度传感器,可能是 DHT11,也可能是 SHT30。如果应用层直接调用 DHT11_Read(),那换传感器就得改应用层代码。但如果你定义一个抽象接口:

// 抽象传感器接口
typedef struct {
    int8_t (*init)(void);
    int8_t (*read_temperature)(float *temp);
    int8_t (*read_humidity)(float *humi);
} sensor_t;

// 应用层只调用这个接口
sensor_t my_sensor;
my_sensor.init();
my_sensor.read_temperature(&temp);

这样,底层换传感器,只需要换一个 sensor_t 实例,应用层代码纹丝不动。我在一个智能家居项目里用过这个模式,后来客户要求从 DHT11 换成 SHT30,我只花了半小时改驱动,应用层一行没动。

1.4 从“能跑”到“好维护”的演进路径

很多初学者觉得:“我的代码能跑就行,搞那么复杂干嘛?”嗯,这话我年轻时也说过。直到项目规模超过 5000 行,bug 开始像雨后春笋一样冒出来,我才明白:能跑只是及格线,好维护才是硬道理。

我建议的演进路径是这样的:

  1. 第一阶段:把所有功能写在一个文件里,先跑通。这叫“原型验证”。
  2. 第二阶段:按功能拆成多个 .c/.h 文件。比如 led.c、key.c、uart.c。这叫“模块化”。
  3. 第三阶段:引入分层思想,把硬件操作和业务逻辑分开。这叫“架构化”。
  4. 第四阶段:定义抽象接口,支持多平台、多硬件。这叫“平台化”。

这门课,我们会从第二阶段开始,一路走到第四阶段。每一章都会配合实战代码,让你亲手感受从“面条”到“模块”再到“架构”的蜕变。

记住:好的架构不是设计出来的,是重构出来的。不要一开始就想搞个大而全的框架,先让代码跑起来,然后一步步优化。我见过太多人因为过度设计,项目还没跑通就夭折了。

1.5 本章小结

这一讲,我们聊了:

  • 面条代码的典型特征和危害
  • 分层架构的三层模型:HAL、中间层、应用层
  • 接口抽象的核心思想:面向接口编程,而不是面向实现
  • 从“能跑”到“好维护”的四个演进阶段

下一章,我们会动手搭建第一个分层项目——一个带按键和 LED 的简单系统。你会亲眼看到,同样的功能,用分层写和用面条写,差别有多大。

嗯,咱们下章见。