STM32项目开源:智能医疗输液点滴系统(代码+原理图+仿真)
做嵌入式这些年,我一直觉得医疗电子是门槛最高、也最有价值的赛道之一。但真正想入门医工交叉方向的同学,往往卡在“不知道做一个什么项目才能把单片机、传感器、执行机构串起来”。今天要拆解的这套智能医疗输液点滴系统,恰好就是这样一个典型的软硬结合项目:用STM32做主控,通过红外对管检测点滴速度,再配合步进电机夹持机构实现异常报警和自动调速,同时还给出了完整的原理图、代码和Proteus仿真工程。
这个项目能解决什么问题?说白了就一件医院里每天都在发生的烦心事:输液时需要有人盯着,药水滴快滴慢全凭肉眼,滴完了一旦没拔针就可能回血。用单片机替代人工巡检,既能把护士从重复劳动里解放出来,又能提高输液过程的安全性。我建议下面几类朋友重点关注:正在做课程设计或毕业设计的电子/通信专业学生,想转行医疗电子方向的嵌入式工程师,以及准备参加电子设计竞赛的团队。整套资料拿到手,你能同时练到传感器信号处理、定时器中断编程、电机驱动控制、Altium Designer画原理图、Proteus联合仿真这几项硬技能,一个项目顶五个小实验。
1. 内容整体设计与思路拆解
先说这套系统最核心的设计逻辑:它本质上是一个“检测—判断—执行”的单闭环控制系统。Sensor端的红外对管负责实时感知滴管中药液的滴落动作,MCU端通过定时器捕获计算滴速,再把实际滴速和预设值做比较,一旦出现偏差,就通过步进电机去调节输液管上夹持装置的松紧程度,从而实现滴速的自动补偿。
这个方案之所以选择STM32F103C8T6而不是51单片机或者Arduino,原因很实在。F103C8T6主频72MHz,片上资源足够跑多路定时器输入捕获和PWM输出,价格在十几块钱上下,开发工具链Keil MDK也是国内高校和公司用得最普遍的。更关键的是,它的GPIO耐压是5V兼容的,可以直接和很多常见传感器模块对接,不需要额外做电平转换,这对初学者来说能少踩一个坑。
再看检测方案的选型。常见的点滴检测方案有红外对管、光电编码器、电容传感器、甚至摄像头图像识别。摄像头方案精度高但成本高、功耗大、算法复杂,对于输液监控这种场景属于杀鸡用牛刀。电容方案无接触但抗干扰能力一般,处理不好就误报。综合成本和可靠性,红外对管是这里的最优解:一对发射管加接收管不到两块钱,响应时间毫秒级,配合比较器整形电路可以直接输出TTL电平的脉冲信号,单片机只要数脉冲个数就能换算滴速。
这个设计还有一个容易被忽略的巧思,就是把检测模块和执行机构做成了分离式结构。检测模块夹在滴管上方,执行模块夹在滴管下方输液管上,互不干扰。这样做的实际好处是,检测模块坏了只需要换传感器,执行机构还能继续用,而且在仿真阶段可以把这两部分分开建模,调试起来要清晰得多。
2. 核心细节解析与实操要点
2.1 滴速检测的核心原理与脉冲整形
先看整个系统最关键的传感器部分。红外对管的工作原理并不复杂:红外发射管持续发射红外光,接收管根据接收到的光强变化改变导通状态。当药液滴落经过红外光束路径时,液滴会折射和吸收红外光,导致接收管接收到的光强出现短暂波动,于是输出端就产生一个对应的脉冲信号。
但这里有个新手很容易踩的坑:直接接MCU的GPIO引脚去检测,会发现信号抖动得没法看。原因在于红外对管输出的模拟信号在液滴边缘处变化不够陡峭,而MCU的GPIO数字输入阈值又有一个不确定区间,结果就是一个液滴可能被识别成两三个脉冲。解决办法是在中间加一级电压比较器,比如用LM393或LM311,把接收管输出的模拟电压和一个可调阈值电压做比较,输出就是干净利落的方波信号。阈值的大小需要根据环境光和输液管的透光率实际调整,一般把阈值设在液滴经过时信号变化的中间值附近,我调试下来大概在1.8V到2.5V之间效果最好。
脉冲信号进入STM32之后,推荐用定时器的输入捕获通道来接,而不是简单地用GPIO外部中断。道理很简单:外部中断在频繁触发时会占用大量CPU时间,如果还要同时处理电机控制和LCD刷新,很容易丢脉冲。输入捕获是硬件级别的操作,定时器自动记录边沿时刻,CPU只需要在捕获中断里读走寄存器值就行,精度可以做到微秒级,换算滴速非常准。
2.2 滴速计算的公式与定时策略
测滴速本质上是在测频率。假设定时器在100ms窗口内捕获到了N个脉冲,那么滴速就是10N滴/分钟。但实际项目中我不会用固定窗口计数的笨办法,而是用两次相邻捕获中断的时间间隔来计算实时滴速,公式是:
滴速(滴/分钟)= 60 / T(单位:秒)
T是相邻两个脉冲的时间间隔。比如T=1秒,滴速就是60滴/分钟,正好是临床上最常见的成人输液速度。用周期法计算的好处是响应快,每次滴完一滴就能立即更新当前速度,系统对滴速异常的反应速度会快很多。但要注意,如果输液管里偶尔有气泡或者检测位置有晃动,单个间隔可能异常跳变,所以我一般会在代码里加一个中值滤波或者滑动平均滤波,取最近三次间隔的中间值或平均值作为有效数据。
这个公式本身不难,难的是确定“滴速异常”的阈值判定策略。静脉输液的滴速设置通常由医生根据药物性质和患者情况开医嘱,比如抗生素类通常要求低速滴注,生理盐水可以适当快一些。系统在设定目标滴速之后,需要设定一个允许的偏差范围,我在工程里默认设置为正负10%以内算正常,超过这个范围就触发报警。如果是用于演示,也可以把阈值放宽到正负20%,因为教学场景里机械执行机构的定位精度有限,太严格的判定会导致频繁误报。
2.3 电机夹持机构:步进电机还是舵机?
执行机构负责调节输液管松紧,从而实现滴速控制。这里有两种主流方案:微型舵机和步进电机。舵机的好处是控制简单,PWM信号直接定位角度,力矩也足够夹紧硅胶输液管;坏处是角度分辨率有限,而且常规舵机无法闭环反馈当前位置,一旦堵转丢步你并不知道。步进电机的好处是开环控制就能精确到步,28BYJ-48加上ULN2003驱动板全套下来也就几块钱,配合减速齿轮组,扭矩完全够用。
我推荐28BYJ-48步进电机作为首选方案,原因除了便宜,还有一个很重要的点:它自带减速箱,输出轴力矩大,可以直接推动夹持滚轮而不用额外加齿轮组。用ULN2003驱动时,采用四相八拍的驱动方式,步距角大约0.0875度,控制精度在医用的调压场景里绰绰有余。转速控制上用定时器产生PWM脉冲序列给步进电机,通过调节脉冲频率就能控制电机转速,进而控制夹持装置对输液管的压力,非常直观。
有一点必须提醒:步进电机和红外对管在电气上是两种截然不同的负载。步进电机是感性负载,启动和换向瞬间会产生较大的电流尖峰和反电动势,如果电源和地线处理不好,会严重干扰传感器的信号。我在实际布线时,把电机驱动部分的电源和传感器部分的电源做了隔离,至少要用0.1uF和10uF的电容分别去耦,必要时加磁珠或者π型滤波。这个问题在Proteus仿真里看不出来,但真做板子的时候十有八九会遇到,先打个预防针。
2.4 异常报警与OLED显示模块
整个系统的人机交互由三部分组成:一个OLED显示屏用于实时显示当前滴速、目标滴速、累计滴数和系统状态;一个蜂鸣器用于异常报警;若干按键用于设定目标滴速和调节阈值。OLED我选的是0.96寸I2C接口的SSD1306,四根线就能搞定,代码用现成的驱动库改一改就行,显示中文需要自己取模,工作量也不大。
报警逻辑要分好几个层次,不只是滴速超出范围才报警。我认为最少要覆盖四类异常:滴速过快、滴速过慢、输液完成(检测到连续若干秒无滴落)、以及传感器故障(接收管持续高电平或持续低电平)。特别是输液完成这个状态,是最容易出危险的情况,所以代码里给它单独设了一个比较高的优先级,一旦判定“无滴落”,不管当前滴速是快是慢,先报警再说。这个设计是从真实临床需求倒推出来的,做项目时可以跟指导老师确认一下课程设计的具体要求,但“安全优先”这个思路本身是通用的。
3. 实操过程与核心环节实现
3.1 硬件BOM清单与选型理由
先把物料清单列出来,方便你照着备料。这个项目所有器件加起来成本控制在50元以内,在嵌入式开源项目里属于非常亲民的配置。
| 器件名称 | 型号/规格 | 数量 | 作用 |
|---|---|---|---|
| 主控MCU | STM32F103C8T6最小系统板 | 1 | 核心控制 |
| 红外对管 | TCRT5000或自制分立式 | 1 | 滴速检测 |
| 电压比较器 | LM393模块 | 1 | 脉冲整形 |
| 步进电机 | 28BYJ-48 + ULN2003 | 1 | 夹持调速 |
| 显示屏 | 0.96寸OLED SSD1306 I2C | 1 | 实时显示 |
| 蜂鸣器 | 有源蜂鸣器模块 | 1 | 异常报警 |
| 按键 | 轻触开关 | 3 | 参数设定 |
| 晶振 | 8MHz(最小系统板自带) | 1 | 时钟源 |
| 电源 | 5V/2A适配器或USB供电 | 1 | 系统供电 |
| 辅助材料 | 硅胶输液管、滴管、夹持支架 | 若干 | 机械结构 |
TCRT5000这个型号要单独说两句。它本身是一个集成了红外发射管和光电晶体管的反射式传感器,模块板上还带了比较器电路,输出数字信号,用起来非常省事。但反射式传感器通常用于循迹测距,测滴液时更透光的方案是直射式,也就是发射管和接收管面对面,中间留出缝隙让输液滴管穿过。如果动手能力强,可以用一个红外发射管加一个红外接收管自己搭,效果其实更好。我在项目里用的就是这种自制直射式结构,用一个3D打印的小夹子固定两个管子,中间留出滴管的位置,成本几毛钱。
3.2 电路与原理图设计:从模块拼接到图纸
原理图设计部分,很多新手拿到模块化硬件会觉得“不就是杜邦线插一插吗,还要画什么原理图”。这话对纯功能验证没错,但如果要做成可复制的开源项目,原理图必须画。原因有三:第一,原理图是逻辑的抽象表达,别人拿到你的代码,没有原理图根本不知道引脚怎么接;第二,画图的过程中你会重新思考每个引脚的功能分配,能发现不少接线时没意识到的问题;第三,后续做PCB打样必须基于原理图导出的网表。
我用的是Altium Designer,工程里需要包含STM32F103C8T6最小系统电路、红外检测与比较电路、步进电机驱动电路、OLED接口电路、蜂鸣器驱动电路、按键电路以及电源电路这几个模块。其中最小系统电路里的启动配置引脚BOOT0和BOOT1必须处理好,BOOT0通过10K电阻下拉到GND,保证从主Flash启动;复位电路用一个0.1uF电容加10K上拉电阻;VDDA引脚要接一个1uF和0.01uF的去耦电容再接到3.3V,如果忽略VDDA的滤波,ADC采样值会抖动得很厉害。
步进电机驱动部分用ULN2003达林顿管阵列,这芯片一个顶七个NPN达林顿对,直接用STM32的GPIO输出5mA左右的电流就能驱动。注意STM32F103的GPIO输出模式要设置为开漏输出,因为ULN2003内部输入已经接了下拉电阻,开漏输出加上外部上拉到5V才能保证高电平的有效驱动电压。27引脚是公共端,接电机电源正极,我建议电机单独用5V供电,和MCU的数字电源分开,避免电流冲击干扰。
这里有个容易忽略的地方:红外接收管的输出信号接到LM393比较器的时候,输入端需要加一个上拉电阻到正电源。因为比较器是开漏输出,必须靠外部上拉才能输出高电平。有些新手用模块板,模块上已经集成了上拉电阻,所以没注意到这个问题,一旦自己画板子就忘了这个电阻,结果输出端永远只有低电平或者悬空。
3.3 软件工程结构:模块化写法是长期维护的基础
软件部分我建议你不要把所有代码堆在一个main.c里,那不是工程,那是电子垃圾堆。合理的划分方式是至少分成以下模块:系统初始化模块、传感器检测模块、步进电机控制模块、显示模块、按键处理模块、报警模块、核心控制逻辑模块。每个模块对应一个.c和.h文件,接口函数命名统一,这样不管是自己调试还是把代码分享给别人,可读性都强得多。
主循环的逻辑大概是这样的流程:系统上电初始化,OLED显示欢迎界面,然后进入参数设定模式,用按键设定目标滴速,设定完成后进入自动监控模式。在自动监控模式下,主循环不断读取传感器数据计算实时滴速,刷新OLED显示,同时判断是否需要调整电机位置、是否触发报警。因为滴速的采集依赖定时器中断,所以主循环里的操作不能阻塞太久,OLED刷新频率控制在5Hz左右就够了,蜂鸣器报警用定时器PWM驱动而不是delay延时,否则报警的时候系统其他功能会被卡死。
定时器分配上,我建议用TIM2做输入捕获检测滴速,TIM3产生PWM驱动步进电机,TIM4做系统时基做非阻塞延时和报警音调控制。TIM1是高级定时器,这个项目用不上,可以直接留空。时钟树配置用STM32CubeMX初始化,这样既准确又省时间,我强烈建议你即使习惯手动写寄存器,也先从CubeMX生成一次初始化代码,再基于生成的工程添加自己的逻辑。纯手写寄存器不是不行,但对这种外设用到三四个定时器的项目,耗时太长且容易出错。
3.4 核心代码实现与讲解
下面我把几个关键代码逻辑展开细说。首先是滴速检测的输入捕获配置,这里我以标准外设库风格的写法为例,CubeMX生成的HAL库函数逻辑类似,对应关系自己体会一下:
// TIM2 输入捕获初始化,PA0引脚 void TIM2_IC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_ICInitTypeDef TIM_ICInitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 使能时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // PA0配置为浮空输入 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 = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // 输入捕获配置:上升沿捕获,直接映射IC1到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); // 使能捕获中断 TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE); // 使能定时器 TIM_Cmd(TIM2, ENABLE); }这里特别要提一下TIM_ICFilter这个参数,它实际上是芯片内部的输入滤波单元,可以过滤掉宽度小于设定时钟周期数的脉冲毛刺。我把它设成0x0F相当于一个较强的滤波,在传感器信号质量一般的时候能有效抑制误触发。如果你发现滴速计算结果明显偏大(比如一个液滴算了两个脉冲),先别急着改算法,把滤波参数调大一点往往就解决了。
然后是滴速计算的中断处理函数。考虑到使用周期法测频,需要记录上一次捕获的时间戳,在中断函数里计算差值:
volatile uint32_t capture_prev = 0; volatile uint32_t capture_now = 0; volatile float drop_interval = 0; // 相邻两滴的时间间隔(秒) volatile float current_speed = 0; // 当前滴速(滴/分钟) void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); capture_now = TIM_GetCapture1(TIM2); // 处理定时器溢出情况 if (capture_now >= capture_prev) { drop_interval = (float)(capture_now - capture_prev) / 1000000.0; } else { drop_interval = (float)(0x10000 + capture_now - capture_prev) / 1000000.0; } capture_prev = capture_now; if (drop_interval > 0.001) // 过滤极小间隔噪声 { current_speed = 60.0 / drop_interval; } } }溢出处理这个细节非常关键。定时器是16位的,计数溢出后回到0,如果两次捕获之间恰好经历了溢出,直接做减法会得到负值。很多新手在这个问题上卡很久,最后计算出来的滴速偶尔会是一个极大的荒谬值。我在上面代码里用了判断分支处理这种溢出情况,虽然不复杂,但很实用。
步进电机的驱动代码核心是给各相绕组依次通电。采用四相八拍时,通电顺序是A-AB-B-BC-C-CD-D-DA循环。用定时器中断周期性切换相序,中断频率就是步进频率。下面是电机控制的示意代码:
// 四相八拍相序表,对应IN1~IN4 const uint8_t step_phase[8] = { 0x08, 0x0C, 0x04, 0x06, 0x02, 0x03, 0x01, 0x09 }; uint8_t current_step = 0; // 旋转指定步数,dir为方向:1正转,0反转 void Stepper_Rotate(int steps, uint8_t dir) { int i; for (i = 0; i < steps; i++) { if (dir) current_step++; else current_step--; current_step &= 0x07; // 将低四位写入PB8~PB11 GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)((step_phase[current_step] >> 0) & 0x01)); GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)((step_phase[current_step] >> 1) & 0x01)); GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)((step_phase[current_step] >> 2) & 0x01)); GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)((step_phase[current_step] >> 3) & 0x01)); delay_us(1500); // 控制步进速度,1.5ms一步 } }延时1.5ms对应的步进频率约666Hz,对于28BYJ-48这个电机来说,在它启动频率范围内,可以可靠转动不失步。如果你要加快调整速度,不能直接把延时改小到500us以下,否则电机可能转速上不去甚至完全不动,因为它的内部减速箱和转子惯量决定了启动频率上限。想让电机转得更快,正确的做法是采用加减速控制,起步用低频率,然后逐步加速到目标频率。这个项目里因为只需要做小幅度的夹持调整,加减速不是必须的,但了解这个约束条件对理解电机特性有帮助。
3.5 Proteus仿真搭建与实际验证
仿真部分是这个项目资料里性价比最高的一块。用Proteus仿真,你不需要焊接任何实体电路就能把整套控制逻辑跑通。Proteus里的STM32仿真需要加载目标芯片的hex文件才能运行,所以你得先在Keil里编译工程生成hex文件,然后在Proteus里双击MCU芯片,在Program File选项里选择该hex文件。
仿真模型搭建的要点是:从元件库中选取STM32F103C8T6、LM393、ULN2003、28BYJ-48步进电机、按键、LED等元件,然后按照原理图连接。红外对管在Proteus里没有现成模型,可以用一个脉冲信号发生器来模拟,信号周期对应液滴滴落周期。比如你想模拟60滴/分钟的滴速,就把脉冲源频率设为1Hz,这样每次上升沿相当于一滴药液滴落,MCU的输入捕获引脚就能检测到脉冲。
我强烈建议把按键、OLED这些交互元件都放进仿真里,这样整个系统的状态转换和异常报警逻辑都能完整调试。仿真和实物的对应关系我总结了几条经验:Proteus的仿真时间比真实时间慢不少,调滴速计算算法时要注意响应延迟;仿真里不存在的干扰源,像电源纹波、电磁耦合这些,也不必过度设计,但代码里的滤波逻辑建议保留,方便移植到硬件时不用改代码;电机模块在仿真里的行为是理想化的,实际电机的启动频率限制在仿真里体现不出来,所以实物调试时要参考前面的频率约束。
4. 常见问题与排查技巧实录
做这个项目的过程中,我在各个技术社区里看到最多的问题集中在下面这几个环节,每一条都是我亲眼见过或者亲自踩过的坑,整理成速查表给大家参考。
| 现象 | 可能原因 | 排查方法 | 解决措施 |
|---|---|---|---|
| 滴速显示为0,传感器有液滴但无脉冲 | 红外对管电路无输出 | 万用表测量接收管两端电压是否有变化 | 检查发射管是否损坏,确认供电极性正确 |
| 滴速数值偏大,一个液滴被识别成多次 | 比较器阈值设置过低 | 用示波器观察比较器输出的波形,看是否有多个上升沿 | 调高比较器阈值电压,加大TIM滤波参数 |
| 步进电机不转,GPIO有输出 | ULN2003输入悬空或驱动电流不足 | 测量ULN2003输入引脚电压,检查是否开漏输出 | GPIO配置为开漏输出并加上拉电阻到5V |
| 电机一启动,传感器数据剧烈跳动 | 电机反电动势干扰电源 | 示波器观察传感器供电电压是否出现毛刺 | 电机和传感器分开供电,加去耦电容 |
| 蜂鸣器一直响,无法消除 | 输液完成误判 | 检查无滴落判定定时器的超时时长 | 延长超时时间或检查传感器信号干扰 |
| 烧录时报错no target found | 调试接口配置不对 | 检查BOOT0引脚电平,检查SWD接线 | 按住复位键再点下载,在Download页面勾选Reset and Run |
这里重点说一下“no target found”这个报错,因为搜热词的时候看到很多人在问。这个问题通常跟代码没多大关系,而跟烧录器和目标板的连接状态有关。出现这个报错时,我一般按三个顺序排查:第一,确认STM32的3.3V供电正常,最小系统板的电源指示灯亮不亮;第二,确认SWDIO和SWCLK两条线没有接反,GND必须共地;第三,也是最容易被忽略的,如果目标程序里把SWD引脚复用成了普通GPIO,会导致调试接口被关闭,解决办法是烧录时按住单片机复位键,让程序不运行,点下载后等待几秒再松开复位键,这个操作屡试不爽。如果是用ST-Link的话,还要检查一下固件版本是否太老,升级一下ST-Link驱动能解决很大一部分识别问题。
再说一个我印象特别深的案例。群里有个朋友自制了传感器模块,PCB是自己画自己打样的,原理图看着完全没问题,但就是滴速检测极其不稳定,时好时坏。远程看了半天没看出毛病,最后让他把PCB实物照片发过来,才发现他把红外发射管和接收管的封装画反了,丝印方向和实际器件方向差180度,管子插上去后发射管对着发射管,浇什么药液都检测不到。这种问题原理图和仿真里完全无法发现,因为逻辑层面连接关系是对的,只有实物装配时会暴露。所以做这类带光电器件的板子,画封装时一定反复核对器件手册的引脚定义。
还有一个小问题我觉得值得提醒:输液管在检测区域的位置很影响信号质量。滴管是略带弧度的塑料管,红外光穿过时如果管壁有划痕,散射会比较明显。我在设计机械夹持结构时,给传感器留了上下调节的余量,实际使用时光束对准液滴滴落轨迹的中心,信号最稳定。如果你用的是3D打印夹子,可以多试几个安装位置,找到信号余量最大的那个高度固定下来,后面能省很多事。
5. 从仿真到实物的迁移与后续扩展方向
如果只是把它当一个课程设计交差,做到上面那一步已经够了。但如果你愿意多花一点时间,这个项目的可扩展空间其实非常大,这也是当初我选择把整套资料开源出来的原因。
第一个扩展方向是把滴速检测升级成多通道。一套系统只监控一路输液,在应用中其实不够实用,病房里一个护士要同时看护好几个病人,如果能设计成四通道甚至八通道的集中监控系统,把每个通道的传感器数据汇总到一块主板上,再通过RS485总线或者CAN总线上传到护士站电脑,那就是一套完整的病区输液监控方案了。STM32F103的外设资源支持做四路输入捕获没问题,再挂一个串口屏或者接手机构上位机,架构也不需要大改。
第二个方向是加无线通信。把ESP8266或者ESP32模块通过串口和STM32连接,滴速异常时除了本地蜂鸣器报警,还能推送消息到手机。用MQTT协议接入物联网平台,代码量不大,但项目一下子就变成了物联网医疗终端,这个方向不管写简历还是参加竞赛都很有说服力。
第三个方向是数据记录与分析。输液过程中的滴速变化曲线、药物剩余量估算、异常事件日志,这些数据如果通过SD卡模块记录下来,后续还能做简单的大数据分析。当然对单片机来说存储空间有限,更合理的做法是边采集边通过串口上传到上位机,Python那边用pyqt或者matplotlib做实时绘图和日志存储。我见过有同学在这个项目基础上加了上位机之后,直接被老师推荐去了医院的信息科实习,可见项目本身的生命力还是在的。
我个人在实际操作中最大的体会是:这种带传感、执行、交互三要素的闭环项目,才是嵌入式入门最该做的类型。点灯和流水实验做得再多,也培养不了“系统怎么闭环跑起来”的全局感。这套智能输液系统虽然不算复杂,但它完整地演示了一个检测信号怎么进来、算法怎么处理、执行机构怎么响应、异常怎么处置的全程。你在调试过程中遇到的每一个问题,都会成为下一次设计同类系统时脑中自动浮现的预案。
如果你打算照着资料动手做,我最后再分享两个细节技巧。第一,OLED显示屏地址在I2C扫描时如果发现是0x3C和0x3D两个可能,而屏幕一直不亮,先确认是不是接线松了,ST官方手册上写的是0x78(7位地址0x3C左移一位),不同厂家的OLED模块地址引脚焊盘可能不同,仔细看模块背面的说明。第二,步进电机在系统启动初始化时先做一次归零动作,也就是让夹持机构回到全开位置,再开始自动调速,这样每次上电的初始状态确定,后续调节逻辑才会准确。这个归零动作看似简单,但能避免很多因为上次停机位置不确定导致的麻烦。
好了,这套智能医疗输液点滴系统的项目拆解就到这里,需要原理图源文件、完整代码和仿真工程的,直接去开源仓库下载就行。遇到问题可以在评论区留言,看到会回复。