基于Microchip PIC单片机的低功耗智能药盒设计与实现
1. 项目概述当药盒遇上微芯片最近在捣鼓一个挺有意思的小玩意儿我管它叫“Microchip Digital Dosette”直译过来就是“微芯片数字药盒”。这想法源于一个挺现实的观察家里老人或者需要长期服药的朋友记错药、吃错量、忘了吃是常有的事。市面上那些智能药盒要么功能花哨不实用要么价格贵得离谱要么就是联网复杂老人根本玩不转。我就琢磨能不能用最朴素的微控制器做一个核心功能扎实、成本可控、而且用户交互极其简单的“数字药盒”这个项目的核心就是利用一片Microchip微芯科技的经典8位单片机比如PIC16F系列来实现一个定时、定量提醒的智能药盒。它不联网、不搞App远程控制就专注于做好“到点响、开对格”这件事。硬件上一个单片机、几个LED、一个蜂鸣器、几个按钮和舵机再加一个实时时钟模块成本可以压得很低。软件上逻辑清晰就是管理多个药格Dosette的定时开启与提醒。我选择Microchip的芯片一方面是其生态成熟开发工具像MPLAB X IDE对爱好者友好另一方面其低功耗特性做得不错适合用电池长期供电的设备。整个做下来你会发现它远不止是一个简单的定时器。从药格机械结构的设计如何防止卡药到低功耗模式下如何精准唤醒再到如何设计固件让设置流程对老年人足够友好每一个环节都有不少门道。它本质上是一个典型的嵌入式系统开发项目涵盖了硬件选型、电路设计、固件开发、结构设计甚至简单的用户界面设计非常适合想从点灯进阶到实际产品开发的电子爱好者练手。接下来我就把自己从构思到实现的过程以及踩过的那些坑详细拆解一遍。2. 核心设计思路与方案选型做这个东西第一步不是画电路图而是想清楚它到底要干什么、为谁干。我的目标很明确做一个给健忘人群或老年人用的、可靠的服药提醒助手。基于这个目标我提炼出了几个核心设计原则并据此进行方案选型。2.1 用户需求与功能定义首先得抛开工程师思维从用户角度想问题。我访谈了几位需要每日服药的亲友总结出他们的核心痛点忘记服药这是最普遍的问题。忘记是否服过药有时吃了却怀疑没吃可能导致重复服药。服用剂量错误特别是需要同时服用多种药且剂量不同时。对复杂电子设备有畏难情绪很多老人不会用智能手机更别说连接Wi-Fi、操作App了。因此我定义的核心功能必须直击痛点多时段定时提醒至少支持一天4个时间点的提醒如早、中、晚、睡前。多药格独立管理每个药格对应一种或一组药能独立设置提醒时间。强提醒机制声音蜂鸣器和灯光LED双重提醒确保能被注意到。防重复服药确认每次提醒后必须通过一个明确的用户操作如按下确认键来关闭提醒并记录“已服药”避免误判。极简设置通过最少的按键如3个上、下、确认和清晰的LED或数码管指示完成时间、药格提醒的设置无需电脑或手机。药格自动/半自动开启提醒时对应的药格能自动弹开通过舵机或者有明确指示引导用户打开正确的药格。为什么不做联网功能这是一个关键取舍。加上Wi-Fi或蓝牙意味着成本增加、功耗飙升、开发复杂度指数级上升更重要的是引入了新的故障点网络连接和用户学习成本。对于这个核心场景离线、自治的可靠性远高于联网的便利性。家人的监督可以通过定期检查设备记录如果有简单显示屏或电话提醒来完成而不是依赖不稳定的远程控制。2.2 主控芯片选型为什么是Microchip PIC主控是大脑选型决定了项目的天花板和成本。我锁定了Microchip微芯科技具体原因如下生态与工具链成熟Microchip的MPLAB X IDE和XC8编译器对个人开发者免费资料和社区支持非常丰富。对于这种控制逻辑明确、对算力要求不高的应用其开发体验很顺畅。型号丰富性价比高我需要至少6-8个IO口控制LED、蜂鸣器、按键、舵机信号、时钟模块接口需要定时器最好有低功耗模式。PIC16F系列如PIC16F887或PIC16F18346完全满足需求单价仅十元左右性价比极高。低功耗特性药盒很可能用电池供电。PIC单片机在SLEEP模式下的功耗可以降到微安级配合外部中断如时钟模块的报警中断唤醒可以极大延长电池寿命。这是很多ARM Cortex-M0芯片在简单应用上难以比拟的优势。高可靠性工业级品质抗干扰能力强适合长期稳定运行的设备。关于网络热词USB4925搜索时可能会看到Microchip的USB4925。这是一款USB Hub控制器芯片跟我们的药盒主控需求完全不搭边。这提醒我们在选型时要紧扣需求关键词避免被不相关的热门型号误导。我们的核心是“低功耗单片机”而不是“USB Hub”。2.3 关键外设与模块选型主控定了周边模块就好选了实时时钟RTC模块这是定时提醒的基石。必须用独立的RTC芯片如DS3231。为什么不用单片机内部定时器内部定时器在单片机深度睡眠时可能停止工作且精度和长期稳定性远不如专业RTC。DS3231自带高精度温补晶振年误差可控制在分钟级且自带报警中断输出可以直接将单片机从睡眠中唤醒完美契合低功耗定时需求。提醒与指示单元蜂鸣器选择有源蜂鸣器驱动简单声音响亮。需注意驱动电流一般要加一个三极管如8050来放大单片机的IO口驱动能力。LED每个药格配一个高亮LED如白色或蓝色用于视觉指示。同时需要几个状态LED如电源、设置模式。显示单元为了极简化我放弃了LCD屏选用4位7段数码管来显示时间和设置参数。成本低显示直观在光照下也清晰。驱动方式采用动态扫描只需7411个IO口通过锁存器如74HC595可以进一步节省IO。用户输入单元3个轻触按键足矣“上翻”、“下翻”、“确认/取消”。通过软件消抖和长按/短按识别可以完成所有设置。执行机构这是机械部分的关键。每个药格需要一个锁止/释放机构。我选择了微型舵机如SG90来实现。舵机旋转一定角度可以带动一个卡销实现药格的弹出。注意舵机工作电流大峰值可达500mA以上绝对不能直接用单片机IO口驱动必须使用独立的电源供电并通过舵机控制板或MOS管开关电路由单片机信号控制。电源管理采用3节AA电池4.5V或一块锂电池3.7V供电。通过低压差稳压器LDO如AMS1117-3.3为单片机和数字电路提供稳定的3.3V电源。舵机直接连接电池电源需经过开关控制。务必在电池输入端加入电源开关。3. 硬件电路设计与核心细节电路是项目的骨架设计不合理后面软件写得再好也白搭。我的设计核心是“分块供电、信号隔离”确保大电流的舵机不会干扰脆弱的数字电路。3.1 主控与电源电路这是整个系统稳定工作的基础。// 电源部分原理简述 // BAT (4.5V) —— 电源开关 —— 分为两路 // 路1 直接给舵机供电V_MOTOR // 路2 经过LDO (AMS1117-3.3) —— 3.3V —— 给MCU、RTC、数码管、蜂鸣器驱动电路供电去耦电容是关键在AMS1117的输入和输出端必须紧贴芯片引脚放置一个10uF的钽电容和一个0.1uF的陶瓷电容。在PIC单片机的VDD和VSS之间每个电源引脚附近都要放一个0.1uF的电容。这是消除电源噪声、防止单片机意外复位的标准操作绝对不能省。电池电压监测虽然非必需但加上会更好。可以通过一个电阻分压网络将电池电压分压到单片机ADC可测量的范围如0-3.3V在固件中定期检测当电压低于阈值如3.0V时让某个LED闪烁提示电量低。3.2 RTCDS3231接口电路DS3231使用I2C接口与单片机通信。I2C是两条线的总线串行数据线SDA和串行时钟线SCL。上拉电阻必须在SDA和SCL线上各接一个上拉电阻通常4.7kΩ到10kΩ到3.3V。没有上拉电阻I2C通信根本无法工作。地址选择DS3231的I2C地址是固定的0x68通常无需配置。中断输出DS3231的INT/SQW引脚是关键。我们可以将其配置为报警输出模式并将其连接到PIC单片机的一个具有外部中断功能的引脚如RB0/INT。当设定的闹钟时间到达时DS3231会将该引脚拉低从而触发单片机的外部中断将单片机从睡眠中唤醒。务必在程序初始化时正确配置DS3231的报警寄存器和控制寄存器。3.3 执行机构舵机驱动电路这是硬件设计中电流最大、最需要小心的地方。绝对不要直连MCUSG90舵机工作电流轻松超过100mA堵转时更大。任何单片机的IO口都无法直接提供这样的电流强行连接会烧毁IO口甚至单片机。推荐方案专用舵机驱动板或MOS管开关方案A省事使用现成的舵机驱动板如PCA9685它通过I2C控制自带驱动电路单片机只需发指令。但成本稍高。方案B经典使用一个N沟道MOS管如IRLZ34N或一个简单的电机驱动芯片如L9110S作为电子开关。单片机的PWM信号引脚通过一个限流电阻如1kΩ连接到MOS管的栅极G。舵机的电源正极VCC接电池V_MOTOR电源负极GND接MOS管的漏极DMOS管的源极S接电池地。当单片机输出高电平时MOS管导通舵机得电工作输出低电平则关闭。舵机的信号线PWM直接连接到单片机的另一个IO口。电源隔离舵机的电源V_MOTOR和数字电路的电源3.3V最后应在电池端单点共地。可以在V_MOTOR进入舵机驱动电路前加一个大的电解电容如100uF来缓冲电机启动时的电流冲击防止电池电压瞬间被拉低导致单片机复位。3.4 用户界面电路按键与数码管按键电路采用最简单的上拉电阻接法。按键一端接地另一端接单片机IO口同时通过一个10kΩ电阻上拉到3.3V。单片机IO口配置为带上拉输入模式。未按下时读高电平按下时读低电平。软件中必须做消抖处理通常检测到低电平后延时10-20ms再读一次确认仍是低电平才算有效按键。数码管驱动为了节省IO口我使用了2片74HC595串行移位寄存器来驱动4位数码管。一片控制段选a-g, dp一片控制位选4个位。单片机只需3个IO口数据、时钟、锁存就能控制所有数码管。在软件上需要编写动态扫描函数在定时器中断中循环刷新每一位数码管利用人眼视觉暂留形成稳定显示。注意硬件焊接完成后不要急着写复杂程序。先用一个简单的“点灯”程序测试每一个模块让每个LED亮起、让蜂鸣器响、让数码管显示数字、读取RTC时间、让舵机动一下。确保每个部分硬件连接正确再进入集成开发阶段。这叫“分模块调试”能帮你快速定位是硬件问题还是软件问题。4. 固件开发逻辑、低功耗与可靠性硬件搭好了灵魂在于软件。固件开发围绕“事件驱动”和“低功耗”两个核心展开。4.1 程序主框架与状态机整个系统可以看作一个状态机。我定义了以下几个主要状态正常显示状态NORMAL数码管滚动显示当前时间、日期和下一个即将到来的服药提醒时间。大部分时间系统处于此状态或由此状态进入睡眠。提醒报警状态ALARM当RTC报警触发时进入。蜂鸣器鸣叫对应药格的LED快速闪烁数码管显示该药格编号。等待用户按下“确认”键。如果用户操作则关闭提醒记录日志并控制舵机打开对应药格或指示用户打开。如果用户不操作提醒应持续一段时间如5分钟后自动停止但LED可能转为慢闪提示有未处理的提醒。设置状态SETTING长按“确认”键进入。通过“上/下”键修改闪烁的项目时、分、药格时间等短按“确认”键切换设置项。这是一个多层菜单逻辑要清晰。睡眠状态SLEEP在无操作一段时间后如1分钟系统自动关闭数码管和大部分外设单片机进入SLEEP模式。此时仅RTC和外部中断电路在工作功耗极低。RTC的报警中断或按键中断都能唤醒单片机。程序主循环非常简单void main(void) { System_Init(); // 初始化IO、定时器、中断、RTC等 while(1) { switch(current_state) { case STATE_NORMAL: Normal_State_Handler(); // 显示时间检测按键超时进入睡眠 break; case STATE_ALARM: Alarm_State_Handler(); // 处理提醒和用户确认 break; case STATE_SETTING: Setting_State_Handler(); // 处理设置菜单 break; } // 其他后台任务如电池检测 if (is_time_to_check_battery()) { check_battery_voltage(); } } }4.2 低功耗实现的关键细节低功耗是电池设备续航的生命线。外设电源管理在进入睡眠前固件要主动关闭所有不必要的外设电源。对于由IO口直接驱动的LED、蜂鸣器将其对应IO口设置为输出低电平确保不发光/发声且配置为输出模式减少功耗。对于数码管关闭动态扫描定时器。单片机配置将未使用的IO口配置为输出并置低或配置为输入并启用内部上拉避免浮空引脚漏电。关闭不用的外设模块ADC、比较器、PWM等。使用SLEEP()指令进入休眠。在PIC中这通常需要先配置好唤醒源。唤醒源配置我们的唤醒源有两个RTC报警中断DS3231的INT引脚和按键中断。需要将对应的单片机引脚如RB0/INT配置为下降沿触发的外部中断。在中断服务程序ISR中首先要判断中断源然后清除中断标志并改变系统状态如从STATE_SLEEP切换到STATE_ALARM或STATE_NORMAL。RTC报警设置这是最精巧的部分。我们可能有多个药格每个有各自的服药时间。但DS3231通常只有两个报警寄存器。怎么办我的策略是动态设置下一个最近的闹钟。在系统初始化或每次完成提醒后程序会遍历所有已设置的药格提醒时间。计算出下一个即将到来的时间点可能是几分钟后也可能是明天。将这个时间点写入DS3231的报警寄存器1或2并启用报警中断。单片机随即进入睡眠。当这个时间到达时RTC触发中断唤醒单片机。单片机被唤醒后处理当前提醒然后立即重新计算并设置下一个闹钟如此循环。这种“滚动闹钟”的方式用两个硬件闹钟实现了任意多个软件闹钟的管理是低功耗定时系统的经典设计模式。4.3 用户设置流程的友好性设计设置流程必须对非技术人员友好。引导清晰进入设置模式后数码管上哪一位在闪烁就表示当前正在设置哪一位。例如小时十位闪烁按“上/下”键调整的就是小时十位。自动退出在设置状态下如果长时间如30秒无任何按键操作系统自动保存已修改的设置并退出到正常显示状态防止设置到一半忘了退出。默认值合理第一次上电或恢复出厂设置后时间应设置为一个明显的错误值如00:00或者药格提醒时间全部禁用迫使用户进行设置避免使用错误的时间。反馈及时任何按键操作都应有及时的反馈比如短促的“滴”声或LED闪一下让用户知道设备接收到了指令。5. 机械结构设计与装配心得电子部分解决了药盒本身还得是个好用的“盒子”。这部分我用了3D打印来制作原型。5.1 药格与舵机联动机构这是机械部分的核心。设计目标是可靠弹开、易于装药、防止卡死。药格设计每个药格是一个独立的小抽屉底部有滑轨。在抽屉关闭位置有一个卡槽被舵机臂上的卡销挡住。舵机安装舵机固定在主壳体内。舵机臂旋转时卡销会从药格卡槽中抽出。弹簧助力在药格后方安装一个小弹簧或使用有弹性的塑料结构。当卡销抽出时弹簧的力将药格自动弹出约1-2厘米方便用户取出。注意弹簧力不能太大否则舵机扭矩可能不够也不能太小否则无法可靠弹出。防呆设计药格和舱室需要有防反插的钥匙结构确保用户只能以正确的方向放回药格。药格关上时应有“咔哒”一声的明确手感提示已锁紧。5.2 3D打印与后处理材料选择推荐使用PLA或PETG。PLA容易打印但较脆PETG更有韧性耐久性更好。ABS收缩率大对打印环境要求高新手慎用。打印方向药格抽屉的滑动面与滑轨接触的面最好垂直于打印平台Z轴。这样层与层之间的纹路方向与滑动方向一致摩擦阻力更小且强度更高。如果平行于平台打印层间粘合力可能不足以承受反复的滑动摩擦。公差设计这是3D打印组装件的精髓。滑动配合处必须留出间隙。我的经验是对于PLA材料单边间隙留0.2mm到0.3mm比较合适。比如设计滑轨宽度是10mm那么滑槽的宽度就设计为10.5mm。需要多打几次测试件来找到最适合自己打印机和材料的“魔法数字”。后处理打印完成后对所有需要滑动、转动的轴孔、滑轨进行打磨使用细砂纸或打磨工具并可以涂抹一点点润滑脂如白色锂基脂能极大提升顺滑度和手感减少舵机负载。6. 系统集成、调试与问题实录把所有模块拼在一起才是挑战的开始。下面是我在集成调试中遇到的一些典型问题及解决方法。6.1 上电复位与电源不稳现象一上电单片机程序好像跑飞了或者舵机一动数码管就乱闪、单片机重启。排查与解决检查电源用万用表测量单片机VDD引脚在舵机动作瞬间的电压。如果电压有大幅跌落如从3.3V跌到3.0V以下说明电源带载能力不足或内阻太大。增加电容在靠近舵机电源输入端并接一个大容量电解电容470uF以上用于提供瞬间大电流。在单片机电源引脚附近增加0.1uF陶瓷电容。检查地线确保电池地、舵机驱动板地、单片机数字地是良好连接的“单点共地”避免地线环路或地电位不同引起的干扰。使用示波器如果条件允许用示波器看电源纹波这是最直接的诊断方法。6.2 RTC时间不准或通信失败现象显示的时间跑得快或慢或者根本无法读取时间。排查与解决检查I2C上拉电阻确保SDA和SCL线上有4.7kΩ的上拉电阻接到3.3V。没有上拉电平无法拉高通信必然失败。检查接线与地址确认SDA、SCL线没有接反。确认程序中DS3231的I2C地址是0x687位地址。降低I2C速度在初始化I2C模块时尝试降低通信速率如设为100kHz标准模式。长导线、面包板连接容易引入干扰高速模式不稳定。检查电池DS3231模块上的纽扣电池CR2032是否电量充足电池没电时主电源断开后时间会丢失。6.3 舵机抖动、异响或无法归位现象舵机在到达指定角度后不停抖动发出“吱吱”声或者角度不准。排查与解决电源功率不足这是最常见的原因。确保给舵机供电的电池是全新的或电量充足的。使用单独的电池组或稳压模块给舵机供电与单片机电源分离。机械负载过重检查药格是否被卡住弹簧力是否过大。空载时测试舵机是否运转正常。可以在舵机臂和药格卡销之间增加一个杠杆结构以牺牲行程为代价换取更大的扭矩。PWM信号问题舵机控制需要50Hz周期20ms的PWM信号其中高电平脉冲宽度在0.5ms到2.5ms之间对应0到180度。确保单片机产生的PWM信号频率和脉宽准确。可以用逻辑分析仪或另一个舵机测试一下信号。程序逻辑问题避免在程序中频繁地、微小地改变舵机目标角度。设置好角度后应保持信号稳定。如果需要运动最好以较大的步进一次性完成。6.4 低功耗模式唤醒失败现象系统睡眠后到了时间不唤醒或者按键无法唤醒。排查与解决检查中断配置确认用于唤醒的引脚如RB0已正确配置为外部中断并且中断边沿上升沿/下降沿与触发信号一致。DS3231的INT引脚通常是低电平有效所以应配置为下降沿或低电平中断。检查全局中断使能在进入睡眠前必须确保相应的外部中断使能位被置位。在PIC中要开启INTE外部中断使能和GIE全局中断使能。清除中断标志在中断服务程序ISR中必须清除对应的中断标志位如INTF否则退出中断后会立即再次进入。信号电平确认用万用表或示波器测量唤醒引脚在睡眠时的实际电平以及触发瞬间的电平变化确认信号确实到达了单片机引脚。6.5 按键操作不灵或误触发现象按一下键程序反应了好几次连击或者有时按了没反应。排查与解决软件消抖这是必须的。最简单的消抖方法是检测到按键按下电平变低后延时10-20ms再次检测引脚电平如果仍然是低电平则确认为有效按键。松手检测同理。硬件消抖如果环境干扰大可以在按键两端并联一个0.1uF的电容吸收抖动。扫描频率确保主循环或定时器中断中扫描按键的频率足够高如每10ms一次避免漏检短按。但也不能太高以免占用过多CPU资源。长按/短按识别通过计时器记录按键按下的持续时间。例如按下超过1秒算长按用于进入设置菜单短于1秒算短按用于调整数值。这能大大增强交互的灵活性。整个项目从构思到做出一个能稳定工作的原型花费了大约两周的业余时间。最大的成就感不是代码跑通了而是看到家里老人能够毫无障碍地使用它并且再也没有错过服药时间。嵌入式开发的乐趣就在于此用一个简单的想法结合硬件和软件做出能真实改善生活的小工具。这个“Microchip Digital Dosette”项目麻雀虽小五脏俱全它涉及了嵌入式系统开发的方方面面是一个绝佳的练手项目。如果你也想尝试不妨就从画第一张电路图开始吧。