资讯动态

基于STM32的智能医疗输液监控系统设计与仿真全开源

发布时间:2026/9/8 3:53:27 来源:尧图企业网站定制
老实说智能医疗输液系统算是STM32嵌入式项目里绕不开的经典题目了。每年毕业季我都能收到不少私信问有没有现成的代码和电路可以参考。但很多流传出来的版本要么只有孤零零的代码没有硬件图纸要么原理图画得乱七八糟无法打样更别提仿真工程了。所以这次我把整套东西完整整理了出来基于STM32F103C8T6的智能医疗输液点滴系统代码、原理图、Proteus仿真全部开源。这篇文章不光给你看工程文件结构还会把每一部分的设计逻辑、选型原因、实测踩坑过程讲清楚。适合正在做嵌入式课设/毕设的同学也适合想转医疗电子方向的开发者参考。1. 这个输液监控系统解决的到底是什么问题1.1 临床输液场景里的三个典型痛点先说一个我在医院陪护时观察到的细节。传统输液依赖护士人工巡检患者液体输完或者滴速异常靠的是患者按铃呼叫。问题在于夜间患者睡着后滴速变慢甚至停滴可能过很久才发现冬天液体温度低患者手臂容易僵硬自己也不好判断是否还在正常滴注。第二个痛点是滴速精度控制。不同药物对滴速的要求差别很大比如硝酸甘油这种药滴速过快会引发低血压过慢则药效不够。人工调节滚轮夹子很难精确控制到特定滴速护士调完一小时后回头看实际滴速往往已经偏离了设定值。第三个痛点是输液过程中的异常检测。管路折叠、针头脱落、液体输完导致空气进入血管——这些都是潜在风险。做过临床信息化项目的人都知道硬件报警比起软件平台监控在及时性上更可靠因为现场的声光报警不依赖网络和上位机。这就是输液监控系统作为独立嵌入式设备存在的价值。1.2 系统功能梳理与工作流程整个系统的功能可以分成四块实时测量、自动调节、状态提醒、人机交互。实时测量指通过液滴传感器统计每分钟滴数换算成输液速度自动调节是检测到滴速偏离设定值时通过控制蠕动泵的转速把滴速拉回目标值状态提醒包括液体输完检测、滴速异常声光报警人机交互则通过LCD屏显示当前滴速、目标滴速、累计输液量和剩余时间配合按键完成参数设置。工作流程大致是这样开机后系统初始化LCD显示默认参数用户通过按键设定目标滴速比如40滴/分启动后红外对管传感器实时检测滴壶中液滴下落单片机统计单位时间滴数PID控制器根据偏差调节步进电机转速带动蠕动泵挤压输液管。万一滴速持续异常或检测到液位过低蜂鸣器和LED就启动报警。1.3 整体架构传感、主控、执行、交互四层从电路角度看系统可以画成四层传感器层负责生理信号采集就一个红外对管模块主控层是STM32F103C8T6承担信号处理、控制算法和逻辑判断执行层是步进电机和蠕动泵负责调整输液速度交互层是LCD、按键、蜂鸣器和LED。这个架构最核心的设计思路是传感和执行分离。传感器不直接调电机中间隔了一个控制器这样方便在软件里加入控制算法和安全互锁。哪怕传感器被水滴反复冲刷产生误信号主控也能通过软件滤波和容错逻辑保证输出不会乱跳。这是类似项目的通用做法也是后面仿真的逻辑主线。2. 硬件选型每一项选择背后的理由2.1 主控为什么是STM32F103C8T6选主控的时候我绕开了一堆选择比如51、Arduino、ESP32最后还是回到STM32F103C8T6。原因很直接这个芯片的生态太成熟了不管是库函数版本还是HAL库版本参考资料到处都是芯片内置64KB Flash和20KB SRAM跑这个项目的代码和显示缓冲绰绰有余拥有多个定时器、外部中断引脚、PWM输出通道和I2C/SPI/USART后面扩展传感器或通讯模块都不用换主控。还有一个更实际的考虑价格和采购方便程度。F103C8T6货量充足几块钱一片在Proteus里也有对应的仿真模型方便先做逻辑验证再买实物这个流程对学习者非常友好。要是用一些冷门国产芯片仿真模型都没有根本没法在电脑上先跑一遍。需要提醒的是这个项目用库函数版本实现会比HAL库简洁很多尤其外部中断和定时器配置代码量差了一截。建议熟悉标准外设库的同学优先选这种方式它更贴近底层能帮你把中断、寄存器这些基础概念真正吃透。2.2 滴速传感器红外对管方案为什么最合适液滴测量在工程上有好几种方案电容式液滴检测、红外对射检测、称重传感器间接测量。我对比过最终选了红外对管槽型光耦。红外对管的工作逻辑相当于一个门禁栏杆。输液器的滴壶刚好卡在红外发射管和接收管之间的槽里液滴下落穿过红外光束时光路被遮挡接收管输出的电平就发生一次跳变。单片机通过外部中断或者GPIO轮询捕捉电平跳变每跳变一次计一滴。这个方案结构简单、响应快、成本低被遮挡一下就是一次脉冲信号边界很清晰。电容式方案虽然能检测到液体经过但抗干扰电路和标定都比较麻烦称重方案依赖液袋重量变化实时性太差滴速变化要等一两分钟才能反映出来。相比之下红外对管的逻辑对单片机最友好也最容易在仿真里模拟。实际制作时提醒一句要选择槽宽能卡住滴壶的对管模块一般5mm左右刚好太窄装不上太宽液滴偏移会影响检测。2.3 执行机构蠕动泵配步进电机精度和安全的平衡输液速度控制不能直接用普通直流电机去挤压输液管那样压力和转速都不好控制。业界标准做法是使用蠕动泵一组滚轮周期性压迫硅胶管通过挤压推动液体向前流动液体只在管内流动不接触泵体污染风险低。这种结构天然适合医疗场景。驱动蠕动泵我选用的是28BYJ-48步进电机配合ULN2003驱动板。用步进电机的原因是转速可以精确控制PWM频率和转速存在线性关系便于PID闭环调节。不用直流减速电机的原因是它受负载影响明显输液管压紧程度稍微变化转速就变了控制精度达不到要求。实际调试时的经验是步进电机不适合长时间高速运行会发热所以PWM占空比不要给到100%通常上限限制在80%左右蠕动泵的滚轮数量决定了电机转一圈输出的液体体积不同泵头参数不同必须通过实测标定“每转对应多少毫升”才能把滴速换算成准确的液体量。2.4 显示与交互器件的取舍显示方面LCD1602足够显示两行信息但信息量受限LCD12864可以显示更多内容比如滴速曲线、文字提示不过接线多、驱动麻烦一点。我做的时候选的LCD1602配I2C转接板只占两根IO口显示当前滴速和目标滴速就够用了。如果你想做成更完整的HMI体验可以换LCD12864或OLED代码结构不用大改。按键最少需要三个设置键、加键、减键。用GPIO上拉输入配合软件消抖。蜂鸣器用有源蜂鸣器接一个三极管驱动LED用一个红色电源指示灯、一个黄色报警灯。这部分没有太高技术含量但要注意布局时按键和LCD要放在方便操作和观察的位置报警器件要足够醒目。3. 原理图设计的几个关键电路3.1 最小系统与电源链路STM32F103C8T6的最小系统包括三部分8MHz晶振和两个20pF负载电容、复位电路10kΩ上拉电阻加0.1uF电容、3.3V电源去耦。电源用USB的5V输入经过AMS1117-3.3稳压给主控供电步进电机驱动直接吃5V。这个电源结构非常重要数字部分和电机驱动部分要分开走线稳压芯片输出端至少加一个100uF电解电容和100nF陶瓷电容电机驱动电源输入端也要加470uF电容。为什么要这么设计因为电机堵转或启动瞬间电流可能到几百毫安大电流导致电源跌落主控就会复位。我在第一版PCB上没注意这个问题步进电机一转单片机就重启排查了半天才发现是共地共电导致的。复位电路里STM32的NRST引脚需要10kΩ上拉到3.3V按键按下接地实现手动复位。如果用到SWD下载调试别忘了给SWDIO和SWCLK引脚留出调试排针仿真时虽然用不到但实物调试离不开。3.2 红外滴速检测电路红外对管模块的电路有两种接法数字量输出和模拟量输出。我推荐在模块上直接接成数字量输出型红外发射管串联一个限流电阻典型100Ω~220Ω接收管集电极接上拉电阻到3.3V发射极接地输出端从集电极引出。有液体滴落遮挡红外光时接收管导通状态翻转输出端电平发生变化。单片机的外部中断引脚我用的PA0配置为下降沿触发检测到电平从高到低跳变就计一次数。实际电路里有个细节要在输出端和地之间并联一个100nF电容做硬件滤波同时外部中断里做一下软件消抖。不这样做的话液滴下落时二次飞溅的水珠会把一次滴落拆成两三个脉冲滴速计数直接翻倍。这是这个项目最典型的一个坑后面实测部分我会详细展开。3.3 步进电机驱动电路与续流保护28BYJ-48电机是五线四相步进电机用ULN2003达林顿管阵列驱动。ULN2003内部每一路都是达林顿对管自带续流二极管可以吸收电机线圈断开时产生的反向电动势。电路连接很简单STM32四个IO引脚PA1~PA4接到ULN2003的1~4输入ULN2003的5~8输出接电机四相线圈公共端接5V有的电机公共线是中间抽头。这里要特别强调一下续流保护。步进电机线圈是感性负载驱动管关断瞬间会产生很高的反向电压。ULN2003内置的续流二极管已经把反向电动势泄放到电源所以项目里不需要额外加外部二极管。但是如果驱动管换成普通三极管或者用MOS管反电动势没有泄放路径非常容易击穿驱动管或者干扰单片机这点务必注意。3.4 PCB布局和布线的几个关键点虽然仿真不需要画PCB但既然开源了原理图就顺便把布线的经验写出来。核心原则是强电和弱电分开模拟和数字分开。电机驱动部分尽量放在板子一角靠近电源输入LCD和按键排在另一侧方便安装到外壳后操作红外对管接口最好做成排针引出因为实际使用时传感器要固定在输液架或滴壶卡槽上离主板有一定距离。布线时电机电源线和信号线不要平行走长线避免电磁干扰耦合进信号路径。地线尽量用覆铜填充保证回流路径通畅。4. 核心代码模块拆解与实现4.1 代码工程结构与模块划分代码按功能模块拆成多个文件方便移植和阅读main.c负责主循环和状态调度timer.c封装定时器用于产生1秒时基和PWM输出exti.c处理外部中断负责滴速计数motor.c封装电机控制正转、反转、停止、调速lcd.c封装显示驱动key.c负责按键扫描与消抖beep.c管理蜂鸣器和LED报警。这种分层的思路对学习和维护都友好。你拿到工程后改显示逻辑不用去翻电机代码换传感器也只需要动exti.c和相关的滤波逻辑。模块之间通过全局变量和函数接口传递数据比如滴速计数值drop_count在中断里累加主循环里读取后清零这个模型非常经典。4.2 滴速检测模块外部中断加定时器时基滴速检测是整个系统的地基检测不准后面啥都白搭。我的实现方式是红外模块输出接到PA0配置成下降沿触发的外部中断滴落一次触发一次中断滴速计数变量自增。TIM2配置成1秒中断一次每秒读走当前计数值计算出当前滴速滴/分钟然后把计数值清零或保存上次的基准值。核心代码大致是这样volatile uint16_t drop_count 0; volatile uint16_t current_rate 0; void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) ! RESET) { /* 简单的软件消抖利用定时器标志判断距上次中断是否超过5ms */ static uint32_t last_tick 0; if ((TIM2-CNT - last_tick) 5000) { drop_count; last_tick TIM2-CNT; } EXTI_ClearITPendingBit(EXTI_Line0); } } void TIM2_IRQHandler(void) { static uint16_t last_count 0; uint16_t current_count; if (TIM_GetITStatus(TIM2, TIM_IT_Update) ! RESET) { current_count drop_count; /* 每秒计数值乘60就是每分钟滴速 */ current_rate (uint16_t)(current_count - last_count) * 60; last_count current_count; TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } }这版代码相比最初的方案改进了一个点用TIM2的计数器值做时间差判断比在中断里delay更加可靠。因为外部中断里的delay会导致后续中断堆积在频繁滴落时可能丢失中断。强调一下中断服务函数时间越短越好不推荐在里面做耗时的滤波等待。4.3 电机调速控制从PWM到简单闭环步进电机转速控制用定时器输出PWM。STM32的TIM3通道1PA6配置为PWM输出模式通过修改比较寄存器CCR的值改变占空比占空比越高电机转速越快蠕动泵单位时间输送的液体越多。但光有开环PWM不够滴速会随着输液管卡紧程度、液袋高度的变化而漂移。所以我在电机控制外面加了一层PID闭环将目标滴速与实测滴速的偏差作为输入PID输出调节PWM占空比。typedef struct { float target; /* 目标滴速 */ float kp; /* 比例系数 */ float ki; /* 积分系数 */ float kd; /* 微分系数 */ float integral; /* 积分累计值 */ float last_error; /* 上次偏差 */ } PID_TypeDef; float PID_Calculate(PID_TypeDef *pid, float feedback) { float error pid-target - feedback; float output; pid-integral error; /* 积分限幅防止积分饱和导致超调 */ if (pid-integral 100) pid-integral 100; if (pid-integral -100) pid-integral -100; output pid-kp * error pid-ki * pid-integral pid-kd * (error - pid-last_error); pid-last_error error; /* 输出限幅在0~80之间预留20%余量防止电机过热 */ if (output 80) output 80; if (output 0) output 0; return output; }PID参数整定是从开环到闭环最痛苦的一步网上有很多关于PID的教程但实际项目里最有效的方法还是先只调Kp让系统不震荡也不迟钝再逐步加入Ki消除稳态误差最后用一丁点Kd抑制超调。具体整定过程我会在第6章写实测复盘时展开。4.4 显示与报警状态机系统在工作时不仅要把实时滴速显示出来还要根据状态决定是否报警。我定义了一个简单的运行状态机STANDBY待机、RUNNING运行中、ALARM报警中、FINISHED输液完成。在RUNNING状态LCD第一行显示实时滴速和目标滴速第二行显示累计输液量和预计剩余时间。累计输液量的计算依赖滴系数也就是每毫升对应多少滴。常规输液器滴系数为20滴/毫升计算逻辑是total_volume_ml (current_rate / 20.0f) * (1.0f / 60.0f);当检测到长时间无滴落或者滴速偏差超过设定值持续一定时长状态机切到ALARM蜂鸣器鸣叫红色LED闪烁。如果累计输液量达到设定总量进入FINISHED状态系统自动停机并报警。状态机的好处是逻辑清晰不会出现“已经输完了还在报警输液异常”这种矛盾。4.5 主循环与中断优先级设计主循环里做的事情很少因为实时性要求高的任务全部交给了中断和定时器。主循环只处理按键扫描、LCD刷新、PID计算、状态机切换这些操作的周期是几十毫秒级别完全够用。中断优先级这里有一个容易犯的错误。外部中断EXTI0和定时器TIM2中断的优先级必须设置好滴速计数丢失一次只是数据不准但定时器中断如果被堵塞时基就不准了。所以TIM2优先级设为抢占优先级0、子优先级0EXTI0设为抢占优先级1、子优先级0。也就是说即使外部中断触发得再频繁也不能影响定时器读取计数值。5. Proteus仿真把整个系统在电脑上先跑起来5.1 仿真工程搭建与元件清单Proteus仿真最大的价值是把硬件调试的时间和成本压到最低。我建这个仿真工程时用到的元件列表如下方便你在Proteus 8.x里直接放置器件Proteus关键字数量STM32F103C8T6STM32F103R61LCD1602LM016L1按键BUTTON4逻辑探头/开关模拟滴落逻辑电平源或手动脉冲开关1步进电机MOTOR-STEPPER1ULN2003ULN2003A1蜂鸣器BUZZER1LED点阵/普通LEDLED-RED、LED-YELLOW2仿真里没有真实的红外对管也无法模拟输液器滴壶里液滴下落。我的做法是用一个按钮开关接PA0手动按键模拟一次液滴遮挡按下产生一个下降沿就相当于一滴落下。这样虽然麻烦但能完整验证主控逻辑是否正常工作。5.2 仿真模型对真实硬件的简化与差异必须说清楚Proteus仿真和真机之间存在一些差异理解这些差异才能避免“仿真通过、实机上电就崩”的窘境。Proteus的STM32模型不包含真实的电源噪声、电磁干扰、接触不良等问题。仿真里ULN2003驱动电机很干净但真机上电机一转电源纹波直接把ADC和LCD搞乱。仿真里红外对管输出是理想的下降沿但真机上的信号会有毛刺和抖动必须靠硬件和软件滤波才能稳定。还有一个差异是时钟精度。仿真里的8MHz晶振是理想的TIM2定时非常准确而真实晶振有误差长时间运行后累计的时间差会导致“预计剩余时间”和实际对不上。所以我在真机上调用了内部低速时钟校准把系统时钟偏差控制在可接受范围。总之仿真验证的是软件逻辑和算法流程凡是涉及模拟信号、噪声、功耗、时序抖动的问题仿真都只能说“大概率没问题”真机调试不可跳过。5.3 联调技巧用仿真快速定位逻辑bug在仿真环境里调试有个很大的优势你可以随时暂停、单步、监视变量这在真机上做不到。我的调试顺序是先验证滴速计数——反复点击模拟按键观察current_rate是否等于点击频率乘60再验证PID——把目标滴速设为40通过模拟脉冲让反馈值偏离观察PID输出是否朝正确方向调整最后验证状态机——模拟长时间不点击按键确认系统能进入报警状态。遇到LCD显示异常的时候先检查LCD的引脚连接和延时函数仿真里延时太短也会出现显示乱码。如果蜂鸣器一直响检查状态机是不是卡在报警状态有可能是滴速计数位置不对导致误判断。仿真跑通全套流程之后再动手做实物成功率会高很多。6. 实测复盘原理图到样机之间那些坑6.1 滴速计数跳变的排查全过程样机做出来后我第一次实测就翻车了。设定40滴/分LCD上显示的数字隔几秒就跳到80甚至120完全没法看。我用示波器抓PA0引脚发现信号波形确实有抖动一次液滴下落会产生两到三个下降沿。仔细分析后发现液滴撞到滴壶底部会飞溅出细小的水珠这些小水珠也会短暂遮挡红外光造成额外脉冲。排查链路是这样的先怀疑传感器换了新的红外对管现象依旧再怀疑电源纹波给传感器单独供电还是没用最后用示波器同时观察传感器输出和实际滴落过程把摄像头慢动作回放和波形对齐才发现是多脉冲问题。解决方案是双管齐下硬件上在PA0对地并联一个100nF电容滤掉高频抖动毛刺软件上在外部中断里用定时器时间戳做5ms的脉冲间隔过滤。这个问题的典型意义在于很多新手一看到计数跳变就立刻怀疑算法其实根子往往在物理信号层面。排查顺序应该是“信号源→硬件滤波→软件滤波→算法逻辑”从源头层层排除而不是盲目改代码。6.2 PID参数整定的实际操作我的PID整定过程属于标准“试凑法”但有一些实操细节值得记录。首先把Ki和Kd全部设0只留Kp。从很小的Kp0.5开始观察滴速响应。Kp太小时滴速像蜗牛爬要很久才回到目标值慢慢加大到Kp2时系统开始出现轻微震荡滴速在目标值附近来回摆此时记录下这个临界Kp。然后按经验把Kp设为临界值的一半左右加入Ki从Ki0.01开始缓慢增大直到稳态误差消除。最后加一点点KdKd0.2就够可以有效抑制超调。有几个具体的坑要提积分饱和问题很明显如果电机卡住或者输液管折叠积分项会一直累加解除异常后输出瞬间冲到最大值导致液体猛地冲一下。所以积分限幅一定要有我把上限设为100。还有PID计算周期要固定必须放在1秒定时中断里调PID不能在主循环里随缘计算否则参数完全没法收敛。6.3 步进电机电磁干扰导致主控复位这个坑发生在整机联调阶段。系统单独跑滴速检测一切正常单独跑电机也正常两个功能一开电机刚启动LCD就闪一下紧接着系统就复位了。排查过程我第一反应是电源容量不够换了大功率电源问题没解决接着怀疑电机驱动板的逻辑电平干扰加了光耦隔离还是没解决最后用示波器抓3.3V电源引脚发现电机启动瞬间3.3V上有近200mV的跌落和振铃。因为ULN2003的公共端和单片机共用了一个电源入口电机启动电流一下拉到几百毫安AMS1117压降瞬间拉低主控直接掉电复位。最终方案是改电源拓扑5V输入先分两路一路直接给ULN2003电机供电另一路经AMS1117给主控供电两路在电源输入端用一个磁珠或0欧电阻隔开。同时给电机供电端并一个470uF的大电容吸收瞬态电流。这样改完以后再没出现复位问题。7. 从教学项目到医疗电子还差哪几步7.1 安全设计层面的思考开源这个项目主要面向课程设计和学习但如果你想把它往真实医疗场景推进有一段很长的路要走。医用输液泵必须满足IEC 60601系列标准包括电气安全、电磁兼容、生物相容性等一堆认证要求。从技术层面看至少还要增加几个模块气泡检测超声气泡传感器检测管路中是否有空气、阻塞压力检测通过压力传感器监测输液管是否堵塞、空液检测液位传感器判断液体是否输完。报警系统也要冗余设计不能只靠一个蜂鸣器要有多级声光报警并且能区分不同报警类型。备份机制同样重要主控死机时要能通过硬件看门狗自动恢复并且自动切换成安全状态。这些内容不是简单加几个传感器就能实现的但学习路径是清晰的先把基础系统吃透再逐项增加安全模块每一步都能加深对嵌入式医疗设备的理解。7.2 项目怎么扩展和复用如果你觉得这个项目做完还不够过瘾有几个方向可以继续玩加上ESP8266或ESP32模块通过WiFi把滴速和报警数据传输到手机或护士站这就是典型的物联网医疗监控原型把红外对管换成毫米波雷达传感器实现非接触式液滴检测这在某些药液不能接触红外光的场景下很有价值把硬件平台迁移到RTOS上比如FreeRTOS让传感器采集、控制算法、显示刷新各自成为独立任务锻炼一下嵌入式操作系统的工程能力。从复用角度看这套“传感器STM32执行器报警显示”的框架可以套用到很多其他场景农田灌溉的流速监测、实验室的液体分装设备、宠物自动喂食器都需要类似的检测、控制、交互逻辑。把核心模块抽出来换一下传感器和执行器就是一个新项目。做这个项目的过程中我最深的体会是真正难的不是把代码跑通而是在“传感器信号不稳定”“电机一开就复位”“PID调了半天还是震荡”这些问题面前能沉住气一项一项排查。把这些坑都踩一遍你对嵌入式系统的理解会上一个台阶。希望这套代码、原理图和仿真能帮你少走这些弯路至于后面的扩展就看你的想象力了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价