简介:基于51单片机的输液报警控制系统设计资源,面向电子、自动化及嵌入式方向的课程设计与毕业设计人群,针对输液过程中滴速与液位监测报警的实际需求,提供一套从检测、显示到报警的完整软硬件方案。压缩包共43个文件、约828KB,包含C语言源程序、Proteus仿真工程、Altium Designer原理图及PDF预览、元件清单、流程图和编译生成的hex、lst、obj等程序构建文件;DSN仿真工程可直接打开运行,SchDoc原理图便于二次修改,能够满足从原理学习到仿真验证、实物烧录的完整流程。目前已有146人学习浏览。设计上以电位器代替液位传感器、信号发生器代替滴速传感器,借助ADC0832进行数据采集,由STC89C52等51系列单片机处理并在LCD1602上显示,同时支持设定报警阈值,测量值越限即报警;其中可重点学习ADC0832采集、LCD1602显示驱动、阈值比较逻辑等模块化编程方法。原理图与仿真工程相互对应,源代码结构清晰,便于初学者理解各模块协作,也可根据实际传感器替换模拟输入,快速扩展为临床输液监测装置原型。
1. 输液报警控制系统:为什么滴速和液位要分开测
我在调试这套基于51单片机的输液报警控制系统时,最先卡住的不是代码,而是「滴速」和「液位」这两路输入根本不是同一种信号:滴速是脉冲频率量,液位是缓慢变化的模拟量。把它们混在一个采集通道里,后面做阈值判断全是错的。这个系统用STC89C52这类51内核单片机,外扩ADC0832双通道ADC和LCD1602显示,在Proteus里用信号发生器模拟滴速脉冲、用电位器模拟液位电压,完整实现了滴速超限报警和低液位报警。对正在做单片机课程设计,或者想快速搭建输液监护原型的工程师来说,这套资料的价值在于:原理图、PCB、C源代码、Proteus仿真文件一次给齐,照着把「传感器替代」这一层看懂,再替换成真实红外对管和液位传感器,逻辑几乎不用改。
2. 原理图与PCB设计:ADC0832双通道采样链路与传感器替代方案
2.1 系统硬件架构与管脚分配
这套系统的单片机按AT89C52或STC89C52处理,12MHz晶振。外围模块主要有LCD1602显示、ADC0832采集、蜂鸣器报警和三个按键输入。Proteus元件清单里能看到Lcd、ADC0832、Resistors、Capacitors、Buzzer、Button、Potentiometer,以及仿真用的信号发生器。我在Keil工程里看main.c,管脚定义基本是这样:
#define LCD_DATA P0 // LCD1602 8位数据口 sbit LCD_RS = P2^0; // 寄存器选择:0命令,1数据 sbit LCD_RW = P2^1; // 读写选择:0写,1读 sbit LCD_EN = P2^2; // 使能信号,下降沿锁存 sbit ADC_CS = P1^0; // ADC0832 片选,低有效 sbit ADC_CLK = P1^1; // ADC0832 时钟 sbit ADC_DIO = P1^2; // ADC0832 双向数据线 sbit BEEP = P2^3; // 蜂鸣器,低电平触发 sbit KEY_SET = P3^2; // 设置键 sbit KEY_UP = P3^3; // 加键 sbit KEY_DOWN = P3^4; // 减键这段代码把LCD数据总线放在P0口,是因为P0内部没有上拉电阻,接LCD时必须在外部加4.7k或10k排阻,否则高电平拉不上去。ADC0832用P1.0到P1.2三根线控制,比ADC0809省了8根并行数据和一堆控制线,做PCB时走线压力小很多。蜂鸣器我按低电平驱动处理,单片机IO口高电平驱动能力弱,用8550三极管在低电平时导通更可靠。
各模块与单片机引脚的对应关系如下:
| 外设 | 信号线 | 单片机引脚 | 说明 |
|---|---|---|---|
| LCD1602 | RS/RW/EN | P2.0/P2.1/P2.2 | 8位数据模式 |
| ADC0832 | CS/CLK/DIO | P1.0/P1.1/P1.2 | 双通道8位ADC |
| 滴速输入 | INT0 | P3.2 | 信号发生器方波脉冲输入 |
| 液位模拟 | CH0 | ADC0832的CH0输入 | 电位器中点电压 |
| 蜂鸣器 | BEEP | P2.3 | 低电平触发 |
| 按键 | SET/UP/DOWN | P3.2/P3.3/P3.4 | 设置报警阈值 |
注意,KEY_SET和滴速中断输入共用P3.2,原资源里信号发生器直接接在外部中断引脚上,所以按键只能用查询方式扫描。做实物时我一般会把这个引脚拆开,滴速走P3.2中断,按键换到P2口,避免仿真能跑、实物按键受脉冲干扰的情况。
2.2 液位检测:电位器怎么代替真实液位传感器
真实输液液位检测常见两种方案:红外对管贴在莫非氏滴管两侧,有液和无液时透光率不同;电容式接近开关探测液面是否降到警戒线。无论哪种,输出基本都是电压等级或开关量。仿真里用10k电位器代替,电位器接在5V和GND之间,中间抽头进ADC0832的CH0,旋转电位器就等于改变液位传感器的输出电压。
原理图上要注意分压范围和ADC输入耐压。ADC0832参考电压接VCC为5V,输入范围0到5V,电位器分压恰好落在这个区间。真实传感器如果输出0到3.3V,可以直接接,但要重新计算阈值;如果输出4到20mA电流,必须加250欧采样电阻转成1到5V电压。我在做实物时会在ADC输入前串联一个100欧电阻和0.1uF电容,滤掉传感器引线上的高频噪声。
2.3 滴速检测:信号发生器与红外对管的等效关系
真实滴速传感器是红外对管:液滴掉入滴壶瞬间遮挡红外光,接收管输出一个脉冲。Proteus里用信号发生器代替,选择方波,频率就代表每秒的滴数。比如1Hz就是每秒1个脉冲,换算成滴速是60滴/分钟。
容易被忽略的是触发条件。单片机外部中断检测下降沿,信号发生器必须选方波,幅度覆盖TTL电平。我一般设幅度5V、偏置2.5V,波形在0V到5V跳变。幅度设成1V或10V都不行,Proteus数字仿真可能识别不到稳定跳变,导致中断不触发。
2.4 PCB布局布线的几个实用惯例
原理图用Altium打开,PCB文件可以直接继续铺板。51单片机这种低速板两层就够。我布线时主要管三件事:晶振X1和两个20pF到30pF负载电容紧靠单片机X1、X2引脚,走线越短越好;ADC0832的模拟输入线远离晶振和P0总线,防止数字噪声耦合进液位采样;蜂鸣器驱动三极管的地要和单片机数字地单点连接,关断瞬间的电流变化不会拉低ADC参考电压。
提示: Proteus仿真文件里只有DSN,PCB工程在Altium一侧。想直接打样的话,先核对电位器和按键封装尺寸,这两种器件最容易买错。
3. C语言固件实现:LCD1602驱动、ADC0832读取与滴速计数
3.1 Keil工程结构与生成HEX的流程
程序文件夹里有main.c、lcd1602.c、ADC0832.C、STARTUP.A51,以及main.uvproj工程文件。用Keil打开main.uvproj,编译后输出main.hex,这个HEX文件在Proteus里加载到单片机。STARTUP.A51是Keil自动生成的启动文件,负责清零和堆栈初始化,通常不用改。
编译设置里要注意:Device选择AT89C52或STC89C52都可以,Output选项卡必须勾选Create HEX File。晶振频率设为12MHz,这样代码里所有延时函数的时间基准才是准的。源代码把LCD1602和ADC0832分文件实现,main.c只做逻辑调度,这是课程设计里比较清晰的分层方式,后续把lcd1602.c换成OLED驱动,或者把ADC0832换成TLC1543,都不会动到主流程。
3.2 LCD1602显示:延时代替读忙
LCD1602初始化我习惯用延时,不读忙标志。因为代码少,Proteus下也很稳定。下面这段是lcd1602.c里最核心的写命令函数:
void LCD_WriteCmd(unsigned char cmd) { LCD_RS = 0; // 命令模式 LCD_RW = 0; // 写操作 LCD_DATA = cmd; // 命令字送到数据口 LCD_EN = 1; // 使能高电平 delay_5us(); // 建立时间,至少几微秒 LCD_EN = 0; // 下降沿锁存数据 delay_1ms(); // 等待内部处理 }逻辑说明:LCD1602在EN引脚的下降沿锁存数据线上的命令或数据,所以先置EN=1,保持一小段时间,再拉低。RS决定访问命令寄存器还是数据寄存器,RW固定为0表示只写。0x38设置8位数据、2行、5x7点阵;0x0C开显示不显示光标;0x01清屏。如果显示乱码,先查RS/RW/EN接线顺序,再看初始化前有没有等15ms以上的上电延时。
3.3 ADC0832读取:三线SPI式时序
ADC0832是8位双通道逐次逼近型ADC,通过CS、CLK、DIO三根线做类似SPI的串行通信。读取CH0的时序是:CS拉低后在CLK上升沿前把DIO置高表示起始位,接着写入通道选择位,再在CLK下降沿读数据。下面代码按常见时序读取一位通道的数据:
unsigned char ADC0832_Read(unsigned char ch) { unsigned char i, dat = 0; ADC_CS = 0; // 片选有效 ADC_CLK = 0; ADC_DIO = 1; // 起始位 ADC_CLK = 1; ADC_CLK = 0; ADC_DIO = ch; // 通道选择,0或1 ADC_CLK = 1; ADC_CLK = 0; ADC_CLK = 1; ADC_CLK = 0; // 第一个转换时钟 for (i = 0; i < 8; i++) // 读取8位数据 { dat <<= 1; ADC_CLK = 1; ADC_CLK = 0; if (ADC_DIO) dat |= 0x01; // 从高位开始读 } ADC_CS = 1; // 片选释放 return dat; }参数说明:ch传0读CH0液位,传1读CH1滴速幅度。滴速本质是频率信号,但也可以先用ADC看一眼波形幅度是否正常。8位ADC在5V参考下分辨率是5/256约0.0195V,对液位报警足够。时序上要注意CLK翻转间隔,Proteus仿真可以很快,实物上51单片机IO翻转速度有限,建议在CLK翻转之间加一个NOP,防止ADC0832采样不稳定。
3.4 滴速计数和报警逻辑:定时器与外部中断配合
滴速测量我采用最常用做法:外部中断INT0对脉冲下降沿计数,定时器T0定时1秒,每秒把计数器累加进数组,再取最近10秒平均值乘6得到滴/分钟。这比直接测单个周期更抗干扰,真实红外对管输出会有毛刺。
unsigned int pulse_count = 0; // 1秒内脉冲数 unsigned int speed_smooth = 0; // 滤波后的滴速 unsigned char time_1s = 0; // 1秒标志 void INT0_ISR() interrupt 0 // 外部中断0,下降沿触发 { pulse_count++; } void Timer0_ISR() interrupt 1 // 50ms中断,累计20次得到1秒 { static unsigned int sum = 0; TH0 = 0x4C; TL0 = 0x00; // 12MHz下50ms重装初值 if (++time_1s >= 20) { time_1s = 0; sum += pulse_count; pulse_count = 0; if (time_1s % 10 == 0) // 每10秒更新一次平滑值 { speed_smooth = sum * 6; // 10秒总脉冲数换算成滴/分 sum = 0; } } }逻辑说明:定时器0工作在方式1,16位计数器,12MHz晶振下每50ms中断一次,20次累积为1秒。每次进入1秒逻辑时把pulse_count累加到sum,10秒后sum*6就是等效每分钟滴数。这样显示值不会每秒跳变。报警条件一般是speed_smooth超过上限或低于下限,并且持续3秒再触发;液位阈值直接和ADC0832读回值比较,低于设定值立刻报警,报警动作就是BEEP=0并让LCD闪烁。
提示: 如果信号发生器频率调到10Hz以上,每秒计数会到600滴/分,要确认上限报警值设置合理。真实临床输液滴速通常在20到60滴/分。
4. Proteus仿真搭建:信号发生器模拟滴速,电位器模拟液位
4.1 打开仿真DSN与加载HEX文件
解压后找到仿真文件夹,用Proteus ISIS打开“仿真.DSN”。文件里已经放好单片机、LCD、ADC0832、电位器、信号发生器和蜂鸣器。双击单片机元件,在Program File属性里选择Keil生成的main.hex,Clock Frequency设为12MHz。点击运行按钮,LCD上应出现滴速和液位数值。
Proteus版本不同会导致部分元件显示为灰色,8.x以上打开老DSN基本兼容,但AT89C52的Program File路径如果丢失,单片机不会执行代码。重新指定HEX后,最好按一下复位按钮再观察。Proteus 8 Professional里这个操作在Debug菜单下也有,仿真运行中改代码后重新加载HEX时,仿真器不会自动复位,手动复位是习惯动作。
4.2 信号发生器参数设置:用频率直接对应滴速
双击信号发生器,波形选择Square方波。频率换算关系:1Hz等于60滴/分钟。常用参数如下:
| 滴速(滴/分) | 信号发生器频率(Hz) | 脉冲周期(秒) |
|---|---|---|
| 20 | 0.333 | 3.0 |
| 30 | 0.5 | 2.0 |
| 40 | 0.667 | 1.5 |
| 60 | 1.0 | 1.0 |
| 120 | 2.0 | 0.5 |
幅度设为5V,偏置设为2.5V。这样方波在0V和5V之间跳变。如果信号发生器输出的是双极性波形,低电平低于0.8V才能被识别成TTL低电平,INT0下降沿才可靠。可以用Proteus右侧工具栏里的虚拟示波器,把信号发生器和单片机引脚同时接上去,观察波形是否满足要求。
4.3 电位器模拟液位:从满瓶到警戒线
液位用电位器RV1调整。按5V供电,电位器调到最高时CH0电压5V,ADC值255,代表液位最高;调到20%时电压约1V,ADC值51,代表液位接近警戒。主程序里液位报警值通常设一个ADC比较值,我建议先旋转电位器到“液位大概1/3处”,看LCD上显示的数字,再把这个数字减去20作为报警点。
如果电位器调整后ADC读数不变,先在电位器滑动端挂一个虚拟电压表,确认电压真的在变化。常见原因是电位器抽头接到ADC0832的CH1而不是CH0,或者接地端悬空。Proteus里电位器默认中间抽头有明细端子,连接时要看清网络标号。
4.4 仿真运行时的常见故障与排查
我在Proteus里遇到过三类典型问题。第一类,LCD只有背光没有字符,原因是P0口没加上拉排阻,或者LCD的VO引脚直接接地导致对比度过高。解决办法:在VO接一个10k电位器到GND,调节出正常对比度。第二类,ADC0832读到255不变,多数是CLK和DIO接反,DIO是双向口,接反就读不回数据。第三类,仿真卡死或提示仿真发散,先查电源节点和信号发生器的幅度是否过大,再把ADC输入端的模拟地和数字地检查一遍。
提示: 虚拟示波器在Proteus右侧“Virtual Instruments”面板里,拖出来挂到信号发生器输出端,确认频率和幅度与设置一致,再排查单片机侧逻辑。
5. 阈值整定与报警边界:让仿真结果逼近真实输液场景
5.1 用线性映射把ADC值换算成物理量
直接拿ADC原始值报警不是不行,但换传感器后要重新改代码。更实用的方式是把ADC值映射成0到100的液位百分比,满量程5V对应255:
unsigned char level_percent; level_percent = (unsigned char)((unsigned long)adc_value * 100 / 255);adc_value是ADC0832读到的8位值,乘100再除以255,结果落在0到100之间。这样报警值设置成20,就代表液位低于约1V时报警。滴速也一样可以做标定系数:真实红外对管的输出频率和滴速不一定是1:1,液滴遮挡光路时可能一个脉冲被分成两次下降沿,解决办法是在中断里加10ms消抖,或者把speed_smooth乘0.5。
5.2 低速滴速用周期测量法
如果滴速很慢,比如低于20滴/分,1秒计数的办法会频繁读到0。我一般在这种场景改用测周期法:外部中断记录相邻两次下降沿的定时器计数值,用定时器频率除以计数值得到单滴间隔,再换算成分速。这个方式分辨率高,但单次测量容易毛刺,最终显示还是要做滑动平均。一个折中方案是把计数窗口从1秒拉长到5秒,读数更新慢一点但稳定很多。
5.3 报警带迟滞,避免反复触发
最后一个技巧:报警阈值不要用单点比较。低液位报警设为20%,恢复阈值设为25%,这样液位在报警点附近波动时,不会刚报警又马上解除。实现上就是定义两个全局变量low_limit和low_limit_recover,判断时分开比较:
if (level_percent < low_limit) BEEP = 0; // 进入报警 else if (level_percent > low_limit_recover) BEEP = 1; // 回差恢复low_limit和low_limit_recover分别存20和25,中间5%就是迟滞带。这段逻辑改动很小,但能把“报警器每隔两秒响一次”的问题彻底压掉。把这些参数整定思路带回真实输液装置:把信号发生器换成红外对管整形电路,把电位器换成液位传感器,代码里只调整采样系数和迟滞带宽度,报警行为基本不用动。
本文还有配套的精品资源,点击获取