news 2026/9/20 11:50:04

基于微信小程序与STM32的智能药盒管理系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于微信小程序与STM32的智能药盒管理系统

简介:一套结合微信小程序与STM32的智能药盒管理系统完整方案,以小程序作为交互入口、STM32作为控制核心,构成端云联动的物联网用药管理方案。主要面向嵌入式开发者、物联网爱好者及医疗健康产品设计人员,解决传统用药管理依赖人工提醒、易漏服错服,以及监护人无法实时掌握服药情况的问题。压缩包共8个文件,大小约71.02MB,主要包含硬件PCB设计、STM32固件源码、小程序前端源码和项目结构说明,另附README与许可证文件,rar工程分模块打包,便于按需选用和二次开发。已有76人下载学习。资源完整覆盖从硬件电路、嵌入式逻辑到移动端交互的全链路,实现药盒定时开启精确控制、用药数据采集上传与远程监护,可作为毕业设计、课程项目或智能医疗产品原型参考。 做这个项目的起因,是去年回老家时看到奶奶的药盒上贴满胶布,早中晚的药还是经常吃重或漏吃。市面上号称“智能药盒”的产品不少,但要么贵得离谱,要么必须装专用App,老人根本用不来。后来我决定自己动手做一套,用微信小程序作为交互端,用STM32作为药盒主控,做成一套基于微信小程序和STM32的智能药盒管理系统。核心目标就三个:用药计划可管理、智能硬件可连接、监护人能远程监护。这套方案我已经跑通了完整链路,从硬件选型到小程序联调都有可复现的细节,这次一次性整理出来。

1. 需求拆解:药盒为什么要拆成“小程序+STM32”两级架构

1.1 真正需要解决的四个用药场景

先说场景,不然容易做成“为了智能而智能”。我在社区里看到过不少同类项目,最后都变成蓝牙控制舵机转一圈的花架子。真实的用药痛点,其实集中在四件事上:

  • 漏服:老人独居,或者子女白天上班,没有人到点提醒。药盒需要主动发声、发光,而不是靠老人自己看。
  • 重复服药:不少老人会“觉得今天好像没吃”,然后补吃一次,危险系数很高。药盒需要记录每次实际取出药品的动作。
  • 子女不知道服药情况:很多老人不愿意承认自己忘了吃,电话里都说“吃了吃了”。子女需要一份客观的、可查询的服药记录。
  • 药品种类和时间经常变:慢性病老人一个月要调整几次药量,今天加一片,明天减一片。药盒设置必须简单到子女远程就能改。

所以这个系统不是“硬件遥控器”,而是一套完整的用药管理闭环:计划由小程序维护,到点由硬件执行,结果自动回传,监护人随时查看。这个定位决定了后面所有技术选型。

1.2 为什么是微信小程序 + STM32,而不是纯App或纯云方案

我在项目中常被问到:为什么不用手机App直接连蓝牙?为什么不上一个带WiFi的板子,直接把数据传到云端?我的答案是:要看这个设备的使用者是谁。

微信小程序的核心优势是“免安装”。给老人用的东西,无论是iOS还是Android,打开微信扫一下就能用,子女在异地也能帮老人设置计划。对老人来说,不需要教他们怎么装App、怎么注册账号,点开小程序直接看到今天的药格子就行。这个体验是普通App给不了的。

STM32这边则负责“真正动起来”的部分。药盒需要控制舵机开锁、驱动蜂鸣器、读取门控状态,这些操作对时序要求高,而且不能因为手机蓝牙断连就罢工。用STM32做主控,一是实时性和稳定性有保障,二是功耗低、成本可控,三是整个方案里你能完全掌控硬件逻辑,不会像某些家用路由器刷开源固件那样受限。

为什么不走“纯云+WiFi模块”方案?我其实试验过:如果药盒直接依赖WiFi模块接收云端指令,一旦家里断网或者路由器重启,整个药盒就处于“哑巴”状态,连本地出药都做不了。而用蓝牙直连方案,手机是临时网关,药盒本体有独立工作能力,断网时只要手机蓝牙还连着,照样能按时出药。系统真正需要的云端能力是“远程查看记录”,而不是“远程实时控制”的强依赖。这个取舍在老人场景下非常重要。

2. 硬件方案:从药格到主控板的实操选型

2.1 主控与外设清单

我的硬件清单如下,都是从常用元件库里能直接买到的型号,不搞稀缺料:

模块型号/规格作用
主控MCUSTM32F103C8T6处理蓝牙指令、控制舵机和传感器
蓝牙透传模块JDY-23 BLE 4.2 / 5.0与微信小程序建立BLE连接
舵机MG90S 金属齿轮舵机 × 6控制6个药格锁扣
药格状态检测微动开关 × 6检测药格是否被打开/关回
蜂鸣器有源蜂鸣器 5V到点提醒、异常报警
显示屏0.96寸OLED I2C显示时间、今日服药状态
电源管理AMS1117-3.3 + 7.4V锂电池给MCU和舵机供电

为什么用MG90S小舵机而不是步进电机?我对比过。步进电机优点是定位精确,但驱动需要驱动芯片,药盒这场景本质上不是“分度定位”,而是“把锁扣拉开一个角度”,舵机最合适。MG90S堵转电流约200-300mA,六路不会同时动作,一个独立电源完全扛得住。如果你用大扭力舵机,比如MG995,就需要单独考虑电源了。

2.2 电路连接与供电细节

硬件连接上容易翻车的点,主要是供电和电平匹配。

STM32的GPIO是3.3V电平,JDY-23蓝牙模块的串口电平通常兼容3.3V,可以直接连,但我不建议直接共地后把模块VCC接到板子的5V上就不管了。稳妥做法是:BLE模块VCC接3.3V,TXD接STM32的PA10(USART1_RX),RXD接PA9(USART1_TX),GND共地。这样收发不会出现电平“半高不高”的问题。

舵机供电要单独给。MG90S的堵转瞬间可能把5V电源拉低,如果和MCU共用同一个电源,轻则屏幕闪烁,重则单片机直接复位。我的方案是:7.4V锂电池直接给舵机电源端,再通过AMS1117降压到3.3V给STM32供电;舵机VCC接5V的独立DCDC模块,信号线接MCU的PA0、PA1等PWM输出引脚。实际接线时,每个舵机的电源线最好加一个100uF电容滤波,能明显减少瞬时压降。

药格打开状态的检测,我用的是微动开关,安装在药格门锁位置,门关上时开关被压住,门弹开后开关释放。STM32的GPIO配置为输入上拉:开关闭合时读到低电平,打开时读到高电平。如果用的是常开型传感器,就要在代码里反过来处理。这里有个顺序问题:安装时先把微动开关固定在盒体上,再装舵机锁扣,否则容易出现“门关上了但锁扣压不住开关”的物理错位。

3. 小程序端:用药计划、BLE通信与远程监护闭环

3.1 页面结构和云开发数据模型

小程序整体结构很简单,一共四个主要页面:

  • 首页:显示设备连接状态、今日用药计划的卡片列表。
  • 计划编辑:添加/修改药品名称、剂量、提醒时间。
  • 记录页:按天查看服药记录,区分“已确认”“未确认”“已漏服”。
  • 监护端:绑定家庭成员后,查看被监护人的实时服药记录和剩余药量。

数据存储我用了微信云开发,省去了自建服务器。云数据库里建三个集合就够了:

  • users:用户信息,包含openid、家庭绑定关系。
  • devices:设备信息,包含deviceId、绑定人ownerId、当前药格数量。
  • plans:用药计划,包含userIddeviceIddrugNamedosagereminderTimesenabled

records我不建议单独建集合,数据量大了之后查询很麻烦。我直接把每日服药记录嵌套在plans文档里,以数组形式保存,每次取当天记录时只查一次plans集合,性能足够,逻辑也清晰。

3.2 微信小程序蓝牙通信的几个关键封装

微信小程序连BLE模块,核心流程是:

wx.openBluetoothAdapter({}) // 初始化蓝牙适配器 wx.startBluetoothDevicesDiscovery({ allowDuplicatesKey: true }) // 过滤名称包含 'MedBox_' 的设备 wx.createBLEConnection({ deviceId }) wx.getBLEDeviceServices({ deviceId }) wx.getBLEDeviceCharacteristics({ deviceId, serviceId }) // 然后通过 writeBLECharacteristicValue 下发指令

这里有三个实际会遇到的问题,值得单独提醒。

第一,发现设备后不要马上就createBLEConnection,要过滤设备名,否则会把周围十几台蓝牙设备都尝试连一遍。我的做法是:在onBluetoothDeviceFound回调里判断device.name是否包含MedBox_,匹配后才执行连接。

第二,iOS和Android对蓝牙权限的处理不同。iOS上如果用户没有打开“定位服务”,蓝牙扫描可能拿不到任何设备,这个坑不实际踩一次很难想到。小程序初始化蓝牙前,最好先用接口判断一下系统版本,如果检测到iOS,就先引导用户打开定位权限,再走蓝牙流程。

第三,写数据时要考虑分包。微信BLE接口一次写入的最大长度通常在20字节左右,我的协议帧只有6个字节,完全没问题。如果你要扩展功能,比如下一条较长的配置指令,就必须把数据拆成多段,每次写完后等待writeBLECharacteristicValue成功回调,再写下一段。同时,写操作要加防抖,不能在极短时间内连续写,否则手机会提示“连接不稳定”。

3.3 监护人远程监护的数据流

远程监护的数据流是这样的:被监护人的手机小程序和药盒保持BLE连接,当药盒检测到某个药格被打开并关回后,会通过BLE回传一条确认帧,小程序收到后调用云函数写入服药记录。监护人打开小程序时,后台根据家庭绑定关系查对应被监护人的plansrecords,页面展示当日服药状态。

这里有一个权限问题要提前设计:微信云开发默认只允许用户读写自己的数据,监护人怎么读取被监护人的数据?我的方案是,在用户表里维护一个family字段:

{ "_openid": "被监护人的openid", "ownerId": "被监护人openid", "family": [ { "openid": "监护人openid", "role": "child" } ] }

云函数里根据当前登录用户的openid,查找ownerId等于该用户或family数组中包含该用户的设备,再返回对应的计划与记录。这样权限关系依然清晰,不会出现任何人能查别人数据的问题。

如果监护人想主动提醒,不使用蓝牙直连(因为他在异地),我用了微信订阅消息:被监护人在小程序里授权“服药提醒”消息模板,监护端点击“提醒服药”时,通过云函数调用微信推送接口,向被监护人发送一条订阅消息。注意订阅消息一次授权只能推送一次,所以我做了一个“连续授权”引导,在用户首次进入计划页时弹窗申请多次授权。这个设计在真机测试中有效,但不要指望它像短信一样强制,只能作为提醒增强。

4. STM32端状态机与自定义BLE协议:一条指令怎样变成一颗药

4.1 自定义BLE指令帧格式与解析

BLE透传模块传输的是裸串口字节,直接传字符串也不是不能做,但项目一旦复杂就会很痛苦。我自定义了一套极简二进制协议,每个指令固定6字节:

字节定义说明
第1字节帧头固定0xAA
第2字节命令字0x01出药、0x02查询状态、0x03复位
第3字节参数药格编号,0~5
第4字节保留固定0x00
第5字节校验和低8位前4字节累加和的低8位
第6字节帧尾固定0x55

举个例子,下发“打开第2格药”指令就是:

AA 01 02 00 AD 55

因为前四个字节0xAA + 0x01 + 0x02 + 0x00 = 0xAD,所以校验码是0xAD。STM32端收到后先判断帧头和帧尾,再验证累加和,校验通过才执行。这个协议看起来简单,但好处是不依赖字符串解析,不会出现换行符干扰、大小写混淆的问题,也方便以后扩展命令字。

4.2 STM32主状态机与出药逻辑

STM32端的核心不是怎么写串口中断,而是怎么把“收到一条指令”变成“一次稳定的出药动作”。我这里用了一个简单的状态机,四个状态:

  • IDLE:空闲,等待BLE指令。
  • POPPING:舵机正在转动,等待到达指定角度。
  • WAIT_CONFIRM:药格已弹开,等待药格被取走并关闭。
  • MISSED:超时未关闭,执行提醒并上报。

核心逻辑大概是这样的:

switch (state) { case IDLE: if (ble_rx.cmd == CMD_POP) { pop_drug(ble_rx.arg); // 控制对应舵机转动 state = WAIT_CONFIRM; } break; case WAIT_CONFIRM: if (door_sensor_closed(ble_rx.arg)) { send_status(STATUS_TAKEN); state = IDLE; } else if (tick >= 15000) { buzzer_beep(3); send_status(STATUS_MISSED); state = IDLE; } break; }

这里有两个细节。第一个是舵机转动的时间:MG90S从0度转到90度约120ms,我在pop_drug里先让蜂鸣器短响一声,再控制舵机转到对应角度,防止老人被突然弹出的药格吓到。第二个是状态机里不要阻塞式等待,用定时器中断维护一个毫秒级的tick,主循环只做状态判断。如果直接写HAL_Delay(120),在延时期间蓝牙指令来了也处理不了,体验会差很多。

4.3 掉电保护与误弹出设计

药盒最怕的就是掉电后状态丢失,或者误触发导致药格弹开。针对这两个问题,我做了三个处理。

第一,在STM32的Flash里保存一个“当前已弹开药格”的状态位。每次上电初始化时读取这个状态,如果发现某个药格在掉电前是“已弹开未确认”,蜂鸣器会持续鸣叫并上报一条待确认记录,提示用户检查。这里用STM32F103的FLASH操作,其实只需要擦写一个扇区,不存在什么难度,注意不要在运行时频繁写Flash就行。

第二,BLE指令执行前加一个“二次校验”逻辑。出药这种动作不能收到一帧就执行,万一飘来一个CRC碰巧校验通过呢?实际项目中我设置了同一个指令3秒内最多执行一次,并且指令必须连续收到两次且内容一致才真正触发。用户在小程序端点一次“出药”,小程序会自动发两帧相同的指令,间隔200ms。这样即使BLE偶尔丢包,也不会造成误操作。

第三,药格的状态检测要消抖。微动开关在机械动作瞬间会有一连串的电平抖动,如果直接读GPIO判断,可能会把一个开合动作识别成多次。我在代码里加了一个简单的软件消抖:GPIO状态变化后,延时20ms再读一次,一致才确认变化。如果用定时器中断做轮询,效果更好,但要注意别在中断里做延时,否则会拖慢主循环。

5. 联调实测与踩坑记录:从点击“出药”到药格弹开

5.1 实测链路延迟与稳定性

整个链路跑通之后,我做了一轮比较完整的实测,数据如下:

测试项目结果
打开小程序到蓝牙连接成功平均耗时2.3秒(iOS),1.8秒(Android)
下发“出药”指令到药格弹开平均耗时180ms
药格状态回传到小程序显示平均耗时480ms
连续操作10次,指令丢失次数0次(同一楼层环境)
蓝牙距离大于8米后丢包率明显上升

实测下来,用户点击“出药”后的实际体感是非常快的,几乎感觉不到延迟。真正影响体验的反而是“打开小程序连蓝牙”这个过程。后来我在小程序首页加了一个自动重连逻辑:如果检测到上次连接的设备ID,就跳过设备扫描,直接用createBLEConnection去连,连接速度从2秒多降到1秒以内。

5.2 我踩过的三个坑

这里必须把几个印象深刻的坑单独拿出来说,因为不踩一次,很多问题看教程根本发现不了。

坑一:舵机供电不足导致STM32频繁复位。最初我把五块面包板接到同一个5V降压模块上,按下出药按键的瞬间,屏幕直接白屏,串口打印全是乱码。后来用万用表量舵机电源端,瞬间跌落到了3.8V,而STM32的3.3V供电又是从同一个5V降压出来的,在低压瞬间直接复位。解决方案就是前面说的:舵机独立供电,STM32通过AMS1117单独降压。这个教训让我明白,在机电一体项目里,供电规划比代码优先级更高。

坑二:微信小程序拿到的BLE服务UUID是“动态”的。JDY-23模块出厂默认有一套Service UUID和Characteristic UUID,但不同固件版本返回的UUID并不一致,甚至在重新上电后可能变化。我开始按照说明书硬编码UUID,结果换了一块模块就连不上。后来改成了动态获取:连接设备后先调用getBLEDeviceServices拿到所有服务,再从中筛选出包含“写入”和“通知”权限的特征值,不再依赖固定值。这样无论模块固件怎么变,都能找到可用的通道。

坑三:微动开关抖动导致药格状态误报。一开始我直接按GPIO电平跳变判断“门被打开”,结果发现老人轻轻关门时,开关会连续抖动,记录上显示“打开-关闭-打开-关闭”了好几次。我折腾半天后加了软件消抖,还在小程序端增加了“状态变化后500ms内不再接受反向变化”的辅助逻辑,最终记录稳定很多。这种事情调试时很难复现,但装上电池放在家里,第二天数据统计就开始出问题。所以凡是读取机械传感器的地方,都别省消抖逻辑。

5.3 可以继续扩展的方向

这套系统的硬件和软件底座都搭好了,后续扩展其实非常自然。我目前已经验证过几个方向:

  • 离线语音播报:加一个SYN6288语音合成模块,到点直接播报“请服用阿司匹林一片”,比蜂鸣器好用太多。语音模块通过串口和STM32通信,协议类似AT指令,非常成熟。
  • 用药数据导出:云函数定期把每周服药依从性汇总成一个PDF,通过小程序让用户下载或分享给家庭医生。这个我已经用云开发的generateUrl做了简单版,能生成临时链接,后续可以接文件存储。
  • 多设备家庭管理:把devices集合改成数组,支持一位用户绑定多个药盒,比如老家一台、自己家一台。小程序首页按设备分组展示计划,监护人端查看不同设备时也能按家庭维度过滤。

最后分享一个我实际用下来最管用的小技巧:给药盒的每颗药格编号,在盒体上刻数字,然后在微信小程序计划编辑页里,让用户拍照绑定“第3格对应哪种药”。这个功能看着不起眼,但老人实际使用时,眼睛看着盒体编号再扫一眼手机,几乎不会放错药。很多同类项目败在功能复杂但“不好用”上,如果把交互细节做到这种程度,整个系统才真正有了长期被使用的价值。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 11:48:45

OpenMMO程序化路网:连接定居点的道路网络生成算法指南

OpenMMO程序化路网:连接定居点的道路网络生成算法指南 【免费下载链接】OpenMMO 项目地址: https://gitcode.com/GitHub_Trending/open/OpenMMO OpenMMO 是一款程序化生成的开放世界 MMO,它的路网系统(Road Network)完全由…

作者头像 李华
网站建设 2026/9/20 11:47:13

Naive UI 入门实战:安装、全局注册与按需引入完整指南

前端UI组件 【免费下载链接】naive-ui A Vue 3 Component Library. Fairly Complete. Theme Customizable. Uses TypeScript. Fast. 项目地址: https://gitcode.com/gh_mirrors/na/naive-ui 点击查看 免费下载 本指南以 naive-ui 仓库中 build/loaders/test/test.m…

作者头像 李华
网站建设 2026/9/20 11:45:44

上门服务系统源码v1.2:订单派单、多端角色与商业化实践

简介:面向上门服务、物业维修等场景的进云jys系统应用上门服务源码 v1.2,是一套基于进云框架的原生插件,主要用于快速搭建预约上门、员工入驻等业务闭环。该源码支持维修类、物业类、服务类等多类业务,可自由开启员工入驻、手机申…

作者头像 李华
网站建设 2026/9/20 11:42:47

LM3S9D90嵌入式平衡检测系统设计与实现

简介:本资源是一套面向嵌入式系统开发者与电子设计竞赛学生的便携式人体平衡检测仪完整工程方案,聚焦低功耗、手持化医疗辅助检测设备开发。项目基于ARM Cortex-M3内核的LM3S9D90单片机实现,解决传统平衡检测仪体积大、操作复杂、成本高等痛点…

作者头像 李华
网站建设 2026/9/20 11:42:21

同一把 TaoToken Key,OpenClaw 从通义千问切到 GPT 只动 Base URL

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华