蓝桥杯嵌入式第七届省赛:模拟液位检测告警系统全模块解析
1. 项目背景与需求解析
第七届蓝桥杯嵌入式省赛的"模拟液位检测告警系统"是一个典型的工业控制场景应用。这个项目要求选手通过STM32开发板实现一个完整的液位监控系统,涉及模拟信号采集、数据处理、人机交互和通信协议等多个嵌入式开发核心技能点。
系统核心需求可以拆解为五个关键模块:
- 模拟量采集:通过电位器R37模拟液位传感器输出,需要完成ADC采集和软件滤波
- 阈值管理:支持三级阈值设置(默认30/50/70cm),参数需存储到EEPROM
- 状态判断:根据当前液位高度自动划分四个等级(0-3级)
- 通信接口:通过USART2实现与PC的数据交互(查询+自动上报)
- 状态指示:三路LED分别表示运行状态、液位变化和通信事件
在实际工业场景中,类似的液位检测系统广泛应用于储罐监控、化工生产等领域。比赛中将工业场景简化为开发板上的电位器模拟,但完整保留了真实系统中的技术要点。
2. 硬件架构设计
2.1 核心硬件配置
系统基于蓝桥杯官方CT117E开发板,主控采用STM32F103RBT6,主要外设包括:
- ADC通道:PA1连接电位器R37(模拟液位信号)
- EEPROM:AT24C02芯片存储阈值参数
- 显示模块:LCD12864液晶屏
- 输入设备:四个独立按键(K1-K4)
- 指示设备:三个LED灯(LD1-LD3)
- 通信接口:USART2(PA2/PA3)
硬件连接示意图:
[电位器R37] --> [PA1(ADC1)] [按键K1-K4] --> [PE2-PE5] [LCD12864] <--> [FSMC接口] [USART2] <--> [CH340G USB转串口]2.2 关键电路设计要点
ADC前端处理:
- 电位器输出接入RC低通滤波(R=10kΩ, C=0.1μF)
- 参考电压使用板载3.3V稳压源
- 采样周期设置为239.5周期(对应约1ms采样时间)
EEPROM电路:
- I2C总线需配置4.7kΩ上拉电阻
- 地址引脚全部接地(设备地址0xA0)
- 写入周期需延时5ms以上
抗干扰设计:
- 所有数字信号线串联22Ω电阻
- 模拟地与数字地单点连接
- 电源入口处增加100μF+0.1μF去耦电容
3. 软件架构实现
3.1 主程序流程图
void main() { HAL_Init(); SystemClock_Config(); Peripheral_Init(); Level_Init(); // 初始化液位等级 Init_Data(); // 从EEPROM加载阈值 while(1) { Setting(); // 按键处理与界面管理 Level_Control(); // 液位状态判断 Usart_Control(); // 串口通信处理 Led_Control(); // LED状态更新 } }3.2 模块化设计要点
ADC采集与滤波:
- 采用递推平均滤波算法(窗口大小=10)
- 电压转高度公式:
Height = ADC_Value * 3300 / 4096 * 100 / 3300 - 关键代码:
#define FILTER_N 10 uint16_t filter_buf[FILTER_N]; uint16_t Get_Filtered_ADC() { static uint8_t index = 0; filter_buf[index++] = HAL_ADC_GetValue(&hadc1); if(index >= FILTER_N) index = 0; uint32_t sum = 0; for(uint8_t i=0; i<FILTER_N; i++) { sum += filter_buf[i]; } return sum / FILTER_N; }
EEPROM存储管理:
- 使用页写入模式(每页8字节)
- 存储结构:
地址 内容 长度 0x00 阈值1(30) 2字节 0x02 阈值2(50) 2字节 0x04 阈值3(70) 2字节
状态机设计:
- 系统存在两个主要状态:
graph LR A[监测模式] -->|K1按下| B[设置模式] B -->|K1按下| A - 设置模式下有三个子状态(对应三个阈值设置)
- 系统存在两个主要状态:
4. 关键难点解决方案
4.1 液位等级变化检测
这是本项目的核心难点,需要准确捕捉液位跨越阈值时刻。解决方案采用"新旧值对比法":
在全局变量区定义:
int Liquid_Level; // 当前等级 int Old_Level; // 上次等级初始化时通过
Level_Init()函数获取初始等级在主循环中实时比较:
void Level_Control() { // 获取当前液位高度 Liquid_Height = Get_Current_Height(); // 判断等级变化 if(Liquid_Height <= Threshold1) { Liquid_Level = 0; } else if(Liquid_Height <= Threshold2) { Liquid_Level = 1; } // 其他等级判断... // 检测变化 if(Liquid_Level != Old_Level) { Send_Report(Liquid_Height, Liquid_Level); // 发送上报 Trigger_LED2(); // 触发指示灯 Old_Level = Liquid_Level; // 更新旧值 } }
4.2 串口协议解析
采用状态机实现协议解析,支持两种查询指令和自动上报:
接收状态机设计:
typedef enum { WAIT_START, RECEIVING, PARSE_COMPLETE } UART_State; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { static UART_State state = WAIT_START; static uint8_t index = 0; switch(state) { case WAIT_START: if(rx_buf[0] == 'C' || rx_buf[0] == 'S') { state = RECEIVING; index = 1; } break; case RECEIVING: if(rx_buf[index++] == '\n') { state = PARSE_COMPLETE; } break; } }数据打包示例:
void Send_Threshold_Response() { char buffer[32]; sprintf(buffer, "S:TL%d+TM%d+TH%d\r\n", Threshold1, Threshold2, Threshold3); HAL_UART_Transmit(&huart2, (uint8_t*)buffer, strlen(buffer), 100); }
5. 调试技巧与常见问题
5.1 典型问题排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| ADC读数不稳定 | 未做滤波/采样时间不足 | 增加软件滤波,调整采样周期 |
| EEPROM写入失败 | 未满足写入时序要求 | 添加5ms延时,检查I2C上拉 |
| 串口数据乱码 | 波特率不匹配 | 核对双方波特率(9600-8-N-1) |
| 液位变化误报 | Old_Level初始化错误 | 上电后立即读取初始液位等级 |
| LCD显示异常 | 未及时清屏 | 切换界面时调用LCD_Clear() |
5.2 实时调试建议
利用SWD接口:
- 在Keil中设置实时变量监控(Watch窗口)
- 重点监测:
Liquid_Height, Liquid_Level, Threshold1-3
串口打印调试:
printf("ADC=%.2fV H=%dcm\r\n", ADC_Voltage, Liquid_Height);LED辅助调试:
- 临时修改LED闪烁模式指示不同状态
- 例如:快速闪烁表示进入异常分支
6. 工程优化建议
6.1 代码结构优化
使用模块化头文件组织:
/Inc ├── adc.h ├── eeprom.h ├── lcd.h ├── uart.h └── main.h采用面向对象思想封装:
typedef struct { uint16_t raw_adc; float voltage; int height; void (*update)(void); } LiquidSensor_TypeDef; void LiquidSensor_Update() { // 实现采集逻辑 }
6.2 性能提升方向
ADC采样优化:
- 启用DMA连续采样模式
- 采用硬件过采样(16倍)
通信协议增强:
- 添加CRC校验字段
- 实现超时重传机制
低功耗设计:
void Enter_LowPower() { HAL_ADC_Stop(&hadc1); HAL_UART_DeInit(&huart2); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); }
7. 备赛训练建议
模块化训练路线:
- 第一阶段:独立模块练习(ADC、EEPROM、USART)
- 第二阶段:功能组合实现(ADC+LCD显示)
- 第三阶段:完整系统集成
真题训练顺序:
- 第十一届省赛(基础外设)
- 第十届省赛(状态机设计)
- 第八届省赛(复杂通信协议)
- 第九届省赛(多任务调度)
调试能力培养:
- 熟练使用逻辑分析仪抓取时序
- 掌握Keil在线调试技巧(断点、变量监控)
- 建立系统化调试日志记录习惯
在实际开发中,我建议先使用STM32CubeMX生成基础外设配置,然后重点编写业务逻辑代码。比赛中要注意合理分配时间,先实现核心功能再完善细节。这个项目的完整代码已经过实际验证,在蓝桥杯官方开发板上运行稳定,可以作为可靠的参考实现。
