1. 课程导论与分层思想:为什么需要分层?
大家好,欢迎来到这门课。
先问一个问题:你写过的裸机代码,是不是经常变成一坨“屎山”?
别急着否认。我做了十几年嵌入式,见过太多这样的项目:一个 main.c 文件写了三千行,中断服务函数里塞满了业务逻辑,全局变量满天飞。改一个 bug,引出三个新 bug。项目越往后拖,越不敢动代码。
为什么会这样?
说白了,就是没有架构。
裸机开发的典型痛点
我们先来盘点一下,裸机开发最常见的几个坑。我敢打赌,你至少踩过其中一个。
| 痛点 | 具体表现 | 后果 |
|---|---|---|
| 代码耦合严重 | GPIO 操作、定时器配置、算法逻辑全揉在一个函数里 | 改一处,崩一片 |
| 可移植性差 | 换一颗 MCU,所有代码重写 | 项目复用率几乎为零 |
| 调试困难 | 逻辑和硬件搅在一起,分不清是 Bug 还是硬件问题 | 排查问题耗时翻倍 |
| 团队协作混乱 | 没有清晰的模块边界,A 改的代码把 B 的功能搞挂了 | 沟通成本剧增 |
| 测试几乎不可能 | 想写单元测试?先得把硬件跑起来 | 质量全靠“人肉” |
我曾经接手过一个智能家居项目,前任工程师把所有代码写在一个文件里,连中断服务函数里都调用了延时函数。结果就是:按键响应延迟、屏幕闪烁、通信丢包。最后没办法,全部推倒重来。那个教训,让我彻底明白了分层的重要性。
分层架构的核心理念
那什么是分层?
简单说,就是把软件按照职责拆成不同的层。每一层只关心自己的事,层与层之间通过定义好的接口通信。
你想想看,这就像一家公司。有销售部、研发部、财务部。销售部不需要知道研发部怎么写代码,研发部也不需要管财务部怎么做账。大家各司其职,通过规范的流程协作。
在嵌入式软件里,我习惯把代码分成这三层:
- 硬件抽象层(HAL):直接跟寄存器、外设打交道。负责读写 GPIO、配置定时器、收发 SPI 数据。
- 驱动层(Driver):封装外设的具体操作。比如 LCD 驱动、传感器驱动、存储芯片驱动。这一层把硬件细节藏起来。
- 应用层(Application):实现业务逻辑。比如读取温度、控制电机、处理按键事件。这一层不关心硬件怎么实现。
嗯,这里要注意:有些项目还会在 HAL 和 Driver 之间再加一层板级支持包(BSP),用来管理板级资源。这个我们后面会细讲。
分层架构的收益
分层之后,你能得到什么?
- 代码可读性飙升:每一层的职责清晰,新人接手也能快速看懂。
- 可移植性大幅提升:换 MCU 时,只需要重写 HAL 层,应用层几乎不用动。我有个项目从 STM32F1 移植到 STM32G4,只花了两天。
- 调试效率翻倍:出问题了,先定位是哪一层。是硬件问题?还是驱动问题?还是逻辑问题?范围一下子缩小了。
- 团队协作顺畅:A 写应用,B 写驱动,C 写 HAL。只要接口约定好,各干各的,互不干扰。
- 可测试性成为可能:应用层可以脱离硬件做单元测试。我在项目中就用过模拟 HAL 接口的方式,在 PC 上跑通整个业务逻辑。
我个人习惯,在项目启动前,先用一张图把分层结构和接口定义画出来。这张图就是整个软件的“蓝图”。后面写代码,就是照着蓝图施工,很少会跑偏。
分层架构的核心逻辑图
下面这张图,就是我这门课的核心思想。你可以把它当作整个课程的“总纲”。
这张图你一定要记住。后面的所有章节,都是围绕这个结构展开的。
避坑指南:分层不是越细越好。我见过有人把一层拆成五层,结果接口传递变得极其复杂,代码量翻倍,性能还下降了。对于裸机项目,三层到四层通常是最合适的。记住:分层是为了解决问题,不是为了炫技。
什么时候该用分层?
不是所有项目都需要分层。我个人的判断标准是这样的:
- 项目代码量超过 5000 行:不分层,后面维护会非常痛苦。
- 需要移植到不同平台:比如产品有多个型号,用不同的 MCU。
- 团队开发:两个人以上协作,没有分层就是灾难。
- 产品生命周期长:要持续迭代、维护好几年。
如果你的项目只是一个简单的点灯程序,或者一次性的 Demo,那确实没必要分层。但话说回来,养成好习惯,从简单项目开始练习分层,后面做大项目才能游刃有余。
小结
这一章我们聊了裸机开发的痛点,也讲了分层架构的理念和收益。说白了,分层就是把复杂问题拆成简单问题,然后各个击破。