ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于STM32的智能输液监护系统设计与PID调速实现

基于STM32的智能输液监护系统设计与PID调速实现 1. 项目概述与整体设计思路1.1 为什么要做“升级版”先聊聊这个项目的来龙去脉。输液监护这件事在医院里其实是个高频需求。传统输液靠护士人工巡检病人或家属盯着液瓶液快完了按铃喊人。遇到病房人多、夜班人手不够的时候靠人盯总会有疏漏空气进入血管这种事虽然概率低但真出了就是大事故。我之前做过一版基础款的输液监护仪功能就是液位检测加报警发现液位低了就响蜂鸣器。做完之后发现一个尴尬的问题报警归报警液体还在继续滴护士赶过来需要时间这中间病人还得盯着不然空气真要进去了。所以这次升级版的核心思路很简单——不止要“监护”还要“调控”检测到滴速异常能主动调速检测到液位快到底能先夹断管路把风险提前掐掉。整套系统的定位是面向电子设计竞赛、毕设、嵌入式入门进阶的完整开源方案从代码到原理图到仿真工程全部开放拿到手就能跑想改也能改。我实测下来这套方案在Proteus里仿真通过移植到实物板子上跑也稳定属于典型的“仿真验证逻辑、实物验证工程”双轨方案。1.2 系统组成与核心功能拆解整套系统可以拆成五个部分来看主控核心STM32F103C8T6负责所有逻辑处理、传感器采样、电机控制、报警输出检测单元红外对管检测滴速液位传感器或电极式传感器检测剩余液量执行单元步进电机或微型蠕动泵通过调速实现滴速闭环控制电磁夹管阀用于液位低时的切断保护人机交互OLED屏显示滴速、液位状态、系统模式按键设置目标滴速蜂鸣器报警辅助功能无线模块预留接口升级项方便接ESP8266或HC-05做数据上报工作流程是这样的红外对管实时采集滴壶里液滴下落产生的脉冲信号STM32通过定时器输入捕获计算出当前滴速把当前滴速和目标滴速放在PID控制器里做比较输出PWM控制蠕动泵转速实现自动调速同时液位传感器持续检测液位状态低于阈值就触发声光报警并通过电磁阀切断输液管路从源头上防止空气进入。这套架构最核心的价值在于它不是一个“检测-报警”的单向系统而是一个“检测-决策-执行-反馈”的闭环系统。这也是升级版和基础版最本质的差别。2. 硬件选型与原理图解析2.1 主控为什么选STM32F103C8T6直接说结论STM32F103C8T6是这类中小型医疗电子项目的性价比之王没有之一。C8T6属于STM32F1系列Cortex-M3内核主频72MHzFlash 64KBRAM 20KB。这个配置看起来不算高但对于输液监护这个场景资源完全够用而且还有相当大的余量。关键是它的外设资源太合适了3个定时器TIM1高级定时器、TIM2/TIM3/TIM4通用定时器滴速检测用输入捕获、电机调速用PWM输出刚好各司其职2个I2C接口OLED屏走I2C很合适占用的引脚也少2个SPI接口如果后续接无线模块或者外部Flash做数据存储直接挂上去就行7通道ADC用来采集液位传感器的模拟量、监测电池电压都没问题37个GPIO在这个项目里还会空出一大半方便后期扩展还有一个很实际的因素是生态。STM32F1系列的库函数开发和HAL库开发资料多到看不完遇到问题搜一下就有答案对新手极其友好。我见过不少同学用STM32做东西不是卡在逻辑上而是卡在配置上换别的芯片冷门一点连个参考工程都找不到那才叫真痛苦。如果一定要说缺点那就是C8T6的Flash只有64KB如果代码写得比较随意加上调试信息比较多后期可能会紧张。不过我在这个项目里做了裁剪编译下来大概45KB左右余量足够。2.2 传感器与执行机构的选型逻辑这一块是整篇原理图里最容易踩坑的地方我一个个说。滴速检测传感器我用的是一体化红外对管发射管和接收管做在同一个支架上安装的时候卡在滴壶两侧。原理是液体滴落时会遮挡红外光接收管导通状态发生变化产生脉冲信号。选用对管而不是用摄像头图像识别核心原因是实时性和成本对管响应速度在微秒级价格几块钱而对图像处理的算力要求高太多在这个场景里属于杀鸡用牛刀。要注意的是红外对管容易被环境光干扰所以选型时优先选带遮光罩的型号或者在结构设计时用热缩管把感应区包起来只留一条光线通路对准滴壶的落液区。我第一版就是没注意环境光干扰白天窗边滴速计数会莫名翻倍后来加了遮光罩才稳定。液位传感器升级版我用的是电极式液位检测原理是在输液瓶或滴壶的液面下方和上方各放一根电极液体导通时两根电极之间有微弱电流液面低过上方电极后电流断开通过检测这个通断状态判断液位是否低于阈值。优点是结构简单、成本低、响应可靠不会有红外那种误判问题。还有一种方案是贴片式电容传感器贴在输液瓶外壁通过电容变化感知液位。优点是非接触、卫生不存在交叉感染问题但成本高不少而且不同的瓶子壁厚不一样需要现场校准通用性差一些。我的建议是做实验和竞赛用电极式就行做产品化方案再考虑电容式。调速执行机构选型时考虑过两种方案一种是微型蠕动泵一种是步进电机驱动滚轮挤压输液管。蠕动泵的优势是流量控制比较线性脉动小和医院现有输液管路配合也方便缺点是贵一点。步进电机方案便宜但需要自己设计一个挤压轮结构机械部分的工作量会变大。考虑到开源项目要照顾大多数人的条件我提供了两种实现的原理图实物版本用微型蠕动泵逻辑简单可靠Proteus仿真版本用步进电机模拟蠕动泵的效果因为Proteus里没有蠕动泵模型用步进电机的转速来等价映射滴速的调节。后面讲仿真的时候细说。电磁夹管阀这是升级版新增的重要执行机构。液位低到危险阈值时控制器会驱动电磁阀的衔铁压住输液管实现物理断流。选型要留意额定电压和功耗我用的是5V版本通过STM32的GPIO加三极管驱动和蜂鸣器共用一组逻辑。买的时候注意选“常开型”夹管阀断电时管路是通的电时压紧断流这样即使系统死机也不会影响输液当然这只是安全冗余的一种真正的临床设备还要更严谨。2.3 原理图关键模块详解原理图这块我不打算贴整张图源文件我已经整理在开源包里了但是几个关键模块必须拆开讲你自己画板的时候直接照抄就行。电源电路系统输入5V经过AMS1117-3.3给STM32和传感器供电。这里有个细节红外对管的发射端建议单独走一路5V串联限流电阻不要和逻辑电路共用3.3V轨。原因是对管发射端瞬间电流比较大如果和MCU共用电源轨红外LED导通瞬间会把MCU的ADC参考电压拉偏导致采集数据抖动。我实测过共用电源轨时ADC采样值的跳动幅度能达到20mV以上分开始后基本稳定在3mV以内。复位电路标准的10K上拉电阻加0.1uF电容到地NRST引脚接按键。这个没什么特殊的但注意电容不要选太大我见过有人用10uF上电复位时间拖得老长偶尔还会出现程序跑飞的情况。经验值是0.1uF就好。滴速检测信号调理电路红外接收管的输出信号要经过一个比较器或者施密特触发器整形再进STM32的输入捕获引脚。不要直接接MCU因为红外接收管的输出波形是缓慢变化的模拟量直接给MCU会触发多次误中断。我用的是LM393比较器参考电压设在2.5V左右输出端加上拉电阻到3.3V得到干净的方波信号。如果你手里有现成的施密特触发器芯片比如74HC14也可以用效果一样。电机驱动电路蠕动泵用的驱动芯片是L298N不过L298N的压降比较大供电5V时输出到电机可能只有3.5V左右转速会偏低。后来我换成了DRV8833这个芯片的导通压降小体积也小很多而且自带电流限制不容易烧电机。驱动方式同样是PWM调速两路输入IN1/IN2控制方向和使能一路PWM控制速度。原理图里我没画太复杂的光耦隔离因为蠕动泵是小功率电机干扰在可接受范围内。如果是驱动大功率电磁阀或者交流设备那就必须加光耦和续流二极管了。3. 开发环境搭建与代码框架3.1 Keil5环境配置与工程创建开发环境这块我就默认大家用Keil MDK这是STM32开发最主流的IDE虽然界面比较老气但稳定性和调试功能确实能打。首先安装Keil5的时候要注意版本问题。C51和MDK是两套独立的安装包如果你以前装过C51版本千万别直接覆盖安装MDK两个版本装在同一个目录会互相干扰。正确做法是先卸载C51或者把两个版本单独装在不同的盘符目录下我见过太多同学在这上面浪费一天工夫。装完MDK后还需要在Pack Installer里安装STM32F1系列的Device Family Pack不然新建工程找不到芯片型号。工程创建的核心步骤打开Keil5点击Project - New uVision Project选择芯片型号STM32F103C8注意是C8中容量不是C8T6送的那个板子命名里的T6T6是封装代码选芯片型号只用C8就行在Manage Run-Time Environment里勾选需要的组件。我用的是标准外设库StdPeriph_Lib而不是较新的HAL库。原因是在这个项目里用标准库写定时器和中断的寄存器操作逻辑更直观代码量也更小很多现成的网上例程可以直接参考配置工程选项Debug选项卡里选择ST-Link DebuggerUtilities选项卡里勾选Reset and Run这样烧录后芯片会自动复位运行不用每次手动按复位键C/C选项卡里在Define框填入USE_STDPERIPH_DEVICE这是标准外设库必需的一个宏定义包含路径Include Paths要添加标准库的头文件目录遗漏了会报一堆fatal error新手最容易死在这3.2 代码目录结构与模块划分整个工程的代码我做了模块化拆分方便阅读和二次开发。目录结构如下├── User │ ├── main.c // 主函数系统初始化 │ ├── stm32f10x_it.c // 中断服务函数 │ └── system_stm32f10x.c // 系统时钟配置 ├── Hardware │ ├── dripper_sensor.c/.h // 滴速检测模块 │ ├── liquid_level.c/.h // 液位检测模块 │ ├── pump_motor.c/.h // 电机驱动模块 │ ├── oled_display.c/.h // OLED显示模块 │ └── buzzer_key.c/.h // 蜂鸣器和按键模块 ├── Algorithm │ ├── pid_control.c/.h // PID控制算法 │ └── filter.c/.h // 数据滤波 ├── Drivers │ └── stm32f10x_xxx.c // 标准外设库源码 └── 其他配置文件这个结构的好处是每个硬件外设都对应独立的.c和.h文件你想换传感器或者改驱动方式只需要改对应的那个文件其他模块的逻辑基本不用动。后面我会详细讲每个模块的核心代码。3.3 烧录与调试流程烧录方式我推荐ST-Link V2便宜好用淘宝二三十块的就能用。接线方式非常简单ST-Link的SWDIO接STM32的PA13ST-Link的SWCLK接STM32的PA14GND接GND3.3V接3.3V如果板子已经单独供电可以不接3.3V避免两块电源打架接好线后在Keil的Debug设置里选择ST-Link Debugger点一下Load按钮程序就会通过SWD接口烧录进去。这里我想多说一句调试的心得Keil5在线调试Debug模式是个被严重低估的功能。很多人烧录完程序发现不对就在代码里到处加串口打印效率极低。正确的方法是直接用调试器在线打断点观察变量值和外设寄存器状态。比如你想知道滴速检测定时器有没有正常捕获到脉冲就在输入捕获中断里打断点跑起来看有没有进中断进了中断看捕获值是多少几分钟就能定位问题。我在调试PID参数的时候就是靠在线调试看曲线效率比一遍遍烧录测试高太多了。4. 核心功能实现与代码解析4.1 滴速检测定时器输入捕获的工程化实现滴速检测是整个系统的“眼睛”如果这个环节的数据不准后面PID控制得再好也白搭。先说原理。红外对管输出的方波信号接入STM32的一个定时器输入捕获引脚我用的是TIM2的CH1也就是PA0。TIM2配置为输入捕获模式上升沿触发。每次检测到上升沿定时器就会把当前的计数值锁存到捕获寄存器触发捕获中断。在主逻辑里用两次相邻的上升沿之间的时间差就可以换算出滴速。计算方法很简单两次捕获的计数值差就是脉冲周期对应的定时器计数个数乘以定时器时钟周期就是时间。比如定时器时钟是72MHz分频系数为72那么定时器计数频率就是1MHz即每个计数值为1微秒。两次上升沿间隔计数值为60000那么脉冲周期就是60ms对应的滴速就是每秒1000/60约等于16.67滴/秒也就是每分钟约1000滴。不过实际医疗输液的滴速一般在每分钟20到80滴之间也就是滴间间隔在750ms到3s之间所以定时器计数频率用1MHz完全够了分辨率1ms误差小于1%。代码实现时要注意两个坑第一个坑是定时器溢出处理。如果滴速极慢比如病人调得很慢每分钟10滴滴间间隔6秒而16位定时器的最大计数范围只有65535在1MHz计数频率下只有约65ms远远不够。所以必须在更新中断溢出中断里做溢出计数实际的时间差要加上溢出次数乘以65536再减去当前计数值。我在代码里用了一个32位的溢出计数器实测即使滴速降到每分钟5滴也能准确测量。第二个坑是滤波。红外对管偶尔会被环境光干扰或者被气泡产生误触发导致测量值跳变。我在软件里加了一个滑动平均滤波连续记录最近5次的滴间间隔取中间值去掉最大最小再平均这样即使有一两个异常脉冲也不会导致显示和控制的剧烈波动。实测下来加入滤波后滴速显示值基本稳定在±1滴/分钟以内。核心代码片段void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_CC1) ! RESET) { uint16_t current_capture TIM_GetCapture1(TIM2); static uint16_t last_capture 0; // 计算时间差防止计数器回绕 uint32_t diff (current_capture last_capture) ? (current_capture - last_capture) : (0xFFFF - last_capture current_capture 1); // 加上溢出计数的补偿 uint32_t period_us overflow_count * 65536 diff; // 更新滴速计算滴/分钟 if (period_us 0) { dripper_period_ring_buffer[dripper_buffer_index] period_us; dripper_buffer_index (dripper_buffer_index 1) % 5; dripper_data_ready 1; } last_capture current_capture; overflow_count 0; TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); } if (TIM_GetITStatus(TIM2, TIM_IT_Update) ! RESET) { overflow_count; TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } }4.2 PID调速控制从原理到调参有了滴速检测接下来就是核心的“调控”环节PID闭环控制。PID控制器的原理我就不长篇大论了简单说就是将目标滴速和当前实际滴速的偏差经过比例P、积分I、微分D三种运算后输出一个控制量去调节电机的PWM占空比从而改变滴速。在这个项目里PID的输出量是PWM的占空比0到999对应0%到99.9%。控制对象是蠕动泵转速被控量是滴速。控制周期我设为500ms即每500ms计算一次当前平均滴速然后执行一次PID计算更新PWM占空比。为什么选500ms而不是更短因为滴速是离散脉冲测量本身就有一个统计周期间隔太短会导致测量值波动大PID输出也会跟着抖间隔太长则响应太慢液速突变时来不及调整。经过实测500ms在响应速度和稳定性之间是比较好的平衡点。位置式PID的核心代码float PID_Calculate(PID_TypeDef *pid, float target, float current) { pid-error target - current; pid-integral pid-error; // 积分限幅防止积分饱和 if (pid-integral pid-integral_limit) pid-integral pid-integral_limit; if (pid-integral -pid-integral_limit) pid-integral -pid-integral_limit; pid-derivative pid-error - pid-last_error; float output pid-kp * pid-error pid-ki * pid-integral pid-kd * pid-derivative; pid-last_error pid-error; // 输出限幅 if (output pid-output_limit) output pid-output_limit; if (output pid-output_min) output pid-output_min; return output; }调参这件事我直接分享一套实战经验比教科书上讲得要靠谱先把Ki和Kd设为0只保留Kp从一个小值如0.5开始加。观察滴速实际值有没有靠近目标值太慢就加Kp出现振荡就减Kp。找到临界振荡的Kp值然后把它除以2作为基准值固定Kp后慢慢加Ki用来消除稳态误差。如果滴速和目标值之间一直有一两滴的偏差就是Ki太小了。继续加到偏差消失但注意如果流速度波动一圈一圈地缓慢起伏就是Ki过大了最后加Kd用来抑制超调。如果目标滴速从30突然改成60滴速冲过了头再回落那就是超调适当加Kd能压住这个过程实际参数我调下来是Kp3.2Ki0.8Kd0.5实测从30滴/分钟突变到60滴/分钟大约6到8秒稳定最大超调不超过4滴/分钟这个指标对这个场景来说是够用的4.3 液位检测与报警机制液位检测代码逻辑相对简单但要注意一个去抖处理。液体快滴完的时候输液管内可能会有气泡间断通过电极探针上的液膜可能会造成短暂导通引入误判断。我在代码里加了一个软件去抖液位信号需要在连续5次采样每次间隔100ms都是“低于阈值”才确认进入低液位状态触发报警和执行切断机构。报警机制设计了三级分级处理比一锅端要合理得多一级报警预警预计剩余液量还能维持5分钟以上时OLED屏提示“液位偏低”蜂鸣器每10秒短鸣一声。目的是提醒家属和护士还有时间准备二级报警主报警液位低于安全阈值OLED屏闪烁显示“低液位”蜂鸣器连续鸣响并自动启动电磁夹管阀切断输液管路。同时系统会停止蠕动泵防止泵继续空转损坏三级报警故障滴速检测信号丢失持续时间超过10秒判定传感器故障或管路堵塞蜂鸣器发出一长两短的故障码OLED屏显示错误代码E01这里特别说明一下电磁夹管阀的执行逻辑触发二级报警后夹管阀动作需要额外供电5V所以我在硬件上做了一个自锁电路——一旦触发夹管阀即使后续MCU因为干扰复位夹管阀也会保持通电状态直到人工按下“复位”按键才解除。这是从工业安全设计里学到的“失效安全”思维确保单点故障不会导致保护动作失效。4.4 OLED显示与按键交互OLED用的是0.96寸I2C接口的SSD1306方案分辨率128x644个引脚GND、VCC、SCL、SDA接线非常简单。显示界面我设计了三页第一页显示实时状态当前滴速、目标滴速、液位百分比、电机PWM占空比 第二页显示PID运行数据误差值、积分累积量、PID输出值方便调试时查看实时曲线变化 第三页显示系统参数设置目标滴速设定、液位报警阈值设定按键一共3个设置键进入设置模式、加/减键调节目标值。长按设置键2秒进入参数设置状态短按切换调节项调节完成后长按确认退出。这套交互逻辑在单片机项目里非常通用直接套用就行。OLED驱动的移植我用的是比较通用的0.96寸OLED库底层只需要实现两个函数I2C起始/停止时序以及发送字节。当然也可以用模拟I2C只要调整引脚定义即可。注意SSD1306的I2C地址默认是0x78写地址如果你的屏幕是别的地址在初始化函数里改一下就行。5. Proteus仿真与验证5.1 仿真工程搭建要点Proteus仿真这个环节很多同学以为就是把实物电路搬进软件其实不是。Proteus里的模型库和真实器件有很大差别直接照搬实物原理图经常会出问题需要做一些适配。我在仿真里用的器件清单和实物有一些对应关系STM32F103C8T6模型Proteus库里有直接的STM32F103C8芯片模型可以直接放红外对管Proteus里没有现成的对管模型我用了一个光耦Optocoupler来模拟。光耦的输入端接一个脉冲发生器模拟液滴遮挡产生脉冲输出端接到STM32的输入捕获引脚。脉冲发生器的频率就是模拟滴速改频率就能模拟不同滴速液位传感器用一个开关模型模拟液位状态闭合代表液位正常断开代表低液位蠕动泵电机用一个步进电机模型替代步进电机的转速通过示波器观察也可以接一个虚拟转速表OLEDProteus V8.9以上版本有SSD1306 OLED模型直接调用即可电磁夹管阀用一个继电器模型模拟继电器的常开触点接到一个LEDLED亮代表夹管阀动作断电简洁明了仿真里最关键的一个设置是STM32的晶振频率和代码里的时钟配置要一致。Proteus里双击STM32芯片在属性里找到Clock Frequency设为72MHz。同时代码里SystemInit函数会将HSE设置为8MHz外部晶振再PLL到72MHz但实际上Proteus运行时是用它自己模拟的时钟这里如果设置错位会导致定时器的时间基准完全不对滴速显示值会离谱。5.2 仿真场景与预期结果我设置了三个仿真场景来验证系统功能每个场景都有明确的通过标准场景一正常调速操作脉冲发生器频率设为1滴/秒目标滴速设置为60滴/分观察系统响应预期结果系统检测到当前滴速约60滴/分1滴/秒乘60PID快速稳定在目标附近PWM占空比输出平稳OLED显示当前值和目标值一致场景二滴速突变模拟输液管受压操作运行中将脉冲发生器频率突然降低到0.5滴/秒模拟滴速骤降预期结果PID检测到偏差后PWM占空比自动升高带动电机加速滴速在5到10秒内回升到60滴/分附近场景三低液位报警操作将液位开关断开模拟液位低于阈值预期结果OLED显示“低液位”蜂鸣器响继电器吸合LED亮起表示夹管阀动作等待复位按键按下后才能恢复这三个场景覆盖了系统的核心功能。如果仿真时某个场景不通过优先排查对应的硬件配置和中断配置不要急着怀疑代码逻辑。我在调试场景二时发现PWM输出总是到顶了滴速还上不去后来发现是仿真里步进电机的响应速度被模拟得太慢属于模型特性不是代码问题。5.3 仿真与实物的关键差异仿真通过不等于实物就能跑这里面的差异值得单拎出来说很多项目就是死在“仿真跑得好好的实物一上电全乱套”。先说时钟差异。Proteus对STM32的模拟是基于指令级模拟的它不太关心你代码里的延时循环到底运行了多久有时候你写一个Delay_ms(1000)在Proteus里实际可能是800ms或1200ms。但在真实芯片上只要晶振正确延时基本是准确的。所以涉及到精确延时的功能比如蜂鸣器鸣响节奏要以实物调试为准。再说电平差异。Proteus里的数字电平是理想的0和3.3V但真实的红外对管输出波形是有上升沿和下降沿时间的还带有噪声。我在实物调试时发现对管输出信号如果不加施密特触发器整形TIM2的输入捕获中断会被噪声反复触发滴速显示高得离谱。这个问题在Proteus里根本不会暴露因为仿真里的信号源是理想方波。所以代码里我加了硬件整形和软件滤波双保险。最后是功耗和驱动能力的差异。仿真里LED直接接GPIO就能亮但实物中蜂鸣器和继电器不能直接接GPIO必须加三极管驱动而且驱动管的基极电阻大小也要算好不然驱动电流不足蜂鸣器声音偏小或者继电器吸合不稳。我在原理图里把这些驱动电路都画好了大家照抄就行。6. 常见问题与排查技巧实录6.1 ST-Link连接失败与烧录故障这个问题在评论区或者群里被问得最多现象是点Load烧录时弹出“No STM32 Target Found”或者“Cannot access Target”排查顺序这个排查顺序非常重要很多人直接跳到重装驱动其实很多时候就是接线问题检查接线SWDIO接PA13SWCLK接PA14GND必须共地这个“共地”是最容易忽略的。如果板子是电池供电而ST-Link通过USB给电脑供电两个电源系统之间没有共地SWD协议根本无法建立通信。拔掉电池只用ST-Link给板子供电能解决80%的问题检查Reset引脚STM32的NRST引脚如果被外部电路拉低芯片会一直处于复位状态SWD也就连不上。我遇到过有人把按键接到了NRST引脚并且一直按着没弹回来排查了半天。用万用表量一下NRST电平正常工作应该是高电平检查Keil的Debug设置Utilities设置里如果选了错误的Flash Download选项烧录会报错。选STM32F10x Med-density Flash最后才是重装驱动和重启软件。ST-Link的驱动在ST官网可以下载如果Keil提示找不到ST-Link去设备管理器里看有没有识别到识别异常的话卸载设备重新扫描6.2 滴速检测数值异常的几类情况第一类滴速显示为0完全不计数检查红外对管的供电和信号线是否接反接收管的输出引脚是否确实连接到TIM2_CH1先用示波器或逻辑分析仪看接收管的输出波形如果是缓慢变化的模拟量确认是否经过比较器整形检查代码里TIM2是否被正确初始化为输入捕获模式有没有在定时器初始化后忘记使能TIM_Cmd(TIM2, ENABLE)第二类滴速显示数值是实际值的两倍大概率是输入捕获同时触发了上升沿和下降沿。检查TIM_ICInitStructure里的TIM_ICPolarity是否设置为TIM_ICPolarity_Rising如果是TIM_ICPolarity_BothEdge就会导致每个液滴计数两次也可能是红外对管信号质量不好在液滴边缘产生了多次抖动。解决办法是硬件加施密特整形软件加滑动滤波第三类滴速数值跳变极大偶尔突然飙升又回落这是环境光干扰的典型症状。红外对管的接收管对红外环境光敏感当阳光直射或者日光灯频闪时会有杂散脉冲混进来。在结构上给对管加遮光罩或者把放大电路的阈值抬高到环境光的峰值之上6.3 PID参数调试中的“坑”PID调参是个体力活但有几个坑可以提前避开坑一控制周期不稳定。如果PID的计算放在了主循环里而主循环里又调用了OLED刷新这种耗时操作PID的执行周期会忽长忽短导致参数怎么调都不稳。解决办法是把PID计算放到定时器中断里固定500ms执行一次主循环只负责显示和按键响应坑二输出限幅没做好。PID输出直接作为PWM的比较值如果输出值超过了定时器的CCR寄存器的最大范围数值就会意外回绕导致电机转速诡异跳变。我在PID_Calculate里加了output_limit同时在应用层再做一次钳位双保险坑三目标值变化太快导致系统过冲。如果用户长按加键把目标滴速从30连续改成90PID会一直处于饱和状态系统会以最大功率加速冲到目标后又因为惯性过冲到100多。解法是在按键调节里做平滑处理每次按键只改变目标值1滴/分同时PID在检测到目标值变化时自动清零积分项避免“刹车”延迟6.4 系统死机与复位问题实机运行中偶尔会出现程序跑飞、画面卡死的情况原因大多出在以下三个地方第一个是看门狗没开。虽然是开源项目我建议在产品级用法里加上独立看门狗IWDG在主循环里周期性喂狗。一旦程序跑飞或者卡死在某个外设的查询循环里看门狗会在600ms左右强制复位系统保证设备不会长时间罢工。我实测过在LCD显示刷新的循环里加了一个不合理的大延时函数如果没有看门狗整个系统就永久卡死了第二个是中断优先级配置。STM32的中断优先级分组要统一如果在初始化里用NVIC_PriorityGroup_2后面又有地方改成了Group_3中断嵌套逻辑就会混乱严重时导致死锁。代码开头统一设置一次中断分组后面不要再动第三个是电源去耦。真实的MCU对电源噪声很敏感尤其是电机PWM切换瞬间的电流冲击会造成VDD波动。如果板子上没有在电源引脚附近放0.1uF去耦电容偶发复位很难排查。我的原理图里在VDD引脚旁边放了两个100nF电容加一个10uF钽电容实物测试中电机启动时抖动明显改善。7. 实操总结与项目扩展建议这个项目从头到尾做下来我最深的体会是嵌入式开发的核心不是代码而是对硬件行为的理解。同样是滴速检测知道红外对管输出的是什么波形、为什么需要整形、环境光怎么干扰信号远比会写那几行输入捕获代码重要得多。代码只是实现方案的工具方案本身才是决定项目能否落地的关键。最后再分享一个实用的小技巧如果你手头有逻辑分析仪二十几块的8通道USB逻辑分析仪就够用强烈建议在调试滴速检测时把它用起来。把红外对管的原始信号、比较器输出信号、MCU的捕获中断引脚这三个点都接上同时抓取波形你会清晰地看到信号从模拟量变成数字量再变成中断事件的整个过程。这套调试方法不仅适用于这个项目以后做任何传感器相关的单片机项目都能用上。关于项目本身的扩展方向我琢磨了几个值得一试的方向一是加无线模块做远程监控把滴速、液位、报警状态通过ESP8266上报到云平台护士站就可以集中监控多个床位。代码层面只需要增加一个串口数据上报函数硬件上加一个ESP8266模块就行注意一下电压匹配就OK二是加触摸屏替代按键液晶的方案把OLED换成2.4寸或者3.5寸触摸屏人机交互体验会有质的提升。不过对STM32F103C8T6来说带触摸屏会比较吃力建议升级到STM32F407或者STM32F103ZET6资源宽裕很多三是做多通道版本一个主控同时监控多路输液这需要增加定时器和引脚资源建议换用更大封装的芯片重新布局。工程上的改动不小但思路是一样的把每个通道的检测和控制封装成独立模块多例化即可四是做成低功耗版本用STM32L系列芯片配合电池供电适合用于患者转运过程中的便携监护场景。这块需要引入RTC定时唤醒和事件驱动的低功耗设计也是个很有意思的优化方向我建议刚入手这个项目的朋友先在Proteus里把逻辑跑通了解整条数据流的走向再动手焊接实物。不要一上来就追求实物先把“测量-计算-控制”这个闭环在仿真里验证清楚实物阶段遇到问题才不会雾里看花。
返回列表