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

三、硬件功能介绍
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); // 初始化PB1
OLED_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; //转换为 滴/min
total_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;
}
}
}
七、单片机实物资料
