
1. 这个输液监护系统到底解决了什么问题说实话第一次在医院看到输液大厅那个场景我就觉得这事儿值得做。几十号病人同时挂着吊瓶护士站到病床的距离少说几十米病人液体输完了只能按铃家属盯着吊瓶盯到脖子发酸。最要命的是输液速度漂移这事几乎没人管——病人手臂动一下、液面高度变化、室温变化滴速就会慢慢跑偏护士忙起来根本不可能每隔几分钟去数一次滴速。市面上的输液监护仪不是没有但大多是“监测报警”的思路发现滴速不对只会叫唤不会自动纠正。我这次开源的这套系统核心就一个词闭环调控。它不仅能实时测出当前滴速还能自动把滴速拉回到设定值发现气泡、液面过低、堵管这类异常情况时报警并主动处置。说白了前一代项目只解决“看得见”这个升级版解决的是“管得住”。整个系统的工作链路是这样的红外对管传感器贴在茂菲氏滴管两侧液体滴落时遮挡光路产生脉冲信号STM32F103C8T6捕获这个脉冲算出实时滴速然后和用户设定的目标滴速比较用PID算法输出控制量驱动步进电机转动改变输液管路阻断装置的压紧程度从而调节流速。同时系统监测管路里的气泡信号和滴空信号一旦异常声光报警并自动关断执行机构。这个项目适合谁个人觉得有三类人强烈推荐复现做嵌入式课程设计/毕业设计的学生这个课题横跨传感器、电机驱动、闭环控制、人机交互答辩时能讲的东西非常多想从裸机开发往“带控制算法”方向走的嵌入式爱好者这套代码把PID和定时器中断的配合写得非常直白还有准备参加电子设计竞赛的队伍这套系统的传感器选型和异常处理链路可以直接改造成竞赛作品的基础框架。产出方面代码我全部开源包含标准库版和HAL库版两套工程原理图用立创EDA绘制导出了PDF和源文件仿真工程基于Proteus 8.15搭建可以直接加载hex文件跑起来看效果。下面我把设计过程中的关键取舍、踩过的坑、算法细节一个个说清楚。2. 硬件架构选型为什么是这些模块和芯片2.1 主控为什么还用STM32F103C8T6可能有人觉得搞个新项目不应该上F4或者H7吗我在这个项目里依然选了STM32F103C8T6理由很实在。第一成本。这个芯片目前几块钱一片打样一版核心板加传感器、电机驱动整套物料成本控制在60块钱以内学生党完全能承受。第二外设资源够用。这套系统用到的外设无非就是定时器输入捕获、PWM输出、GPIO中断、I2C/SPI驱动屏幕、串口打印调试F103C8T6的72MHz主频和这些外设跑这套逻辑绰绰有余没必要为了炫技上高性能芯片。第三生态成熟。不管是标准库还是HAL库资料满天飞遇到问题搜一下就有答案Proteus对F103的仿真支持也最完善。不过我要提醒一点F103C8T6的Flash只有64KBRAM只有20KB。如果你后续要加RTOS、加字库、加更复杂的界面空间会有点紧张。我这个工程开了O2优化之后代码量大概在28KB左右余量还是有的。但如果想扩展建议提前考虑换成F103RCT6或者F407引脚兼容性上要重新核一遍。2.2 传感链路滴速检测、气泡检测、滴空检测的选型逻辑这套系统一共用了三路传感信号很多人搞混它们的作用我先把职责理清楚。滴速检测用的是红外对管型号是常见的ST188或者ITR8102。原理非常简单红外发射管持续发光接收管导通状态下输出低电平液体滴落经过光路时光线被折射和遮挡接收管截止输出变成高电平。每滴液体产生一个脉冲单片机捕获脉冲边沿就能数滴。这里有一个关键选型问题——对射式和反射式怎么选我强烈建议用对射式发射管和接收管面对面夹在滴管两侧光路是直线遮挡信号干净利落。反射式要靠液滴反射红外光对安装角度和滴管透光度极其敏感我一同事在类似项目里用反射式调试了两周最后换了对射式两天就稳定了。气泡检测的方案选择上工业上常用超声波或电容式但成本对开源项目不友好。我用的思路是在输液管靠近针头的那段管路上再装一组对射式红外管液体中有连续液柱时光路被均匀液体折射接收信号是一个相对稳定的中间电平一旦有气泡经过气泡和管壁的界面会改变光线传播路径接收信号出现明显跳变。用ADC采样这个模拟量连续检测到多次跳变就判定为有气泡。这个方案成本几乎为零但需要做比较精细的阈值标定后面软件章节我会详细说。滴空检测相对简单。滴速传感器本质上也能感知滴空——滴管里没有液体落下时滴速脉冲就消失了。但如果只靠“没有脉冲”来判断滴空反应时间取决于滴速假如当前滴速只有每分钟20滴要等几秒钟才能确认。所以我在药液瓶出口的滴管上方加了一路液位检测选用小型浮子式液位开关或者另一组对射光路液面低于设定阈值立刻触发信号比等滴速消失快得多。2.3 执行机构步进电机加阻断装置能把滴速“管住”的部件是步进电机驱动的管路阻断装置。它的原理和医院输液泵里的滑块夹持机构一致步进电机通过丝杆或者凸轮带动一个压块压块向下压输液管管路的横截面积变小流速随之下降。压得越紧流速越小完全压死就是阻断。为什么用步进电机而不是直流电机加编码器三个原因。第一步进电机可以开环精确控制位置一个脉冲对应固定角度通过计算丝杆导程就能换算压块的位移量不需要额外的位置传感器。第二步进电机有保持力矩在某个位置停下后即使管路回弹力比较大都顶不动它这样压紧程度可以长时间稳定。第三堵转时不会烧毁电机前提是驱动电流设置合理只是丢步方便我做保护逻辑。驱动方案我用的是ULN2003加28BYJ-48减速步进电机。很多人嫌弃28BYJ-48转速慢、噪音大但在这个场景下反而是优点——因为控制的是微流量滴速校正只需要压块做极小范围的位移慢速意味着精细加上减速比带来的大力矩压管动作很可靠。如果你想用更安静的方案推荐换成42步进电机加A4988驱动我代码里把步进控制封装成了接口换驱动只需要改底层函数控制逻辑不用动。2.4 人机交互与电源设计的几个细节人机交互方面我保留了最简单的组合4个独立按键加、减、启动/暂停、模式切换一块0.96寸OLED显示屏一个有源蜂鸣器。显示屏用I2C接口占用资源少显示当前滴速、目标滴速、累计液滴数、报警状态。蜂鸣器用三极管驱动注意要给基极串联一个限流电阻直接接GPIO拉不动。电源设计是很多新手容易翻车的地方。整套系统的供电链是12V适配器给步进电机驱动供电同时经过MP1584降压模块输出5V给单片机和传感器OLED和其余逻辑器件用AMS1117-3.3从5V转换。这里有两个关键点一是12V和5V、3.3V的GND必须共地否则传感器信号和单片机之间没有参考电平信号会乱跳二是每个芯片的电源引脚旁边必须放0.1uF去耦电容并联一个10uF钽电容特别是步进电机启停瞬间母线上会有明显的电压跌落不加去耦电容单片机偶尔会复位。原理图里我把这些电容都标出来了打板时别省。3. 软件实现的几个关键模块3.1 时间基准与任务调度这套系统的软件没有上RTOS一是没必要二是裸机配合定时器中断可以让核心逻辑更透明。我用TIM2做1ms时基中断在这个中断里做三件事按键扫描去抖、显示刷新计时、控制周期计时。滴速检测用TIM3的输入捕获通道捕获上升沿并记录计数值PWM输出用TIM4产生步进电机的脉冲序列。任务调度的思想是“主循环加标志位”。1ms中断里只置标志、不做耗时操作主循环检测到标志后再执行对应任务。比如每10ms扫描一次按键每100ms刷新一次屏幕每500ms计算一次滴速每1s执行一次PID调节。这样划分的好处是实时性要求高的滴速捕获由硬件中断保证而显示这类耗时操作不会阻塞关键路径。这个分层思路在很多嵌入式项目里都能复用。3.2 滴速检测的防抖与滤波滴速计算的核心公式很直白滴速滴/分钟 60秒 / 两滴之间的时间间隔秒如果两滴间隔0.5秒滴速就是120滴/分间隔2秒就是30滴/分。所以只要准确测得相邻两个上升沿的时间差就能实时换算出滴速。但直接测单次间隔的问题在于抖动。液滴下落时偶尔会有一滴很小、或者管路晃动导致光路被半遮挡产生毛刺脉冲。如果直接拿单次间隔算滴速显示值会来回跳病人可能看到屏幕上滴速在120和90之间乱摆。我的处理办法是滑动窗口平均维护一个长度为8的环形缓冲区每来一个新间隔就把旧值覆盖掉滴速取这8个数据的平均值。实测下来即使有个别抖动显示值也很平稳。还有一个必须处理的问题是边沿消抖。液体滴落的遮挡信号不是一个理想的方波而是有一个缓慢的过渡过程。我在输入捕获中断里只对上升沿计数但在软件里加了一个最小间隔判断——如果两次上升沿间隔小于50ms就判定为毛刺信号直接丢弃。因为正常的液滴滴落间隔至少是300ms以上50ms以内的脉冲不可能是真液滴。3.3 气泡识别与异常分级气泡检测是这套系统里安全等级最高的模块。我没有简单地用“检测到跳变就报警”因为输液管壁上的微小气泡或者管路抖动也会引起信号波动误报比漏报更烦人——护士被折腾几次就会把报警器关了那才是真正的安全隐患。我的算法分三层。第一层是模拟量滤波用滑动平均滤掉高频噪声。第二层是状态判断记录正常液流时的ADC基础值然后实时检测信号偏离基础值的幅度和持续时间。如果偏离超过设定阈值且持续200ms以上才判定为疑似气泡。第三层是确认机制连续出现3次疑似气泡事件才会触发真正的气泡报警。这个三层判断在实测中几乎没有误报。异常处置我分成三个等级。一级警告滴速偏差超过设定值20%蜂鸣器响三声屏幕提示“滴速偏移”但系统继续自动调节不干预。二级报警检测到气泡或滴速偏差超过50%声光报警持续响系统自动加大压紧程度限制流量。三级紧急检测到滴空或者完全堵管系统立刻完全压紧管路、停止电机、持续声光报警直到人工按键确认解除。分级处理的好处是避免所有异常都一刀切护士可以按轻重缓急响应。3.4 增量式PID闭环控速这是升级版和基础版最大的分水岭。基础版的“调速”是人工按键调整电机角度本质上还是在手动。升级版实现了自动闭环把目标滴速和当前滴速的偏差交给增量式PID输出值是电机需要调整的脉冲步数。先用公式把增量式PID讲清楚。设当前偏差为e(k)上一次偏差为e(k-1)上上次为e(k-2)则增量输出Δu(k) Kp × [e(k) - e(k-1)] Ki × e(k) Kd × [e(k) - 2e(k-1) e(k-2)]这个Δu表示电机的调整步数正数表示压紧一点负数表示放松一点。之所以用增量式而不是位置式是因为增量式只输出变化量即使PID系数整定得不够完美也不会造成电机角度飞掉安全性更好。而且增量式天然自带积分限幅不容易产生深度饱和。参数整定方面我实测下来给出了一个比较稳妥的起点Kp0.8Ki0.1Kd0.2控制周期1秒。以60滴/分为目标系统从启动到稳定大约需要10秒左右稳定后误差在±2滴/分以内。如果发现系统振荡优先减小Kp如果发现响应太慢适当增大Ki。我一直认为PID参数一定要在实物上跑过才算数仿真里的参数只能当参考因为步进电机的细分、丝杆的阻力、管路的弹性都会影响实际响应。另外我加了两个保护逻辑。一是输出限幅电机每次调整最多15步防止单次修正过猛把管路瞬间压死。二是死区控制当偏差在±1滴/分以内PID输出强制为零避免电机在目标值附近反复微调、来回抖动。这两个细节在仿真里看不出来在实物上作用非常明显。4. Proteus仿真复现从零搭环境的操作与坑4.1 仿真工程的搭建我用的Proteus版本是8.15这个版本对STM32F103C8T6的支持很成熟。新建工程时芯片选择“STM32F103C8T6”注意要把VDD、VSS、VDDA、VSSA这些电源引脚全部连接上很多人在原理图里漏接网络标签导致仿真时芯片完全不工作。时钟配置是仿真里非常关键的一步。在Proteus里STM32默认用内部HSI时钟但我的代码里配置的是外部8MHz晶振加PLL倍频到72MHz。如果仿真电路里没有放置晶振或者晶振参数设置不对程序启动时会卡在时钟初始化里。我的做法是在仿真原理图上放置一个8MHz晶振并在属性里把“Clock Frequency”设置为8M同时确保两个负载电容选择了20pF。4.2 传感器和电机在仿真里的模拟方法Proteus里没有现成的茂菲氏滴管传感器模型我是用脉冲信号发生器来模拟滴速信号的。用一个“Pulse Generator”产生周期可调的方波输出接到单片机的PA0滴速捕获引脚方波的频率直接对应滴速。比如要模拟60滴/分就把脉冲周期设为1秒模拟120滴/分周期设为0.5秒。注意这里有一个细节Proteus的脉冲发生器默认输出范围是0到1V而STM32的GPIO识别高低电平需要0.3×VDD以下为低、0.7×VDD以上为高3.3V供电时高电平阈值约2.31V。所以必须把脉冲发生器的幅值设为3.3V否则单片机的输入捕获根本触发不了。这个问题我见过不少人踩现象就是仿真死活不进中断。步进电机在仿真里直接用“MOTOR-STEPPER”模型驱动端接ULN2003模型和我实物电路完全一致。但仿真电机只能观察是否在转无法模拟真实的管路阻力。为了验证闭环控制逻辑我在仿真里用了一个“Gauge”元件实时显示电机的角位置再通过一个自定义的信号回调来改变滴速脉冲的频率——这样可以模拟“电机压紧管路导致滴速下降”的物理过程。这个技巧比较进阶代码仓库里我写了一个说明文档。4.3 固件加载与调试手段Proteus仿真加载程序有两种方式。第一种是直接加载hex文件在STM32芯片属性里找到“Program File”选择编译生成的hex即可运行。第二种是联合调试模式把Keil配置成Debugger为“Proteus VSM Simulator”可以在Keil里断点调试观察变量。我建议先用第一种确认整体流程跑通再切到第二种深入调试算法。调试手段上我强烈推荐在代码里多留几个“软件探针”。比如在滴速计算完成处把一个全局变量赋值然后在Proteus里通过“Virtual Terminal”或者“Virtual Oscilloscope”观察。我习惯把PID输出值和当前滴速分别映射到两个PWM引脚用虚拟示波器看波形能直观看到系统是否振荡。这个经验在实物调试时同样适用逻辑分析仪拉出来的波形非常清晰。4.4 仿真里最容易被忽略的三个问题第一个是芯片的“Low Speed External Clock”属性。Proteus默认识别的是HSE如果代码里用的是LSI或者LSE需要额外配置。我这套代码全部用的HSE所以这个配置保持一致即可。第二个是复位电路。仿真模型虽然不像实物那样必须要有上电复位但没有复位电路时偶尔会出现程序已经运行但外设状态不对的怪现象。我习惯在NRST引脚接一个RC复位电路虽然仿真模型不一定严格模拟但可以避免玄学问题。第三个是电源网络标签的名称必须完全一致。Proteus对网络标签大小写敏感我在原理图里用“VCC_3V3”代码或者其它模块里写成“VCC_3v3”仿真就会报错。这些问题看起来琐碎但排查起来非常耗时建议从一开始就用统一的命名规范。5. 实测效果、调试踩坑与二次开发建议5.1 实测数据与精度表现我在自己搭的测试平台上做了一组数据使用生理盐水配合输液器标准管路设定值从20滴/分到120滴/分每档运行5分钟取平均滴速设定滴速滴/分实测平均滴速滴/分偏差稳定时间秒20211约124039-1约1160611约108078-2约91001011约8120118-2约8整体来看闭环稳定后的误差控制在±2滴/分以内这个精度满足临床输液的一般要求。从启动到稳定的时间大约10秒因为管路弹性形变需要一些时间来响应电机位移。如果通过增大Ki可以缩短稳定时间到6秒左右但代价是超调量会变大考虑到输液场景的容错性我倾向于接受稍慢的响应换取更平稳的控制。5.2 高频误触发的排查链路调试过程中让我最头疼的问题是滴速传感器偶尔会高频误触发。现象是屏幕上的滴速时不时飙升到四五百然后又恢复正常。一开始我怀疑是红外对管受到环境光干扰于是加了遮光罩但问题依旧。后来用示波器挂在传感器输出端发现在液体滴落瞬间信号确实有一个干净的高电平脉冲但随后会出现一串衰减振荡幅度不足以完全穿过阈值却能偶尔触发单片机的输入捕获。排查链路是这样的先用示波器确认传感器输出波形发现低压侧的噪声不足以触发GPIO中断再用万用表测量传感器和单片机之间的地线压差发现两端地之间约有0.3V的浮动最后用逻辑分析仪对比电机驱动PWM信号和传感器输出信号确认传感器输出的振荡出现在电机换相瞬间。根因就是步进电机的脉冲电流通过地线回流在地线上产生噪声叠加到传感器信号上。解决办法有两步第一步在传感器供电端加100nF去耦电容并单独走线到主电源地第二步软件里把最小间隔判定从50ms放宽到100ms等于加了一道软件滤波器。双重处理之后这个故障就彻底消失了。这个案例我想多说一句排查硬件问题时不要一开始就怀疑程序也不要一开始就怀疑传感器。先做信号隔离把传感器输出接到示波器上看真实波形很多问题一眼就能看出答案。5.3 步进电机“卡死”的边界处理步进电机在管路已经完全压死时如果还在输出正转脉冲就会发生堵转。堵转时间长了会掉转矩、产生噪音严重的还会让电机驱动芯片过热。最开始我的代码里没有堵转检测有次调试时电机堵转了一分多钟ULN2003芯片烫到手不敢摸。加上堵转检测后逻辑就安全多了。检测原理很朴素电机每次收到正转脉冲后滴速应该在一定时间内开始下降如果连续5个控制周期输出正转步进但滴速没有任何变化就判定为堵转立即停止电机并进入“已完全阻断”的状态标志。恢复方法是检测到反向脉冲也就是用户把目标滴速调高或者取消报警后电机才会允许反转。另外步进电机的驱动电流也要注意。28BYJ-48的额定电流每相约280mAULN2003本身没有限流功能电机停转时如果一直保持通电线圈发热会很严重。我的方案是电机停止动作0.5秒后把所有励磁相都关掉让电机进入完全断电状态。因为这套系统的保持力矩只靠丝杆自锁不需要电机持续通电这样既省电又避免发热。5.4 代码仓库的使用与个人体会最后说下开源文件怎么用起来。仓库根目录下有三个文件夹Firmware/StdPeriph_Lib和Firmware/HAL_Lib分别放的是标准库和HAL库的工程文件用Keil 5打开直接编译即可Hardware/Schematic里是立创EDA的原理图源文件和PDF版本Simulation/Proteus里是仿真工程把对应版本的hex文件直接加载进去就能跑。跑通步骤就三步先用立创EDA打开原理图核对一遍器件的引脚连接然后打开Keil工程编译生成hex最后打开Proteus工程双击STM32芯片加载hex点击运行。建议第一次运行时把滴速脉冲发生器的频率设置为1Hz也就是模拟60滴/分然后修改目标滴速为80滴/分观察电机会不会自动正向转动、频率计读数会不会逐步靠近80。这套系统适合扩展的方向也很多。如果你对传感器感兴趣可以把红外对管方案升级成工业级的槽型光耦或者光纤传感器抗干扰能力会更强如果你对算法感兴趣可以在PID基础上加入模糊自适应参数整定让系统在不同品牌的输液管特性下都能快速适应如果你想往产品化方向走可以加入Wi-Fi模块把滴速和报警状态上传到护士站大屏再配合心率血氧模块一起监测。我代码里的模块划分比较干净传感器接口、执行机构接口、控制算法之间是解耦的改任何一个模块都不影响其他部分。这套系统我从基础版做到升级版最深的感触是所谓“智能”并不等于算法花哨而是在每一个细节上都考虑到实际操作中可能发生的意外。一个简单的防抖逻辑、一个堵转检测、一个异常分级这些单个看起来都不复杂但连在一起系统才真正变得可靠。希望这份开源资料能帮你少走一些弯路也期待看到你把它改造成更有意思的作品。