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

大家好,我是你们这趟旅程的向导。先聊聊我自己的经历吧。十年前我刚入行时,写STM32程序就是典型的“裸奔”——一个main.c里塞满所有外设初始化、中断处理和业务逻辑。那时候项目小,感觉还挺爽。直到有一次接手一个带Wi-Fi、蓝牙、LCD显示和多个传感器的项目……嗯,那代码简直成了意大利面条,改一个定时器参数,莫名其妙把LCD刷新搞崩了。

从那天起,我开始认真思考一个问题:为什么我们的代码不能像搭积木一样,各玩各的,互不干扰?

1.1 从裸机开发到分层架构的演进

先看一张图,直观感受一下这种演进过程。

嵌入式软件架构演进路线 阶段一:裸机大循环 main.c 单文件 所有逻辑堆在一起 中断直接操作全局变量 阶段二:模块化 按外设拆分文件 uart.c / spi.c / lcd.c 全局变量依然满天飞 阶段三:分层架构 应用层 服务层 驱动层 核心变化:从“所有代码平铺”到“各层各司其职” 裸机:硬件中断直接调用业务逻辑 → 分层:硬件中断只通知驱动层,驱动层回调服务层 裸机痛点 • 改一处崩全局 • 多人协作困难 分层优势 • 每层独立修改 • 接口清晰,团队并行

说白了,分层架构就是给代码划地盘。每一层只关心自己的事,通过固定的接口跟上下层打交道。我见过太多新手一上来就怼RTOS,结果任务之间互相抢资源,死锁频繁——其实根源不是RTOS不好,而是底层没有做好隔离。

1.2 为什么需要分层?三个核心理由

维度 裸机/平铺式 分层架构
可维护性 改一个外设驱动,可能影响三个业务模块 驱动层修改,上层接口不变,业务层无感知
可移植性 换MCU型号,几乎重写全部代码 只换最底层HAL驱动,应用层代码几乎不动
团队协作 两个人同时改同一个文件,合并时想哭 A写驱动层,B写应用层,接口约定好就行

我个人习惯:在项目启动前,先用白板画出三层结构——硬件抽象层、服务层、应用层。哪怕后面要调整,也比直接写代码强十倍。

1.3 分层架构在STM32 HAL库中的落地

你可能会问:HAL库本身不就是一层封装吗?没错,但HAL库只做到了硬件抽象,它没有帮你解决任务调度和模块间通信的问题。

举个例子:你用HAL_UART_Receive_IT接收数据,中断来了,数据存到哪儿?谁来处理?如果此时LCD正在刷新,会不会冲突?

这就是我们这门课要解决的核心问题——在HAL库之上,构建一套清晰的分层任务调度框架。

一个小技巧:把HAL库当作“硬件驱动层”,不要在里面写任何业务逻辑。我在项目中见过有人直接在UART中断回调里做JSON解析……那场面,简直灾难。

1.4 课程目标与学习路径

这门课不是教你怎么点灯,也不是教你怎么用RTOS。我们的目标是:

  • 掌握分层架构的设计思想——知道什么时候该拆,什么时候该合
  • 学会在HAL库基础上搭建任务调度框架——不用RTOS也能实现多任务协同
  • 写出可移植、可维护的驱动代码——换芯片不换逻辑

整个课程分四个阶段:

  1. 基础篇(第1-8章):分层架构理论 + HAL库底层机制剖析
  2. 框架篇(第9-16章):搭建任务调度核心,实现队列、信号量、事件标志组
  3. 驱动篇(第17-24章):用分层思想重写UART、SPI、I2C、定时器等外设驱动
  4. 实战篇(第25-30章):综合项目——多传感器数据采集与远程上报系统

注意:如果你对HAL库的基本用法还不熟(比如不知道HAL_UART_Transmit怎么用),建议先补一下基础。这门课默认你已经能独立使用HAL库操作常用外设。

1.5 本章小结

一句话总结:分层不是炫技,是让你少加班。我当年要是早点明白这个道理,至少能少熬几十个通宵。