蜂鳴器源代碼(蜂鳴器初始化代碼)
前沿拓展:
最近幾天總是下雨,搞的人心情也很差,昨天看到有粉絲留言說,導師讓他們組做一個關于超聲波控制液體水位的項目,但是無從下手,希望我幫幫他,可以有償。他是我的鐵粉,下面我就把我前段時間幫人家設計的一個超聲波水位自動控制系統 分享出來,希望可以幫到他們。
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
鑒于篇幅限制,只能寫部分代碼
最后,如果有什么意見或者建議歡迎您留言給我,讓我們共同學習一起進步,
如果需要 完整代碼或設計文件,請在下方留言或者私信我,看到后會第一時間回復。
謝謝!
感謝你的閱讀,希望您有所收獲,喜歡請點贊評論加關注!
拓展知識:
下一篇:蜂鳴器源代碼(蜂鳴器匯編程序)
- 億田燃氣灶維修知識(億田燃氣灶維修技巧)11-18
- 1海信42k11p怎么折開(海信42K11P:全方位展示超清畫質)
- 2電視頻道沒了怎么恢復(快速解決方法)
- 3Fardior燃氣灶售后維修電話號碼查詢(Fardior燃氣灶售后維修電話查詢)
- 4艾木歐防盜門沒電打不開怎么辦(艾木歐防盜門沒電無法啟動?解決方法總結)
- 5ENS指紋鎖售后熱線(ENS指紋鎖售后熱線-專業解決您的問題)
- 6打電話顯示關機是什么原因(如何解決手機無法接通問題)。
- 7v500hk1 cs5故障維修(v500hk1 cs5故障維修指南)
- 8創維液晶電視的遙控器怎么調試(創維電視遙控器調試指南)
- 9林內空氣能售后服務官網熱線(林內空氣能售后服務官網熱線)
- 10朝友精工保險柜24小時售后電話(朝友精工保險柜24小時售后電話 - 完善24小時保
-
開利24小時人工服務熱線(開利空調一開斷路器就跳閘可能的原因及解決方法)。
2024-09-12
-
三菱重工空調廠家維保電話是多少(三菱空調缺相故障怎么修三菱空調缺相故障
2024-09-12
-
三菱中央空調售后電話24小時人工電話(中央三菱空調油位故障如何有效解決中央
2024-09-12
-
開利空調全國客服(開利空調25gw是什么意思詳解25gw型號的特點與用途)。
2024-09-12
-
廣州增城日立HITACHI電視售后維修(電視機怎么手動切換AV信號)
2024-09-12