超聲波測距(超聲波模塊+18B20+1602液晶)
#include"reg52.h"
#include"math.h"
#define uchar unsigned char
#define uint unsigned int
#define LcdData P0 //1602數據端口
sbit LCD_RS=P3^5; //1602 RS端口
sbit LCD_RW=P2^5; //1602 RW端口
sbit LCD_EN=P3^4; //1602 EN端口
sbit Echo=P1^6; //HC-SR04 接收端口
sbit Trig=P1^7; //HC-SR04 發射端口
sbit Resets_Key=P3^3; //復位清零按鍵
sbit Single_Key=P3^2; //單次測量按鍵 誤差較大
sbit Contin_Key=P1^3; //連續測量按鍵 誤差小
sbit Averag_Key=P1^2; //連續(平均測量)按鍵 誤差較小
sbit DQ=P2^2; //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/10;
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;
}
}
}
}
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碼
}
|