1、课程导论:为什么需要软件架构?单片机开发从裸机到架构的演进之路

各位同学,欢迎来到这门课。

先问大家一个问题:你写单片机代码时,是不是经常这样——

  • 功能都能跑,但改一个需求要翻遍整个 main.c?
  • 加一个新传感器,得把原来的初始化流程重写一遍?
  • 项目做到一半,自己都看不懂上个月写的逻辑?

如果你点头了,那这门课就是为你准备的。

1.1 裸机开发的“舒适区”与“陷阱”

我刚入行那会儿,也觉得单片机嘛,不就是点灯、读按键、串口打印?一个 while(1) 搞定所有事,简单粗暴。

但后来我接手了一个项目:智能温控器。需求很简单——

  • 采集温度传感器
  • 控制加热器 PID 输出
  • OLED 显示实时数据
  • 按键设置目标温度

我按老习惯,把所有代码塞进 main.c。刚开始很爽,200 行搞定。但客户开始改需求了:

  • “加一个蜂鸣器报警” → 我插一段 GPIO 翻转
  • “温度采样频率改成 10Hz” → 我改 delay 参数
  • “增加蓝牙上报” → 我……开始怀疑人生

三个月后,main.c 膨胀到 3000 行。一个按键消抖的 bug,我查了三天。最后发现是延时函数被中断服务程序改了全局变量。

这就是裸机开发的典型陷阱:代码耦合度高、可维护性差、调试成本指数级增长。

核心问题: 裸机开发把“业务逻辑”和“硬件操作”揉在一起。你改一个外设,可能牵动整个系统。

1.2 从“裸机”到“架构”的演进路径

那怎么解决?说白了,就是给代码分层、分模块、定规矩。

我总结了一个演进路径,大家看看自己处在哪个阶段:

阶段 特点 典型问题 我见过的案例
阶段0:纯裸机 所有代码在 main.c,靠延时和轮询 改需求等于重写 一个智能灯项目,加个定时功能花了2周
阶段1:模块化 按外设拆文件(led.c、uart.c) 模块间全局变量乱飞 温控器项目,三个模块同时写同一个全局标志位
阶段2:分层架构 驱动层、中间件层、应用层分离 层间接口不统一 换了传感器型号,应用层代码全改
阶段3:框架+状态机 外设驱动框架 + 状态机协同 学习曲线陡,但一劳永逸 工业控制器项目,6个月零返工

嗯,这里要注意:不是所有项目都需要阶段3。但如果你做的是产品级项目、或者代码量超过 5000 行,我建议你至少走到阶段2。

1.3 为什么需要“外设驱动框架”?

你想想看,一个典型的单片机项目,外设无非就是:GPIO、UART、I2C、SPI、ADC、PWM、定时器……

这些外设的操作模式其实高度相似:

  • 初始化(配置时钟、引脚、参数)
  • 控制(发送数据、设置状态)
  • 读取(获取数据、查询状态)
  • 中断处理(响应事件)

我在项目中遇到过最头疼的事:同一个 I2C 总线挂了三个传感器,每个传感器的驱动都是不同同事写的。初始化顺序、错误处理、超时机制全都不一样。联调的时候,一个传感器卡死,整条总线都挂了。

所以,我们需要一个统一的驱动框架:

  • 定义标准接口(init、write、read、ioctl)
  • 统一错误处理机制
  • 支持外设热插拔或动态配置
  • 隔离硬件差异

我的建议: 驱动框架不是让你写更复杂的代码,而是让你写“可替换”的代码。换一个传感器,只需要改底层驱动文件,应用层一行代码都不用动。

1.4 状态机:让复杂逻辑变得可控

再说状态机。很多人觉得状态机就是 switch-case,太简单了。其实不然。

我曾经做一个多模式电源管理项目:待机、充电、放电、保护、故障恢复……5个状态,每个状态有进入动作、退出动作、状态内循环、超时转移。如果用裸机标志位来写,我估计要写出 20 个 if-else 嵌套。

但用状态机,逻辑清晰得像一张地图:

  • 每个状态是一个独立模块
  • 状态转移由事件触发
  • 状态内行为与状态间解耦

说白了,状态机就是把“时间维度的逻辑”变成“空间维度的结构”。你一眼就能看出系统在什么条件下做什么事。

避坑指南: 我曾经犯过一个错——在状态机里直接调用硬件操作。结果状态转移时,硬件还没准备好,导致系统卡死。记住:状态机只负责“决策”,不负责“执行”。硬件操作交给驱动层。

1.5 本章知识体系总览

下面这张图,概括了本章的核心逻辑:从裸机痛点出发,引出架构的必要性,再拆解为驱动框架和状态机两条主线。

单片机软件架构演进逻辑 裸机开发痛点 为什么需要软件架构? 外设驱动框架 状态机协同设计 统一接口 硬件隔离 状态转移 事件驱动 驱动框架 + 状态机 协同实战

1.6 这门课能带给你什么?

我不喜欢画大饼。直接说干货:

  • 一套可复用的外设驱动框架:GPIO、UART、I2C、SPI、ADC……你以后写驱动,直接套模板
  • 状态机设计方法论:从简单 switch-case 到嵌套状态机、层次状态机
  • 驱动框架与状态机的协同模式:这是市面上很少讲的内容,但实际项目中最常用
  • 大量实战案例:每个知识点都有完整代码,不是伪代码

一句话总结: 学完这门课,你写的单片机代码不再是“一次性用品”,而是可以积累、复用、传承的工程资产。