说明:
本设计中液晶显示有4个字母,分别为
H------容器的最高水位设定值(不能高于实际高度)
L------容器的最低水位设定值
D-----容器实际高度(可以设置)
C-----容器内液体的高度(在实际演示中,障碍物离探头越近,液晶C显示越大,因为障碍物好比液面,离探头近了说明水位高了)
特别提醒:如果容器实际高度D你设置为1米,那么C液体的高度最高能测到98cm,因为探头的盲区在2cm左右。如果D设为2米,那么最高能测到1.98m.
按键功能分别为:设置键 增加键 减小键 复位键
三个指示灯的分别功能为:红色----超过设定的最高水位H 黄色-----低于设定的最低水位L
绿色----最高H和最低L中间
本文采用AT89C52单片机系统实现了水塔水位的自动控制,设计出一种低成本、高实用价值的水塔水位控制器。该系统具有水位检测、水位高度LCD显示、低水位高水位报警以及自动加水等功能。
本设计过程中主要采用了传感技术、单片机技术、光报警技术以及弱电控制强电的技术。本设计传感器使用了超声波模块,并且详细阐述了超声波测距测的原理,给出了系统构成框图。此系统具有易控制、工作可靠、测量精度高的优点,可实时监控液位。并采用52单片机系统控制整个电路的信号处理以及采用光电耦合和继电器来实现弱电控制强电来实现加水系统的自动控制。它能自动完成水位检测、光报警、上水停水的全部工作循环,保证液面高度始终处于较理想的范围内,它结构简单,制造成本低,灵敏度高,节约能源显著,是用于各种高层液体储存的理想设备。
为了大家更好的理解,请如下看示意图
制作出来的实物图如下:
AD的设计图如下:
超声波水位控制器元件清单
9*15万用板 1
AT89C51单片机 1
超声波探头 0
40脚IC座 1
4脚排针 0
杜邦线4根 0
继电器*2 0
LCD1602液晶 1
103电位器 0
16脚IC座 0
16脚排针 1
蜂鸣器 0
8550三极管*3 0
1k电阻*8 0
10k电阻 0
10uf电容 0
30pf电容*2 0
12M晶振 1
3mmLED(红、绿各2个,黄1个) 0
轻触按键*4 1
自锁开关 1
DC电源插口 1
USB电源线(电池盒)
直流水泵*2(根据客户自选)
单片机程序源码如下:
/***************************************************************
名称:基于51单片机的超声波水位监测报警系统
单片机型号:AT89C51
单片机设置:时钟12T,晶体12MHZ
作者:从零开始学单片机
注:修改增加水泵控制和排水控制,即双继电器
***************************************************************/
#include #include #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); 1 2 3 } // 延时100us void delay100us(void) //@12MHz { uchar i; _nop_(); i = 47; while (--i); 1 2 3 } // 延时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); 1 2 3 4 5 6 } // 延时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;
上一篇:51单片机控制的智能台灯设计
下一篇:单片机双机通讯 非常详细的UART串口异步通讯
推荐阅读最新更新时间:2024-11-09 12:01
推荐帖子
- 菜鸟关于时钟电路M41T81的疑惑
- 一个以ATMEGA128为主控的单片机系统,时钟是M41T81(U18),现通电LED屏无反应。测ATMEGA128的晶振起振,但M41T81的32.768晶振不起振,1脚是4.7V,2脚是0V。数据脚SDA5脚,SCL6脚无波形都是5V,7脚悬空,后备电池坏。现换了M41T81,晶振和电池也不行。现象不变。请问:M41T81除了供给给电源或电池供电外,还是否需要主控指令才起振?因为看PDF说可以通过总线发送停止码使M41T81停振以节省电力。。。。本人搞硬件维修为主,单片机知识很菜,
- 假如3 微控制器 MCU
- 显示器改装谈论
- 有台废弃的显示器,已经坏了,我想把它充分利用一下,看看能不能作为开发板的显示屏用?大家觉得可行么?不知道显示器内部电路复杂不?显示器改装谈论液晶的?卖给收的人一般价格多少?液晶屏肯定是好的么?能不能用什么东西和你换?那第一件事是先修好了再说。是液晶的,是不是好的我还需要测试一下回复沙发wangfuchong的帖子嗯,我想知用液晶灯管部分,估计是其他电路坏了,现在不是有很多液晶驱动板吗?回复板凳chunyang的帖子大屏和小屏的驱动板可是不同的。回复5楼dongs
- dongsy2012 DIY/开源硬件专区
- 【NXP Rapid IoT评测】+神器Rapid IoT Studio online IDE
- RapidIoTStudioonlineIDE为什么说是神器,“任何人都可以“调整”或修改设备行为,而无需C语言编程”。简单入门,易上手!一、发现RapidIoTStudioonlineIDE无须安装,直接打开浏览器就可以使用https://www.nxp.com/cn/support/developer-resources/rapid-prototyping/rapid-iot-studio-online-ide:RAPID-IOT-STUDIO二、登陆
- 蓝雨夜 RF/无线
- 手机信号强度是-109dbm,31asu--- 为什么dbm是负值?-100dbm和-120dbm,哪个信号更...
- 手机信号强度是-109dbm,31asu---为什么dbm是负值?-100dbm和-120dbm,哪个信号更强?31asu是啥含义手机信号强度是-109dbm,31asu---为什么dbm是负值?-100dbm和-120dbm,哪个信号更...发射功率低,当然是负值了asu值越大越好,dBm负值越小越好google给android手机定义的特有信号单位,dBm(1毫瓦的分贝数)和asu(alonesignalunit独立信号单元)。换算dBm=-113+
- QWE4562009 测试/测量
- 怎样计算三角函数
- 按照C430的说法,#includeMATH.H可以调用三角函数sin()、cos(),但我用C430编译可以,LINK出错!大家平时是怎样求三角函数值的呢?用MSP430系列的C语言或汇编。谢谢大家,请多指教!怎样计算三角函数可以的呀需要什么特别的设置吗?我用的怎么不行你的是不是4K限制版的4k限制版的就不行是吗?我的IAR好像版本是比较老的限制版的不行的,正常的版本只要#includeMATH.H就行了,不用设计别的地方好像是什么1.24A怎么样可以看到版本信息
- opcpwm 微控制器 MCU
- NXP-EVB-P6UL(I.mx6ul)的3G网络测试《三》
- 3G测试:Linux3G拨号工具:Linux3G拨号工具,包括pppd与chat,有时甚至需要usb_modeswitch。pppdPPP(PointtoPointProtocol)协议是一种广泛使用的数据链路层协议,在国内广泛使用的宽带拨号协议PPPoE其基础就是PPP协议。Linux中PPP实现主要分成两大部分:PPPD和PPPK。PPPD是用户态应用程序,负责PPP协议的具体配置,如MTU、拨号模式、认证方式、认证所需用户名/密码
- szypf2011 ARM技术
设计资源 培训 开发板 精华推荐
- AL3065EV1,基于 AL3065 高效升压控制器的评估板,用于驱动 WLED 背光
- 广达HSEC阵列卡转接板
- 使用 Analog Devices 的 LTC1434CGN 的参考设计
- voron2.4 集线板
- DC1813A-G,用于 LTC2367CMS-18、18 位、500 ksps、31MHz 低功率、低噪声模数转换器的演示板
- NUCLEO-F302R8,STM32 Nucleo 开发板,带有 STM32F302R8T6 MCU,支持 Arduino 和 ST morpho 连接
- 基于STNRGPF01数字控制器的3kW三通道交错式PFC(功率因数校正)
- mmos蓝牙16键
- TAR5S32U 点稳压器(低压差稳压器)的典型应用
- 具有 6V 栅极驱动器的 LTC3892IUH-2 高效率、双路 3.3V/8.5V 输出同步降压转换器的典型应用电路
- 有奖征集:推荐你用过或了解的好用的电源芯片
- 罗姆有奖直播|从0到1,带你了解电机及其驱动 开始报名啦~
- 【新年活动】2023,兔 do list!
- 有奖直播|TI 符合 USB 2.0 标准的最新隔离器件
- 论坛小程序上线!扫码解锁逛坛新姿势啦!!
- 来翻牌吧!解锁示波器的N种玩法
- 现场抽取PS5等诸多好礼 SiFive RISC-V 中国技术论坛 上海、北京、深圳 3场线下活动邀您出席!
- 如何“配齐”脉冲负载的电源设计需求
- 有奖测评 | 英飞凌新品情报站:最新 5V XENSIVTM PAS CO2 传感器 套件测评
- 下载有礼喽!2017年泰克亚太专家大讲堂第三期: 超宽带复杂电磁信号产生与实时分析技术