超声波测距(超声波模块+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码
}
|