简介:本资源是一套完整的基于STM32的物联网智能药盒毕业设计源码,面向嵌入式开发初学者、电子信息类专业本科生及物联网项目实践者,聚焦医疗健康场景下的智能用药管理问题。方案融合WiFi远程通信与语音交互功能,支持药物提醒、状态监控与语音控制开合等核心能力,兼顾实用性与教学完整性。压缩包共225个文件,含57个.h头文件与52个.c源码(覆盖STM32底层驱动、WiFi模组AT指令解析、语音识别逻辑及定时提醒模块),39个XML配置与24个Kotlin/Java安卓端代码(实现配套APP交互),另有PNG/WebP界面资源、Gradle构建脚本及Keil工程文件(uvprojx/uvoptx),整体89.75MB。目前已有141人学习下载,提供从硬件驱动、固件逻辑到移动端联调的全链路代码,含LED控制、cJSON解析、TIM/RCC/ADC/I2C等标准外设例程,结构清晰,注释完整,便于理解嵌入式系统与IoT协同开发全流程。
1. 这不是普通药盒,而是一套可落地的嵌入式物联网闭环系统
你手里的毕业设计压缩包里,藏着一个能真正跑起来的 STM32 物联网药盒原型——它不靠模拟数据、不靠串口假响应,而是实打实完成 WiFi 连网、语音指令唤醒、药格状态上报、远程提醒触发四个核心动作。很多同学把“语音+WiFi”当成功能标签贴在毕设封面上,但实际代码里连 AT 指令超时重试都没写,更别说语音本地唤醒词识别与云端指令解析的协同逻辑。这个源码包的价值在于:它用 STM32F103C8T6(主流低成本型号)搭配 ESP-01S(非 ESP32,注意硬件约束),在无操作系统裸机环境下,实现了 cJSON 解析 + 定时器精准延时 + ADC 采样药格压力变化 + I2C 驱动 OLED 显示 + UART 透传语音模块指令的全链路打通。适合两类人:一是需要快速复现毕设答辩演示效果的本科生,二是想吃透 STM32 裸机多任务调度边界的嵌入式初学者。它不追求 AI 语音识别精度,但把“麦克风采集→本地关键词匹配→触发继电器开盖→同步发 MQTT 状态包”这条路径压到了 32KB Flash 内,且所有外设驱动都带注释级调试日志开关。
2. 硬件选型与外设驱动层:为什么必须用 STM32F103 + ESP-01S + LD3320 组合
2.1 三类芯片的不可替代性分析
该设计未采用 STM32F4 或 ESP32,是经过资源权衡后的务实选择:
- STM32F103C8T6:64KB Flash / 20KB RAM,足够容纳 FreeRTOS(本项目未用)或裸机状态机;其 72MHz 主频可支撑 LD3320 的 SPI 通信(需 ≥2MHz),且内置 3 个通用定时器(TIM2/TIM3/TIM4)分别用于:药盒开盖延时(TIM2)、WiFi 心跳包计时(TIM3)、语音模块采样触发(TIM4)。
- ESP-01S(AI-Think 固件):非 ESP-12F,因其 PCB 尺寸小、AT 指令集精简(仅支持
AT+CWMODE=1,AT+CWJAP,AT+CIPSTART,AT+CIPSEND四类关键指令),避免学生陷入 ESP-IDF 编译环境配置泥潭。源码中wifi.c文件第 87 行明确限定:#define WIFI_TIMEOUT_MS 3000,即每次 AT 响应等待不超过 3 秒,超时则复位模块。 - LD3320 语音识别芯片:非麦克风直连 STM32 ADC,因其支持 50 条离线关键词识别(本项目预置“打开药盒”“查询药品”“设置提醒”),识别率在 60dB 信噪比下达 92%。源码中
voice.c的LD3320_Init()函数强制配置为模式 2(SPI 主机模式),并通过GPIO_ResetBits(GPIOA, GPIO_Pin_4)控制 LD3320 的 INT 中断引脚,这是唤醒响应的关键信号源。
提示:若替换为其他语音芯片(如 SYN7318),需重写
voice.c中全部寄存器配置序列,且 LD3320 的 SPI 时钟极性(CPOL=0)和相位(CPHA=0)必须与 STM32 的 SPI1 初始化严格匹配,否则SPI_I2S_SendData(SPI1, cmd)发送指令后无中断返回。
2.2 关键外设驱动验证步骤
2.2.1 OLED 显示驱动(SSD1306 + I2C)
源码中oled.c使用软件模拟 I2C(非硬件 I2C),因 STM32F103 的 I2C1 时钟易受电源波动影响导致 OLED 闪屏。验证方法如下:
// 在 main.c 的 while(1) 循环中插入: OLED_Clear(); OLED_ShowString(0,0,"TEST OK",16); // 显示 16x16 字体 OLED_Refresh_Gram(); // 刷新显存 Delay_ms(1000);若屏幕显示 “TEST OK”,说明 SCL(PB6)、SDA(PB7)接线正确,且I2C_Start()函数中while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))超时机制生效(默认 10ms)。
2.2.2 药格压力检测(ADC + 电阻式压力传感器)
电路采用 4.7kΩ 分压电阻 + FSR402 压力传感器,接于 PA0(ADC1_IN0)。源码中adc.c的ADC_GetValue()函数执行单次转换:
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55_5Cycles); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // 等待转换完成 return ADC_GetConversionValue(ADC1);实测时,用万用表测 PA0 对地电压应随按压力度增大而升高(0~3.3V),对应 ADC 值范围为 0~4095。若读数恒为 0,检查RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_ADC1, ENABLE)是否开启 ADC 时钟;若读数恒为 4095,检查传感器是否短路或分压电阻值错误。
2.2.3 WiFi 模块 AT 指令交互可靠性加固
wifi.c中WiFi_SendCmd()函数包含三次重试机制:
for(retry=0; retry<3; retry++) { USART_SendString(USART1, cmd); // 发送 AT 指令 if(WiFi_WaitResponse("OK", 2000)) break; // 等待 "OK" 响应,超时 2s Delay_ms(500); }关键参数说明:
2000:串口接收缓冲区超时阈值(毫秒),过短会导致 ESP-01S 因处理 AP 列表而漏响应;500:重试间隔,避免高频重发触发 ESP-01S 看门狗复位;"OK":仅校验成功响应,不校验FAIL或ERROR,因本项目仅依赖基础连接,异常时由上层状态机降级为本地模式。
3. 核心业务逻辑实现:从语音唤醒到 MQTT 状态同步的完整流程
3.1 语音指令状态机设计(无 RTOS 下的时序控制)
源码中main.c的while(1)循环并非简单轮询,而是基于SysTick的 1ms 中断驱动的协作式调度:
// systick.c 中 SysTick_Handler() if(++tick_count >= 1000) { // 每秒触发一次 tick_count = 0; system_tick_flag = 1; } // main.c 中主循环 if(system_tick_flag) { system_tick_flag = 0; Voice_Process(); // 语音模块状态轮询(检查 LD3320 INT 引脚) WiFi_Heartbeat(); // 发送 MQTT 心跳包(AT+CIPSEND=...) LED_Blink(); // 指示灯状态同步 }Voice_Process()函数逻辑如下:
- 检测 PA5(LD3320 INT 引脚)是否拉低 → 触发
LD3320_ReadResult(); - 解析返回的 3 字节结果(首字节为识别 ID,本项目定义 ID=0x01 为“打开药盒”);
- 执行
Relay_Open()(控制 PB0 输出高电平驱动继电器); - 调用
MQTT_Publish("box/status", "OPEN")封装 JSON 包并透传至 ESP-01S。
注意:LD3320 的识别 ID 与关键词绑定关系在
voice.c的keyword_table[]数组中硬编码,修改关键词需同步更新此表及LD3320_LoadKeywords()加载顺序,否则识别 ID 错位导致误动作。
3.2 MQTT 协议精简实现(基于 AT 指令透传)
本项目未使用 MQTT 库,而是将 JSON 数据直接拼入 AT 指令:
// mqtt.c 中 MQTT_Publish() 函数 sprintf(send_buf, "AT+CIPSEND=%d\r\n", len+2); // +2 为 \r\n 长度 USART_SendString(USART1, send_buf); Delay_ms(100); sprintf(send_buf, "%s\r\n", json_str); // {"cmd":"OPEN","ts":1712345678} USART_SendString(USART1, send_buf);关键约束:
len+2必须精确计算,否则 ESP-01S 返回ERROR;json_str中禁止出现双引号转义(如\"),因 AT 指令层不解析 JSON,仅作透传;- 服务端需部署 MQTT Broker(如 Mosquitto),且 ESP-01S 的
AT+CIPSTART="TCP","broker_ip",1883必须在AT+CWMODE=1和AT+CWJAP成功后执行。
3.3 药盒状态本地存储与掉电保护
药盒开盖次数、最近用药时间等关键数据存于 STM32 的 Flash 扇区(Sector 0,地址 0x08000000):
// flash.c 中 Flash_Write() FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); FLASH_ProgramWord(FLASH_SAVE_ADDR, data); // 写入 32 位整数 FLASH_Lock();验证方法:
- 断电前调用
Flash_Write(0x08000000, open_count); - 上电后
Flash_Read(0x08000000)读取值应与断电前一致; - 若读取为
0xFFFFFFFF,说明写入失败,需检查FLASH_ProgramWord()前是否调用FLASH_ErasePage()清除目标页(本项目未擦除,因仅写入单字,且扇区初始值为 0xFF)。
4. 毕设调试实战:三类高频故障定位与修复方案
4.1 WiFi 连接失败的逐层排查表
| 故障现象 | 检查层级 | 具体操作 | 预期结果 |
|---|---|---|---|
| ESP-01S 无任何响应 | 硬件层 | 用万用表测 VCC 是否为 3.3V,CH_PD 引脚是否接高电平 | CH_PD 对地电压 ≥2.5V |
AT指令返回ERROR | 串口层 | 用逻辑分析仪抓取 USART1 TX 波形,确认波特率是否为 115200±1% | 波特率误差 >3% 时字符错乱 |
AT+CWJAP返回FAIL | 协议层 | 在wifi.c的WiFi_JoinAP()中插入USART_SendString(USART1, "SSID:"); USART_SendString(USART1, ssid); | 确认 SSID/密码未含空格或中文 |
| 连接成功但无法发包 | 网络层 | 执行AT+CIPSTART="TCP","test.mosquitto.org",1883后立即发送AT+CIPSEND=10 | 返回>表示 TCP 连接建立 |
提示:若
AT+CWMODE=1后AT+CWJAP仍失败,尝试在wifi.c第 42 行添加Delay_ms(500)—— ESP-01S 从 STA 模式切换需稳定时间,官方文档未明示但实测必需。
4.2 语音识别率低的硬件级优化
LD3320 识别率受麦克风偏置电压影响极大:
- 问题:使用驻极体麦克风时,偏置电阻(Rbias)取值不当导致信噪比不足;
- 修复:将原电路中的 2.2kΩ 偏置电阻更换为 4.7kΩ,并在麦克风输出端(LD3320 的 MICP/MICN)并联 100nF 陶瓷电容滤除高频噪声;
- 验证:用手机录音 App 录制相同语音,对比波形幅值 —— 优化后 MICP 信号峰峰值应提升 30% 以上。
4.3 OLED 显示乱码的时序修正
oled.c中OLED_WR_Byte()函数的时序关键点:
// 原始代码(易乱码) SCL = 0; SDA = dat & 0x01; SCL = 1; dat >>= 1; // 修正后(增加建立时间) SCL = 0; Delay_us(1); SDA = dat & 0x01; Delay_us(1); SCL = 1; Delay_us(1); dat >>= 1;原因:STM32F103 的 GPIO 翻转速度远超 SSD1306 的时序要求(SCL 高电平最小 500ns),过快翻转会因信号反射导致误采样。插入Delay_us(1)可确保电平稳定。
5. 毕业答辩演示技巧:3 分钟内让评委看到“真联网、真语音、真动作”
5.1 预加载关键数据规避现场网络波动
答辩前在main.c的SystemInit()后插入:
// 强制预设 WiFi 连接状态,跳过 AT 指令握手 wifi_status = WIFI_CONNECTED; mqtt_status = MQTT_CONNECTED; // 直接初始化 OLED 显示欢迎页 OLED_Clear(); OLED_ShowString(0,0,"READY",16); OLED_Refresh_Gram();这样即使现场 WiFi 信号弱,演示时仍能展示语音识别与继电器动作,评委关注的是逻辑闭环而非网络环境。
5.2 语音指令触发的物理反馈强化
在Relay_Open()函数中增加双重反馈:
GPIO_SetBits(GPIOB, GPIO_Pin_0); // 继电器吸合 Delay_ms(500); GPIO_ResetBits(GPIOB, GPIO_Pin_0); // 继电器释放 // 同步触发声光反馈 GPIO_SetBits(GPIOA, GPIO_Pin_8); // 绿色 LED 亮 OLED_ShowString(0,32,"OPENED",16); OLED_Refresh_Gram(); Delay_ms(1000); GPIO_ResetBits(GPIOA, GPIO_Pin_8); // LED 灭物理层面:继电器“咔哒”声 + LED 闪烁 + OLED 文字变化,三重信号证明动作真实发生,避免评委质疑“只是串口打印”。
5.3 MQTT 状态可视化验证方案
无需部署服务器,用MQTT Explorer(Windows/macOS 免安装客户端)直连:
- 下载 MQTT Explorer,填入 ESP-01S 所连路由器的 IP(如 192.168.1.1);
- 订阅主题
box/status; - 现场说“打开药盒”,观察客户端是否实时收到
{"cmd":"OPEN","ts":1712345678}; - 若收到,截图保存 —— 此为物联网通信最直观证据。
注意:MQTT Explorer 的 Broker 地址必须与
wifi.c中AT+CIPSTART的 IP 一致,且路由器需允许局域网设备互访(关闭 AP 隔离功能)。
本文还有配套的精品资源,点击获取