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
鉴于篇幅限制,只能写部分代码
最后,如果有什么意见或者建议欢迎您留言给我,让我们共同学习一起进步,
如果需要 完整代码或设计文件,请在下方留言或者私信我,看到后会第一时间回复。
谢谢!
感谢你的阅读,希望您有所收获,喜欢请点赞评论加关注!
一种基于单片机的液位控制器设计
吴兴中,屈泽明 (湖南湘潭钢铁集团有限公司,湖南 湘潭 411101)
摘要: 针对湖南湘潭钢铁集团管廊沟潜水泵控制现状和实际要求,设计了一种基于单片机的液位自动控制器。该控制器具有实时监测液位的功能,同时可根据高、低液位设定值,实现自动启停潜水泵。采用RS485总线协议,可实现远程监控功能。实际运行结果表明,该控制器具有成本低、运行可靠、稳定、抗干扰能力强等优点,并具有一定的推广意义。随着控制技术越来越成熟,芯片运行愈来愈稳定,目前越来越多的各种控制器被应用于工矿企业,用于替代过去的人工操作和控制,并取得了巨大的效益和超越人工控制的令人满意的效果。
湖南湘潭钢铁集团公司五米宽厚板厂水处理车间许多电缆、管道铺设在管廊沟内,由于管廊沟内四壁渗水、水管老化而产生漏水,存在淹没管道和电缆的风险,由此可能造成管道腐蚀或电缆短路“放炮”的重大事故。故原设计时在管廊沟的积水坑内都安装了潜水泵控制器,它通过在水中放置3个电极监测积水坑液位的高水位和低水位,实现高水位自动启动潜水泵运行,低水位时自动停止潜水泵运行。此控制器只能指示高、低两个液位,不能显示液位实际值。目前由于潜水泵控制器投运时间较长,元件老化严重,90%的控制器已经出现电路板元件烧毁不能使用的现象。为了保证管廊沟内积水不淹没管道和电缆,湖南湘潭钢铁集团公司五米宽厚板厂水处理车间员工需要每天3次去管廊沟内点检。如果发现有积水,则需要人工启动潜水泵把水排出管廊沟外,水位低时手动关闭潜水泵,防止潜水泵因无水发热而烧毁潜水泵电机。
基于此,本文设计了一种基于单片机的超声波液位控制器,实现了液位实时监测、潜水泵无人操作自动运行等功能。
原潜水泵控制器通过在水中放置3个电极监测积水坑液位的高水位和低水位,实现高水位自动启动潜水泵,低水位时自动停止潜水泵,此控制器存在如下缺陷。
(1)只能指示液位高低,不能显示液位实际值,由于不知道液位实际值,给在管廊沟内检修作业带来不便。
(2)水中放置的3个电极由于产生电解反应,造成电极腐蚀快或结垢严重,需要定期更换电极。
(3)原控制器成本较高,需要2 500元左右,且维护成本较高。
基于上述情况,设计了基于单片机的超声波液位控制器。此控制器具有实时监测实际液位的功能,由于不直接与水接触,故传感器使用寿命长,控制器具有维护简单、成本低廉的特点。
本系统原理结构图如图1所示,系统主要由单片机、通信接口电路、LED显示电路、键盘电路、超声波模块及控制信号电路组成。
选取 AT89S52单片机作为控制核心, AT89S52单片机是一种低功耗、高性能 CMOS 8位微控制器。它具有以下资源:8KB Flash,256 B RAM,32位I/O端口,2个数据指针,3个16位定时器/ 计数器, 1个6向量2级中断结构,全双工串行口, 片内晶振及时钟电路等[1]。
HCSR04是深圳市捷深科技有限公司的一款超声波测距模块,它有4个管脚,分别是+5 V Vcc,电源地Gnd,控制端Trig,接收端Echo。HCSR04模块如图2所示。其基本工作原理是:给控制端Trig提供一个10 μS 以上脉冲触发信号,模块将发出 8个40 kHz周期波并检测回波,一旦检测到有回波信号则输出回响信号Echo;回响信号Echo的脉冲宽度与所测的距离成正比[2];由此通过发射信号到收到的回响信号时间间隔计算得到距离,距离=高电平时间×声速/2。
键盘电路由数字增加键、数字减少键、确认键、测试键4个键组成,键盘电路采用矩阵式键盘电路设计,4个键占用4个I/O资源。
LED显示电路由4位共阴极LED数码管组成,采用动态扫描方式。利用达林顿集成芯片ULN2008驱动LED数码管以及继电器,这样设计既简化了电路,也使电路板更紧凑、简约。数码管用来显示实际液位以及设定的高低液位值。通过程序控制继电器通、断,实现对潜水泵的启停控制。
通信接口电路采用芯片MAX485,它符合RS485协议,通过它实现了TTL电平转换为RS485电平[1,3]。
工作原理分析:控制器以AT89S52单片机为控制核心,通过单片机I/O端口触发超声波测距模块HCSR04发出40 kHz的超声波信号。利用单片机I/O端口监测HCSR04模块回响信号,一旦回响信号由低电平变为高电平时,启动单片机定时器,开始计时。当回响信号由高电平变为低电平时,停止计时,读出回响信号为高电平的时间。根据HCSR04模块距离计算公式,计算出传感器与液位的实际距离LH。实际液位LACT =LSET-LH,其中LSET为量程,LH为传感器与液位的实际距离。根据实际情况设定高、低液位值,逻辑判断控制继电器的通、断,即潜水泵启、停控制信号。利用LED数码管对实际液位LACT进行显示,实现对实际液位的在线监控。通过RS485接口电路实现远程操作和监控。另外,控制器可以通过键盘电路对高、低液位值进行参数设置操作。为了保证在控制器出现程序“飞跑”的情况下能自动使控制器复位重启,设计了看门狗电路。
1.2液位控制器的程序设计
控制器程序采用模块化结构设计,主要包括主程序模块、键盘程序模块、显示程序模块及通信程序模块等。
在主程序模块中完成定时器的初始化、中断初始化以及测量实际液位等功能,主程序功能如图3所示。
键盘程序模块包括键盘识别部分、参数显示部分以及4个键的处理部分,设计时采用外部中断程序来满足键盘对及时响应的要求。
显示程序采用动态扫描方式实现LED数码管对数据的显示,通过定时中断来保证数码管扫描时间间隔一致,使数码管显示稳定、不闪烁。
通信程序用于液位控制器与PC通信,实现液位控制器与PC数据交换,便于远程操作与监控。
2实验与结果
通过实验板对液位控制器进行了测距精度、显示效果、通信等方面的测试。
实验表明模块的盲区为2 cm,探测距离范围为2~450 cm,控制器有较高的精度,能够满足现场的控制要求。
LED数码管显示稳定、鲜艳 、清晰,非常适合用在光线暗淡的环境。
通过RS485总线与PC连接通信,实现了液位控制器与上位机PC远程通信。利用液位控制器与PC通信界面可对高、低液位进行设定,并可监控液位的实际值,通信界面如图4所示。
参考文献
[1] 吴兴中,朱松林,彭新良.利用单片机实现对云台的控制[J].四川兵工学报,2011,32(3):71-73.
[2] 深圳市捷深科技有限公司.HCSR04超声波测距模块说明书[Z].20110227.
[3] 吴兴中,欧青立.一种PC与单片机多机 RS232串口通信设计[J].国外电子测量技术,2009,28(1):7476.
相关问答
单片机 分布式 水位控制系统 电子电路设计翻译成英语,翻译翻译,...[最佳回答]请放心采用ElectronicCircuitDesignofDistributedWaterLevelControlSystemBasedonMCU(或SCM)请放心采用El...
如果 水位 低了就产生信号传送到 单片机 ,在由 单片机 转换成一...[最佳回答]压力传感器没有这个功能,要有压力,它才的信号,你可以用水位感应报警器
如何用 单片机控制 开关?就是可以控制开关“打开和闭合”的电路啊通过这些开关的打开或者闭合,可以实现许多控制功能,举个最简单的例子,水箱的进水和出水,各有一个开关,通过传感器...
求解C语言编写的51 单片机 用按键实现 暂停 开启-ZOL问答再次按按键就唤醒单片机};4水位{当水位<中关村在线vivoX90Pro+举报U盘纽曼5人讨论1.0w次围观关注问题写回答讨论回答(5)zb821002502while...
洗衣机用 水位 传感器的原理是怎样的?_住范儿家装官网洗衣机几乎是每个家庭必备的电器,它给们的生活带来了不少便利,那么全自动洗衣机水位传感器原理是什么,全自动洗衣机的水位传感器是利用气压的原理推...
如何实现用拨动按钮实现 水位 上下限的设定说明设计一个自动水...[最佳回答]定时就是设定上水的时间,设定上水时间前,先要把时间调好.上水就是手动上水,上水的时候按一下上水键就可以.保温就是冬季0度的时候,给水管保温用的,...
运用 单片机 什么知识点可以实现 电热水器无水自动断电 功能运用单片机什么知识点可以实现电热水器无水自动断电功能
海尔eb75m2wh 水位 传感器坏了影响脱水吗?会影响脱水,如果洗衣机传感器坏了,洗衣机将无法准确控制时间和温度,从而影响脱水的效果。洗衣机传感器的作用是控制洗衣机的运行状态,如果传感器坏了,洗衣机...
lg洗衣机 水位 传感器怎么测量好坏?判断洗衣机水位传感器好坏方法:1、检查前首先确认洗衣机盛水桶里没有残留水、导气管有无扭结或堵塞的现象。2、电磁式水位传感器(水位传感器):若水位传感器...
4-20ma模拟量无线传输有哪些成熟的方案?以上就是这个问题的回答,感谢留言、评论、转发。更多电子设计、硬件设计、单片机等内容请关注本头条号:玩转嵌入式。感谢大家。4-20mA模拟量无线传输有哪些成熟...