做嵌入式这么久,我经手过不少医疗电子相关的项目和Demo,说实话,真正让我觉得“有实际价值”的,是这套智能输液监护调控系统的升级版。病房里护士调滴速、数滴数的场景,经历过陪护的人应该都清楚,传统输液全靠人工盯,滴速准不准全凭手感,液面低了没人及时发现,管路里混入气泡更是个隐患。这套基于STM32F103C8T6开源的系统,把代码、原理图、仿真工程一起放了出来,核心思路就是从“被动报警”升级成“主动调控”:既能把滴速控制在设定范围,又能实时监测液面、气泡、阻塞等异常状态。它不光是毕业设计的好素材,对于想入门STM32医疗电子方向、想搞懂传感器采集加电机控制加闭环算法的工程师来说,也是一份很值得翻阅的参考。
1. 项目整体设计与系统架构
1.1 核心痛点与功能升级点
传统输液监护存在几个很现实的问题:第一,滴速只能靠护士手动调节滚轮,输液过程中病人体位变化、液体温度变化都会让滴速悄悄漂移;第二,输液完毕或者管路阻塞时,如果没有家属盯着,很容易出现回血甚至空气进入血管的风险;第三,护士站无法远程感知每床的输液状态,巡视全靠定时跑病房。
这套升级版系统,目标就盯在这几个痛点上。它做的事情可以归纳成三句话:能实时检测滴速并自动调节,能监测管路异常并分级报警,能通过本地屏幕和按键实现人机交互。相比简单版本的“滴速检测加蜂鸣器报警”,升级版的差异核心体现在三个地方。
| 对比维度 | 基础版 | 升级版 |
|---|---|---|
| 控制方式 | 开环,滴速检测后仅提示 | 闭环,PID调节步进电机转速 |
| 监测维度 | 仅滴速 | 滴速、液面、气泡、阻塞、累计量 |
| 人机交互 | LED灯加蜂鸣器 | OLED显示、按键设定、故障代码 |
| 数据接口 | 无 | 预留串口/USART,可扩展Wi-Fi或蓝牙模块 |
这三点升级不是拍脑袋加上去的。做过实际项目就会明白,增加检测维度意味着硬件上要多几路传感器输入,代码上要多几层状态机;闭环控制意味着要从简单的“读值”变成“读值-计算-输出”的实时控制链路;人机交互则要求系统有一个清晰可靠的显示和按键反馈逻辑。整套系统的复杂度会上一个台阶,但实际价值也完全不一样。
1.2 系统硬件架构与主控选型
硬件架构我习惯用“感知-决策-执行”这个框架来理解:感知层是滴速传感器、液位传感器、气泡检测模块和压力检测模块;决策层是STM32主控,负责信号采集、数据处理、PID运算和报警判断;执行层是步进电机驱动的蠕动泵、声光报警电路和OLED显示。
主控选择STM32F103C8T6,这个选择在今天仍然非常合理。这颗芯片是Cortex-M3内核,主频72MHz,内置64KB Flash和20KB RAM,虽然算不上一颗大资源芯片,但对于这个项目来说绰绰有余。它带有多个定时器、ADC、I2C、USART和SPI接口,滴速检测可以用外部中断加定时器实现,OLED显示可以走I2C或SPI,步进电机控制可以走定时器PWM输出,串口还能留给Wi-Fi模块或者上位机通信。更关键的是,这颗芯片的资料极其丰富,Keil环境、标准外设库和HAL库都有大量现成示例,遇到问题很容易找到参考。
在传感器选型上,滴速检测最常用的是红外对管,利用液滴下落时遮挡红外光产生电平跳变来计数。液位检测可以用光电式或者电容式传感器,放在输液瓶的液面位置,输出高低电平信号判断液面是否到达低位。气泡检测采用对射式红外传感器,贴装在输液管两侧,当管路中通过透明液体时接收管收到信号,当气泡通过时因为折射率变化导致信号跳变,利用这个特性可以识别出气泡。阻塞检测可以用压力传感器贴在管路某一段,检测管路内压力异常升高。
执行机构这块,步进电机加蠕动泵是输液控制的主流低成本方案。蠕动泵的原理是用滚轮挤压弹性软管,推动管内液体定向流动,液体只接触软管内部,不接触泵体,干净卫生。步进电机可以精确控制滚轮转动的角度,从而控制挤压频率,也就是控制流速。这种方案结构简单、成本可控,很适合做样机和教学演示。
2. 核心功能模块设计:代码侧
2.1 滴速检测与信号处理
滴速检测是整个系统的基础,检测不准,后面的控制全部失去意义。红外对管检测液滴的基本原理是:输液滴壶两侧安装红外发射管和接收管,液滴从滴壶中滴落时,会短暂遮挡红外光线,接收管导通状态发生变化,经过整形电路后输出一个脉冲信号给MCU。MCU通过检测脉冲的上升沿或者下降沿来计数,再根据单位时间内的脉冲数量计算出滴速。
实际检测时会发现一个问题:红外对管输出的信号并非理想的方波,液滴表面张力变化、外界环境光干扰、滴壶壁上的水雾,都可能造成信号抖动。直接用GPIO读取电平变化计数,结果会出现大量毛刺计数。我的做法是启用一个外部中断引脚,配合定时器做输入捕获,同时在软件里做消抖处理。
下面是一段滴速检测与平滑滤波的参考代码,基于STM32标准外设库实现:
// 滴速检测:外部中断计数 + 定时器1秒窗口统计 volatile uint16_t drop_count = 0; volatile uint16_t drop_rate = 0; // 实际滴速,单位:滴/分钟 uint16_t drop_history[10] = {0}; uint8_t history_index = 0; void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) != RESET) { // 简单消抖:读取引脚电平,确认确实是下降沿 if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0) { drop_count++; } EXTI_ClearITPendingBit(EXTI_Line0); } } // 定时器1秒中断中调用,完成滴速计算和平滑滤波 void Timer1_Second_Handler(void) { uint16_t current_rate = drop_count * 60; // 1秒计数换算成每分钟滴速 drop_count = 0; // 滑动平均滤波:用最近10次数据取平均,抑制瞬时波动 drop_history[history_index] = current_rate; history_index = (history_index + 1) % 10; uint32_t sum = 0; uint8_t i; for (i = 0; i < 10; i++) { sum += drop_history[i]; } drop_rate = sum / 10; }这段代码里有几个细节值得说。计数换算成滴速用的是drop_count * 60,因为计数窗口是1秒,要得到“滴/分钟”就得乘60。滑动平均滤波的窗口是10次,也就是10秒内的平均值,这个窗口太短则滤波效果差,太长则系统响应变慢,实测下来10秒是比较折中的选择。另外消抖处只判断了下降沿,如果传感器极性相反,判断条件要改成读取为高电平才计数。
输液总量可以基于滴速和时间累计。常见输液器的滴系数是20滴/mL,也就是每20滴为1mL,累计量计算公式是:累计量(mL) = 总滴数 / 20。系统里可以用一个变量累加总滴数,再定时换算成累计输液量显示在屏幕上。如果要更精确,可以在系统初始化时通过按键设置滴系数,兼容不同规格的输液器。
2.2 步进电机闭环调速控制
滴速检测解决的是“感知”问题,步进电机调速解决的是“执行”问题。基础版系统只做报警,护士听到报警后手动去调节滚轮,升级版则用步进电机驱动蠕动泵来实现自动调速。这里的控制链路是:设定目标滴速,和实际检测滴速比较,经过PID运算得到电机转速调节量,再通过PWM输出控制步进电机的转动速度。
为什么必须要闭环?因为输液管路中的阻力会变化。输液瓶高度变化、病人手臂位置变化、液体温度变化、管路被压迫,都会让滴速发生偏移。开环控制只能保证“电机转得均匀”,但不能保证“滴速稳定”。只有把实际滴速反馈回来,不断修正电机转速,才能实现稳定的闭环控制。这就像开车时定速巡航,不是踩住油门不动,而是根据实际车速不断微调油门。
PID控制算法是这个模块的核心。针对步进电机调速,我推荐使用增量式PID,因为增量式PID只输出控制量的增量,不会出现积分饱和导致的大幅度超调,而且对执行机构的冲击更小。下面是增量式PID的参考实现:
typedef struct { float target; // 目标值 float actual; // 当前实际值 float err; // 当前误差 float err_last; // 上一次误差 float err_prev; // 上上次误差 float Kp, Ki, Kd; float output; // 输出增量 } PID_TypeDef; void PID_Calc(PID_TypeDef *pid) { pid->err = pid->target - pid->actual; // 增量式PID公式 pid->output = pid->Kp * (pid->err - pid->err_last) + pid->Ki * pid->err + pid->Kd * (pid->err - 2 * pid->err_last + pid->err_prev); pid->err_prev = pid->err_last; pid->err_last = pid->err; }调用PID计算后,得到的output是一个增量值,把这个增量加到当前的电机转速设定上,再映射成步进电机的脉冲频率。步进电机的转速和脉冲频率是线性关系,例如28BYJ-48步进电机在四相八拍驱动方式下,每转一圈需要4096个脉冲,那么目标转速对应的脉冲频率就能直接算出来。将PID输出的增量叠加到基础脉冲频率上,再通过定时器PWM输出即可。
PID参数整定是很多新手最头疼的环节。我分享一个比较实用的整定步骤:先把Ki和Kd设为0,只保留Kp,从小到大增加Kp,让系统出现等幅振荡,记录此时的Kp和振荡周期;然后根据经验公式设置Ki和Kd的初值,再微调。实际测试中,这个项目的初始参数一般从Kp = 2.0,Ki = 0.5,Kd = 0.1开始,再根据响应曲线微调。有一点要特别提醒:参数整定必须在真实滴速反馈下进行,不能只在仿真里调,仿真和实物的延迟特性差异很大。
2.3 异常监测与安全机制
输液监护系统如果只看滴速和调速,那还不够。真正体现“监护”价值的是异常检测和安全机制。这套系统设计了四个维度的异常检测:液面过低、管路气泡、管路阻塞、滴速异常。
液面过低检测比较简单,在输液瓶低位处安装光电液位传感器,当液面低于传感器位置时,输出电平翻转,MCU检测到后进入低液位报警状态。气泡检测用对射式红外传感器,贴在输液管外侧,无气泡时接收管处于稳定导通状态,有气泡经过时输出信号出现跳变,如果在短时间内检测到多个跳变,就判定为气泡异常。阻塞检测最直接的方式是使用压力传感器贴在管路表面,当管路内压力超过阈值时判定阻塞;低成本方案也可以通过检测步进电机是否丢步来间接判断,但精度差一些,这里建议优先用压力传感器。
所有异常状态统一由MCU中的状态机管理。状态机分为正常运行、滴速异常、低液位报警、气泡报警、阻塞报警、待机等状态。不同状态对应不同的声光报警等级和控制动作。下面是一个简化的异常处理逻辑参考:
typedef enum { STATE_NORMAL = 0, STATE_LOW_LEVEL, STATE_BUBBLE, STATE_BLOCK, STATE_RATE_ABNORMAL } SysState; void System_State_Update(void) { if (low_level_flag == 1) { // 低液位:停止电机,长鸣报警 Motor_Stop(); Buzzer_On(); OLED_ShowErrorCode(0x01); return; } if (bubble_flag == 1) { // 气泡:停止电机,立即报警 Motor_Stop(); Buzzer_On(); OLED_ShowErrorCode(0x02); return; } if (block_flag == 1) { // 阻塞:停止电机,间歇报警 Motor_Stop(); Buzzer_Config(INTERMITTENT); OLED_ShowErrorCode(0x03); return; } // 滴速偏差超过设定阈值,持续一段时间后报警 if (abs(drop_rate - target_rate) > RATE_THRESHOLD) { rate_abnormal_count++; if (rate_abnormal_count > 10) { Motor_Stop(); Buzzer_Config(INTERMITTENT); OLED_ShowErrorCode(0x04); return; } } else { rate_abnormal_count = 0; } }报警分级的设计思路是:低液位和气泡属于需要立即处理的高危状态,必须马上停止输液并发出持续报警;阻塞属于需要尽快处理但不至于瞬间危险的状态,采用间歇报警;滴速偏差先给一个缓冲窗口,因为短时间的滴速波动可能是病人活动造成的,持续偏差才判定为异常。
2.4 人机交互与状态显示
一个嵌入式系统要真正好用,人机交互不能省。这套系统使用了一块0.96寸OLED屏幕,I2C接口,分辨率128x64,用来显示当前滴速、目标滴速、累计输液量、运行状态和故障代码。OLED的好处是自发光、视角好、功耗低,而且I2C只要两根线就能驱动,不占用太多IO资源。
按键部分设计了四个功能键:设定加、设定减、启动/停止、消音。设定加和设定减用来调整目标滴速,按住可以连续加减,松开停止。启动键负责电机的启动和停止,消音键在报警时按下可以暂时关闭蜂鸣器,但如果异常状态没有解除,蜂鸣器会在延时后再次响起。
这里有个交互细节值得分享:按键扫描放在定时器中断里,每10ms扫一次,配合软件消抖,避免按一次触发多次。代码如下:
void Key_Scan_10ms(void) { static uint8_t key_state = 0; uint8_t key_now = (GPIO_ReadInputDataBit(KEY_PORT, KEY_PLUS_PIN) == 0) | ((GPIO_ReadInputDataBit(KEY_PORT, KEY_MINUS_PIN) == 0) << 1) | ((GPIO_ReadInputDataBit(KEY_PORT, KEY_START_PIN) == 0) << 2) | ((GPIO_ReadInputDataBit(KEY_PORT, KEY_BUZZER_PIN) == 0) << 3); switch (key_state) { case 0: // 等待按下 if (key_now != 0) { key_state = 1; } break; case 1: // 确认按下 if (key_now != 0) { key_state = 2; Handle_Key_Event(key_now); } else { key_state = 0; } break; case 2: // 等待释放 if (key_now == 0) { key_state = 0; } break; default: key_state = 0; break; } }这种三段式按键状态机比简单的延时消抖要可靠得多,不会因为按键抖动产生误触发,也不会阻塞主循环。OLED显示建议不要每次刷新全屏,而是分区域刷新,比如滴速数据每500ms刷新一次,故障代码和状态信息只在变化时刷新,这样能减少I2C通信负担,也让屏幕更稳定。
另外如果要扩展无线监控,串口就是现成的通道。把当前状态数据按照固定帧格式通过USART发送,比如帧头加设备号加数据载荷加校验和,护士站的上位机或者Wi-Fi模块收到后就能解析显示。这一步为后续做多床位监控打下了基础。
3. 原理图设计与仿真验证
3.1 原理图设计要点
原理图是硬件设计的地基,画的时候偷懒,后面调试就会吃苦。这套系统的原理图按照功能模块划分,大致分为电源电路、主控最小系统、传感器接口电路、电机驱动电路、人机交互接口五块。
电源电路是所有硬件稳定工作的前提。系统外部输入一般是5V USB供电或者适配器供电,但OLED、传感器、STM32和部分逻辑电路需要3.3V,所以要用一个LDO稳压芯片把5V降到3.3V。我习惯在电源输入端加一个防反接二极管和一个100uF的大电容,避免电源反接烧板、同时抑制上电瞬间的电压跌落。3.3V输出端要加多个0.1uF去耦电容,分别放在主控电源引脚附近,高频噪声会被就近滤掉。
主控最小系统核心是STM32F103C8T6、8MHz晶振、复位电路、BOOT配置和SWD下载接口。晶振的两个负载电容取20pF左右,布局时要尽量靠近芯片晶振引脚。复位引脚接一个10K上拉电阻,并联一个0.1uF电容到地,实现上电自动复位。BOOT0和BOOT1下拉到地,让芯片从Flash启动。SWD接口引出SWDIO、SWCLK、GND、3.3V和复位引脚,下载调试就靠这四根线,比JTAG省IO。
传感器接口电路里,我最想强调的是上拉电阻和滤波电容。红外对管接收端通常输出开漏或者集电极开路信号,必须加上拉电阻才能输出高电平。上拉电阻选10K比较合适,既能保证信号边沿够陡峭,又不会消耗过多电流。在每个传感器的电源和地之间加一个0.1uF去耦电容,可以有效滤除电机启停带来的电源噪声。
电机驱动电路要特别小心,因为步进电机是感性负载,启停瞬间会产生很大的反向电动势,如果不做保护,很容易把主控或者驱动芯片打坏。使用ULN2003驱动28BYJ-48电机时,ULN2003内部自带续流二极管,外部电路相对简单;如果使用A4988驱动42步进电机,则要在电机电源端加一个大容量电解电容,同时在电机输出端并联续流二极管。驱动芯片的电源和单片机电源建议分开走线,在汇合点单点接地,这样能显著减少电机电流对主控电源的干扰。
3.2 仿真验证思路与结果
仿真不是摆设,它能帮你在焊接实物之前先把逻辑跑通。这个项目用Proteus做仿真验证,我建议分两步走:先仿真验证控制逻辑,再设计实物验证。
Proteus里搭建的仿真工程包括STM32F103C8T6模型、OLED显示屏模型、步进电机模型和用于模拟滴速传感器信号的信号发生器。滴速传感器在仿真里无法真实模拟液滴,可以用信号发生器产生方波来代替,方波的频率就对应滴速。例如目标滴速是40滴/分钟,信号发生器就设置成大约0.67Hz的方波信号,MCU检测这个方波的频率,计算出的滴速应该接近40滴/分钟,然后PID输出控制步进电机转速,观察步进电机是否稳定转动。
仿真阶段最容易发现的是逻辑错误,比如状态机跳转条件写反了、OLED显示刷新逻辑错误、按键消抖参数不合理等。这些问题在仿真里改代码成本很低,但如果到实物阶段才发现,往往需要反复烧录测试,浪费时间。仿真还能验证一个很重要的东西:中断和主循环之间的时序关系。如果滴速计数中断和PID计算中断优先级设置不当,可能导致数据竞争,仿真运行时钟是固定的,能一定程度上暴露这类问题。
但仿真和实物有差异,这一点必须有清醒认识。仿真里信号是理想的,方波就是方波,而实物的红外传感器信号会有毛刺、有上升下降沿时间、有环境光干扰;仿真里的步进电机模型也是理想的,实物的步进电机会有发热、丢步、共振问题。所以仿真验证通过只是第一步,不能替代实物调试。我的建议是:仿真验证逻辑正确性,实物验证真实表现,两者互为补充,谁都别省。
仿真完成后的实测数据也印证了这一点。在样机上,设定目标滴速为40滴/分钟,系统稳定后实际滴速基本能维持在39到41滴/分钟之间,波动幅度在正负2.5%以内,比人工调节滚轮的精度高不少。响应时间方面,当人为压住管路模拟阻塞时,滴速传感器计数立刻下降,PID在1到2秒内开始反应,电机转速自动加快补偿,如果阻塞持续超过3秒,系统会判定为阻塞异常并停机报警。
4. 常见问题与调试经验实录
4.1 滴速检测测不准怎么办
滴速检测是这套系统里最容易出问题的地方。常见的现象是计数偏大、计数忽高忽低,或者完全不计数。我把自己踩过的坑和排查方法整理成了一张排查表。
| 故障现象 | 可能原因 | 排查与解决 |
|---|---|---|
| 滴速计数明显偏大 | 环境光干扰、传感器灵敏度太高 | 加遮光罩,调整比较器阈值,软件滑动平均 |
| 滴速计数波动剧烈 | 液滴大小不均、滴壶挂壁、传感器位置偏移 | 调整传感器对准位置,增大滤波窗口 |
| 完全不计数 | 红外管引脚接反、上拉电阻缺失、GPIO配置错误 | 用万用表测接收管输出电平变化,检查初始化代码 |
| 偶尔丢一个脉冲 | 液滴下落位置偏离光路 | 调整滴壶固定夹具,让液滴稳定垂直下落 |
最典型的坑是环境光干扰。红外接收管对太阳光里的红外成分非常敏感,白天靠窗的位置,接收管可能直接被环境光饱和,导致液滴遮挡时的信号变化很小,计数丢失。解决办法有两个层面:硬件上给传感器加上不透明的遮光罩,只留出滴壶位置;软件上把检测阈值改成自适应,系统启动后先采集一段背景信号,动态确定判断阈值,这样即使环境光缓慢变化也能自适应。
另一个容易被忽略的细节是传感器响应速度。红外对管接收电路如果RC常数太大,输出信号的上升沿会变缓,MCU外部中断可能无法准确捕获。可以在比较器输出端加一个施密特触发器或者使用具有施密特输入的GPIO,让边沿更陡峭。软件层面也可以在中断里加一个简单的状态判断,防止同一个液滴被重复计数。
4.2 电机调速不稳和系统复位问题
步进电机调速不稳定,通常表现为电机抖动、丢步、转速突然变化。抖动很多时候来自PWM频率设置不当,步进电机在低频段容易产生共振,可以跳过共振频率区间,或者使用细分驱动方式,比如A4988设置16细分,电机运行会平滑很多。丢步则和驱动电流不足有关,需要检查电机驱动电源的带载能力,28BYJ-48这种小电机用ULN2003驱动时,工作电流在100到200mA级别,电源需要预留足够的余量。
系统复位是另一个经典问题。表现形式是电机一转,单片机就复位重启。这种情况几乎可以断定是电源问题:电机启动瞬间电流突增,导致电源电压跌落,低于STM32的最低工作电压,看门狗或者欠压复位电路就把芯片复位了。解决思路有三个:电机供电和主控供电分开,用独立的5V电源给电机驱动供电;在电源输出端加大容量电解电容,我实际用220uF加470uF并联,效果明显;软件上在电机启动时做软件缓冲,不要瞬间全速启动,而是用梯形加速曲线,从低速逐渐增加到目标转速,这样能显著减小启动冲击。
调试这类问题,我强烈建议用串口打印关键数据。在STM32的USART1上接一个USB转串口模块,把滴速、PID输出、电机转速、系统状态这些变量实时打印出来,用串口助手记录下来。很多偶发问题在现象上很难复现,但串口日志能把现场还原出来。比如复位问题,看日志里滴速计数突然中断、然后重新出现系统初始化信息,就能确认是复位而不是死机。
4.3 STM32下载与调试的常见坑
做STM32开发,下载调试是避不开的环节。很多新手在第一次连接ST-Link或者J-Link时,会遇到找不到目标芯片的错误,提示信息类似 "error: no stm32 target found! if your product embeds debug authentication..."。遇到这种提示,先别慌,按下面几条逐一排查。
第一,确认接线是否正确。SWD接口只需要四根线:SWDIO、SWCLK、GND、VCC。VCC是用来给目标板供电或者做电平参考的,如果目标板已经独立供电,也要保证VCC连到目标板的3.3V,否则调试器无法识别目标芯片电平。第二,检查目标板是否在运行状态。如果芯片内部程序跑飞,或者进入了低功耗模式,调试器可能无法连接。解决办法是按住目标板的复位键,点击连接的同时松开复位键,很多下载器都支持这种连接方式。第三,检查BOOT引脚。BOOT0如果被拉高,芯片会进入系统存储器引导模式,此时SWD功能可能被改变,需要把BOOT0恢复到低电平。第四,优先使用四线加复位线的五线连接方式,ST-Link的NRST引脚接目标板复位脚,可以提升连接成功率。
下载不成功还有一个容易被忽视的原因:目标板电源质量太差。特别是电机驱动共用电源时,调试器连接瞬间如果电压跌落,芯片就处于不稳定状态,自然连不上。我的习惯是,调试阶段给主控板单独用USB供电,电机驱动电路先断开,等程序功能验证没问题了再接上电机,这样能大大减少调试干扰。
4.4 从仿真工程到实物移植的差异
从Proteus仿真工程移植到实物板子上,通常不会一次点亮,这是正常的。仿真和实物之间的差异集中在几个方面:时钟配置、外设初始化、信号质量和时序。
时钟差异是最常见的坑。仿真环境对晶振的参数不敏感,8MHz晶振配20pF电容在仿真里能正常工作,实物上如果电容值偏差太大,可能导致晶振不起振,系统完全没反应。实物的晶振焊接要牢固,两个负载电容要对称布局,如果起振困难,可以用示波器测量晶振引脚的振荡波形确认。另外,很多STM32工程默认使用内部HSI时钟,精度约±1%,滴速检测时短期计时问题不大,但长期累计输液量会有误差,建议切换到外部HSE晶振。
外设初化顺序也容易出问题。实物上电瞬间,电源和传感器信号需要时间稳定,如果代码在上电后立刻去读传感器状态并判断液位或气泡,很可能会读到错误值。解决办法是在main函数开头加一个延时,比如延时300ms再初始化外设和读取传感器状态,让电源稳定下来。还可以在初始化后做一次传感器自检,把所有传感器的状态打印到串口,确认硬件接线是否正确,再进入主循环。
最后说一个和项目定位相关的问题。这套系统作为开源项目,定位是学习、教学和科研验证,不是可以直接用于临床的医疗器械。真实的输液设备需要考虑生物相容性、无菌操作、电磁兼容、冗余设计等大量工程因素,还要经过严格的医疗设备法规测试和注册流程。做工程的人要有这个边界意识,在实验和论文里使用没问题,但不要试图直接把它用在患者身上。不过这不影响这个项目的学习价值,它把一个完整的感知、控制、执行和人机交互链路串了起来,对理解嵌入式系统设计和医疗电子开发流程非常有帮助。
我个人在实际操作中的体会是,这套系统最花时间的不是代码,也不是原理图,而是把闭环控制调到稳定的过程。第一次调PID的时候,我在仿真里觉得参数已经很好了,结果实物一跑,滴速波动还是很大。后来静下心来做了一件事:用串口把每次的检测滴速和目标滴速记下来,画成曲线看趋势,这才发现是电机加速太猛,导致液滴在滴壶里飞溅,传感器计数混乱。把电机启动改成梯形加速,再把滴速滤波窗口加到10次,系统才真正稳定下来。这个教训告诉我,做嵌入式项目,数据日志和现象观察比拍脑袋调参数重要得多。
如果你也想基于这个项目继续扩展,我建议从两个方向入手:一是加上无线通信模块,把每台输液设备的数据汇总到护士站,做成多床位监控系统,这个方向很贴近实际需求;二是把滴速控制精度继续提升,换成带编码器的直流电机加光电测速盘,实现更高精度的闭环控制。这套代码和原理图就是很好的起点,动手去改一版,收获会比读十遍资料都大。