1. 课程导论与分层架构全景
1.1 为什么需要分层架构?
先说说我自己的经历。十年前我刚入行时,接手过一个智能灯控项目。代码全写在一个 main.c 里,全局变量满天飞,中断服务函数里还塞着延时。功能倒是能跑,但每次加需求我都得熬夜改代码。有一次客户要换个 WiFi 模块,我整整重构了两周——因为驱动和业务逻辑全搅在一起了。
你想想看,MCU 开发其实有个很尴尬的现实:硬件迭代快,但软件复用率极低。换个芯片、换个外设,代码就得重写大半。为什么会这样?说白了,就是缺少分层意识。
分层架构的核心价值:
- 隔离变化——硬件换了,只改底层;需求变了,只改上层
- 提升复用——写一次驱动,多个项目通用
- 便于测试——每层可以单独验证,不用等硬件就绪
- 团队协作——有人写驱动,有人写业务,互不干扰
1.2 MCU 软件开发的痛点与挑战
这些年我带过不少项目,也踩过很多坑。总结下来,MCU 开发有三大顽疾:
| 痛点 | 表现 | 后果 |
|---|---|---|
| 耦合过紧 | 驱动代码和业务逻辑混在一起 | 换芯片等于重写整个项目 |
| 可移植性差 | 代码依赖特定 MCU 寄存器操作 | 换个平台,移植成本比新写还高 |
| 调试困难 | 问题定位需要全盘排查 | 一个 bug 查三天,最后发现是时序问题 |
我曾经踩过的坑:有个温控项目,我把 DS18B20 的时序操作直接写在温度采集函数里。后来要换成 NTC 热敏电阻,结果发现温度采集、滤波、阈值判断全耦合在一起。改了一个星期,还引入了新 bug。从那以后,我坚持驱动层必须独立封装。
1.3 经典三层架构详解
我习惯把 MCU 软件分成三层。这个结构不是拍脑袋想的,是经过多个项目验证的。你记住这个图,后面所有章节都围绕它展开。
HAL 层:硬件抽象层
这一层直接跟寄存器打交道。我习惯把每个外设封装成一个独立的模块。比如 UART,就提供 uart_init()、uart_send()、uart_recv() 三个接口。上层调用时,根本不用关心底层是 STM32 还是 GD32。
我的经验:HAL 层接口要尽量简洁。别想着把所有功能都暴露出来。接口越少,上层越稳定。我一般每个外设只暴露 3-5 个核心函数。
OSAL 层:操作系统抽象层
这一层是很多初学者容易忽略的。你想想看,如果你的项目从裸机切换到 FreeRTOS,任务创建、延时、信号量的 API 全都不一样。OSAL 就是给这些系统服务包一层统一的接口。
举个例子:
// OSAL 统一接口
void osal_task_create(void (*task)(void*), void *param);
void osal_delay_ms(uint32_t ms);
int osal_sem_take(osal_sem_t *sem, uint32_t timeout);
// 底层可以是 FreeRTOS
// #define osal_task_create(task, param) xTaskCreate(task, ...)
// 也可以是 RT-Thread
// #define osal_task_create(task, param) rt_thread_create(...)
APP 层:应用层
这一层只关心业务逻辑。比如温控系统,APP 层只处理:温度到了多少该开加热?温差多大该报警?至于温度怎么读、继电器怎么控制,APP 层一概不管。
1.4 模块化设计原则
分层是纵向切分,模块化是横向切分。我总结了两条铁律:
- 高内聚:一个模块只做一件事,并且把它做好。比如温度采集模块,就只负责采集和滤波,别掺和报警逻辑。
- 低耦合:模块之间通过接口通信,别直接访问对方的全局变量。我见过最离谱的代码,一个模块直接修改另一个模块的内部数组——这种代码根本没法维护。
模块化设计的检查清单:
- 每个模块是否有独立的 .h 和 .c 文件?
- 模块对外暴露的接口是否少于 5 个?
- 模块内部是否有 static 关键字保护私有数据?
- 模块之间是否只通过函数调用通信?
- 删除一个模块,其他模块是否不受影响?
1.5 课程项目概览:智能家居温控系统
光讲理论没意思。这门课会带着你从零搭建一个完整的智能温控系统。项目包含:
| 模块 | 功能 | 涉及知识点 |
|---|---|---|
| 温度采集 | 读取 DS18B20 / NTC 温度 | HAL 层驱动封装、滤波算法 |
| 温控策略 | PID 控制 / 开关控制 | APP 层业务逻辑、状态机 |
| 显示模块 | OLED 显示当前温度 | HAL 层 I²C 驱动、OSAL 任务管理 |
| 按键交互 | 设置目标温度、模式切换 | 中断处理、去抖算法 |
| 通信模块 | UART 上报数据 | OSAL 消息队列、数据协议 |
我建议你这样做:每学完一章,就把对应的代码写到你的开发板上。别光看。我当年学 RTOS 时,把书上的例程一个个敲了一遍,虽然慢,但理解得特别深。
这个项目虽然看起来简单,但它覆盖了 MCU 开发中 90% 的常见场景。学完之后,你完全可以把这个架构套用到其他项目上——不管是智能家居、工业控制还是物联网终端。