目录
[一、为什么 90% 人的裸机代码都是 "垃圾代码"](#一、为什么 90% 人的裸机代码都是 “垃圾代码”)
[1. 底层驱动层(Driver)](#1. 底层驱动层(Driver))
[2. 中间逻辑层(Middleware)](#2. 中间逻辑层(Middleware))
[3. 业务应用层(App)](#3. 业务应用层(App))
[1. 禁止跨文件乱调用函数](#1. 禁止跨文件乱调用函数)
[2. 全局变量统一管理](#2. 全局变量统一管理)
[3. 驱动绝不写业务](#3. 驱动绝不写业务)
[4. 业务绝不操作寄存器](#4. 业务绝不操作寄存器)
[5. 所有任务时间分片](#5. 所有任务时间分片)
[八、裸机项目常见架构 Bug 汇总](#八、裸机项目常见架构 Bug 汇总)
前言
会外设、会写函数,不代表会做项目。 很多人写代码的通病: 所有逻辑揉在主循环、函数乱调用、变量全局乱飞、业务和底层混在一起、改一个 BUG 崩整个项目、无法迭代、无法维护、无法复用。
学生代码:功能跑起来就行。 工程师代码:可维护、可复用、可迭代、稳定、分层、解耦。
本篇正式收官裸机工程架构 ,手把手教你搭建工业级标准裸机框架。 包含:分层架构、模块化拆分、状态机任务调度、延时非阻塞、解耦设计、文件规范、量产模板。
学完本篇,你的代码将彻底告别 "单片机流水账代码",真正具备商业项目架构能力。
一、为什么 90% 人的裸机代码都是 "垃圾代码"
常见低质量项目特征:
- 所有业务全部塞在 while (1) 大循环
- 大量全局变量,随处修改
- 底层驱动和业务逻辑混在一个文件
- 到处 HAL_Delay、死循环等待
- 函数过长、逻辑堆叠、无状态管理
- 新增功能必须改旧代码,越写越崩
- 无法复用、无法移植、无法迭代
裸机不是乱写的借口,裸机更需要架构。
二、量产裸机标准三层架构(核心精髓)
所有工业裸机项目强制分层:底层驱动层 + 中间逻辑层 + 业务应用层
1. 底层驱动层(Driver)
只做一件事:操作寄存器、操作外设
包含:GPIO、ADC、TIM、PWM、UART、SPI、I2C、Flash、看门狗、低功耗
原则:
- 只提供接口,不写业务
- 无全局业务变量
- 纯硬件适配,可直接跨项目移植
2. 中间逻辑层(Middleware)
做数据处理、协议解析、滤波、校验、数据转换
包含:CRC、滤波、协议栈、数据校准、数值转换、缓存管理
原则:
- 不碰硬件寄存器
- 对接底层接口,服务上层业务
3. 业务应用层(App)
只做业务逻辑、状态判断、任务调度
包含:设备流程、按键逻辑、设备状态、报警逻辑、自动流程
原则:
- 不直接操作硬件
- 调用中间层接口
- 只关心业务,不关心硬件怎么实现
三层架构终极好处: 换芯片只改底层、改业务不动驱动、逻辑清晰、永不乱套。
三、文件目录规范(量产标准)
Project
├── Driver // 底层外设驱动
├── Middle // 算法、滤波、协议、缓存
├── App // 业务逻辑、状态机、任务
├── System // 系统初始化、时钟、中断管理
├── User // 配置、参数、宏定义
- 驱动只管硬件
- APP 只管流程
- 系统只管调度
四、裸机最大痛点:阻塞式代码根治
新手代码最大问题:阻塞等待 HAL_Delay()、while(!flag)、死循环等待
后果: 系统卡顿、响应滞后、无法多任务、功能互相阻塞、体验极差
工程标准:所有任务必须「非阻塞延时」
用系统滴答定时器做时间戳对比,不阻塞、不等待、不卡死
// 非阻塞定时模板
uint32_t timer_key = 0;
void Key_Scan_Task(void)
{
if(HAL_GetTick() - timer_key >= 20)
{
timer_key = HAL_GetTick();
// 按键扫描业务
}
}
所有任务:按键、显示、采集、上报、刷新全部用时间分片轮询 实现裸机伪多任务并行
五、状态机架构(裸机项目灵魂)
复杂设备流程必须用状态机,禁止 if-else 堆砌。
设备常见状态:
- 待机状态
- 工作状态
- 报警状态
- 配置状态
- 休眠状态
标准状态机框架
typedef enum
{
DEV_STA_IDLE,
DEV_STA_WORK,
DEV_STA_ALARM,
DEV_STA_CONFIG,
DEV_STA_SLEEP
}DEV_StateTypeDef;
DEV_StateTypeDef g_dev_state = DEV_STA_IDLE;
void Device_State_Machine(void)
{
switch(g_dev_state)
{
case DEV_STA_IDLE:
Device_Idle_Process();
break;
case DEV_STA_WORK:
Device_Work_Process();
break;
case DEV_STA_ALARM:
Device_Alarm_Process();
break;
case DEV_STA_SLEEP:
Device_Sleep_Process();
break;
default:
g_dev_state = DEV_STA_IDLE;
break;
}
}
状态机优势
- 逻辑分层清晰,每个状态独立
- 不会出现多层 if-else 嵌套
- 新增功能只需要新增状态,不改旧代码
- 设备流程可控、稳定、可维护
六、模块化解耦核心规范(必须遵守)
1. 禁止跨文件乱调用函数
统一通过对外接口访问
2. 全局变量统一管理
所有全局变量集中在变量管理文件,禁止随处定义
3. 驱动绝不写业务
驱动只开放:Init、Set、Get、Read、Write
4. 业务绝不操作寄存器
所有硬件动作封装接口调用
5. 所有任务时间分片
禁止阻塞、禁止死等、禁止延时
七、标准裸机主循环架构(可直接量产)
int main(void)
{
// 1. 系统底层初始化
System_Init();
GPIO_Init();
UART_Init();
ADC_Init();
TIM_Init();
// 2. 业务初始化
App_Param_Init();
State_Init();
while(1)
{
// 分层轮询任务(非阻塞)
Key_Scan_Task();
ADC_Collect_Task();
Data_Filter_Task();
UART_Process_Task();
Device_State_Machine();
LowPower_Check_Task();
}
}
这是工业设备标准裸机架构,稳定、不卡、不乱、可无限迭代。
八、裸机项目常见架构 Bug 汇总
- 主循环执行耗时过长 部分函数执行太久,导致其他任务卡顿
- 全局变量滥用 随处改写变量,状态错乱、偶现 BUG
- 阻塞延时过多 系统整体响应迟钝
- 业务与驱动耦合 换硬件必须大改代码,无法复用
- 无状态管理 设备流程混乱、随机跳转、逻辑失控
- 中断业务过重 中断只做标记,不做业务
九、量产级项目优化技巧
- 所有外设统一初始化入口
- 所有任务统一时间分片
- 所有状态统一状态机管理
- 所有参数统一结构体管理
- 所有底层统一封装接口
- 所有异常统一容错处理
- 所有关键数据统一掉电保存
十、架构升级总结
- 新手代码:流水账、堆逻辑、到处阻塞、全局乱飞
- 工程代码:分层、模块化、状态机、非阻塞、高解耦