带温度补偿的超声波测距程序
/**程序:基于HC-SR04得超声波测距系统
*单片机型号: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 〈reg51。h>
#include 〈intrins。h>
#define Delay4us(){_nop_();_nop_();_nop_();_nop_();}
/*宏定义*/
#define uchar unsignedchar?//无符号8位
#define uint?unsigned int//无符号16位
#define ulongunsigned long ?//无符号32位
/*全局变量定义*/
sbit BEEP=P1^5;??//报警测量超出范围
sbit Trig=P3^4; //HC-SR04触发信号输入
sbitEcho=P3^2;?//HC—SR04回响信号输出
float xdataDistanceValue=0。0;?//测量得距离值
float xdata SPEEDSOUND; ??//声速
float xdataXTALTIME; ?//单片机计数周期
uchar xdata stringBuf[6];??//数值转字符串缓冲
//LCD1602提示信息
uchar codePrompts[][16]=
{
?{"Measure Distance"}, //测量距离
{"-Out of Range -"}, //超出测量范围
?{"MAX range400cm "}, //测距最大值400cm
{”MIN range 2cm"},?//测距最小值2cm
{”"},?//清屏
};
uchar xdata DistanceText[]="Range: ";//测量结果字符串
uchar xdata TemperatureText[]="Temperature:";//测量温度值
/*外部函数声明*/
extern voidLCD_Initialize(); //LCD初始化
extern void LCD_Display_String(uchar*, uchar);
externvoid ReadTemperatureFromDS18B20();
extern int xdataCurTempInteger;
void DelayMS(uint ms);?//毫秒延时函数
voidDelay20us(); //20微秒延时函数
voidHCSR04_Initialize();//HCSR04初始化
float MeasuringDistance();?//测量距离
float DistanceStatistics();?//测距得数值排序求平均
void DisplayDistanceValue(float dat); //输出距离值到LCD1602上
uchar UnsigedIntToString(uintvalue);?//将无符号得整数转成字符串,返回字符串长度,不包括'\0'结束符void Beep(uchar time); //蜂鸣器
void DisplayTemperatureValue(); //显示温度值
/***测量距离***/
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初始化***/
void HCSR04_Initialize()
{
?XTALTIME=12/12;??//计算单片机计数周期晶振=12M 单位us
?SPEEDSOUND=334。1+25*0、61;?//温度25度时声速得值??
?Trig=0;
Echo=0;
TMOD=0x01;
}
/***输出距离值到LCD1602上***/
void DisplayDistanceValue(floatdat)
{
uchari=0,j=0,len;
?uint value;
value=(uint)dat;
//范围检查大于4000mm与小于20mm都为超出测量范围
if(value〉4000)
?{
?LCD_Display_String(Prompts[1],0x00);
LCD_Display_String(Prompts[2],0x40);
Beep(2);?
}
?else if(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); ?}
}
/***显示温度值***/
void DisplayTemperatureValue()
{
TemperatureText[13]=CurTempInteger/10+'0';
TemperatureText[14]=CurTempInteger%10+'0';
TemperatureText[15]='C';
LCD_Display_String(TemperatureText,0x00);?
}
/***将无符号得整数转成字符串,返回字符串长度***/
ucharUnsigedIntToString(uint value)
{
uchar i=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’;
?return length;
}
/***蜂鸣器***/
void Beep(uchar time)
{
?uchar i;
for(i=0;i〈100;i++)
?{
?BEEP=!BEEP;
?DelayMS(time);?
?}
BEEP=0;
DelayMS(100);
}
/***延时函数毫秒@12、000MHz***/ void DelayMS(uint ms)
{
?uchar i, j;
while(ms—-)
{
?_nop_();
??i=2;
j=239;
do
??{
while(—-j);
??}while (--i);
?}
}
/***延时函数20微秒12、000MHz***/ void Delay20us()
{
uchar i;
_nop_();
?i=7;
while (--i);
}
/***定时器0中断***/
void Timer0() interrupt 1
{
}
//DS18B20代码:
/*—------—-——-------——--—----—---——-———--—--—--—
*程序功能: DS18B20温度检测程序
*单片机型号:STC89C5212MHz
* 晶振: 12Mhz
-—----—--—-——-—--—-——--—------—-------—-------——*/
/*包含头文件*/
#include<reg51。h>
#include
/*宏定义*/
#defineuchar?unsigned char ?//无符号8位
#define uint?unsigned int//无符号16位
sbit DS18B20_DQ =P3^3;?//定义DS18B20端口DS18B20_DQ
int xdata CurTempInteger; //当前采集得温度值整数部分
int xdata CurTempDecimal;//当前采集得温度值小数部分
/***功能:延时函数STC89C52 12MHz12T模式参数:无返回:无***/
void Delayus(uintcount) ?
{
?while (--count);
}
/***功能:DS18B20复位及状态检测参数:无返回:0或1,1表示未准备好,0表示准备好***/ uchar Reset_DS18B20()
{
?uchar status;
?DS18B20_DQ=1;
?Delayus(1);
//开始复位过程
DS18B20_DQ=0;?//数据线拉低
?Delayus(100); //延时480us-960us
?DS18B20_DQ=1; ?//数据线拉高
?Delayus(10); ?//延时15us-60us
status=DS18B20_DQ;?//读取数据线上得状态
?Delayus(120);
?return status;
}
/***功能:写一字节到DS18B20中参数:dat=数据返回:无***/
void WriteByteToDS18B20(uchar dat)
{
?uchar i;
for(i=0;i〈8;i++)
?{
??DS18B20_DQ=0;
?DS18B20_DQ=dat&0x01;?//发送1位数据
?Delayus(15);???//延时60us以上
DS18B20_DQ=1;???//释放总线,等待总线恢复
?dat〉〉=1;???//准备下一位数据
?}
}
/***功能:从DS18B20中读一字节参数:无返回:读取得数据***/
uchar ReadByteFromDS18B20()
{
?uchar i,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;
}
/***功能:读取温度值并转换成有符号得数值形式参数:无返回:无***/ void ReadTemperatureFromDS18B20()
{
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端口***/
sbit LCD_RS=P2^0;
sbit LCD_RW=P2^1;
sbit LCD_EN=P2^2;
/*** 功能:毫秒级延时函数参数:ms=毫秒数值?返回:无***/
void LCDDelay(uintms)
{
?uchar i, j;
while(ms-—)
{
??_nop_();
??i =2;
j=239;
?do
??{
??while (——j);
?}while (--i);
?}?
}
/***功能:1602液晶忙状态检测参数:无返回:0或1,1表示状态忙,0表示状态闲***/
bit LCD_Busy_Check()
{
bit result;
LCD_RS=0; LCD_RW=1;?LCD_EN=1;
?Delay4us();
result=(bit)(P0&0x80);
?LCD_EN=0;
returnresult;
}
/***功能:1602液晶写指令参数:cmd=1602LCD指令返回:无***/ void Write_LCD_Command(uchar cmd)
{
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=一个字节数据返回:无***/void Write_LCD_Data(uchar dat)
{
?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=位置地址值返回:无***/void LCD_Set_POS(uchar pos)
{
Write_LCD_mand(pos|0x80);
}
/*功能:1602液晶初始化参数:无返回:无***/
void LCD_Initialize()
{
Write_LCD_Command(0x01);?LCDDelay(5);
?Write_LCD_mand(0x38);?LCDDelay(5);
Write_LCD_Command(0x0C);?LCDDelay(5);
Write_LCD_Command(0x06);?LCDDelay(5);
}
/***功能:在1602液晶指定得行上显示字符串(共两行,一行16个字符) 参数:*str=字符串指针,LineNo=行首地址(第一行0x00,第二行0x40)
返回:无***/
void LCD_Display_String(uchar*str, uchar LineNo)
{
uchar k;
?LCD_Set_POS(LineNo);
?for(k=0;k<16;k++)
{
Write_LCD_Data(str[k]);
?}?
}
/***功能:在1602液晶指定位置显示一个字符(共两行,一行16个字符)
参数:Dat=一个字符,X=列位置(0-15)Y=行位置(0,1) 返回:无***/
void LCD_Display_OneChar(uchar Dat, uchar X, 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);
}
/***主函数***/
void main()
{
?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;
??else if(CurTempInteger〉26)
???CurTempInteger=26;
??SPEEDSOUND=334.1+CurTempInteger*0、61;//计算声速??DistanceValue=DistanceStatistics();//测距并返回距离值??DisplayDistanceValue(DistanceValue);//显示距离值?}
?}
//测距得数值排序求平均
float DistanceStatistics()
{
?uchar i,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; }