【STM32项目开源】STM32单片机医疗点滴控制系统
目录
一、设计背景和意义
1.1设计背景:
1.2设计意义:
二、实物展示
三、硬件功能介绍
2.1 硬件清单:
2.2 功能介绍:
四、软件设计流程图
五、硬件PCB展示
六、软件主函序展示
七、单片机实物资料
资料获取 查看主页介绍:兆龙电子单片机设计
一、设计背景和意义
1.1设计背景:
在医院病房、社区诊所及家庭护理的静脉输液场景中,点滴的精准控制、安全预警与便捷管理是核心需求。传统点滴系统存在明显局限:一方面,高端智能输液设备(如医用全自动输液泵、品牌定制化输液管理系统)功能虽全但成本高昂,安装调试复杂,依赖专业医护人员操作与特定品牌售后支持,难以普及到基层诊所、家庭护理等场景,且设备兼容性差,更换或升级成本高,无法灵活满足不同患者(如儿童、老人、重症患者)的输液速度需求;另一方面,普通简易点滴装置(如重力式输液器、手动调节滚轮型)虽操作简单,但功能单一,仅能通过人工观察滴速并手动调节,缺乏滴速精准控制、药液余量监测、气泡检测及异常报警等功能,无法满足现代化医疗场景下对输液安全、精准管理的需求。
现有点滴控制方案还存在功能割裂与集成度低的问题:部分高端输液设备虽具备多模式控制与安全监测功能,但依赖复杂的电路设计与专业维护,后期使用成本高,难以覆盖预算有限的基层医疗机构或家庭护理场景;而低成本点滴装置又在功能完整性与智能化上存在欠缺,无法实现输液数据与医护终端、移动端 APP 的联动,导致滴速偏差大、药液耗尽未及时处理、气泡进入血管等安全风险,无法为患者输液记录追溯及医护人员工作效率优化提供数据支撑。基于此,本设计以 STM32 单片机为核心,融合高精度参数采集模块(如红外滴速传感器、超声波液位传感器、气泡检测传感器、压力传感器)、LCD 显示模块、数据存储模块及电机控制与报警模块,构建低成本、高集成度的 STM32 单片机医疗点滴控制系统,以解决传统点滴设备功能单一、智能化程度低、安全风险高及管理效率低的问题。
1.2设计意义:
本设计通过整合 STM32 单片机的高效数据处理能力与多模块协同工作机制,在医疗输液管理领域具有多重实用价值,具体体现在以下三方面:
从使用体验与管理效率角度,该系统突破了传统点滴设备的局限:一是实现了多参数同步监测与多功能联动(如支持滴速、药液余量、联动步进电机调速模块、药液余量预警模块),无需医护人员频繁巡查或人工调节,减少人工操作繁琐性与失误率;二是配备OLED实时显示模块,直观呈现当前滴速(单位:滴 / 分钟)、药液剩余量、输液时长及运行模式,同时支持数据自动存储(可通过蓝牙或 WiFi 传输至医护终端 / 移动端 APP),方便医护人员长期追溯患者输液记录,为患者治疗方案优化及医护工作流程管理提供完整数据支撑;三是新增异常预警与自动调控功能,当监测到某项参数超出安全范围,系统自动触发声光报警(同时向医护终端发送预警信息),并联动电机停止输液、启动气泡排除程序或关闭输液通路,无需人工干预即可及时处理异常,大幅提升了输液管理的便捷性与安全性。
从技术实践与成本控制角度,本设计以 STM32 单片机为核心,充分利用其低功耗、高性价比的优势,搭配低成本的高精度参数传感器与通用外围模块,在保证数据精度(滴速测量误差可控制在 ±1 滴 / 分钟以内,药液余量检测误差可控制在 ±5mL 以内)的前提下,有效降低了系统整体成本,相比同功能的高端智能输液设备成本降低 40%-60%,更易普及到基层诊所、社区卫生服务中心及家庭护理等场景。同时,系统支持模块化扩展(如后续可新增语音交互模块、远程输液参数设置功能),为后续功能升级预留了空间,具备良好的灵活性与可扩展性。
从应用场景与行业价值角度,该系统可广泛适配多类输液场景:在医院病房中,可作为患者输液的智能管理终端,实时调控滴速、监测安全状态,减轻医护人员巡查压力;在高校医学工程、电子信息相关专业教学中,可作为单片机与医疗设备结合的实践案例,帮助学生理解嵌入式系统在医疗场景中的应用原理;在基层诊所或家庭护理场景中,可为患者提供低成本的安全输液方案,减少输液安全事故风险与医护人员工作负担。此外,本设计探索了 STM32 单片机在低成本医疗输液设备领域的应用方案,推动传统点滴装置从 “人工观察、手动调节” 向 “多参数监测、智能控制、自动预警” 升级,为低成本智能化医疗输液设备的开发提供了可参考的集成思路,具有较好的实践应用与行业推广价值。
二、实物展示
下方为实物演示视频
点击下方链接跳转演示视频 https://www.bilibili.com/video/BV13PaczHEFZ/?spm_id_from=333.1387.upload.video_card.click&vd_source=2a672ca4e8794dca68cbe6d047b42ca5
https://www.bilibili.com/video/BV13PaczHEFZ/?spm_id_from=333.1387.upload.video_card.click&vd_source=2a672ca4e8794dca68cbe6d047b42ca5
下方为实物展示图片

三、硬件功能介绍
2.1 硬件清单:
- STM32F103C8T6
- OLED液晶显示
- 滴速传感器
- ULN2003步进电机驱动
- 非接触式水位传感器
- 声光报警电路
- WIFI模块
2.2 功能介绍:
(1)点滴流速监测:光耦测速传感器实时检测点滴流速,当流速超过上限或低于下限报警,同时步进电机调整流速
 (2)数据可视化:所有监测数据不仅在OLED屏幕上显示,还能通过WIFI模块上传至手机APP,实现远程监控
 (3)按键设置:按键设置液体流速上限和下
 (4)报警系统:当流速超过上限或低于下限蜂鸣器报警
 (5)液位传感器:采用非接触式液位传感器实时检测剩余液体量
 (6)手机APP交互:流速和液体有无可实时监控,阈值可以通过手机APP设置,提供便捷的用户交互体验
四、软件设计流程图

五、硬件PCB展示


六、软件主函序展示
#include "sys.h"
#include "delay.h"
#include "gpio.h"
#include "OLED_I2C.h"
#include "timer.h"
#include "usart1.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>#define Coil_8B_A  {A=1;B=0;C=0;D=0;}//A相通电,其他相断电
#define Coil_8B_AB {A=1;B=1;C=0;D=0;}//AB相通电,其他相断电
#define Coil_8B_B  {A=0;B=1;C=0;D=0;}//B相通电,其他相断电
#define Coil_8B_BC {A=0;B=1;C=1;D=0;}//BC相通电,其他相断电
#define Coil_8B_C  {A=0;B=0;C=1;D=0;}//C相通电,其他相断电
#define Coil_8B_CD {A=0;B=0;C=1;D=1;}//CD相通电,其他相断电
#define Coil_8B_D  {A=0;B=0;C=0;D=1;}//D相通电,其他相断电
#define Coil_8B_DA {A=1;B=0;C=0;D=1;}//DA相通电,其他相断电#define  Coil_OFF   {A=0;B=0;C=0;D=0;}//全部断电
#define  SampleNum       3    //取样数量
#define  SampleTimeout   15   //取样超时时间,单位(秒)int PulseCount = 0;     //记录脉冲
int Speed = 0;          //滴速
int speed_min = 60;      //滴速下限
int speed_max = 180;     //滴速上限u8 setFlag = 0;  //设置标志
u8 direction = 0;//方向标志bool SendFlag = 0;
bool shanshuo = 0; //shanshuo
bool shuaxin = 0;  //刷新标志
bool NoWater = 0;  //缺水标志
char display[16];void InitDisplay(void)   //初始化显示
{unsigned char i=0;for(i=0;i<6;i++)OLED_ShowCN(i*16+16,0,i+8,0);//显示中文:智能点滴系统for(i=0;i<2;i++)OLED_ShowCN(i*16,2,i+0,0);//显示中文:滴速for(i=0;i<2;i++)OLED_ShowCN(i*16,6,i+4,0);//显示中文:药水OLED_ShowChar(32,6,':',2,0);
}void displaySetValue(void)  //显示设置的值
{if(setFlag == 1 || setFlag == 2){
sprintf(display,"%003d",(int)speed_min);
OLED_ShowStr(40, 3, (u8*)display, 2,setFlag+1-1);//显示滴速下限
sprintf(display,"%003d",(int)speed_max);
OLED_ShowStr(40, 5, (u8*)display, 2,setFlag+1-2);//显示滴速上限}}void keyscan(void)   //按键扫描
{unsigned char i=0;if(KEY1 == 0) //设置键{
delay_ms(15);if(KEY1 == 0){
while(KEY1 == 0);setFlag ++;if(setFlag == 1){
OLED_CLS(0);    //清屏OLED_Fill_Row(0xFF,0);   //填充白色OLED_Fill_Row(0xFF,1);   //填充白色/* 显示直线框 */
OLED_DrawHorizLine(63,0,127);
OLED_DrawVerticaLine(0,2,8);
OLED_DrawVerticaLine(127,2,8);for(i=0;i<4;i++)OLED_ShowCN(i*16+32,0,i+14,1);//显示中文:设置滴速for(i=0;i<2;i++)OLED_ShowCN(i*16,3,i+22,0);//显示中文:下限
for(i=0;i<2;i++)OLED_ShowCN(i*16,5,i+24,0);//显示中文:上限OLED_ShowChar(32,3,':',2,0);OLED_ShowChar(32,5,':',2,0);OLED_ShowStr(62, 3, "/min", 2,0);OLED_ShowStr(62, 5, "/min", 2,0);}if(setFlag >= 3){setFlag = 0;
OLED_CLS(0);    //清屏InitDisplay();if(NoWater==1)
OLED_ShowCN(56,6,7,1);//显示中文:无
else
OLED_ShowCN(56,6,6,1);//显示中文:有  }
displaySetValue();   //显示没有设置值}}if(KEY2 == 0) //加键{
delay_ms(100);if(KEY2 == 0){if(setFlag == 1){
if(speed_max-speed_min>1)speed_min++;}
if(setFlag == 2){
if(speed_max<999)speed_max++;}displaySetValue();   //显示没有设置值}}if(KEY3 == 0) //减键{
delay_ms(100);if(KEY3 == 0){if(setFlag == 1){
if(speed_min>0)speed_min--;}
if(setFlag == 2){
if(speed_max-speed_min>1)speed_max--;}displaySetValue();   //显示没有设置值}}
}int main(void)
{GPIO_InitTypeDef GPIO_InitStructure;  // 将变量声明移到函数开始处NVIC_Configuration();	   //中断优先级配置delay_ms(200); I2C_Configuration();     //IIC初始化OLED_Init();             //OLED液晶初始化OLED_CLS(1);              //清屏OLED_ShowStr(0, 2, "   loading...   ", 2,1);delay_ms(1000);// 配置PB1为上拉输入模式(替代PA1)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  // 使能GPIOB时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;              // 选择PB1引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;          // 设置为上拉输入模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      // 设置IO口速度GPIO_Init(GPIOB, &GPIO_InitStructure);                 // 初始化PB1OLED_CLS(0);  InitDisplay();KEY_GPIO_Init();        //按键引脚初始化MOTOR_GPIO_Init();     //步进电机初始化if(water==0)NoWater=1;TIM3_Init(99,719);   //定时器初始化,定时1ms
//Tout = ((arr+1)*(psc+1))/Tclk ; 
//Tclk:定时器输入频率(单位MHZ)
//Tout:定时器溢出时间(单位us)while(1){ keyscan();  //按键扫描if(setFlag == 0)   //不在设置状态下{if((Speed!=0)&&((Speed<speed_min)||(Speed>speed_max))&&shanshuo)   //滴速不在范围,闪烁显示{OLED_ShowStr(32, 2,":         ", 2,0);     //显示空白}else{sprintf(display,": %003d/min ",(int)Speed);OLED_ShowStr(32, 2, (u8*)display, 2,0);//显示滴速}if(Speed!=0){if(Speed<speed_min) direction=1;         //滴速过慢,电机正转,模拟放开调节阀else if(Speed>speed_max) direction=2;    //滴速过快,电机反转,模拟收紧调节阀else direction=0;  //在正常滴速范围,电机停止}else{direction=0;  //停止}if(shuaxin == 1){shuaxin = 0;}if(water == 1)   //无药水{
if(NoWater==0)
OLED_ShowCN(56,6,7,0);//显示中文:无NoWater  = 1;    //缺水标志}else{if(NoWater==1)OLED_ShowCN(56,6,6,0);//显示中文:有NoWater  = 0;}}delay_ms(10);}
}unsigned long times=0;        //取样时间
unsigned long total_time=0;   //取样总时间
unsigned long timeout=0;      //取样超时时间 
bool start_flag=0;            //开始计时标志void TIM3_IRQHandler(void)//定时器3中断服务程序,用于记录时间
{ static u16 timeCount1 = 1000;static u16 timeCount2 = 4000;static u16 timeCount3 = 0;static u8 in_flag = 0;static u8 index = 0;if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 { 
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除中断标志位  /********************************************  以下为滴速计算  *********************************************//* 方法:取N个脉冲,计算每个脉冲与脉冲直接的间隔时间,求出平均每个脉冲之间的时间间隔,最终转换为(滴/min) */if(drop == 1)//高电平{
if(in_flag == 0)in_flag = 1;
if(start_flag) {start_flag = 0;total_time += times;  //计算累计的时间PulseCount ++;       //脉冲计数,由低电平到高电平的一个跳变才算一个times = 0;}}
else{if(in_flag == 1){in_flag = 0;start_flag = 1;}}
if(start_flag){times ++;     //脉冲与脉冲之间的时间计数,单位ms}
// 无条件累加timeout,确保即使没有脉冲也能触发清零timeout++;// 修改清零判断条件,直接比较毫秒数
if(timeout >= SampleTimeout*1000)  //取样时间太长了,取消计时{
/* 相关参数清0 */total_time = 0;PulseCount = 0;start_flag = 0;Speed = 0;timeout = 0;times = 0;}if(PulseCount>=SampleNum){PulseCount = 0;total_time = total_time / SampleNum; //计算平均每个取样脉冲之间的时间Speed = 60000 / total_time;         //转换为  滴/mintotal_time = 0;timeout = 0;}
/********************************************   END    *********************************************/
/**************************************************************************************************/timeCount1 ++;timeCount2 ++;timeCount3 ++;if(timeCount1>=1000)  //1s{timeCount1 = 0;shuaxin = 1;}if(timeCount3>=300)  //300ms{timeCount3 = 0;shanshuo = !shanshuo;if(!setFlag){
if(NoWater==1)  //无药水,蜂鸣器一直报警{beep = 1;}
else{
if(((Speed!=0)&&((Speed<speed_min)||(Speed>speed_max))))//滴速温度心率血氧不在范围,蜂鸣器报警{beep = ~beep;}
else{beep = 0;}	}}
else{beep = 0;}}
if(direction == 0)       //步进电机停止{Coil_OFF ;}
else if(direction == 1)  //步进电机正转{
switch(index) {
case 0:Coil_8B_A; break; 
case 1:Coil_8B_AB;break;  
case 2:Coil_8B_B; break; 
case 3:Coil_8B_BC;break; 
case 4:Coil_8B_C; break; 
case 5:Coil_8B_CD;break;  
case 6:Coil_8B_D; break; 
case 7:Coil_8B_DA;break; }index ++; 
if(index == 8) index = 0;}
else if(direction == 2)  //步进电机反转{
switch(index) {
case 0:Coil_8B_DA; break; 
case 1:Coil_8B_D;  break;  
case 2:Coil_8B_CD; break; 
case 3:Coil_8B_C;  break; 
case 4:Coil_8B_BC; break; 
case 5:Coil_8B_B;  break;  
case 6:Coil_8B_AB; break; 
case 7:Coil_8B_A;  break; }index ++; 
if(index == 8) index = 0;}}
}七、单片机实物资料

