用STM32+物联网做个智能药盒:手把手教你搞定毕设硬件选型与代码框架
基于STM32的智能药盒开发实战:从硬件选型到云端联调
在老龄化社会加速和慢性病管理需求激增的背景下,智能医疗设备正从医院走向家庭。作为嵌入式开发者,将STM32与物联网技术结合打造智能药盒,不仅能解决实际用药管理痛点,更能掌握硬件开发全流程的核心技能。不同于市面上简单的定时提醒装置,我们将构建具备药品识别、用药记录云端同步、异常用药预警等完整功能的小型物联网终端。
1. 需求分析与系统架构设计
智能药盒的核心痛点在于解决"何时用药"、"是否正确用药"以及"用药记录追溯"三大问题。通过实地调研养老机构和慢性病患者家庭,我们提炼出以下核心功能矩阵:
| 功能类别 | 具体需求 | 技术实现方案 |
|---|---|---|
| 基础功能 | 多时段用药提醒 | RTC实时时钟+蜂鸣器 |
| 药品识别 | 药品种类自动识别 | RFID标签+RC522读写模块 |
| 用药记录 | 本地存储最近30次记录 | SPI Flash存储 |
| 远程通知 | 漏服提醒推送至监护人 | ESP8266 WiFi模块 |
| 人机交互 | 操作反馈与状态显示 | 1.3寸OLED+触摸按键 |
| 扩展功能 | 药品存量预警 | 重量传感器+HX711ADC |
系统采用分层架构设计,底层硬件驱动层基于HAL库实现,中间件层包含FreeRTOS实时操作系统管理多任务,应用层通过状态机模式处理业务流程。特别需要注意的是,在资源有限的STM32F103系列上,我们采用以下内存优化策略:
// 任务栈空间分配示例
#define MAIN_TASK_STACK_SIZE 256
#define RFID_TASK_STACK_SIZE 384 // 需要较大栈空间处理MFRC522驱动
#define NET_TASK_STACK_SIZE 512 // WiFi协议栈需要更多内存
// 全局变量使用__attribute__优化存储段
__attribute__((section(".ccmram"))) uint8_t rfidBuffer[64];
提示:在CubeMX配置FreeRTOS时,建议将堆大小设置为至少12KB,并为关键任务配置看门狗定时器,防止单个任务崩溃导致系统死锁。
2. 关键硬件选型与电路设计
2.1 主控芯片选型对比
面对STM32系列众多型号,我们需要平衡性能、外设资源和成本。以下是经实测验证的选型方案:
-
STM32F103C8T6(主流选择)
- 72MHz Cortex-M3内核
- 64KB Flash/20KB RAM
- 3个USART(满足WiFi、调试、备用接口)
- 市场价格约15-20元
-
STM32L452RET6(低功耗方案)
- 80MHz Cortex-M4F
- 512KB Flash/160KB RAM
- 内置硬件加密引擎
- 运行FreeRTOS时功耗仅2.8mA
推荐采用最小系统板+扩展板的设计模式,核心板保留SWD调试接口和BOOT选择跳线,扩展板集成以下模块:
-
电源管理电路
- TP4056锂电池充电管理
- AMS1117-3.3V稳压芯片
- 充放电状态LED指示
-
RFID识别模块
- MFRC522芯片+13.56MHz天线
- 有效识别距离3-5cm
- 支持ISO14443A协议
-
无线通信模块
- ESP-01S WiFi模块
- AT固件版本需≥1.7.0
- 内置TCP/IP协议栈
# 模块连接测试命令(通过串口工具)
AT+CWMODE=1 # 设置为Station模式
AT+CWJAP="SSID","password" # 连接WiFi
AT+PING="www.baidu.com" # 测试网络连通性
2.2 人机交互设计要点
为提升老年用户使用体验,我们采用"声光触"三重交互:
- 视觉反馈:OLED显示当前时间、下次用药信息(字号≥16pt)
- 听觉反馈:有源蜂鸣器提供不同频率的提示音
- 触觉反馈:5向导航键替代传统矩阵按键
典型操作流程如下:
- 系统启动后播放开机提示音
- 主界面显示时钟和药品槽状态
- 短按选择键查看药品详情
- 长按确认键同步云端数据
注意:OLED显示屏在低温环境下可能出现残影,建议在初始化代码中加入预热程序:
void OLED_Preheat() {
for(uint8_t i=0; i<3; i++) {
OLED_Fill(0xFF);
HAL_Delay(100);
OLED_Fill(0x00);
HAL_Delay(100);
}
}
3. 嵌入式软件框架搭建
3.1 FreeRTOS任务划分策略
在CubeMX中创建以下任务并设置合理优先级:
-
主控任务 (优先级3)
- 处理用户输入
- 管理状态机切换
- 协调各子系统运行
-
RFID扫描任务 (优先级4)
- 周期读取RC522数据
- 校验药品标签有效性
- 更新当前药品信息
-
网络通信任务 (优先级2)
- 维护WiFi连接
- 同步时间服务器
- 上传用药记录
-
显示刷新任务 (优先级1)
- 定时更新界面元素
- 处理动画效果
- 低功耗模式管理
关键同步机制采用FreeRTOS的队列和信号量:
// 定义全局通信对象
QueueHandle_t xRFIDQueue = xQueueCreate(5, sizeof(RFID_Event_t));
SemaphoreHandle_t xSPIMutex = xSemaphoreCreateMutex();
// 典型任务间通信示例
void vRFIDTask(void *pvParameters) {
RFID_Event_t event;
while(1) {
if(MFRC522_Check(&event)) {
xQueueSend(xRFIDQueue, &event, portMAX_DELAY);
}
vTaskDelay(pdMS_TO_TICKS(200));
}
}
3.2 低功耗优化技巧
通过以下措施可使系统在待机时电流降至1.2mA:
- 动态时钟调整
- 运行模式:72MHz
- 空闲模式:8MHz
- 外设智能供电
- 采用MOSFET控制模块电源
- 非活跃期关闭显示屏背光
- WiFi连接策略
- 每小时同步一次时间
- 仅在用药事件后立即上传数据
对应的电源管理代码实现:
void Enter_LowPowerMode() {
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
SystemClock_Config(); // 唤醒后重新配置时钟
}
4. 物联网平台对接实战
4.1 阿里云IoT接入方案
采用MQTT协议实现设备-云端双向通信,关键步骤包括:
-
三元组获取
- 产品Key:a1**********
- 设备名称:medicine_box_001
- 设备密钥:采用动态注册方式获取
-
Topic定义
- 上行:/sys/a1******/${deviceName}/thing/event/property/post
- 下行:/sys/a1******/${deviceName}/thing/service/property/set
-
数据格式示例
{
"id": "123",
"version": "1.0",
"params": {
"medicine_id": "B001",
"take_time": "2023-08-20 08:00:00",
"status": "missed"
}
}
4.2 本地数据缓存机制
为应对网络不稳定情况,设计环形缓冲区存储未成功发送的记录:
#define MAX_CACHE_RECORDS 20
typedef struct {
uint32_t timestamp;
uint8_t medicineID[10];
uint8_t status; // 0=未发送 1=已发送
} Record_t;
Record_t cacheBuffer[MAX_CACHE_RECORDS];
uint8_t cacheHead = 0;
uint8_t cacheTail = 0;
void AddToCache(uint8_t *id, uint8_t stat) {
cacheBuffer[cacheHead].timestamp = HAL_GetTick();
memcpy(cacheBuffer[cacheHead].medicineID, id, 10);
cacheBuffer[cacheHead].status = 0;
cacheHead = (cacheHead + 1) % MAX_CACHE_RECORDS;
}
重要:每次上电后应先检查缓存区是否有未同步记录,建议在Flash中保存最近100条记录,采用磨损均衡算法延长存储寿命。
5. 开发调试与问题排查
5.1 常见硬件问题解决方案
-
RFID读取不稳定
- 检查天线匹配电路:27pF电容需精确匹配
- 调整MFRC522的增益寄存器:
MFRC522_WriteRegister(RFCfgReg, 0x38); // 38h为推荐值
-
WiFi频繁断开
- 在ESP8266电源端增加100μF电容
- 修改AT指令重试机制:
AT+CIPRECONNCFG=3000,10 # 3秒间隔,最多重试10次
-
RTC走时不准
- 更换32.768kHz晶振负载电容(典型值12.5pF)
- 启用时钟校准:
HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, RTC_SMOOTHCALIB_PLUSPULSES_SET, 127);
5.2 软件调试技巧
-
利用SEGGER RTT
- 不占用串口资源
- 实时输出调试信息
- 配置方法:
#include "SEGGER_RTT.h" SEGGER_RTT_printf(0, "RFID detected: %s\n", id);
-
内存泄漏检测
- 在FreeRTOSConfig.h中启用堆检查:
#define configUSE_TRACE_FACILITY 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 - 通过命令查看任务栈使用:
task list task stats
- 在FreeRTOSConfig.h中启用堆检查:
-
崩溃定位方法
- 在HardFault_Handler中打印LR和PC值
- 使用addr2line工具定位问题代码
在实际项目开发中,最耗时的往往是硬件兼容性问题。建议先在开发板上验证各模块功能,再设计PCB。遇到信号干扰问题时,可采用以下措施:
- 在数字信号线串联33Ω电阻
- 敏感模拟信号使用屏蔽线
- 确保所有未使用的GPIO设置为模拟输入模式
更多推荐
所有评论(0)