STM32智能输液监控系统:增量式PID闭环调速设计与Proteus仿真实践
2026/9/9 5:31:18 网站建设 项目流程

手头这个项目是STM32F103C8T6平台的智能输液监护调控系统升级版,代码、原理图、Proteus仿真三件套齐整。这两年陆续有不少人做输液监控类的课设和毕设,但多数停在“检测+报警”这一步,泵能转、滴速能测,却没有形成真正的闭环调控。这次我重新画了板子、重写了底层驱动和控制算法,把整个系统从“能演示”提升到“能连续跑一两个小时不慌”的状态,这里把设计思路和踩过的坑一并记录下来,给准备做类似项目的同学当个参考。

这套系统的核心价值在于两点:一是不光能实时测出当前输液滴速,还能根据设定目标速度自动调整蠕动泵转速,做到无人工干预下的闭环调节;二是对异常情况(滴速偏差过大、输液完成、管路堵塞)能及时报警并夹紧管路,防止空气进入。升级版相对基础版的区别主要在控制层——加入了增量式PID算法,同时优化了滴速检测的滤波逻辑,人机交互从按键加数码管改成了旋转编码器加OLED屏幕,操作手感好了不少。

这套资料更适合有STM32基础、想进阶做完整小系统的同学,或者做课程设计、毕业设计需要“软硬结合”完整方案的人。

1. 项目整体设计与方案选型

1.1 升级版要解决的核心问题

基础版的输液监护仪通常只做一件事:用红外对管卡在莫非氏滴管两侧,液滴落下时遮挡红外光,产生一个脉冲,单片机数脉冲个数再换算成“滴/分钟”。这个方案本身没毛病,但实际用起来有几个让人头疼的地方——第一个是环境光干扰,白天靠窗的位置红外的误触发率能高到你怀疑人生;第二个是患者体位变动或者输液架晃动,滴速会突然波动;第三个最要命,就是它只能“看”不能“治”,滴速偏快了或者变慢了,只能靠护士手动去滚轮调节。

升级版的目标很明确:在这个基础上加执行机构,用蠕动泵代替人手调节,让系统自动把滴速拉回设定值。同时把抗干扰和异常处理做得更扎实,不能因为一次误检就乱报警,也不能因为病人动了一下就让泵疯狂加速减速。

整套系统的功能定位如下:

  • 实时测量输液滴速,精度到1滴/分钟以内
  • 支持旋转编码器设定目标滴速(范围1~60滴/分钟)
  • 增量式PID闭环控制蠕动泵,自动修正速度偏差
  • OLED实时显示设定速度、实际速度、泵状态和报警信息
  • 滴速异常、输液完成、管路堵塞时声光报警并自动夹管
  • 掉电保存参数,重新上电后恢复上次设置

1.2 硬件方案选型思路

主控这块没什么悬念,选了STM32F103C8T6。这个芯片被用得太多,资料全、外设够用(定时器、ADC、I2C、USART、PWM都有)、价格也稳,做这种小系统性能绰绰有余。有人问为什么不用ESP32或者国产替代芯片,我觉得在这个项目里没必要——不需要WiFi,不需要复杂计算,F103的低功耗特性和外设配置已经非常成熟,并且Proteus里的仿真模型也是以这个芯片为主,方便做软硬件联调。

滴速检测方案我对比过几次,最终用的还是红外对管加电压比较器。摄像头方案精度高但成本和功耗都上去了,超声波方案对液滴这种小目标完全不合适。红外对管的问题是输出信号毛刺多,液滴经过检测区域时需要一定的时间阈值,响应快了容易把飞溅的水珠也算进去,响应慢了又可能漏检。解决办法是前端加一级LM393比较器整形,用可调电阻设定阈值电压,把红外接收管的模拟信号变成干净的高低电平脉冲,再送进单片机的定时器输入捕获引脚。

执行机构选了蠕动泵加28BYJ-48步进电机。蠕动泵的好处是液体只接触泵管,不接触泵体,换管路就能继续用,符合医疗场景的基本卫生要求;28BYJ-48虽然转速慢、扭矩一般,但胜在便宜、控制简单、低速下扭矩还可以,配合4相8拍驱动完全能带动输液泵管。如果想升级平滑性,可以考虑42步进电机加A4988驱动板,但功耗和体积都会明显增加。

人机交互这块,显示用0.96寸I2C接口OLED,四根线就能接,显示信息密度比数码管高太多;输入用旋转编码器而不是矩阵键盘,主要是调节数字时手感好,一个旋钮完成加减和确认三个动作,代码里只需要一个外部中断加两个GPIO就能解析方向和步数。

2. 硬件设计与原理图核心模块拆解

2.1 主控最小系统与电源分配

原理图画起来,主控最小系统是最基础的,但也是最容易被忽视的。STM32F103C8T6的BOOT0要接10K下拉电阻到地,保证从Flash启动,这个引脚悬空状态下偶尔能跑、偶尔起不来,排查时极其浪费时间。复位电路用经典的10K上拉加0.1uF电容到地,NRST引脚低电平复位。晶振用8MHz无源晶振,两个20pF负载电容匹配,如果有条件可以加一个1M电阻并联在晶振两端帮助起振。

电源部分这次特意做了两个供电回路:系统主电源(MCU、传感器、OLED、编码器)用AMS1117-3.3从5V降压,步进电机驱动单独从5V取电。主要原因是我实测时发现,28BYJ-48启动瞬间电流能冲到250mA以上,如果和MCU共用一条电源轨,OLED亮度会闪、红外检测阈值会漂,严重时候还会让单片机复位。原理图上这两个回路的滤波电容也分开布局,数字地和功率地在电源入口处单点汇合,模拟地和数字地用0欧电阻隔离。

供电入口加了一个SS34肖特基二极管做防反接,容量够大、压降小。电源指示灯选蓝色LED,串联1K电阻限流,亮度适中不刺眼。这个部分虽然简单,但做出来整板的稳定性会有明显提升。

2.2 滴速检测电路与信号调理

滴速检测是整个系统的感知端,这部分做得不好,后面控制算法再厉害也白搭。

红外发射端我用一个8050三极管驱动红外发射管,串联100欧限流电阻,发射电流控制在20mA左右。接收端用光敏三极管,基极悬空,集电极接一个10K电阻到VCC,发射极接地,液滴经过时遮挡红外光,集电极电压会从高电平跳变到低电平。这里注意一点:光敏管的响应速度跟负载电阻有关,阻值越大输出幅度越大但响应越慢,实测10K是个比较合适的折中值。

信号调理的核心是LM393比较器。红外接收端输出的模拟信号接到LM393的同相输入端,反相输入端接一个10K电位器调节比较阈值。LM393是开漏输出,必须接一个10K上拉电阻到3.3V才能输出正常的高电平。我建议把比较器输出的脉冲信号同时引到两个地方:一路进STM32的PA0(TIM2_CH1)做输入捕获,另一路留给示波器观察,调试时能直观看到波形有没有问题。

这里有一个关键的硬件细节:光电对管安装位置一定要加遮光罩。滴管两侧各留一个狭缝,只让液滴经过的路径上的光线通过,否则环境光直接打在接收管上,LM393的输出就会一直翻转。我用黑色热缩管套在管子上做了个简易遮光结构,效果立竿见影。

2.3 步进电机驱动与蠕动泵控制

28BYJ-48步进电机是5线4相制,驱动板用ULN2003,原理图上输入侧接STM32的四个GPIO(PA4~PA7),输出侧接电机线圈。ULN2003内置续流二极管,电机换相瞬间产生的反向电动势会被吸收,不需要额外加保护电路。每个输入引脚串一个1K电阻,防止上电瞬间GPIO为高电平时电流过大。

驱动时序用经典的4相8拍:A-AB-B-BC-C-CD-D-DA。8拍模式比4拍模式步距角小一半,分辨率更高,蠕动泵需要的转速本来就慢,8拍模式下转矩波动也小一些。控制周期上,我建议PID输出映射到步进脉冲周期间隔而不是直接控制速度,这样更平滑。

蠕动泵的安装也是个容易忽略的细节。泵管必须卡在泵轮和泵壳之间的轨道上,松紧程度直接影响输液精度——太紧电机转不动,太松泵管挤压不充分,液体流量和电机转速不成比例。第一次装的时候调了快半小时,后来总结经验:装上泵管后手动转电机,感觉有阻尼但能顺畅转动,这个松紧度就差不多。

2.4 显示、输入与报警电路

OLED用的是SSD1306驱动芯片的0.96寸屏,I2C地址默认0x3C。I2C的SDA和SCL都要接上拉电阻到3.3V,STM32的PB6和PB7内部上拉也可以用,但我还是习惯外部加4.7K上拉,实测波形更稳。OLED的供电用3.3V,部分型号在5V下也能跑,但时间长了容易发烫,别图省事直接怼5V。

旋转编码器用的是EC11,带按键功能。A、B相分别接PB0、PB1,配置成外部中断,触发模式选双边沿。按键那一相接PB2,按下时接地,配置成输入下拉加外部中断。编码器的A、B相到MCU之间各加一个100nF电容到地做硬件消抖,比纯软件消抖可靠得多,而且不占用CPU时间。

蜂鸣器用有源蜂鸣器,一个NPN三极管驱动,GPIO控制三极管通断。有源蜂鸣器内部自带振荡源,给高电平就响,不用PWM驱动。并联一个SS34二极管防反向电动势——蜂鸣器是感性负载,断电瞬间会产生反向高压,不接二极管三极管会有击穿风险。

3. 软件架构与核心代码实现

3.1 程序整体流程与模块划分

代码结构上我按功能拆成了几个模块:main.c负责初始化调度,timer.c管理滴速检测和系统计时,motor.c封装步进电机驱动,pid.c实现增量式PID,oled.c处理显示,encoder.c解析旋转编码器输入,alarm.c管理报警状态机。每个模块接口清晰,改一个功能不用动其他地方,调试起来很省心。

系统主流程是典型的“主循环+中断”结构。主循环里跑状态机和OLED刷新,定时器中断里做高速实时任务——TIM2的输入捕获处理滴速脉冲,TIM3产生1ms时基驱动PID计算和电机脉宽更新。关键点在于:PID计算放在中断里,OLED刷新放在主循环里,两者用共享变量通信,访问共享变量时暂时关闭中断保护,避免数据错乱。

状态机是系统的大脑,我定义了以下几种运行状态:

  • IDLE:待机,显示系统就绪
  • SETTING:设置目标滴速
  • RUNNING:运行中,PID闭环控制
  • ALERT:报警,夹管并停机
  • PAUSE:暂停运行

状态切换由事件驱动,比如在IDLE状态短按编码器按键进入SETTING,设定完成后长按确认进入RUNNING,运行中检测到滴速异常进入ALERT。这种设计比裸奔式的if-else嵌套清晰得多,后面加新功能也方便。

3.2 滴速检测核心实现

滴速检测的核心是靠TIM2的输入捕获功能测量相邻两个液滴脉冲的时间间隔。输入捕获的原理是硬件自动记录定时器计数值,不需要CPU逐条指令参与,精度很高,而且不阻塞主循环。

用定时器输入捕获测滴速,计算逻辑是这样的:定时器时钟72MHz,预分频设为72,计数频率就是1MHz,即每微秒计一个数。液滴脉冲到来时,捕获寄存器记下当前计数器的值,和上一次捕获值做差,得到的就是两个液滴之间的微秒数。滴速换算成“滴/分钟”公式很简单:

滴速(滴/分钟) = 60,000,000 / 脉冲间隔(微秒)

比如间隔500ms,就是60/0.5=120滴/分钟,这个速度太快了,现实中输液一般不超过60滴/分钟,所以正常脉冲间隔应该在1秒以上。

实际代码里不能只看单次间隔,液滴在管口悬挂的过程中有时候会因为表面张力反复抖动,产生连续两三个伪脉冲。我的处理办法是连续采集5个脉冲间隔,去掉最大值和最小值,取中间3个的平均值作为有效数据。这样可以滤掉大部分干扰,又不会像纯均值滤波那样把真实的速度变化“抹平”掉。

以下是定时器输入捕获初始化代码:

void TIM2_Capture_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_ICInitTypeDef TIM_ICInitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; // 使能时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); // PA0 配置为浮空输入,作为TIM2_CH1输入捕获引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // 72MHz/72 = 1MHz计数频率 TIM_TimeBaseStructure.TIM_Period = 0xFFFF; TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // 输入捕获配置:上升沿触发,直接映射到TI1 TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0x0F; // 滤波,抗毛刺 TIM_ICInit(TIM2, &TIM_ICInitStructure); NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE); TIM_Cmd(TIM2, ENABLE); }

中断回调里处理捕获数据并做滤波计算:

uint32_t last_capture = 0; uint32_t interval_buffer[5]; uint8_t buffer_index = 0; uint32_t filtered_interval = 0; void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); uint32_t current_capture = TIM_GetCapture1(TIM2); uint32_t interval = current_capture - last_capture; last_capture = current_capture; // 忽略明显异常的间隔(<200ms或>10s) if (interval < 200000 || interval > 10000000) { return; } interval_buffer[buffer_index++] = interval; if (buffer_index >= 5) { buffer_index = 0; // 冒泡排序取中间3个的平均值 uint32_t temp[5]; for (int i = 0; i < 5; i++) temp[i] = interval_buffer[i]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4 - i; j++) { if (temp[j] > temp[j+1]) { uint32_t t = temp[j]; temp[j] = temp[j+1]; temp[j+1] = t; } } } filtered_interval = (temp[1] + temp[2] + temp[3]) / 3; } } }

3.3 增量式PID控制步进电机

闭环控制是升级版的核心改动。手动调节输液速度的问题在于,人的反应速度跟不上滴速的变化,而且调节量完全靠经验。PID控制器的思路就是不断对比实际滴速和目标滴速,根据偏差的大小和变化趋势自动调节电机的转速。

增量式PID和位置式PID的区别在于,它不是直接输出一个绝对的控制量,而是输出控制量的增量,执行机构只需要在上一次的基础上增加或减少这个增量就行。这样有个好处:即便PID参数设置有问题导致输出振荡,也不会一下子跳到极端值,系统相对安全。

增量式PID公式如下:

ΔU(k) = Kp * [e(k) - e(k-1)] + Ki * e(k) + Kd * [e(k) - 2*e(k-1) + e(k-2)]

其中e(k)是本次偏差,e(k-1)是上次偏差,e(k-2)是上上次偏差。每次计算完,新的控制量就是上一次的控制量加上这个增量。

代码实现如下:

typedef struct { float Kp; float Ki; float Kd; float target; float current; float error_last; float error_prev; float output; } PID_TypeDef; void PID_Init(PID_TypeDef *pid, float kp, float ki, float kd) { pid->Kp = kp; pid->Ki = ki; pid->Kd = kd; pid->target = 40.0f; pid->current = 0.0f; pid->error_last = 0.0f; pid->error_prev = 0.0f; pid->output = 0.0f; } float PID_Calculate(PID_TypeDef *pid, float target, float current) { pid->target = target; pid->current = current; float error = target - current; float delta_u = pid->Kp * (error - pid->error_last) + pid->Ki * error + pid->Kd * (error - 2.0f * pid->error_last + pid->error_prev); pid->error_prev = pid->error_last; pid->error_last = error; pid->output += delta_u; // 输出限幅,防止电机转速超出合理范围 if (pid->output > 100.0f) pid->output = 100.0f; if (pid->output < 0.0f) pid->output = 0.0f; return pid->output; }

PID参数整定我推荐用“先P后I再D”的顺序。先把Ki和Kd设成0,只保留Kp,从小到大慢慢加,观察滴速的响应曲线——系统开始稳定震荡时,记下此时的Kp作为临界增益,然后再逐步加Ki消除稳态误差。这个项目里我最后用的参数是Kp=0.8,Ki=0.15,Kd=1.2,实际响应大概需要5到10秒能把滴速稳定在目标值附近。注意这个参数跟你的机械结构、泵管松紧度都有关系,换了一根新的泵管或者换了一个电机,参数可能需要微调。

PID计算周期设成1秒一次。因为滴速的反馈本身要累积1.5秒左右才能算出一次有效值,PID算得太快反而会在两次有效反馈之间瞎折腾。控制输出映射到电机上时,我做了线性转换:PID输出的0~100对应步进电机的脉冲周期从200ms到5ms变化。这样电机随着控制量增大而加速,随着控制量减小而减速。

3.4 状态机与报警逻辑

状态机的实现不复杂,关键是报警触发的条件要设计得合理,不能误报也不能漏报。我设置了以下几种报警场景:

  • 滴速偏差超过设定值的20%且持续10秒以上,判定为异常
  • 3秒内没有检测到任何液滴脉冲,判定为输液完成或堵管
  • 实测滴速超过60滴/分钟,判定为失控

报警触发后系统会做两件事:一是蜂鸣器间歇鸣叫、OLED图标闪烁;二是夹管机构动作——我用一个舵机旋转90度压紧输液管,防止空气继续进入静脉。这个安全机制在真实医疗场景里是必备的,在实验环境里也体现了一个完整的监护系统该有的逻辑。

状态切换的代码结构用了函数指针数组的方式,每个状态对应一个处理函数,事件发生时查表切换。代码可读性和可扩展性都不错,后面想加“预充”或者“排空”模式,只需要新增状态和处理函数就行,不用改主体逻辑。

4. 仿真搭建与调试要点

4.1 Proteus仿真电路搭建方法

Proteus里搭建这套系统,核心思路是用信号发生器来模拟红外对管输出的液滴脉冲。真实硬件中LM393比较器输出的是一串方波脉冲,脉冲频率对应滴速,在Proteus里我直接用DSEG信号发生器(即数字脉冲信号源)接到PA0引脚,设置脉冲频率来模拟不同滴速。

搭仿真电路的时候注意几点:首先是STM32F103C8T6的模型在Proteus里选对封装,VDD和VSS引脚一定要接电源和地,否则程序下载后仿真跑不动;其次是OLED在Proteus里有现成模型,SSD1306的I2C接口接到PB6和PB7,跑起来能直接显示内容;第三,步进电机和ULN2003在仿真里也有对应的模型,可以用虚拟示波器观察电机驱动的时序波形。

调滴速检测逻辑的时候,我建议把信号发生器的频率设成2Hz左右(对应30滴/分钟),观察OLED上的显示值是否接近30。如果显示偏大或偏小,优先检查TIM2的预分频系数和捕获中断的处理逻辑,先确认微秒计数值对不对,再往下查滤波算法。

4.2 仿真与实际运行的差异提醒

仿真跑通了不代表实物就能直接跑,这里面的差异我踩了不少坑。Proteus里红外传感器、比较器、电机这些模拟器件的电气特性都是理想化的,不存在环境光干扰、触点抖动、电源噪声这些实际难题。所以仿真里的滴速波形干净漂亮,代码放到实物上就可能会出现误触发、信号抖动。

我在实际调试中遇到的第一个典型问题是:比较器的输出在滴速较快时出现毛刺,单片机把同一个液滴的上升沿和下降沿都当作有效脉冲,导致滴速读数翻了近一倍。排查方法是先用示波器观察比较器输出波形,确认波形是不是一个完整干净的低电平脉冲,如果波形边沿有毛刺,就需要调整比较器阈值电压或者在软件里加大输入捕获的滤波系数。

另一个差异是电机启动的机械惯性。仿真里步进电机给脉冲就转、停脉冲就停,但实际蠕动泵有管路的弹性和流体的惯性,电机停转后泵管会缓慢恢复形状,液体还会继续流一会儿。这意味着PID控制的实际响应会有滞后,参数需要比仿真里更保守一些,否则容易震荡。

5. 实测经验与常见问题排查

5.1 实测中遇到的高频问题

第一类问题是滴速检测不稳定。红外对管装好后,我第一天测试时发现滴速读数跳得厉害,从设定值40跳到十几又跳回五十几。排查下来有两个原因:一是遮光罩没有完全遮住环境光,窗户边下午太阳斜射进来会直接打在接收管上;二是滴管的固定位置偏了,液滴不是垂直经过检测区,而是从边缘滑过去,导致红外遮挡不彻底。解决方案是把遮光罩加长加严实,然后用3D打印做了一个滴管固定座,保证滴管垂直插在检测槽里。

第二类问题是蠕动泵丢步。28BYJ-48在快速启动或者负载突然变大时会出现丢步现象,现象是泵的实际转速比程序设定的慢,但程序并不知道,还是按照自己的节奏发脉冲,PID闭环发现滴速偏慢就继续加速,直到控制量输出饱和。丢步的根本原因就是启动频率太高,超出了电机的自启动频率范围。解决办法是把步进电机的加速过程做成梯形加速曲线,起步时脉冲频率低,然后逐步提高,避免瞬间高速。

第三类问题是OLED刷新导致滴速显示卡顿。一开始我在主循环里每50ms刷新一次OLED,结果屏幕闪得不行,而且滴速数字刷新时视觉上有明显的跳动。后来把刷新频率降到200ms一次,同时只在数值变化超过1时才更新屏幕,感官上反而流畅了。OLED显示本身有I2C通信的耗时,刷新太频繁会挤占主循环里其他任务的执行时间。

5.2 问题排查速查表

现象可能原因排查方法解决方案
滴速读数跳变/偏大环境光干扰、比较器阈值不当、脉冲滤波不足示波器观察比较器输出波形,看是否有毛刺加遮光罩,调整比较器阈值电位器,增大TIM捕获滤波器系数
滴速读数偏小/漏检液滴路径偏移、红外对管灵敏度不足检查滴管是否垂直经过检测区调整滴管固定位置,重新对准红外对管
电机不转电机驱动引脚接错、电源不足、GPIO配置错误万用表量电机线圈电压,检查ULN2003输入电平核对原理图连接,检查电源电流是否满足电机启动要求
电机丢步/失步启动频率过高、负载过大监视电机是否发出“咔哒”声但不同步增加梯形加速曲线,降低启动频率
PID输出振荡Kp过大、控制周期太短观察滴速曲线是否等幅振荡降低Kp,增加Ki的积分作用,适当延长控制周期
系统运行中自动重启电源压降过大、看门狗误触发用示波器抓取电源电压实测波形电机单独供电,加大电源滤波电容
OLED显示乱码/不亮I2C地址不对、上拉电阻缺失用I2C扫描程序枚举设备地址确认OLED地址是0x3C或0x3D,补上拉电阻
编码器操作反向A/B相定义反了转动旋钮观察位数变化方向软件里交换A/B相极性,或将A/B接线对调

5.3 升级迭代方向

这套系统做到现在这个版本,已经能满足基本的监护闭环控制需求。我在测试时也在想后续还能往哪些方向扩展。第一个方向是无线化,加一个ESP8266或者蓝牙模块,把滴速和报警信息发到手机或护士站,这在实际场景里意义很大。第二个方向是输液余量检测,用称重传感器或者液位传感器监测输液瓶的重量变化,提前预警“快输完了”,而不是等到滴管里没有液滴了才报警。第三个方向是数据记录,把每次输液的滴速曲线存到SD卡或者Flash里,方便事后分析。

代码上也有优化空间。目前PID的参数是静态的,如果输液过程中管路被压迫或者液体粘稠度变化,固定参数可能不够用。可以考虑引入模糊PID或者自适应控制,根据偏差大小动态调整PID参数。不过这些属于锦上添花,先把基础版本的稳定性做好更重要。

最后分享一个我个人的调试习惯:任何嵌入式系统,先保证“开环能跑”,再做“闭环控制”。也就是先手动设置电机转速,确认蠕动泵的实际输出和预期一致,确认滴速检测读数是准确的,然后再把PID加上去。很多人一上来就写完整闭环代码,结果出了问题不知道是传感器不准、电机执行不对还是PID参数不对,排查起来非常痛苦。从这个项目的经验来看,按“检测—执行—控制”的顺序逐层验证,调试效率是最高的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询