关于超声波测距仪的研究
桂林电子科技大学 梁宇彤
一些传统的距离测量方式在某些特殊场合存在不可克服的缺陷。利用超声波测量距离可以解决很多问题,如工业上的工业控制,勘探测量,机械人定位和安全防范等领域得到广泛的应用。在现在的汽车泊车测距系统中一般都使用超声波测距。这里就介绍一下超声波测距系统的实现。本文是由本人原创,只限在本人《单片的天空》的博客中发表。如作其它用途请与本人联系。
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
超声探测器的选型与工作方式:
1、超声探测器的选型
超声探测技术主要用于中程测距、结构探伤等领域,超声波换能器是其核心部件,换能器按其工作介质可分为气相、液相和固相换能器;按其发射波束宽度可分为宽波束和窄波束换能器;按其工作频率又可分为38KHz、40KHz等不同等级。
按题目要求我们选用气相、窄波束、40KHz的超声波换能器。
2、用超声波探测器测距的工作方式的选取
当利用超声波探测器测距时常用二种方法——强度法和反射时间法,强度法是利用声波在空气中的传输损耗值来测量被测物的距离,被测物越远其反射信号越弱,根据反射信号的强弱就可以知道被测物的远近,但在使用这种方法时由于换能器之间的直接耦合信号很难消除,在放大器增益较高时这一直接耦合信号就可使放大器饱和从而使整套系统失效,由于直接耦合信号的影响强度法测距只适合较短距离的且精度要求不高的场合。反射时间法是利用检测声波发出到接收到被测物反射回波的时间来测量距离其原理如图所示,对于距离较短和要求不高的场合我们可认为空气中的声速为常数,我们通过测量回波时间T利用公式S=C*(T/2)<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /> 其中,S为被测距离、V为空气中声速、T为回波时间(T=T1+T2),可以计算出路程,这种方法不受声波强度的影响,直接耦合信号的影响也可以通过设置“时间门”来加以克服,因此这种方法非常适合较远距离的测距,如果对声速进行温度修订,其精度还可进一步提高,本题中我们选用此方法。
这样可以求出距离:
S=C(T1-T2)/2
式中,C为超声波在空气中传播的速度。
其与环境温度的关系式为:
C=331.4+0.61xT
由此可见,声速与温度的密切的关系。在应用中,如果温度变化不大或者对测量要求不太高(例如汽车泊车测距系统)则可认为声速是不变的。否则,必须进行温度补偿。
本次超声波测距仪的设计要求:
1.测量距离范围小于等6m;
2.精度优于1%;
3.进行温度补偿;
4.显示方式为数码管显示(可以改为LCD显示);
5.具有RS-232通信能力,便于扩展;
6.有强抗干扰能力,安装简单;
设计方案的确定:
(1)以AT89S52作为样机,进行调试。调试完成后移植到PHILIPS的89LP932作为系统核心。
因为其具封装体积小低功耗等特点。能很多地符合作为产品核心的要求。
(2)采用6位数码管显示,后4位为距离,前两位为温度。数码管接口基于MAX7219进行设计。
(3)采用DS18B20作为温度测量传感器。
超声波测距仪的硬件设计
超声波测距仪主要包括:温度检测电路,超声波发射及控制电路,超声波接收及信号处理电路,显示
电路,微处理及其辅助电路,以及RS-232通信接口电路6部分组成。由于通信接口电路比较简单,
这里就不作详细讨论。
超声波发射电路的设计:
超声波发送器包括超声波产生电路和超声波发射控制电路两个部分,超声波探头的型号选用CSB40T
。可采用软件发生法和硬件发生法产生超声波。前者使用软件产生40Hz的超声波信号,通过输出引脚输入至驱动器,经驱动器驱动后推动探头产生超声波。第二种方法是利用超4专用发生电路产生超声波信号,并直接驱动换能器产生超声波。两种方法各有优缺点,可根据实际情况而定。
本次设计是用555时基电路振荡产生40Hz的超声波信号。其振荡频率计算公式如下:
f="1".43/((R9+2*R10)*C5)
CNT为超声波发射控制信号,由单片机进行控制。
超声波接收器的设计
超声波接收器包括超声波接收探头,信号放大电路及波形变换电路三部分。其原理图如下:
接收探头取用与发射探头对应的CSB40R。为减少负荷电源的使用,放大电路采用单电源供电,信号放大和变换采用了一片LM324通用放大器,前三级为放大器设计,后一级为比较器设计。每一级放大器都采用阴容电路进行电平偏移,实现单电源条件下交流信号的放大。
基于DS18B20的温度测量电路
温度测量电路基于DS18B20一线式数字温度传感器,电路非常简洁,具体电路如上图所示。
基于MAX7219的6位共阴极数码管显示
目前市面上已有的LED显示驱动芯片种类繁多,从性价比以及功能实用性的角度考虑。本次设计取用MAX7219。其峰值电流可达40MA,最高串行扫描频率为10MHz,典型为1.3KHz。仅使用3条
线串行接口传送数据。多片级联时可控制更多的LED。
本设计的显示电路原理图如下图所示:
超声波测距仪的软件设计
超声波测距仪的程序主要包括以下几个功能模块:
(1)DS18B20温度传感器接口模块,分为初始化子程序,写入子程序及读取子程序等部分;
(2)基于MAX7219的显示模块,分为MAX7219初始化子程序,写入子程序及显示子程序等部分;
(3)温度补偿与距离计算模块,分为超声波发射控制程序,接收处理子程序,温度补偿子程序及距离计算子程序等部分;
(4)主模块,分为系统的初始化,按键处理及各子程序的调度管理等部分。
下图描述了各模块功能及相互之间的关系:
(未完待续....)
以下为本次设计的调试源程序:
/***************************************************************
测距仪C51源程序 桂林电子科技大学 课程设计
调试日期:2006年12月
作者:梁宇彤 darkkiiss@163.com
*****************************************************************/
#include
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define MAX7219STA 0x01 /*MAX7219的显示首地址*/
/***********************************************************
;变量定义
***********************************************************/
uchar dispbuf[8];
uchar jsh,jsl;
uchar canbuf[13];
uchar count="0";
uint distance;
uint temp;
/*标志变量*/
uchar bdata flag1,flag2;
sbit sta_flag =flag1^0;
sbit fuhao =flag1^1;
sbit s1_flag =flag1^2;
/**************************************************************
;输入输出引脚定义
************************************************************/
sbit ENTER = P0^0;
sbit S2 = P0^1;
sbit S3 = P0^2;
sbit S4 = P0^3;
sbit led = P0^6;
sbit DIN7219 = P1^1;
sbit LOAD7219 = P1^2;
sbit CLK7219 = P1^3;
sbit CSBIN = P2^1;
sbit CNT = P2^2;
sbit WDIO = P2^3;
/**************************************************************
;函数声明
***************************************************************/
void delay1ms(void);
void sys_init(void);
void init_7219(void);
void write7219(uchar address,uchar cmd);
void display(void);
void computer(void);
void hex2bcd(void);
void bm(void);
void init_18b20(void);
uint read_word(void);
void write(uchar wr);
void testtemp(void);
uint wd(void);
void delay15(uchar us);
/**************************************************************
系统主函数:
***************************************************************/
void main(void)
{
uchar i,j,k;
for(k=0;k<100;k++)
for(i=0;i<255;i++)
for(j=0;j<255;j++);
sys_init();
init_7219();
display();
sta_flag=0;
waitforstarting:
while(ENTER);
for(i=0;i<20;i++)
delay1ms();
if(ENTER) goto waitforstarting;
s1_flag=!s1_flag;
if(!s1_flag)
{
TR0=0;
ET0=0;
goto waitforstarting;
}
TR0=1;
ET0=1;
testtemp();
while(1)
{
if(sta_flag)
{
while(CSBIN);
TR0=0;
jsh="TH1";
jsl="TH1";
if(count==100)
{
temp="wd"();
count="0";
testtemp();
}
computer();
hex2bcd();
display();
sta_flag=0;
}
}
}
/*****************************************************
;延时1ms子函数
*****************************************************/
void delay1ms(void)
{
uchar i,j;
for(i=0;i<2;i++)
for(j=0;j<255;j++);
}
/**************************************************
;系统初始化子程序
***************************************************/
void sys_init(void)
{
uchar i;
EA="0";
s1_flag=0;
for(i=0;i<6;i++)
dispbuf=0;
TMOD="0X01";
TH0=0XD8;
TL0=0XF0;
CNT="0";
ET0=1;
TR0=1;
EA="1";
}
/***************************************************
;MAX7219初始化函数
****************************************************/
void init_7219(void)
{
uchar address,cmd;
address="0x0c";
cmd="0";
write7219(0x0c,0);
delay1ms();
delay1ms();
delay1ms();
address="0x0b";
cmd="0x07";
write7219(0x0b,0x07);
address="0x0a";
cmd="0x0d";
write7219(0x0a,0x0d);
address="0x09";
cmd="0xff";
write7219(0x09,0xff);
address="0x0c";
cmd="0x01";
write7219(0x0c,0x01);
}
/*****************************************************
;MAX7219写入函数
;参数:address寄存器地址,cmd为命令数据
*****************************************************/
void write7219(uchar address,uchar cmd)
{
uchar out,i;
LOAD7219=1;
out="address";
for(i=0;i<8;i++)
{
DIN7219=(bit)(out&0x80);
out="out"<<1;
_nop_();
_nop_();
_nop_();
CLK7219=0;
_nop_();
_nop_();
_nop_();
CLK7219=1;
}
out="cmd";
for(i=0;i<8;i++)
{
DIN7219=(bit)(out&0x80);
out="out"<<1;
_nop_();
_nop_();
_nop_();
CLK7219=0;
_nop_();
_nop_();
_nop_();
CLK7219=1;
}
LOAD7219=0;
_nop_();
_nop_();
_nop_();
_nop_();
LOAD7219=1;
}
/**************************************************
;显示函数
;入口:显示内容在disbuf中(BCD码形式)
***************************************************/
void display(void)
{
uchar i,st,add,dat;
st="MAX7219STA";
for(i=0;i<8;i++)
{
dat="dispbuf";
if(i==6)dat=dat|0x08;
add="st";
write7219(add,dat);
st++;
}
}
/****************************************************
;定时器0溢出中断函数,每10ms中断
****************************************************/
void time0(void)interrupt 1 using 1
{
TH0=0XD8;
TL0=0XF0;
TH1=0;
TL1=0;
sta_flag=1;
CNT="1";
TR1=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
CNT="0";
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
count++;
}
/*******************************************************************
;距离计算函数
*******************************************************************/
void computer(void)
{
float c;
uint t;
float tp;
if(temp<0x8000)
tp="temp"*0.0625;
else
tp="temp"*(-0.0625);
t="jsh"*256+jsl;
c="331".4+0.61*tp;
distance="c"*t*0.001/2;
}
/********************************************************************
;数据转换函数
将转换后的数据存入显示缓冲区以供显示
待转换的数据有:温度值,距离值,并送存相应的显示缓冲区
*********************************************************************/
void hex2bcd(void)
{
float tp;
unsigned long int tmp;
fuhao="0";
if(temp<0x8000)
tp="temp"*0.0625;
else
{
bm();
tp="temp"*0.0625;
fuhao="1";
}
tp="tp"*10000.0;
tmp="tp";
dispbuf[5]=tmp/100000;
dispbuf[5]=dispbuf[5]%10;
if(fuhao)dispbuf[5]=dispbuf[5]|0x80;
tmp=tmp%100000;
dispbuf[4]=tmp/10000;
tmp=distance;
dispbuf[3]=tmp/10000;
tmp=tmp%10000;
dispbuf[2]=tmp/1000;
tmp="tmp"%1000;
dispbuf[1]=tmp/100;
tmp=tmp%100;
dispbuf[0]=tmp/10;
}
/*************************************************************************
;ds18b20复位函数
读存在脉冲,无存在脉冲刚清标志
*************************************************************************/
void init_18b20(void)
{
WDIO="1";
_nop_();
WDIO=0;
delay15(36);
WDIO=1;
delay15(6);
if(WDIO==0)
flag2=1;
else
flag2=0;
delay15(18);
}
/*************************************************************************
字节写DS18b20函数
待写参数:wr
*************************************************************************/
void write_18b20(uchar wr)
{
uchar i;
for(i=0;i<8;i++)
{
WDIO="0";
delay15(1);
_nop_();
_nop_();
WDIO="wr"&0x01;
delay15(1);
WDIO="1";
wr>>=1;
}
}
/***********************************************************************
字读DS18b20函数
***********************************************************************/
uint read_word(void)
{
uchar i;
uint u;
for(i=0;i<16;i++)
{
WDIO="0";
u>>=1;
WDIO=1;
delay15(1);
if(WDIO==1)
u|=0x8000;
_nop_();
_nop_();
_nop_();
}
return(u);
}
/**********************************************************************
启动温度函数
注意:必须启动后750ms才能读温度
**********************************************************************/
uint wd(void)
{
init_18b20();
if(flag2)
{
write_18b20(0xcc);
write_18b20(0xbe);
return(read_word());
}
}
/**********************************************************************
延时15us函数
***********************************************************************/
void delay15(uchar us)
{
do
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
us--;
}while(us);
}
/***********************************************************************
对读出的温度值temp求补码函数,得到原码
***********************************************************************/
void bm(void)
{
temp=~temp;
temp=temp+1;
}
用户101003 2007-9-10 23:29
请问能安装在物体上用于测物体与水平面的距离吗?