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