基于STM32的智能输液点滴监控系统:从红外检测到蠕动泵闭环控制

📅 发布时间:2026/9/6 8:46:25
基于STM32的智能输液点滴监控系统:从红外检测到蠕动泵闭环控制
1. 为什么做这套STM32输液点滴系统病房里的真实痛点先别急着看代码聊聊我在医院陪床时观察到的一个场景护士站每天要处理大量输液任务病人液体输完或流速异常时只能靠家属盯着、按铃呼叫。遇到夜间加床多的时候护士一个人要管几十个床位滴速偏差、气泡、堵针这些问题全靠人工巡检效率低不说漏判风险也确实存在。我当时就在想能不能用嵌入式手段把输液监控这件事变得可靠一点。测滴速、控制流速、异常报警这些需求拆开来看并不复杂难的是把它们稳定地跑在一块低成本主控上并且能在实验室里把逻辑先仿真验证清楚再去碰实物。这也是我开源这套系统的初衷。这套基于STM32的智能医疗输液点滴系统核心解决三件事第一用红外对管实时检测点滴速率第二通过蠕动泵自动调节滴速让实际滴速逼近目标值第三出现堵针、滴速异常、液面过低时立刻声光报警并自动停止输液。它适合谁参考正在做电子设计竞赛、嵌入式课程设计、医疗器械方向预研的工程师或学生都适用。尤其是想搞懂传感器采集电机控制人机交互这套完整链路的人这套开源工程可以省掉大量从零开始的时间。整个项目包含完整的STM32工程代码、Altium Designer格式原理图、Proteus仿真工程以及我在调试过程中踩过的坑和对应的解决方案。下面我会把从硬件选型到代码架构再到仿真验证和实物调试的完整过程讲清楚。2. 需求定义把输液监控翻译成具体的工程指标做任何嵌入式项目第一件事不是画原理图而是把模糊的需求转成能写进代码的量化指标。这一步做不好后期全是返工。我在这套输液系统上花了不少时间做需求拆解这里直接分享我的结论。2.1 功能需求向硬件模块的映射输液监控系统拆到最后需要以下几个功能块滴速检测红外对管透过滴壶液滴经过时产生信号变化输出脉冲滴速调节微型蠕动泵挤压输液管通过调节电机转速改变滴速人机交互OLED屏幕显示目标滴速、实测滴速、累计液量和报警状态按键用于设置参数和启停系统异常报警蜂鸣器配合LED灯区分滴速超限和液面过低两种报警状态液面检测在滴壶下端加装光电传感器无液体时输出高电平触发停机在功能映射阶段我建议把每个模块的接口方式确定下来红外检测输出是脉冲信号接EXTI或定时器捕获引脚电机控制输出是PWM接驱动芯片OLED走I2C总线按键用GPIO上拉输入蜂鸣器用三极管驱动的有源蜂鸣器。2.2 量化指标与系统约束在实验室复现场景下我给自己定了几个硬性指标参数指标备注滴速检测范围10-150滴/分钟覆盖成人常见输液速度滴速控制精度目标值±5滴/分钟蠕动泵为开环/半闭环控制报警响应时间信号异常后2秒内主循环轮询中断配合流量换算精度≤10%误差默认20滴/mL可校准系统供电5V USB供电电机外置12V独立电源这些指标的设定是有讲究的。滴速下限10滴/分钟对应的信号频率只有约0.17Hz信号变化极慢如果软件滤波器参数没调好很容易把有效信号滤掉。上限150滴/分钟虽然在成人输液场景不常见但在某些药物快速滴注场景下会出现预留余量比较稳妥。报警响应2秒这个指标靠单纯的主循环轮询很难保证所以滴速检测必须走中断而报警判定逻辑可以放在主循环里轮询只要中断记录的数据够新、主循环执行够快2秒内响应完全可行。3. 硬件设计原理图里的关键电路与选型逻辑这一节是很多人拿到开源工程后最容易看不懂的部分。我尽量把每个核心电路的原理和参数选择依据讲透让大家不只是抄图而是理解为什么这么画。3.1 主控选型与最小系统设计主控选择STM32F103C8T6原因很直接资源够用、价格便宜、资料海量、竞赛和课设里用的人多遇到问题容易找到人问。64KB Flash跑这套代码绰绰有余20KB RAM也完全够用不用担心资源瓶颈。最小系统里要注意的是复位电路和时钟电路。复位脚接10kΩ上拉电阻到3.3V、100nF电容到地这是标准接法确保上电复位可靠。晶振我用的8MHz无源晶振两个20pF负载电容布局时尽量靠近芯片OSC_IN和OSC_OUT引脚走线短而粗别在晶振下方走高频信号线。另外特别提醒一点BOOT0引脚必须接10kΩ下拉电阻到地保证从Flash启动。这个电阻漏画或者虚焊会导致芯片无法正常启动很多人拿到板子发现程序烧不进、跑不起来排查半天结果是BOOT0悬空这种低级错误真的很浪费时间。3.2 滴速检测电路红外对管的信号调理滴速检测是整个系统最关键的传感器部分。我选的是对射式红外对管发射管和接收管分别放在滴壶两侧液滴从中间落下时会遮挡红外光线接收管导通状态发生改变从而产生脉冲信号。但红外接收管的输出信号不能直接进STM32的GPIO。原因有两个一是信号边沿不够陡峭二是幅值可能不在TTL电平范围内。所以必须加信号调理电路我用了LM393比较器做整形接收管集电极接3.3V发射极接10kΩ电阻到地形成分压输出分压输出接LM393的同相输入端反相输入端接一个10kΩ电位器的抽头用于调节比较阈值LM393输出端接10kΩ上拉电阻到3.3V输出经RC滤波后进STM32的PA0这个阈值调节很关键。滴壶挂壁、环境光线变化、不同批次的滴管透光率差异都会让信号幅值漂移。用一个电位器预留调节空间比固定电阻可靠得多。3.3 电机驱动与电源隔离蠕动泵我选的是12V微型蠕动泵工作电流约300mA这个级别用DRV8871或L298N都行。我的原理图里用的是DRV8871理由比较简单单H桥、内阻小、带电流限制封装也比L298N小很适合这种只做单向调速的场合。这里有一个很重要的设计原则电机电源与主控电源必须分开供电只共地不能共用同一路电源。蠕动泵启动瞬间的电流冲击会导致电压跌落如果主控和电机共用电源轻则ADC采样跳变重则看门狗复位、系统重启。我见过太多人在这上面栽跟头。具体做法系统提供两个电源输入接口一个是5V USB给主控板和OLED供电经过AMS1117-3.3降压到3.3V给STM32和外设另一个是12V直流电源单独给蠕动泵供电两者在PCB上通过单点共地连接。3.4 液面检测与报警电路液面检测用的是光电传感器放在滴壶下端输液管位置。当管内没有液体时传感器输出高电平有液体时输出低电平。这个信号接PA1配置为外部中断触发下降沿报警。这比在主循环里轮询更及时液面过低时能在几百毫秒内触发停机。报警电路用有源蜂鸣器NPN三极管S8050驱动基极串1kΩ电阻接PA2。LED灯接PA3和PA4分别指示滴速异常和液面过低。注意蜂鸣器必须是续流二极管保护的那种或者自己在蜂鸣器两端反并联一个1N4148防止关机瞬间的感应电动势击穿三极管。4. 软件架构状态机中断驱动的裸机方案软件设计上我没有用RTOS。这套系统的实时性要求主要集中在滴速检测和报警响应上用裸机中断完全能够满足还能减少系统复杂度和排查难度。工程代码基于STM32标准外设库用Keil MDK 5编译调试。4.1 系统状态机设计整个系统运行在四个状态之间切换状态说明入口动作退出条件SYS_IDLE待机OLED显示待机画面按下启动键SYS_RUNNING正常输液开启滴速检测和蠕动泵按下停止键或出现异常SYS_ALARM报警停机蜂鸣器响、LED亮、蠕动泵停按下复位键SYS_CALIBRATE滴速校准收集30秒实际滴数校准完成自动返回这个状态机的好处是逻辑清晰。刚开始写代码时我直接在主循环里堆逻辑结果耦合度越来越高改一个功能旁边两个功能跟着出错。后来重构为状态机之后每个状态下要做什么、什么时候跳走一目了然后续加功能也只需要在状态表里加一项。4.2 滴速检测中断计数主循环计算滴速检测的实现思路是红外对管输出脉冲接到PA0配置为外部中断下降沿触发。每次下降沿代表一滴液体落下中断处理函数里做两件事滴数计数器加一记录当前时间戳。主循环里每1秒读取一次滴数计数器计算最近15秒内的平均滴速公式如下滴速滴/分钟 (15秒内滴数 / 15) × 60这个计算周期选15秒是有权衡的。太短比如3秒滴速波动大瞬时值跳动明显控制算法容易误判太长比如30秒响应迟钝滴速突变时要等很久才能察觉。15秒在灵敏度和稳定性之间取了中间值实测下来控制效果比较平滑。中断处理函数里还有一个防抖逻辑如果相邻两次滴数间隔小于60毫秒直接丢弃这一次计数。为什么因为红外信号通过比较器整形后边沿仍然可能有毛刺抖动一个真正的液滴不会在60毫秒内连续落下两滴这个时间窗口能有效滤掉噪声。4.3 蠕动泵控制Bang-BangPID混合调速蠕动泵调速是软件里最能体现控制思维的部分。我采用的策略是Bang-Bang控制和PID控制结合按偏差大小分档切换。当实测滴速偏离目标值超过10滴/分钟时用Bang-Bang快速追平实测偏慢就加大PWM占空比偏快就减小占空比每次调整幅度较大让滴速尽快回到目标附近。当偏差小于10滴/分钟时切换到比例控制PI控制器用一个较小的比例系数Kp和一个消除稳态误差的积分系数Ki来微调PWM占空比。之所以不全程用PID是因为增量式PID的积分项在偏差大时容易积分饱和导致超调严重Bang-Bang在这种场景下更直接高效。PWM输出频率我选的10kHz。蠕动泵是直流电机PWM频率低了会有明显的咔咔声而且转速波动大10kHz既能避开人耳敏感区又不会因为频率过高导致驱动芯片开关损耗过大。PI参数的整定我走了不少弯路最后用的方法是先把Ki设为0只调Kp从小往大加直到滴速出现约2-3滴/分钟的轻微振荡然后回退一点再加入Ki从0开始往上加直到稳态误差消失且不出现持续振荡。调试记录显示最终Kp取0.8、Ki取0.05时滴速能在15-20秒内收敛到目标值附近。4.4 OLED显示与按键交互显示部分用0.96寸I2C接口OLEDSSD1306方案驱动IC非常成熟。我用的是软件I2C模拟没用硬件I2C原因是硬件I2C在F103上有时候会因为时钟延展问题出现通信卡死软件模拟虽然CPU占用高一点但胜在稳定可靠。OLED显示的内容分两屏第一屏显示目标滴速、实测滴速、运行状态第二屏显示累计液量滴数换算和系统电压。两屏通过按键KEY1切换。按键处理必须做消抖。我采用的是10毫秒软件延时消抖状态机检测的方式按键按下后延时10ms再检测电平状态确认稳定后再判断是短按还是长按。短按用于切换屏幕长按用于启动/停止系统。这个交互逻辑虽然简单但用起来手感确实不错没有误触发的烦恼。5. 控制精度与参数标定20滴/mL到底靠不靠谱做输液系统绕不开一个基础换算问题多少滴等于1毫升我在代码里默认写的是20滴/mL这是大多数输液器的标准规格但实际使用中不同品牌、不同批次的输液器滴径不同这一换算关系可能偏移到15-25滴/mL。这个问题不解决系统的累计液量显示就没有意义。我加的解决方案是校准模式在系统停止状态下长按按键进入校准此时系统会提示用户通过按键手动滴液累计30滴然后按确认键代码用30滴除以实际液量得到真实的滴/毫升系数存储到Flash中。这样每次更换输液器品牌后校准一次即可保证液量显示准确。另一个与精度相关的问题是滴速检测的起始时刻。刚启动时滴壶内的液体可能还没有形成稳定液滴前几秒的检测结果波动很大。我的处理方式是启动后先进行3秒的稳定等待期间不计滴速但保持蠕动泵以设定的基础占空比运行之后才开始正常检测和控制。这个细节看似不起眼但对控制收敛速度影响很大。6. 仿真验证Proteus在系统逻辑调试中的实战用法硬件打样之前先用Proteus把整个系统的逻辑跑一遍能省掉大量的硬件调试时间。很多人觉得仿真没用认为仿真过了实物也不一定行这说法有道理但不全面——仿真的目的不是验证硬件可靠性而是验证逻辑和算法正确性。6.1 仿真工程的核心搭建思路Proteus里搭建这套系统的关键点在于STM32F103C8T6模型是现成的但红外对管、蠕动泵这类物理传感器和执行器没有对应的仿真模型怎么处理我的办法是信号模拟用Pulse Generator脉冲发生器模拟红外传感器的输出脉冲频率对应滴速用示波器观测PWM波形用电压表监测电机驱动端的占空比变化。这样一来滴速检测、PID调速、报警逻辑全都能在仿真里验证。具体参数设置如下脉冲发生器初始频率设为1Hz对应60滴/分钟用于模拟正常滴速目标滴速设为40滴/分钟让系统处于需要减速的状态验证控制逻辑运行过程中手动把脉冲频率改为0.5Hz对应30滴/分钟观察系统是否输出报警6.2 仿真帮我抓出的两个逻辑Bug这套仿真流程不是走过场确实帮我发现了两个实物调试时很难发现的逻辑问题。第一个Bug液面报警与滴速检测的优先级冲突。原本的设计是液面传感器触发时系统直接进入报警停机状态。但在仿真中发现如果液面传感器误触发比如输液管晃动导致光路短暂遮挡系统会误报警停机。最后在状态机里加了液面低信号持续2秒才触发报警的防抖逻辑效果很好。第二个Bug累计液量在报警停机状态下仍然累加。因为滴数计数用的是外部中断而报警停机时并没有把中断关闭导致停机后滴壶里的残余液体滴落时液量还在增加。修正方案是在进入报警状态时显式关闭滴速检测中断退出报警并复位后才重新开启。6.3 仿真的局限性和实物调试的必要性说句公道话Proteus仿真在时序方面的表现和真实硬件存在不少差异。仿真模型不会模拟引脚驱动能力、信号完整性和电源纹波也不会模拟电机启停带来的电压跌落。所以仿真只能验证软件的流程正确性不能验证硬件可靠性。我的建议是仿真阶段把数据流理清楚确保各种输入组合下系统状态转移正确实物阶段专心调信号质量和电源稳定性。两者配合开发效率最高。7. 实物调试全流程从串口打印到闭环调速的调通记录拿到打样好的PCB后调试过程我分了三个阶段每个阶段都有明确的验证目标和退出标准。7.1 板级验证最小系统和外设逐一跑通第一步是烧录一个最简单的LED闪烁程序确认最小系统工作正常。然后逐个验证外设OLED能显示、按键能读取、蜂鸣器能响。这个阶段最大的收获是发现了一个PCB封装问题——OLED排针孔位画反了飞线解决后才点亮屏幕。然后是红外检测模块的调试。把示波器探头接到比较器输出端用手在红外对管中间快速划过观察是否有方波脉冲输出。实际调的时候发现一个问题阈值电位器拧到不同位置信号的占空比变化很大但边沿始终不够陡峭。后来在比较器输出端加了一个100nF的电容对地滤掉了高频噪声信号才干净起来。7.2 开环调试蠕动泵的PWM-转速关系测定在接PID控制之前先做了一组开环测试测定不同PWM占空比下蠕动泵的实际转速换算成滴速。数据记录如下PWM占空比实测滴速滴/分钟30%1250%2870%5590%96这组数据说明PWM占空比与滴速之间基本呈线性关系只是低速段有死区占空比低于25%时泵几乎不转。这个特性对控制算法的意义在于最小控制输出不能低于25%否则蠕动泵堵转电机发热严重。这段数据也让我确认了另一个问题蠕动泵的启动阻力大于运行阻力从静止直接给定低占空比泵往往转不起来。解决方法是启动阶段用60%占空比强制启动1秒然后回落到目标占空比。这个启动冲击逻辑放在状态机的RUNNING状态入口处。7.3 闭环调试PID参数整定的实际效果开环数据测完之后开始跑闭环控制。实际滴水测试中我设置目标滴速为50滴/分钟观察系统从启动到稳定的完整过程启动瞬间蠕动泵以60%占空比启动滴速快速爬升5秒后实测滴速达到45滴/分钟Bang-Bang控制介入占空比回落到40%12秒后实测滴速冲到接近60滴/分钟出现约15%的超调20秒后PI控制器把滴速拉回并稳定在50滴/分钟左右这个收敛过程虽然不是教科书级别的优雅但应用在输液场景已经足够了——病人不会因为滴速在20秒内波动10%而受影响稳定后的精度能满足±5滴/分钟的要求。8. 踩坑记录那些最容易让人抓狂的疑难问题实物调试过程中踩了不少坑挑几个典型问题分享出来。这些问题不看实际调试经验根本想不到写在这里希望能帮大家避开。8.1 红外对管的瓶中信式误检红外对管装好后发现一个诡异现象系统运行几分钟后滴速读数开始大幅波动有时候能飙到200滴/分钟以上完全不符合实际。排查过程先怀疑是传感器硬件问题换了新的红外对管故障依旧然后怀疑是电路干扰加了去耦电容也没有明显改善。最后用示波器长时间观察比较器输出端才发现波形间歇性出现一串高频脉冲持续时间几百毫秒。根因找到了输液管壁上残留的水滴会反射红外光线。液滴落下时主液滴划过光路产生了正确的脉冲但管壁上附着的小水珠会在主液滴之后慢慢滑落每滑过光路一次就产生一次错误的脉冲。这不是硬件问题也不是软件问题而是物理安装角度问题。解决办法调整红外对管的安装高度和角度让光路的焦点对准滴壶中心液滴下落的位置避开管壁边缘区域。同时在软件里把防抖窗口从60毫秒加大到150毫秒进一步过滤高频误检。8.2 蠕动泵启停导致的系统复位另一个高频问题系统在启动蠕动泵的瞬间经常复位表现为OLED闪一下、滴速计数器清零。用万用表实测发现泵启动瞬间电源电压从5.0V跌落到3.8V持续时间约80毫秒。这个问题的根因在电源布局。为了节省空间我一开始把电机电源和控制电源设计在同一块板子上结果电机驱动的高频开关噪声通过地平面传导到了主控电源域。解决方案分两步走硬件上把电机驱动部分的地分割成独立区域通过单点连接到主控地在电机电源输入处加大容量电解电容470μF/25V吸收启动瞬间的大电流冲击。软件上在电机启动前延迟50毫秒避免电机启动和系统上电同时进行。8.3 Keil5工程配置中的两个隐形陷阱代码编译调试过程中还遇到两个工程配置层面的问题。第一个问题是printf重定向无效。在Keil中使用MicroLIB时需要重写fputc函数才能把printf输出重定向到串口。但有时候即使步骤做对了还是不输出最后发现是因为忘记了勾选Use MicroLIB选项。这个选项藏在魔术棒工具条的Target标签页里不勾选的话即使写了fputc重定向也不会生效。第二个问题是变量被优化导致调试观测不到。默认优化级别-O0不会有什么问题但为了减小Flash占用改成-O2后有些局部变量的值在调试器里显示为optimized out。排查这类问题的办法是在关键变量前加volatile修饰或者把优化级别改回-O0进行调试。8.4 滴速偏差越来越大别忘了输液管磨损这是一个很隐蔽的长期问题系统连续运行几个小时后滴速会逐渐偏离目标值而且调大PWM占空比也拉不回来。原因分析蠕动泵是通过滚轮挤压硅胶管来输送液体的长时间运行后硅胶管的弹性和内径都会发生变化导致单滴体积轻微增大同样的滴速下实际流量反而偏大。换句话说系统显示的滴速和实际流速之间的换算关系在慢慢漂移。这个问题目前没有一个完美的实时解决方案因为要实时测量单滴体积需要额外的重量传感器或者流量计。在现有成本约束下我的处理方式是增加一个运行时长提醒功能系统连续运行超过4小时后OLED提示建议更换输液管并重新校准。这个提醒虽然简单但能有效避免长时间运行带来的精度漂移问题。9. 开源资料导航代码结构、原理图与仿真工程怎么用最后这部分写给拿到开源工程但不知道怎么下手的读者。我把整个工程的目录结构和每个文件的作用讲清楚方便大家快速定位自己需要的部分。9.1 工程目录结构与关键文件说明STM32_Infusion_System/ ├── Doc/ │ ├── 硬件设计说明.md │ ├── 软件设计说明.md │ └── 调试记录.md ├── Hardware/ │ ├── Infusion_System.SchDoc // AD原理图 │ ├── Infusion_System.PcbDoc // AD PCB │ └── BOM表.xlsx // 元器件清单 ├── Simulation/ │ ├── Infusion_System.pdsprj // Proteus仿真工程 │ └── Readme.txt // 仿真使用说明 └── Software/STM32F103C8T6/ ├── Core/ │ ├── Inc/ │ └── Src/ ├── Drivers/ │ ├── CMSIS/ │ └── STM32F1xx_HAL_Driver/ ├── App/ │ ├── main.c // 主函数和状态机 │ ├── dripsensor.c/.h // 滴速检测模块 │ ├── motor.c/.h // 蠕动泵控制模块 │ ├── display.c/.h // OLED显示模块 │ ├── key.c/.h // 按键处理模块 │ ├── alarm.c/.h // 报警模块 │ └── calibrate.c/.h // 滴速校准模块 └── MDK-ARM/ // Keil工程文件9.2 快速上手三步走拿到工程后不建议一上来就看全部代码按下面的顺序走效率最高第一步先打开Doc目录下的硬件设计说明.md配合Hardware目录里的原理图把电源域、信号流向、各模块接口引脚理清楚。同时对照BOM表采购元器件这个PCB设计的是双面板嘉立创打样价格很低新手也能直接做。第二步打开Simulation目录下的Proteus仿真工程先跑通仿真再碰实物。仿真里我预留了几组测试场景正常滴速、滴速超限、液面过低拨动仿真里的开关就能验证报警逻辑。仿真跑通后对系统的整体工作方式就有了直观认识。第三步有了仿真基础后再打开Keil工程编译烧录到实物上。实物调试从LED灯和OLED显示开始逐步点亮外设最后再联调闭环控制。9.3 如何把这套代码移植到自己的项目里很多人拿开源工程是为了改装成自己的作品。这套代码的外设驱动和应用逻辑分层比较清晰复用起来很方便。如果只需要滴速检测显示功能只需要复制dripsensor.c、display.c、main.c中的状态机框架去掉电机控制部分即可。如果你的项目用的是STM32F407或者其他F1系列芯片HAL库驱动的引脚配置重新映射一下就行核心算法代码完全不用改。如果你用的是其他MCU平台比如GD32、AT32由于它们大多兼容STM32的引脚定义和库函数接口移植成本也很低。唯一需要重新适配的是HAL库底层应用层代码基本可以无缝迁移。10. 写在最后这套系统的局限与后续扩展方向项目做到这个程度基本达到了我最初设定的目标低成本、可复现、逻辑清晰。但我也得坦率地讲这套系统距离能直接进临床使用还有很长的路要走。核心的局限有三个。一是蠕动泵本身是开环执行器没有位置反馈长时间运行后精度必然漂移这也是为什么必须加校准功能二是红外检测方式对安装角度、环境光、输液管材质比较敏感实际使用中对安装要求比较高三是报警逻辑目前只区分了滴速异常和液面过低没有覆盖气泡检测、堵针检测等更复杂的临床场景。如果后面继续迭代我觉得比较有价值的扩展方向包括加入DS18B20温度传感器监测药液温度增加无线模块如ESP8266或HC-08蓝牙把输液状态上报到护士站后台引入步进电机驱动的蠕动泵实现精确的流量控制在外观结构上做一体化外壳设计把传感器和泵体集成到一个可快拆的模块里方便消毒和更换。最后再分享一个小经验很多人做这种项目总想把功能堆得多多的但我做下来最大的收获反而是减法——把每一个功能做扎实比堆砌十个功能却没几个好用要有价值得多。这套系统最终砍掉了语音播报、触摸屏这些锦上添花的东西留下来的都是每一行代码都经得起推敲的核心功能。如果你也在做类似的嵌入式项目希望这套开源的实现过程能给你一些参考。