产品选型

单片机水位检测 一种新型的水位检测系统

小编 2024-11-24 产品选型 23 0

一种新型的水位检测系统

付存谓1,费美芬1,李军1,孙睿咛2,李炫志2,黄旭铭2,周晋怡2,陈光乐2

(1.浙江比华丽电子科技有限公司,浙江 桐乡314500;2.中国计量大学 机电工程学院 求是电子科技协会,浙江 杭州 310000)

主要从系统原理的简单描述,硬件、软件的设计和介绍,数据采集处理方式及创新点几个方面介绍了一种新型水位检测系统。该系统采用非接触式测量,针对接触式水位检测系统的测量电路测量速度慢、测量精度低、要与水接触、测高温液体时会产生误差等不足之处进行了改善,利用新型的压力传感器,能在传感器不接触到水的情况下对水位进行测量,延长了系统寿命。并且添加了温度补偿的功能来减小误差,提高了系统测量高温液体液位时的测量精度。该系统结构简单,成本较低,速度比接触式测温更快且使用寿命较长,适用于对液位测量精度要求较高的场合。

水位监测;温度补偿;压力传感器

目前,水位检测系统已被广泛地应用于检测地下、河道、水库等水位的变化情况,以便人们在水位过高或过低时及时地进行调整。水位检测系统可分为接触式测量系统和非接触式测量系统,接触式水位检测系统检测电路(包括传感器)需放在水下,与水接触,这就导致了传感器寿命变短,并且大部分水位检测系统不含有温度补偿功能,当待测水的温度随天气的变化而变化时,不能对温度变化进行补偿以减小温漂,降低对水压的影响,会对水位的测量结果产生一定影响。本文对一种应用了HM1600B型压力传感器的水位检测系统进行了详细描述。此系统针对上述缺陷一一进行了解决。本系统采用将软管放入水中,根据管内气压变化来反映液位变化的方法来进行液位测量,当水温变化时软管内气压也会发生变化,传感器不与待测液体直接接触,增长了系统使用寿命,并添加了温度补偿功能,提高了水位测量的精度。整个系统结构简单,测量速度更快,适合于大规模的普及应用。

1系统简介

本系统应用了STM32单片机、2.8英寸TFTLCD显示、HM1600B型压力传感器,还应用了精度较高的热电偶温度计,以便于采集待测液体温度数据并进行温度补偿。将传感器采集到的压力信号转化为液位高度值传到液晶显示屏显示并传到上位机进行处理,实现历史水位值查询、水位变化曲线图的绘制等功能。压力水位检测系统的总体框图如图1。

测量过程:将一根软管一端与压力传感器连接,另一端放入水槽中,此时管内的气压会随着容器中液位的增加或减少而产生变化,由传感器采集气压的数据并经温度补偿等处理后转化为线性规律的电压信号输出,电压信号由STM32单片机的12位ADC进行采集并对采集到的信号进行进一步处理,将其转换为水位值在液晶显示屏上显示,同时将处理好的数据通过串口发送到上位机,得到水位变化的曲线图,并可实现历史水位数据的查询。温度补偿已包含在压力传感器内部,因此不做详细介绍。系统结构如图2,系统原理如图3。

2系统硬件

2.1HM1600B型传感器模块

传感器的选择是系统制作的核心部分。目前测水位的液位传感器主要有浮子式水位传感器、水位跟踪式传感器、超声波水位传感器、雷达激光水位传感器、压力式水位传感器等。其中,压力传感器可将压力转化为电流或电压从而对其进行测量。本系统中使用的传感器为应用较为普遍且体积较小的硅压阻式传感器。它是一个由4个等值电阻构成的惠斯通电桥,当受到压力时,其中一对桥臂电阻值增大,另一对则减小,根据惠斯通电桥的基本原理,电桥输出电压与所受到的压力成正比,通过对电桥输出电压的测量即可得出电桥所受的压力[1]。本系统使用的是由深圳恒敏传感科技有限公司生产的HM1600B型压力传感器,针对传统的硅压阻式传感器进行进一步的改进。以下是该传感器的一些参数:

测量范围:0~7 kPa(G)

供电:5 V DC

输出:0.5~4.5 V DC

静态精度:±2.5%FSO(即误差17.5 mm水位)

综合误差:±5%FSO(包括在0~70℃的温度误差)

由于此传感器是利用单晶硅的压阻效应制成,气压阻系数随温度的变化而变化,压阻效应原理本身就会引起传感器输出的温度漂移[2]。所以要对传感器进行温度补偿。本传感器中已包含温度补偿部分。安装时,只需将本传感器直接焊接在电气PCB主板上即可,注意对传感器加的电压不宜过大,否则易导致传感器损坏。此压力传感器输出的电压曲线公式如下:

其中,Vout为压力传感器输出电压,Vin为采集到的电压信号,Vin=2.8~5.4 V DC。

传感器结构如图4。

本传感器为减小误差、提高精度而加入了温度补偿部分,通过采用热电偶温度计对液体温度进行测量并对得到的温度信号进行采集,通过计算对温度进行补偿,从而提高了测量的精度。传感器规范配置如图5。

2.2单片机模块

本系统采用STM32F103RCT6单片机,芯体为32 bit,是一种嵌入式微控制器,采用2~3.6 V电压对其进行供电,内核采用ARM CortexM3,工作频率最高为72 MHz,1.25 Mips/MHz(如果CPU运行在1 MHz的频率下,每秒可执行125万条指令),单片机支持3种低功耗模式:睡眠模式、停机模式和待机模式。

本实验应用了单片机中的ADC模块,将采集到的模拟信号(线性变化的电压值)转换为便于微处理器处理的数字信号,再由系统根据一定规律进行处理来间接地得到待测液体的液位值。单片机应用12位ADC,其为一种逐次逼近型模拟数字转换器。有18个通道,通道的A/D转换有4种执行模式,分别为单次、连续、扫描和间断。其结果将以左对齐或右对齐的方式存储在16位数据寄存器中。

2.3液晶显示模块

本系统中采用TFTLCD来对待测液体的液位高度进行显示。TFTLCD即薄膜场效应晶体管LCD,主要构成包括:萤光管、导光板、偏光板、滤光板、玻璃基板、配向膜、液晶材料、薄膜晶体管等部分。每个像素节点都相对独立,并可以连续控制,可在提高显示屏反应速度的同时精确控制显示色阶,使显示效果更加逼真。

2.4电源模块

对STM32单片机供电电压一般在2~3.6 V之间,不能过大,否则单片机容易被损坏。本系统中单片机直接通过电脑USB接口供电,并未单独设立电源模块,使操作更方便,系统结构更简单,且电脑USB端口供电较稳定,单片机不易被烧坏。由于HM1600B型传感器工作电压为5 V,所以应单独使用一个5 V电源为其供电,保证压力传感器和STM32单片机均可正常使用。

3系统软件设计

系统软件设计包含以下几个部分:各个模块初始化;压力传感器采集气压数据并转换成电压;单片机ADC对传感器电压数据进行接收;单片机对接收到的数据进行处理;LCD显示。

3.1系统工作过程

将一根软管的一端与压力传感器连接,另一端放入水槽中,软管内的气压随容器内液位的升高或降低而产生变化,各模块初始化后,压力传感器通过感受软管内气压的变化,进而在OUT口产生电压,单片机通过ADC来接收压力传感器OUT口产生的电压。STM32F103RCT6的ADC模块可检测0~3.3 V的电平,OUT口连接单片机的PA1引脚,接收到电压后,通过转换,将电压值转换成水位值在LCD屏幕上进行显示并将转化后的数据发送给上位机进行处理。系统程序流程如图6。

图6系统程序流程图

3.2上位机设计

上位机应用QT软件编程制作而成。在上位机中,操作者可根据单片机的需要来改变连接的串口号和波特率,经过转化后的水位值可在“水位高度”处进行显示,并且可利用QT自带的数据库对历史检测的水位值进行查询,还可根据水位的变化自动绘制出水位随时间的变化曲线图,便于操作人员对水位的变化趋势进行进一步的了解和研究,并及时对因水位变化而带来的问题进行警戒和解决。还可根据需要在上位机中添加报警系统,当水位超过某一设定值时,可通过添加的提示灯的亮灭情况来判定水位是否符合标准需求。

4数据的采集及处理

当传感器向单片机输出线性电压信号时(电压信号由传感器的OUT口输出),由单片机的ADC模块对电压信号进行采集,ADC模块将采集到的模拟信号(线性变化的电压值)转换为便于微处理器处理的数字信号,OUT口接单片机的PA1脚,再由单片机对转换后的数据进行处理,将采集到的电压信号转换为待测液位的高度,并将其在液晶显示屏上输出和传入上位机进行处理。

将电压信号转化为液位高度的公式如下:

其中h为液位高度,Vin为采集到的电压信号,Vin=2.8~5.4 V DC。

由实际测量可知,尽管传感器内部进行了温度补偿,温度的变化对测量值的准确性还是有一定影响,所以在进行水位测量时,要对环境的温度有所限制,在不同的环境下,测量时所要求的温度应有所改变,以保证液位显示值的准确性。

5结论

本文详细介绍了一种新型的液位检测系统,该系统采用非接触测量的方式,对插入水中的软管内随水位而变化的气压进行测量采集并将其转化为线性变化的电压信号,再用STM32单片机的ADC对电压信号进行采集,并对其进行处理后将液位值显示在LCD和上位机上,解决了接触式测量的测量速度慢、测量精度低、传感器寿命短等问题,同时传感器中加入了温度补偿,使测量结果更精确,充分利用了STM32单片机强大的控制功能和通信接口[3],使得测量结果的精确度大大提高。HM1600B型传感器性能优良,设计独特且使用方便[4],使系统可应用性更强。本系统结构简单,测量精度较高,具有很高的应用价值和很大的普及性,发展前景可观。

参考文献

[1] 谢少伟,刘吉来.基于MPX系列压力传感器的智能水位实时检测系统[J].绍兴文理学院学报:自然科学版, 2007, 27(10):58-62.

[2] 郭凤仪,李斌,马文龙,等.深水水位检测用压力传感器补偿方法研究[J].仪表技术与传感器, 2010(6):6-8.

[3] 马俊,陈靖.基于单片机的水塔水位检测控制系统仿真设计[J].电子设计工程, 2009, 17(4):85-86.

[4] 祝勉.MPX系列X型横向压阻式硅压力传感器[J].仪表技术与传感器, 1994(1):39-41.

AET会员年终大福利!

51单片机超声波水位控制器设计 (C源码+PCB+原理图与实物制作)

最近几天总是下雨,搞的人心情也很差,昨天看到有粉丝留言说,导师让他们组做一个关于超声波控制液体水位的项目,但是无从下手,希望我帮帮他,可以有偿。他是我的铁粉,下面我就把我前段时间帮人家设计的一个超声波水位自动控制系统 分享出来,希望可以帮到他们。

51单片机超声波水位控制器设计

设计说明:

本设计中液晶显示有4个字母,分别为

H------容器的最高水位设定值(不能高于实际高度) L------容器的最低水位设定值

D-----容器实际高度(可以设置)

C-----容器内液体的高度(在实际演示中,障碍物离探头越近,液晶C显示越大,因为障碍物好比液面,离探头近了说明水位高了)

特别提醒:如果容器实际高度D你设置为1米,那么C液体的高度最高能测到98cm,因为探头的盲区在2cm左右。如果D设为2米,那么最高能测到1.98m.

按键功能分别为:设置键 增加键 减小键 复位键

三个指示灯的分别功能为:红色----超过设定的最高水位H 黄色-----低于设定的最低水位L

绿色----最高H和最低L中间

本文采用AT89C52单片机系统实现了水塔水位的自动控制,设计出一种低成本、高实用价值的水塔水位控制器。该系统具有水位检测、水位高度LCD显示、低水位高水位报警以及自动加水等功能。

本设计过程中主要采用了传感技术、单片机技术、光报警技术以及弱电控制强电的技术。本设计传感器使用了超声波模块,并且详细阐述了超声波测距测的原理,给出了系统构成框图。此系统具有易控制、工作可靠、测量精度高的优点,可实时监控液位。并采用52单片机系统控制整个电路的信号处理以及采用光电耦合和继电器来实现弱电控制强电来实现加水系统的自动控制。它能自动完成水位检测、光报警、上水停水的全部工作循环,保证液面高度始终处于较理想的范围内,它结构简单,制造成本低,灵敏度高,节约能源显著,是用于各种高层液体储存的理想设备。

为了大家更好地理解,请如下看示意图

制作出来的实物图如下:

AD的设计图如下:

超声波水位控制器元件清单

1) 9*15万用板 1

2) AT89C51单片机 1

3) 超声波探头 0

4) 40脚IC座 1

5) 4脚排针 0

6) 杜邦线4根 0

7) 继电器*2 0

8) LCD1602液晶 1

9) 103电位器 0

10) 16脚IC座 0

11) 16脚排针 1

12) 蜂鸣器 0

13) 8550三极管*3 0

14) 1k电阻*8 0

15) 10k电阻 0

16) 10uf电容 0

17) 30pf电容*2 0

18) 12M晶振 1

19) 3mmLED(红、绿各2个,黄1个) 0

20) 轻触按键*4 1

21) 自锁开关 1

22) DC电源插口 1

23) USB电源线(电池盒)

24) 直流水泵*2(根据客户自选)

单片机程序源码如下:

/***************************************************************

名称:基于51单片机的超声波水位监测报警系统

单片机型号:AT89C51

单片机设置:时钟12T,晶体12MHZ

作者:从零开始学单片机

注:修改增加水泵控制和排水控制,即双继电器

***************************************************************/

#include <reg51.h>

#include <intrins.h> // 包含循环移位:_cror_

#include "main.h"

//----------------------------------------------------------------------

uchar code TabNumASCII[10] = {'0','1','2','3','4','5','6','7','8','9'};

bool g_flag = isNo; //用于标记超时(65.536ms)

bool g_flag05s = isNo; //用于标记0.52秒

uchar ucCount = 0; //用于计数0.52秒

uint uiH = 80; //设定的最高报警水位 H

uint uiL = 30; //设定的最低报警水位 L

uint uiD = 100; //检测探头到水库底部的距离 D

bool g_flagSwitch = isNo; //控制阀门连续开启间隔延时(保护)标志

bool g_flagBeepTimer = isNo; //定时提醒标志

//-----------------------------------------------------------------------

// 延时10us

void delay10us(void) //@12MHz

{

unsigned char i;

_nop_();

i = 2;

while (--i);

}

// 延时100us

void delay100us(void) //@12MHz

{

uchar i;

_nop_();

i = 47;

while (--i);

}

// 延时125us

void delay125us(void) //@12MHz

{

unsigned char i;

i = 60;

while (--i);

}

// 延时5ms

void delay5ms(void) //@12.000MHz

{

unsigned char i, j;

i = 10;

j = 183;

do

{

while (--j);

} while (--i);

}

// 延时500ms

void delay500ms(void) //@12MHz

{

unsigned char i, j, k;

_nop_();

i = 4;

j = 205;

k = 187;

do

{

do

{

while (--k);

} while (--j);

} while (--i);

}

//-----------------------------------------------------------------------

//初始化IO端口

void initIO(void)

{

P0 = 0xff;

P1 = 0xff;

P2 = 0xff;

P3 = 0xff;

}

// 初始化定时器0,定时器时钟12T模式 模式1,16位 @12.000MHz

void initTimer0(void)

{

TMOD &= 0xF0; //设置定时器模式

TMOD |= 0x01; //设置定时器模式

TL0 = 0; //定时器初值清零

TH0 = 0; //定时器初值清零

//TR0 = 1; //开定时器0

ET0 = 1; //开定时器0中断

EA = 1; //开总中断

}

// 初始化定时器1,定时器时钟12T模式 模式1,16位 @12.000MHz

void initTimer1(void) //50毫秒@12.000MHz

{

TMOD &= 0x0F; //设置定时器模式

TMOD |= 0x10; //设置定时器模式

TL1 = 0xB0; //设置定时初值

TH1 = 0x3C; //设置定时初值

TR1 = 1; //定时器1开始计时

ET1 = 1; //开定时器0中断

}

//-----------------------------------------------------------------------

//定时器0中断

void zd0(void) interrupt 1

{

g_flag = isYes; //中断溢出标志,g_flag = isYes超过测距范围

if(++ucCount >= 8)

{

ucCount = 0;

g_flag05s = isYes; //g_flag05s = isYes定时0.52秒到,用于测量周期延时

}

TL0 = 0; //设置定时初值

TH0 = 0; //设置定时初值

}

//定时器1中断 定时50ms

void tm1_isr() interrupt 3 using 1

{

static uchar count = DATA_switchTime; //50ms的200倍 = 10S

static uchar uiCount = 1200; // = 1分钟

static uint uiCount_BeepTimer = DATA_BeepTimer;

TL1 = 0xB0; //设置定时初值

TH1 = 0x3C; //设置定时初值

if (g_flagSwitch == isNo)

{

if (count-- == 0) //50ms * 200 -> 10s

{

count = DATA_switchTime;

g_flagSwitch = isYes;

// TR1 = 0;

}

}

if(g_flagBeepTimer == isNo)

{

if (uiCount-- == 0) //= 1分钟

{

uiCount = 1200;

if(uiCount_BeepTimer-- == 0)

{

uiCount_BeepTimer = DATA_BeepTimer;

g_flagBeepTimer = isYes;

// TR1 = 0;

}

}

}

}

//-----------------------------------------------

//外部中断1

void exint1() interrupt 2

{

EX1 = 0; //关闭当前中断

TR0 = 0; //关闭时器0

}

//-----------------------------------------------------------------------

//读LCD忙状态并等待忙状态结束

void LCD_waitNotBusy(void)

{

IO_LCD_Data = 0xFF;

io_LCD_RS = 0;

io_LCD_RW = 1;

io_LCD_E = 0;

_nop_();

_nop_();

io_LCD_E = 1;

while(IO_LCD_Data & 0x80); //检测如果是忙信号,一直等到不忙

}

//给LCD写指令

void LCDWriteCommand(uchar command,bool ifReadBusy) //ifReadBusy = 1 时先进行忙检测

{

if (ifReadBusy == isReadBusy) LCD_waitNotBusy(); //根据需要检测忙

IO_LCD_Data = command;

io_LCD_RS = 0;

io_LCD_RW = 0;

io_LCD_E = 0;

_nop_();

_nop_();

io_LCD_E = 1;

}

//给LCD写数据

void LCDWriteData(uchar dat)

{

LCD_waitNotBusy(); //等到不忙

IO_LCD_Data = dat;

io_LCD_RS = 1;

io_LCD_RW = 0;

io_LCD_E = 0;

_nop_();

_nop_();

io_LCD_E = 1;

}

// 初始化LCD1602液晶显示屏

void initLCD1602(void)

{

uchar i;

IO_LCD_Data = 0; // 数据端口清零

for(i = 0; i < 3; i++) // 设置三次显示模式

{

LCDWriteCommand(0x38,isNotReadBusy); // 不检测忙信号

delay5ms();

}

LCDWriteCommand(0x38,isReadBusy); // 设置显示模式,检测忙信号

LCDWriteCommand(0x08,isReadBusy); // 关闭显示

LCDWriteCommand(0x01,isReadBusy); // 显示清屏

LCDWriteCommand(0x06,isReadBusy); // 显示光标移动设置

LCDWriteCommand(0x0F,isReadBusy); // 显示开及光标设置

}

//按指定位置显示一个字符

void putOneCharToLCD1602(uchar line, uchar position, uchar ucData)

{

line &= DATA_LineMax;

position &= DATA_PositionMax;

if (line == DATA_LineTow) position |= 0x40; //当要显示第二行时地址码+0x40;

position |= 0x80; //设置两行显示格式 D7 = 1;

LCDWriteCommand(position, isReadBusy); //发送命令 设置字符地址

LCDWriteData(ucData); //写入字符的数据

}

//按指定位置显示一串字符

void putLineCharsToLCD1602(uchar line, uchar position, uchar count, uchar code *ucData)

{

uchar i;

for(i = 0; i < count; i++) //连续显示单个字符

{

putOneCharToLCD1602(line, position + i, ucData[i]);

}

}

//按指定位置连续显示三个字符(三位数字)

void putThreeCharToLCD1602(uchar line, uchar position, uint uiNumber)

{

uiNumber %= 1000;

putOneCharToLCD1602(line, position, TabNumASCII[uiNumber / 100]);

putOneCharToLCD1602(line, ++position, TabNumASCII[uiNumber % 100 / 10]);

putOneCharToLCD1602(line, ++position, TabNumASCII[uiNumber % 100 % 10]);

}

// 按键检测子程序,有键按下返回键端口数据,无键返回0

uchar GetKey(void)

{

uchar KeyTemp = (IO_KEY | DATA_KEY_ORL); //获取按键端口数据

if( KeyTemp != DATA_KEY_Null ) // 如果不为空

{

uchar CountTemp = 0;

do

{

delay125us();

if(KeyTemp != (IO_KEY | DATA_KEY_ORL)) return 0; //在延时期间检测键,如果不稳定保持则退出

} while(++CountTemp > Data_Key20msCountMax); // 延时20ms去抖动

while((IO_KEY | DATA_KEY_ORL) != DATA_KEY_Null); //等键释放

return KeyTemp; // 有键按下返回键端口数据

}

return 0; // 无有效键返回0

}

//加一

uchar INC_Number(uchar Number, uchar Min, uchar Max)

{

if(Number >= Max) return Min; else return (++ Number);

}

//减一

uchar DEC_Number(uchar Number, uchar Min, uchar Max)

{

if(Number <= Min) return Max; else return (-- Number);

}

// 检测到有按键后 这里执行按键任务

void execute_key_task(uchar ucKeyValue)

{

uchar state = 0; //定义调整数据的状态变量

uchar keyValue = 0; //定义键值得临时变量

if(ucKeyValue != DATA_KEY_Set) return; //不是设置键退出

//是设置键继续-----------------------------------------------------

putLineCharsToLCD1602(lineTow, 8, 8, "C:000cm "); //清零显示当前距离CURRENT

putThreeCharToLCD1602(lineOne, 8 + 2, uiD); //光标调整到调整总距离(检测探头到水库底部的距离“D:000cm”)

while(1)

{

keyValue = GetKey();

if(keyValue == 0) continue;

switch(keyValue)

{

case DATA_KEY_Set:

{

// 如果按的是设置键,顺序设置总距离D——高水位H——低水位L——退出

switch(state)

{

case 0: // 如果是设置总距离状态,改变为设置高水位状态,并显示高水位,实现移动光标到高水位后面

{

state = 1;

putThreeCharToLCD1602(lineOne, 0 + 2, uiH);

}

break;

case 1:

{

uchar tempMax = uiD - DATA_uiD_Min;

if(tempMax < 2 + 2) tempMax = 2 + 2;

if(uiH > tempMax)

{

uiH = tempMax;

putThreeCharToLCD1602(lineOne, 0 + 2, uiH);

}

else if(uiH < 2 + 2)

{

uiH = 2 + 2;

putThreeCharToLCD1602(lineOne, 0 + 2, uiH);

}

state = 2;

putThreeCharToLCD1602(lineTow, 0 + 2, uiL);

}

break;

case 2:

{

if(uiL > uiH - 2)

{

uiL = uiH - 2;

putThreeCharToLCD1602(lineTow, 0 + 2, uiL);

}

return;

}

break;

}

}

break;

// 如果按的是增加键,改变相应数据并显示

case DATA_KEY_INC:

{

switch(state)

{

case 0:

{

uiD = INC_Number(uiD, DATA_uiD_Min, DATA_uiD_Max);

putThreeCharToLCD1602(lineOne, 8 + 2, uiD);

}

break;

case 1:

{

uchar tempMax = uiD - DATA_uiD_Min;

if(tempMax < 2 + 2) tempMax = 2 + 2;

uiH = INC_Number(uiH, 2, tempMax);

putThreeCharToLCD1602(lineOne, 0 + 2, uiH);

}

break;

case 2:

{

uiL = INC_Number(uiL, 0, uiH - 2);

putThreeCharToLCD1602(lineTow, 0 + 2, uiL);

}

break;

}

}

break;

// 如果按的是减少键,改变相应数据并显示

case DATA_KEY_DEC:

{

switch(state)

{

case 0:

{

uiD = DEC_Number(uiD, DATA_uiD_Min, DATA_uiD_Max);

putThreeCharToLCD1602(lineOne, 8 + 2, uiD);

}

break;

case 1:

{

uchar tempMax = uiD - DATA_uiD_Min;

if(tempMax < 2 + 2) tempMax = 2 + 2;

uiH = DEC_Number(uiH, 2, tempMax);

putThreeCharToLCD1602(lineOne, 0 + 2, uiH);

}

break;

case 2:

{

uiL = DEC_Number(uiL, 0, uiH - 2);

putThreeCharToLCD1602(lineTow, 0 + 2, uiL);

}

break;

}

}

break;

}

}

}

// 蜂鸣器

void buzzerCall(void)

{

uchar i;

for(i = 0; i < 90; i++)

{

io_Buzzer = 0;

delay100us();

io_Buzzer = 1;

delay100us();

delay100us();

}

delay100us();

delay100us();

}

//计算水位

bool CalculatedWaterLevel(void)

{

uchar i = 8 + 2; //当前水位的数字在LCD屏显示的起点位置

uint uiTime; //声波传播时间

ulong ulDis; //实时测量到距离

uiTime = TH0 << 8 | TL0;

ulDis = (uiTime * 3.40) / 200; //计算当前测量的距离,单位cm

TH0 = 0;

TL0 = 0;

if((ulDis > uiD) || (g_flag == isYes )) // ulDis > uiD 超出测量范围;g_flag == isYes超时;

{

g_flag = isNo;

TR0 = 0;

putLineCharsToLCD1602(lineTow, i, 3, "Err"); // 显示Err

//阀门动作:

// if(g_flagSwitch == isYes)

// {

// io_Control_Inlet = isio_Control_Inlet_OFF;

// io_Control_Outlet = isio_Control_Outlet_ON;

// g_flagSwitch = isNo;

// }

//指示灯:

ioLed_Red = ! ioLed_Red; // 三个灯同时快速闪亮

ioLed_Green = ! ioLed_Green;

ioLed_Yellow = ! ioLed_Yellow;

// 蜂鸣器叫:

if(buzzerCallFlag == isCall)

{

buzzerCall(); // 蜂鸣器叫

}

return isNo; // 返回错误信息

}

else

{

ulDis = uiD - ulDis; // 当前水位C = 总距离 - 当前检测到的距离

if(ulDis > uiH) // 如果水位超高

{

//阀门动作:

io_Control_Inlet = isio_Control_Inlet_OFF;

io_Control_Outlet = isio_Control_Outlet_ON;

g_flagSwitch = isNo;

//指示灯:

ioLed_Red = ! ioLed_Red; // 红灯闪

ioLed_Green = isLedOFF;

ioLed_Yellow = isLedOFF;

// 蜂鸣器叫:

if(ulDis - uiH > (uiD - uiH) / DATA_alarmCoefficient) //当“当前水位”超出最高水位“ ((“总高度减高水位)除以2的值”)时报警

{

buzzerCall(); // 蜂鸣器叫

}

}

else if(ulDis < uiL) // 如果水位超低

{

//阀门动作:

if(g_flagSwitch == isYes)

{

io_Control_Outlet = isio_Control_Outlet_OFF;

io_Control_Inlet = isio_Control_Inlet_ON;

g_flagSwitch = isNo;

}

//指示灯:

ioLed_Red = isLedOFF;

ioLed_Green = isLedOFF;

ioLed_Yellow = ! ioLed_Yellow; //黄灯闪

// 蜂鸣器叫:

if( uiL - ulDis > uiL / DATA_alarmCoefficient)//uiL / 2 当“当前水位”低于“低水位” “低水位除以2的值”时报警

{

buzzerCall(); // 蜂鸣器叫

}

}

else // 水位在正常范围

{

ioLed_Red = isLedOFF;

ioLed_Green = ! ioLed_Green;

ioLed_Yellow = isLedOFF;

}

putThreeCharToLCD1602(lineTow, i, ulDis);

return isYes;

}

return isYes;

}

void main(void)

{

initIO(); //初始化IO端口

delay500ms(); //启动延时,给器件进入正常工作状态留够时间

initLCD1602(); //LCD初始化

putLineCharsToLCD1602(lineOne, 8, 8, "D:000cm "); //显示distance (总)距离(检测探头到水库底部的距离)D

putThreeCharToLCD1602(lineOne, 8 + 2, uiD); //显示三位数值

putLineCharsToLCD1602(lineOne, 0, 8, "H:000cm "); //显示设定的最高报警水位H

putThreeCharToLCD1602(lineOne, 0 + 2, uiH); //显示三位数值

putLineCharsToLCD1602(lineTow, 0, 8, "L:000cm "); //显示设定的最低报警水位L

putThreeCharToLCD1602(lineTow, 0 + 2, uiL); //显示三位数值

putLineCharsToLCD1602(lineTow, 8, 8, "C:000cm "); //显示当前CURRENT水位C

initTimer0(); //初始化定时器0

initTimer1();

//阀门动作:初始先排水

io_Control_Inlet = isio_Control_Inlet_OFF;

io_Control_Outlet = isio_Control_Outlet_ON;

g_flagSwitch = isNo;

while(1)

{

io_US_TX = 1; //启动超声波模块信号

delay10us();

io_US_TX = 0;

while(io_US_RX == 0); //等待计时开始

TR0 = 1; //开启定时器0,计时开始

IT1 = 1; //设置外中断INT1输入信号模式(1:Falling only仅下降沿有效 0:Low level低电平有效)

EX1 = 1; //使能外中断INT1

while(EX1 == 1 && g_flag == isNo)//等待中断或超时退出

{

uchar ucKeyValue = GetKey(); //在等待中检测按键

if(ucKeyValue) execute_key_task(ucKeyValue); //如果有键按下则执行按键任务

}

if(CalculatedWaterLevel() == isNo) continue; //计算水位,如果超出范围返回isNo并重新循环

TR0 = 0; //暂时关闭定时器0

//清零定时器和计数变量以及标志

TL0 = 0;

TH0 = 0;

g_flag = isNo;

ucCount = 0;

g_flag05s = isNo;

TR0 = 1; //打开定时器0

鉴于篇幅限制,只能写部分代码

最后,如果有什么意见或者建议欢迎您留言给我,让我们共同学习一起进步,

如果需要 完整代码或设计文件,请在下方留言或者私信我,看到后会第一时间回复。

谢谢!

感谢你的阅读,希望您有所收获,喜欢请点赞评论加关注!

相关问答

英语翻译采用8051 单片机 系统实现了 水位 的自动控制,设计一种...

[最佳回答]采用8051单片机系统实现了水位的自动控制,设计一种成本低、实用价值高的水塔水位控制器.\x05Usingthe8051single-chipmicrocomputersystemrea....

全自动 水位 水塔传感器原理?

随着科技的进步啊,人们研究科技的手法也成熟起来了,对于水位传感器,不管是在水箱上,还是在水塔上,还是在洗衣机上,都会用到这个技术,那么你知道什么是水位...

lg洗衣机 水位 传感器怎么测量好坏?

判断洗衣机水位传感器好坏方法:1、检查前首先确认洗衣机盛水桶里没有残留水、导气管有无扭结或堵塞的现象。2、电磁式水位传感器(水位传感器):若水位传感器...

洗衣机 水位 不准确的维修方法?

1、首先洗衣机的水位传感器是一个LC电路,是和电脑板中电路共同组成一LC振荡电路,通过气压的大小来改变电感量,从而改变振荡电路的频率,电脑板中的单片机来检...

...线直接接51 单片机 的I/O口吗?另外它的 水位 测量是电_汽配人问答

[最佳回答]一个热敏电阻,测量水温;一个可变电阻,电阻值根据水位变化而变化。用万用表打一下就能找出来。至于你要怎么控制,那就把这两个电阻连接到你的电路中...

太阳能水温 水位 控制器原理是什么?_住范儿家装官网

水位控制器是指通过机械式或电子式的方法来进行高低水位的控制,可以控制电磁阀、水泵等,成为水位自动控制器或水位报警器,从而来实现半自动化或者全...

如何用 单片机 控制开关?

就是可以控制开关“打开和闭合”的电路啊通过这些开关的打开或者闭合,可以实现许多控制功能,举个最简单的例子,水箱的进水和出水,各有一个开关,通过传感器...

水温 水位 探头能控制电磁阀吗?

自动控制液位和温度是吧。液位计+感温器+电磁阀+编好程序的单片机+一些电路和元器件。这样就可以达到你的目的了。自动控制液位和温度是吧。液位计+感温器+电...

智能马桶 水位 传感器原理-ZOL问答

智能马桶水位传感器主要是用来检测马桶的水位,以便于自动控制加水或排水。其原理是通过电极对液体进行电容测量,并将得到的信号转换为数字信号,再通过处理单元...

怎么样判断洗衣机 水位 传感器好坏-ZOL问答

因为如果盛水桶有水或者导气管管路不畅,则都可能使储气室内气压过高或过低,造成水位传感器反馈信息输出错误导致不进水或进水不止。如有以上故障排除后,再进行...

猜你喜欢