|
利用STC89C52單片機(jī)、超聲波模塊(HC-RS04)、DS18B20數(shù)字溫度傳感器和LCD1602液晶顯示模塊制作一個(gè)超聲波測(cè)距儀,液晶屏第一行顯示溫度和超聲波速度“T:30°C V:349m/s”,第二行顯示測(cè)量距離“S=X.XXXm”。
所設(shè)計(jì)的測(cè)距儀測(cè)量單位為米,精確到小數(shù)點(diǎn)后面3位(毫米),測(cè)量范圍:0.05m~5m。
(一)基本部分
1、液晶顯示功能
(1)開機(jī)時(shí),液晶屏第一行顯示溫度和超聲波速度,例如“T:30°C V:349m/s”,第二行顯示測(cè)量距離“S=0.000m”
(2)操作對(duì)應(yīng)的功能按鍵時(shí),液晶屏第一行顯示溫度和超聲波速度,例如“T:30°C V:349m/s”,第二行顯示測(cè)量距離“S=X.XXXm”。
(3)本超聲波測(cè)距儀使用4個(gè)獨(dú)立按鍵。第1個(gè)按鍵為復(fù)位清零功能;第2個(gè)按鍵為單次測(cè)量功能;第3個(gè)按鍵為瞬時(shí)連續(xù)測(cè)量功能;第4個(gè)按鍵為平均連續(xù)測(cè)量功能。
(4)第1個(gè)按鍵為復(fù)位清零功能。無論什么時(shí)候按下該鍵,液晶屏第二行均顯示測(cè)量距離“S=0.000m”
(5)第2個(gè)按鍵為單次測(cè)量功能。每按一次該鍵,就發(fā)射一次超聲波,液晶屏第二行對(duì)應(yīng)顯示一次測(cè)量距離“S=X.XXXm”
(6)第3個(gè)按鍵為瞬時(shí)連續(xù)測(cè)量功能。按下該鍵,連續(xù)發(fā)射超聲波,液晶屏第二行對(duì)應(yīng)顯示瞬時(shí)測(cè)量距離“S=X.XXXm”,再按一次該鍵,數(shù)字保持,以便讀數(shù)
(7)第4個(gè)按鍵為平均連續(xù)測(cè)量功能。按下該鍵,連續(xù)發(fā)射超聲波,液晶屏第二行對(duì)應(yīng)顯示平均測(cè)量距離“S=X.XXXm”,再按一次該鍵,數(shù)字保持,以便讀數(shù)
(8)第5個(gè)按鍵為自動(dòng)/手動(dòng)溫度設(shè)置按鍵,轉(zhuǎn)換到手動(dòng)設(shè)置溫度值,這時(shí)可以利用加鍵和減鍵使溫度在0度至50度范圍內(nèi)調(diào)節(jié),再按一次該鍵,重新回到自動(dòng)溫控狀態(tài),如此循環(huán)。
(9)第6個(gè)按鍵為溫度加按鍵,當(dāng)處于手動(dòng)溫度控制狀態(tài)時(shí),按下本按鍵可以加溫度,最高可以加到50攝氏度。
(10)第7個(gè)按鍵為溫度減按鍵,當(dāng)處于手動(dòng)溫度控制狀態(tài)時(shí),按下本按鍵可以減溫度,最低可以減0攝氏度。
程序代碼如下:
- /**************************************/
- /* 超聲波測(cè)距(自動(dòng)/手動(dòng)溫度校正) */
- /* (超聲波模塊+18B20+1602液晶) */
- /**************************************/
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define LcdData P0 //1602數(shù)據(jù)端口
- sbit LCD_RS=P2^6; //1602 RS端口
- sbit LCD_RW=P2^5; //1602 RW端口
- sbit LCD_EN=P2^7; //1602 EN端口
- sbit Echo=P2^4; //HC-SR04 接收端口
- sbit Trig=P2^3; //HC-SR04 發(fā)射端口
- sbit Resets_Key=P1^0; //復(fù)位清零按鍵
- sbit Single_Key=P1^1; //單次測(cè)量按鍵 誤差較大
- sbit Contin_Key=P1^2; //連續(xù)測(cè)量按鍵 誤差小
- sbit Averag_Key=P1^3; //連續(xù)(平均測(cè)量)按鍵 誤差較小
- sbit Setting_Key=P1^4; //溫度修正按鍵
- sbit Add_Key=P1^5; //溫度加1按鍵
- sbit Sub_Key=P1^6; //溫度減1按鍵
- sbit DQ=P3^7; //DS18B20單總線接口
- bit Temp_Flag; //正負(fù)溫度標(biāo)志:溫度為正Temp_Flag=0,否則為1
- uint temp=25; //溫度值
- bit flag_flow=0,flag_one=0,flag_clear=0,flag_con1=0,flag_con2=0,flag_temp=0;
- uchar i=0,m,j,k;
- uint time=0,S=0,S1=0,totle=0;
- float V=346.0;
- uint Sav[11]; //連續(xù)測(cè)量時(shí)10次平均值數(shù)組
- uchar Line1[16]={"T: C V:346m/s"}; //1602第一行初始字符顯示數(shù)組
- uchar Line2[16]={"S= m "}; //1602第二行初始字符顯示數(shù)組
- void Delayms(uchar xms); //延時(shí)xms函數(shù)
- void WriteLcd(uchar Dat,bit x); //1602寫函數(shù)
- void InitLcd(void); //1602初始化函數(shù)
- void DisplayLcd(); //1602顯示函數(shù)
- void init(); //初始化函數(shù)
- void keyscan(); //鍵掃描函數(shù)
- void StartModule(); //啟動(dòng)模塊函數(shù)
- void Conut(void); //測(cè)量計(jì)算函數(shù)
- void Delayus(uchar xus); //us級(jí)延時(shí)函數(shù)
- bit Init_DS18B20(void); //初始化DS18B20函數(shù)
- uchar Read_DS18B20(void); //讀DS18B20函數(shù)
- void Write_DS18B20(uchar Dat); //寫DS18B20函數(shù)
- void GetTemp(); //取溫度函數(shù)
- void CalcTestTemp(); //溫度處理函數(shù)
- void main(void) //主函數(shù)
- {
- init();
- InitLcd();
- while(1)
- {
- keyscan(); //鍵掃描函數(shù)
- DisplayLcd();
- if(flag_temp==0)
- {
- GetTemp();
- CalcTestTemp();
- }
- if(flag_one==1||flag_con1==1||flag_con2==1)
- {
- StartModule(); //開始發(fā)射超聲波
- while(!Echo); //當(dāng)RX為零時(shí)等待
- TR0=1; //開啟計(jì)數(shù)
- while(Echo); //當(dāng)RX為1計(jì)數(shù)并等待
- TR0=0; //關(guān)閉計(jì)數(shù)
- Conut(); //計(jì)算
- Delayus(200);
- flag_one=0;
- }
- }
- }
- void Delayms(uchar xms) //延時(shí)ms函數(shù)
- {
- uchar i,j;
- for(i=xms;i>0;i--)
- for(j=110;j>0;j--);
- }
- void WriteLcd(uchar Dat,bit x) //1602寫函數(shù)(寫指令時(shí)x=0,寫數(shù)據(jù)時(shí)x=1)
- {
- LCD_EN=0;
- LcdData=Dat;
- LCD_RS=x;
- LCD_RW=0;
- LCD_EN=1;
- Delayms(1);
- LCD_EN=0;
- }
- void InitLcd(void) //1602初始化函數(shù)
- {
- WriteLcd(0x38,0); //功能設(shè)定(38H),8位數(shù)據(jù),2行顯示,5*7點(diǎn)陣
- WriteLcd(0x0C,0); //顯示開、關(guān)設(shè)定(0CH),開顯示,不顯示光標(biāo),光標(biāo)不閃爍
- WriteLcd(0x06,0); //輸入模式設(shè)定(06H),讀寫一個(gè)字符后,地址指針加1,且光標(biāo)加1
- WriteLcd(0x01,0); //清除顯示(01H),清除數(shù)據(jù)RAM中的數(shù)據(jù)
- }
- void DisplayLcd() //液晶屏顯示函數(shù)
- {
- uchar y;
- V=(331.4+temp*0.607);
- Line1[2]=temp/10+0x30;
- Line1[3]=temp%10+0x30;
- Line1[4]=0xDF; //顯示℃中C前面的小圓
- Line1[10]=(uint)V/100+0x30;
- Line1[11]=(uint)V%100/10+0x30;
- Line1[12]=(uint)V%10+0x30;
- if(flag_clear==1)
- S1=0;
- if((S1>=7000)||flag_flow==1) //超出測(cè)量范圍顯示“-”
- {
- flag_flow=0;
- Line2[2]='-';
- Line2[3]='.';
- Line2[4]='-';
- Line2[5]='-';
- Line2[6]='-';
- }
- else
- {
- Line2[2]=S1/1000+0x30;
- Line2[3]='.';
- Line2[4]=S1%1000/100+0x30;
- Line2[5]=S1%100/10+0x30;
- Line2[6]=S1%10+0x30;
- }
- WriteLcd(0x80,0); //設(shè)定第一行地址
- for(y=0; y<16; y++)
- WriteLcd(Line1[y],1);
- WriteLcd(0xc0,0); //設(shè)定第二行地址
- for(y=0; y<16; y++)
- WriteLcd(Line2[y],1);
- }
- void init() //初始化函數(shù)
- {
- TMOD=0x01; //設(shè)T0為方式1,GATE=1;
- TH0=0;
- TL0=0;
- ET0=1; //允許T0中斷
- EA=1; //開啟總中斷
- }
- void keyscan() //鍵掃描函數(shù)
- {
- if(Resets_Key==0) //復(fù)位清零鍵
- {
- Delayms(5);
- if(Resets_Key==0)
- {
- while(Resets_Key==0);
- flag_clear=1;
- }
- }
- if(Single_Key==0) //單次測(cè)量鍵
- {
- Delayms(5);
- if(Single_Key==0)
- {
- while(Single_Key==0);
- flag_one=1;
- flag_con1=0;
- flag_con2=0;
- flag_clear=0;
- }
- }
- if(Contin_Key==0) //連續(xù)瞬時(shí)測(cè)量鍵
- {
- Delayms(5);
- if(Contin_Key==0)
- {
- while(Contin_Key==0);
- flag_con1=~flag_con1;
- if(flag_con1==1)
- {
- flag_one=0;
- flag_con2=0;
- flag_clear=0;
- }
- }
- }
- if(Averag_Key==0) //連續(xù)平均測(cè)量鍵
- {
- Delayms(5);
- if(Averag_Key==0)
- {
- while(Averag_Key==0);
- flag_con2=~flag_con2;
- if(flag_con2==1)
- {
- flag_one=0;
- flag_con1=0;
- flag_clear=0;
- }
- }
- }
- if(Setting_Key==0) //自動(dòng)和手動(dòng)轉(zhuǎn)換鍵
- {
- Delayms(5);
- if(Setting_Key==0)
- {
- while(Setting_Key==0);
- flag_temp=~flag_temp;
- }
- }
- if(Add_Key==0) //溫度減鍵
- {
- Delayms(5);
- if(Add_Key==0)
- {
- while(Add_Key==0);
- if(flag_temp==1)
- {
- temp++;
- if(temp>=50)
- temp=50;
- }
- }
- }
- if(Sub_Key==0) //溫度加鍵
- {
- Delayms(5);
- if(Sub_Key==0)
- {
- while(Sub_Key==0);
- if(flag_temp==1)
- {
- if(temp>0)
- temp--;
- if(temp<=0)
- temp=0;
- }
- }
- }
- }
- void StartModule() //啟動(dòng)模塊函數(shù)(觸發(fā)一次,提供大于10us的高電平)
- {
- Trig=1; //啟動(dòng)一次模塊
- Delayus(15); //延時(shí)2i+5=35us
- Trig=0;
- }
- void Conut(void) //測(cè)量計(jì)算函數(shù)
- {
- time=TH0*256+TL0;
- TH0=0;
- TL0=0;
- V=(331.4+temp*0.607); //由溫度計(jì)算速度值,單位是m/s
- S=(uint)(time*V/2000); //算出來是mm
- if(flag_con2==1) //如果是連續(xù)測(cè)量,則取10次的平均值
- {
- if(k<=10)
- k++;
- if(k>=11)
- k=1;
- Sav[k]=S;
- j++;
- if(j<10)
- S1=S;
- if(j>=10)
- {
- j=10;
- for(m=1;m<=10;m++)
- totle=totle+Sav[m];
- S1=(uint)(totle/10); //取10次的平均值
- totle=0;
- }
- }
- if(flag_one==1||flag_con1==1) //如果是單次測(cè)量或連續(xù)瞬時(shí)測(cè)量,則取1次的值
- {
- S1=S;
- }
- }
- void Delayus(uchar xus) //晶振為12MHz,延時(shí)時(shí)間為2i+5 us
- {
- while(--xus);
- }
- bit Init_DS18B20(void)
- {
- bit x;
- DQ=1;
- DQ=0;
- Delayus(250);
- DQ=1;
- Delayus(20);
- if(!DQ) x=0;
- else x=1;
- Delayus(250);
- DQ=1;
- return x;
- }
- //讀DS18B20函數(shù)
- uchar Read_DS18B20(void)
- {
- uchar i=0,Dat=0;
- for(i=0;i<8;i++)
- {
- DQ=1;
- DQ=0;
- Dat>>=1;
- DQ=1;
- if(DQ) Dat |= 0x80;
- DQ=1;
- Delayus(30);
- }
- return Dat;
- }
- //寫DS18B20函數(shù)
- void Write_DS18B20(uchar Dat)
- {
- uchar i=0;
- for(i=0;i<8;i++)//循環(huán)8次,寫入一個(gè)字節(jié)
- {
- DQ=1;//未發(fā)送前的狀態(tài)
- Dat >>= 1;//將要傳送的最低位放入CY
- DQ=0;//將總線拉低,產(chǎn)生寫時(shí)序
- DQ=CY;//將要傳送的位狀態(tài)送到總線上
- Delayus(30);//延時(shí)50us,即保持總線狀態(tài),待DS18B20采樣
- DQ=1;//恢復(fù)期,總線置1
- }
- }
- void GetTemp(void) //獲取溫度函數(shù)
- {
- uchar a=0,b=0;
- Init_DS18B20();
- Write_DS18B20(0xcc); //跳過ROM
- Write_DS18B20(0x44); //開啟溫度轉(zhuǎn)換
- Init_DS18B20();
- Write_DS18B20(0xcc); //跳過ROM
- Write_DS18B20(0xbe); //讀暫存器
- a=Read_DS18B20(); //讀取高速暫存字節(jié)0,溫度低8位
- b=Read_DS18B20(); //讀取高速暫存字節(jié)1,溫度高8位
- temp=b;
- temp<<=8;
- temp=temp|a; //將高、低位溫度編碼合在一起
- if(b>=8) //判斷溫度值是否為負(fù),如果溫度高字節(jié)大于等于8說明溫度值為負(fù)
- {
- temp=~temp+1; //將補(bǔ)碼轉(zhuǎn)換成原碼
- Temp_Flag=1; //溫度標(biāo)志為1,表示溫度為負(fù)
- }
- else
- {
- Temp_Flag=0; //溫度標(biāo)志為0,表示溫度為正
- }
- temp=temp*0.0625+0.5;//將溫度編碼轉(zhuǎn)換成溫度值,加0.5是為了四舍五入
- }
- void CalcTestTemp() //溫度處理函數(shù)
- {
- if(temp<100) Line1[2]=' '; //如果溫度值小于10,十位顯示空白(不顯示0)
- else Line1[2]=temp%100/10+0x30; //取溫度十位并轉(zhuǎn)換成ASCII碼
- Line1[3]=temp%10+0x30; //取溫度個(gè)位并轉(zhuǎn)換成ASCII碼
- }
復(fù)制代碼
|
評(píng)分
-
查看全部評(píng)分
|