基于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选择跳线,扩展板集成以下模块:

  1. 电源管理电路

    • TP4056锂电池充电管理
    • AMS1117-3.3V稳压芯片
    • 充放电状态LED指示
  2. RFID识别模块

    • MFRC522芯片+13.56MHz天线
    • 有效识别距离3-5cm
    • 支持ISO14443A协议
  3. 无线通信模块

    • 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向导航键替代传统矩阵按键

典型操作流程如下:

  1. 系统启动后播放开机提示音
  2. 主界面显示时钟和药品槽状态
  3. 短按选择键查看药品详情
  4. 长按确认键同步云端数据

注意: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中创建以下任务并设置合理优先级:

  1. 主控任务 (优先级3)

    • 处理用户输入
    • 管理状态机切换
    • 协调各子系统运行
  2. RFID扫描任务 (优先级4)

    • 周期读取RC522数据
    • 校验药品标签有效性
    • 更新当前药品信息
  3. 网络通信任务 (优先级2)

    • 维护WiFi连接
    • 同步时间服务器
    • 上传用药记录
  4. 显示刷新任务 (优先级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:

  1. 动态时钟调整
    • 运行模式:72MHz
    • 空闲模式:8MHz
  2. 外设智能供电
    • 采用MOSFET控制模块电源
    • 非活跃期关闭显示屏背光
  3. 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协议实现设备-云端双向通信,关键步骤包括:

  1. 三元组获取

    • 产品Key:a1**********
    • 设备名称:medicine_box_001
    • 设备密钥:采用动态注册方式获取
  2. Topic定义

    • 上行:/sys/a1******/${deviceName}/thing/event/property/post
    • 下行:/sys/a1******/${deviceName}/thing/service/property/set
  3. 数据格式示例

{
    "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 常见硬件问题解决方案

  1. RFID读取不稳定

    • 检查天线匹配电路:27pF电容需精确匹配
    • 调整MFRC522的增益寄存器:
      MFRC522_WriteRegister(RFCfgReg, 0x38); // 38h为推荐值
      
  2. WiFi频繁断开

    • 在ESP8266电源端增加100μF电容
    • 修改AT指令重试机制:
      AT+CIPRECONNCFG=3000,10  # 3秒间隔,最多重试10次
      
  3. RTC走时不准

    • 更换32.768kHz晶振负载电容(典型值12.5pF)
    • 启用时钟校准:
      HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, 
                              RTC_SMOOTHCALIB_PLUSPULSES_SET, 127);
      

5.2 软件调试技巧

  1. 利用SEGGER RTT

    • 不占用串口资源
    • 实时输出调试信息
    • 配置方法:
      #include "SEGGER_RTT.h"
      SEGGER_RTT_printf(0, "RFID detected: %s\n", id);
      
  2. 内存泄漏检测

    • 在FreeRTOSConfig.h中启用堆检查:
      #define configUSE_TRACE_FACILITY    1
      #define configUSE_STATS_FORMATTING_FUNCTIONS 1
      
    • 通过命令查看任务栈使用:
      task list
      task stats
      
  3. 崩溃定位方法

    • 在HardFault_Handler中打印LR和PC值
    • 使用addr2line工具定位问题代码

在实际项目开发中,最耗时的往往是硬件兼容性问题。建议先在开发板上验证各模块功能,再设计PCB。遇到信号干扰问题时,可采用以下措施:

  • 在数字信号线串联33Ω电阻
  • 敏感模拟信号使用屏蔽线
  • 确保所有未使用的GPIO设置为模拟输入模式
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐