带温度补偿的超声波测距程序之欧阳科创编.docx
《带温度补偿的超声波测距程序之欧阳科创编.docx》由会员分享,可在线阅读,更多相关《带温度补偿的超声波测距程序之欧阳科创编.docx(18页珍藏版)》请在冰豆网上搜索。
带温度补偿的超声波测距程序之欧阳科创编
/**程序:
基于HC-SR04的超声波测距系统
时间:
2021.02.05
创作:
欧阳科
*单片机型号:
STC90C51612MHz
*说明:
开始连续进行7次超声波测距,每次测距间隔80ms,
*完成后对7次结果排序并将最大的2个数值和最小的2个数值去除,对剩余的
*3个数值取平均值。
完成后指示灯灭,输出结果到LCD1602上。
测量超出范围则发出报警声。
*使用两个IO端口控制HC-SR04触发信号输入和回响信号输出,
*以及一个T0定时器用于时间计数。
*使用DS18B20测量环境温度,声速公式:
V=334.1m/s+Temperature*0.61,
*单片机晶振为12Mhz(11.953M),计数时为T=1us
*计算公式:
S=(334.1m/s+Temperature*0.61)*N*T/2,N为计数值=TH0*256+TL0*/
/*包含头文件*/
#include
#include
#defineDelay4us(){_nop_();_nop_();_nop_();_nop_();}
/*宏定义*/
#defineucharunsignedchar//无符号8位
#defineuintunsignedint//无符号16位
#defineulongunsignedlong//无符号32位
/*全局变量定义*/
sbitBEEP=P1^5;//报警测量超出范围
sbitTrig=P3^4;//HC-SR04触发信号输入
sbitEcho=P3^2;//HC-SR04回响信号输出
floatxdataDistanceValue=0.0;//测量的距离值
floatxdataSPEEDSOUND;//声速
floatxdataXTALTIME;//单片机计数周期
ucharxdatastringBuf[6];//数值转字符串缓冲
//LCD1602提示信息
ucharcodePrompts[][16]=
{
{"MeasureDistance"},//测量距离
{"-OutofRange-"},//超出测量范围
{"MAXrange400cm"},//测距最大值400cm
{"MINrange2cm"},//测距最小值2cm
{""},//清屏
};
ucharxdataDistanceText[]="Range:
";//测量结果字符串
ucharxdataTemperatureText[]="Temperature:
";//测量温度值
/*外部函数声明*/
externvoidLCD_Initialize();//LCD初始化
externvoidLCD_Display_String(uchar*,uchar);
externvoidReadTemperatureFromDS18B20();
externintxdataCurTempInteger;
voidDelayMS(uintms);//毫秒延时函数
voidDelay20us();//20微秒延时函数
voidHCSR04_Initialize();//HCSR04初始化
floatMeasuringDistance();//测量距离
floatDistanceStatistics();//测距的数值排序求平均
voidDisplayDistanceValue(floatdat);//输出距离值到LCD1602上
ucharUnsigedIntToString(uintvalue);//将无符号的整数转成字符串,返回字符串长度,不包括'\0'结束符
voidBeep(uchartime);//蜂鸣器
voidDisplayTemperatureValue();//显示温度值
/***测量距离***/
floatMeasuringDistance()
{
//最大定时时间约65ms
TH0=0;
TL0=0;
//生成20us的脉冲宽度的触发信号
Trig=1;
Delay20us();
Trig=0;
while(!
Echo);//等待回响信号变高电平
TR0=1;//启动定时器0
while(Echo);//等待回响信号变低电平
TR0=0;//关闭定时器0
return(SPEEDSOUND*XTALTIME*((float)TH0*256+(float)TL0))/2000;//返回距离值(mm)
}
/***HCSR04初始化***/
voidHCSR04_Initialize()
{
XTALTIME=12/12;//计算单片机计数周期晶振=12M单位us
SPEEDSOUND=334.1+25*0.61;//温度25度时声速的值
Trig=0;
Echo=0;
TMOD=0x01;
}
/***输出距离值到LCD1602上***/
voidDisplayDistanceValue(floatdat)
{
uchari=0,j=0,len;
uintvalue;
value=(uint)dat;
//范围检查大于4000mm和小于20mm都为超出测量范围
if(value>4000)
{
LCD_Display_String(Prompts[1],0x00);
LCD_Display_String(Prompts[2],0x40);
Beep
(2);
}
elseif(value<20)
{
LCD_Display_String(Prompts[1],0x00);
LCD_Display_String(Prompts[3],0x40);
Beep
(2);
}
else
{
len=UnsigedIntToString(value);//将数值转换成字符串
//保留1位小数
while(stringBuf[i]!
='\0')
{
if(len-j==1)
{
DistanceText[6+j]='.';
j++;
}else
{
DistanceText[6+j]=stringBuf[i];
i++;
j++;
}
}
DistanceText[6+j]='c';
j++;
DistanceText[6+j]='m';
i=7+j;
//剩余位置补空格
while(i<16)
{
DistanceText[i]='';
i++;
}
LCD_Display_String(DistanceText,0x40);//LCD_Display_String(Prompts[0],0x00);
}
}
/***显示温度值***/
voidDisplayTemperatureValue()
{
TemperatureText[13]=CurTempInteger/10+'0';
TemperatureText[14]=CurTempInteger%10+'0';
TemperatureText[15]='C';
LCD_Display_String(TemperatureText,0x00);
}
/***将无符号的整数转成字符串,返回字符串长度***/
ucharUnsigedIntToString(uintvalue)
{
uchari=0,t,length;
//从个位开始转换
do
{
stringBuf[i]='0'+value%10;
value=value/10;
i++;
}while(value!
=0);
length=i;
//将字符串颠倒顺序
for(i=0;i<(length/2);i++)
{
t=stringBuf[i];
stringBuf[i]=stringBuf[length-i-1];
stringBuf[length-i-1]=t;
}
stringBuf[length]='\0';
returnlength;
}
/***蜂鸣器***/
voidBeep(uchartime)
{
uchari;
for(i=0;i<100;i++)
{
BEEP=!
BEEP;
DelayMS(time);
}
BEEP=0;
DelayMS(100);
}
/***延时函数毫秒@12.000MHz***/
voidDelayMS(uintms)
{
uchari,j;
while(ms--)
{
_nop_();
i=2;
j=239;
do
{
while(--j);
}while(--i);
}
}
/***延时函数20微秒@12.000MHz***/
voidDelay20us()
{
uchari;
_nop_();
i=7;
while(--i);
}
/***定时器0中断***/
voidTimer0()interrupt1
{
}
//DS18B20代码:
/*----------------------------------------------
*程序功能:
DS18B20温度检测程序
*单片机型号:
STC89C5212MHz
*晶振:
12Mhz
------------------------------------------------*/
/*包含头文件*/
#include
#include
/*宏定义*/
#defineucharunsignedchar//无符号8位
#defineuintunsignedint//无符号16位
sbitDS18B20_DQ=P3^3;//定义DS18B20端口DS18B20_DQ
intxdataCurTempInteger;//当前采集的温度值整数部分
intxdataCurTempDecimal;//当前采集的温度值小数部分
/***功能:
延时函数STC89C52@12MHz12T模式参数:
无返回:
无***/
voidDelayus(uintcount)
{
while(--count);
}
/***功能:
DS18B20复位及状态检测参数:
无返回:
0或1,1表示未准备好,0表示准备好***/
ucharReset_DS18B20()
{
ucharstatus;
DS18B20_DQ=1;
Delayus
(1);
//开始复位过程
DS18B20_DQ=0;//数据线拉低
Delayus(100);//延时480us-960us
DS18B20_DQ=1;//数据线拉高
Delayus(10);//延时15us-60us
status=DS18B20_DQ;//读取数据线上的状态
Delayus(120);
returnstatus;
}
/***功能:
写一字节到DS18B20中参数:
dat=数据返回:
无***/
voidWriteByteToDS18B20(uchardat)
{
uchari;
for(i=0;i<8;i++)
{
DS18B20_DQ=0;
DS18B20_DQ=dat&0x01;//发送1位数据
Delayus(15);//延时60us以上
DS18B20_DQ=1;//释放总线,等待总线恢复
dat>>=1;//准备下一位数据
}
}
/***功能:
从DS18B20中读一字节参数:
无返回:
读取的数据***/
ucharReadByteFromDS18B20()
{
uchari,dat=0;
for(i=0;i<8;i++)
{
DS18B20_DQ=0;//拉低总线,产生读信号
dat>>=1;
DS18B20_DQ=1;//释放总线,准备读1位数据
Delayus
(2);//延时4us
if(DS18B20_DQ)dat|=0x80;//合并每位数据
Delayus(15);//延时60us
DS18B20_DQ=1;//拉高总线,准备读下1位数据
}
returndat;
}
/***功能:
读取温度值并转换成有符号的数值形式参数:
无返回:
无***/
voidReadTemperatureFromDS18B20()
{
ucharflag=0;//正负符号标志
//存储当前采集的温度值
ucharTempValue[]={0,0};
if(Reset_DS18B20())//DS18B20复位
{
CurTempInteger=255;
CurTempDecimal=0;
}
else
{
WriteByteToDS18B20(0xCC);//跳过ROM命令
WriteByteToDS18B20(0x44);//温度转换命令
Reset_DS18B20();//复位
WriteByteToDS18B20(0xCC);//跳过ROM命令
WriteByteToDS18B20(0xBE);//读取温度暂存器命令
TempValue[0]=ReadByteFromDS18B20();//先读低字节温度值
TempValue[1]=ReadByteFromDS18B20();//后读高字节温度值
Reset_DS18B20();//复位
//计算温度值:
先进行正温度与负温度判断,高5位全为1(0xF8)则为负数
if((TempValue[1]&0xF8)==0xF8)
{
//负温度计算:
取反加1,低字节为0时,高字节取反加1,否则不需要。
TempValue[1]=~TempValue[1];
TempValue[0]=~TempValue[0]+1;
if(TempValue[0]==0x00)TempValue[1]++;
flag=1;//负数标志
}
//将温度值分为整数和小数两部分存储(默认为12位精度)
CurTempInteger=((TempValue[1]&0x07)<<4)|((TempValue[0]&0xF0)>>4);
if(flag)CurTempInteger=-CurTempInteger;
CurTempDecimal=(TempValue[0]&0x0F)*625;
}
}
//LCD1602程序代码:
/*程序功能:
1602液晶显示程序单片机型号:
STC90C16012MHz*/
/***1602液晶显示器控制端口分配,数据使用P0端口***/
sbitLCD_RS=P2^0;
sbitLCD_RW=P2^1;
sbitLCD_EN=P2^2;
/***功能:
毫秒级延时函数参数:
ms=毫秒数值返回:
无***/
voidLCDDelay(uintms)
{
uchari,j;
while(ms--)
{
_nop_();
i=2;
j=239;
do
{
while(--j);
}while(--i);
}
}
/***功能:
1602液晶忙状态检测参数:
无返回:
0或1,1表示状态忙,0表示状态闲***/
bitLCD_Busy_Check()
{
bitresult;
LCD_RS=0;LCD_RW=1;LCD_EN=1;
Delay4us();
result=(bit)(P0&0x80);
LCD_EN=0;
returnresult;
}
/***功能:
1602液晶写指令参数:
cmd=1602LCD指令返回:
无***/
voidWrite_LCD_Command(ucharcmd)
{
while(LCD_Busy_Check());
LCD_RS=0;LCD_RW=0;LCD_EN=0;_nop_();_nop_();
P0=cmd;Delay4us();
LCD_EN=1;Delay4us();LCD_EN=0;
}
/***功能:
1602液晶写数据参数:
dat=一个字节数据返回:
无***/
voidWrite_LCD_Data(uchardat)
{
while(LCD_Busy_Check());
LCD_RS=1;LCD_RW=0;LCD_EN=0;
P0=dat;Delay4us();
LCD_EN=1;Delay4us();LCD_EN=0;
}
/***功能:
设置1602液晶显示位置参数:
pos=位置地址值返回:
无***/
voidLCD_Set_POS(ucharpos)
{
Write_LCD_Command(pos|0x80);
}
/*功能:
1602液晶初始化参数:
无返回:
无***/
voidLCD_Initialize()
{
Write_LCD_Command(0x01);LCDDelay(5);
Write_LCD_Command(0x38);LCDDelay(5);
Write_LCD_Command(0x0C);LCDDelay(5);
Write_LCD_Command(0x06);LCDDelay(5);
}
/***功能:
在1602液晶指定的行上显示字符串(共两行,一行16个字符)
参数:
*str=字符串指针,LineNo=行首地址(第一行0x00,第二行0x40)
返回:
无***/
voidLCD_Display_String(uchar*str,ucharLineNo)
{
uchark;
LCD_Set_POS(LineNo);
for(k=0;k<16;k++)
{
Write_LCD_Data(str[k]);
}
}
/***功能:
在1602液晶指定位置显示一个字符(共两行,一行16个字符)
参数:
Dat=一个字符,X=列位置(0-15)Y=行位置(0,1)返回:
无***/
voidLCD_Display_OneChar(ucharDat,ucharX,ucharY)
{
Y&=0x01;//限制Y不能大于1(2行,0-1)
X&=0x0F;//限制X不能大于15(16个字符,0-15)
if(Y){X|=0x40;}//当要在第二行显示时地址码+0x40;
X|=0x80;//算出指令码
Write_LCD_Command(X);
Write_LCD_Data(Dat);
}
/***主函数***/
voidmain()
{
LCD_Initialize();//1602初始化
LCD_Display_String(Prompts[0],0x00);
LCD_Display_String(Prompts[5],0x40);
ReadTemperatureFromDS18B20();//测温度
HCSR04_Initialize();//HC-SR04初始化
while
(1)
{
Beep
(1);
ReadTemperatureFromDS18B20();//测温度
DisplayTemperatureValue();
if(CurTempInteger<14)
CurTempInteger=14;
elseif(CurTempInteger>26)
CurTempInteger=26;
SPEEDSOUND=334.1+CurTempInteger*0.61;//计算声速
DistanceValue=DistanceStatistics();//测距并返回距离值
DisplayDistanceValue(DistanceValue);//显示距离值
}
}
//测距的数值排序求平均
floatDistanceStatistics()
{
uchari,j;
floatdisData[7],t;
//连续测距
for(i=0;i<7;i++)
{
disData[i]=MeasuringDistance();
DelayMS(80);
}
//排序
for(j=0;j<=6;j++)
{
for(i=0;i<7-j;i++)
{
if(disData[i]>disData[i+1])
{
t=disData[i];
disData[i]=disData[i+1];
disData[i+1]=t;
}
}
}
return(disData[2]+disData[3]+disData[4])/3;
}
时间:
2021.02.05
创作:
欧阳科