基于AT89S52单片机的超声测距系统设计
我们人类耳朵能听到的声波频率为20~20,000赫兹。当声波的振动频率大于20000赫兹或小于20赫兹时,我们便听不见了。因此,我们把频率高于20000赫兹的声波称为“超声波”。超声波是一种波动形式,它可以作为探测与负载信息的载体或媒介;超声波同时又是一种能量形式,当其强度超过一定值时,它就可以通过与传播超声波的媒质的相互作用,去影响,改变甚至破坏后者的状态,性质及结构。超声波依其波传送方向的波动方式可分为纵波、横波、表面波、蓝姆波四种。超声波具有如下特性:
(1) 超声波可在气体、液体、固体、固熔体等介质中有效传播。
(2) 超声波可传递很强的能量。
(3) 超声波会产生反射、干涉、叠加和共振现象。
(4) 超声波在液体介质中传播时,可在界面上产生强烈的冲击和空化现象。
超声波测距的原理是利用超声波在空气中的传播速度为已知,测量声波在发射后遇到障碍物反射回来的时间,根据发射和接收的时间差计算出发射点到障碍物的实际距离。由此可见,超声波测距原理与雷达原理是一样的。
1、压电式超声波发生器工作原理
压电式超声波发生器实际上是利用压电晶体的谐振来工作的。超声波发生器内部结构如图1所示,它有两个压电晶片和一个共振板。当它的两极外加脉冲信号,其频率等于压电晶片的固有振荡频率时,压电晶片将会发生共振,并带动共振板振动,产生超声波。反之,如果两电极间未外加电压,当共振板接收到超声波时,将压迫压电晶片作振动,将机械能转换为电信号,这时它就成为超声波接收器了。
共振板
压电晶片
2、超声波发射电路
超声波发射电路如上图2-2所示,发射电路主要由反向器74LS04和超声波换能器构成,AT89S52单片机在P1.0口每65ms产生两个40kHz的方波,由单片机产生的发射脉冲信号一路经一级反向器后送到超声波换能器的一个电极,另一路经两级反向器后送到超声波换能器的另一个电极,用这种推挽形式将方波信号加到超声波换能器两端可以提高超声波的发射强度、增强驱动能力,输出端采用两个反向器并联,用以提高驱动能力。这样,两倍的反相器输出电压施加在传感器上。超声波传感器将输入的电信号转换为超声波信号传输出去,电容C可以除去直流分量,压电式超声波换能器是利用压电晶体的谐振来工作的。
3、超声波接收电路
图2-3 超声波接收电路
该接收电路如图2-3所示,集成电路CX20106A是一款红外线检波接收的专用芯片,其内部框图如图2-4所示:常用于电视机红外遥控接收器。考虑到红外遥控常用的载波频率38kHz与测距的超声波38kHz相等,可以利用它制作超声波检测接收电路,适当更改电容C4的大小可以改变接收电路的灵敏度和抗干扰能力。在上面的接收电路中,使用CX20106A集成电路对接收探头受到的信号进行放大、滤波。其总放大增益为80dB左右。
4、超声测距系统的总体结构图及测距原理
超声波测距的方法主要是测量超声在介质中的传播时间,常用的方法是回波探测法。如图1-1所示,这种方法主要是通过捕捉超声波脉冲的回波,根据超声波信号在空气中的传播时间并通过公式的计算来确定被测目标的距离。由超声波发射器向某一方向发射超声波,在发射超声波时刻的同时开始计时,超声波在空气中传播,当途中碰到障碍物就会立即返回,当超声波接收端的接收器接收到反射波便立即停止计时。超声波在空气中的传播速度为340m/s,根据计时器记录的时间t,就可以通过公式计算出发射点与障碍物之间的距离d,即:d=340*t/2
单位为m。这就是所谓的时间差测距法。
5、功能描述与性能指标
本系统是基于AT89S52单片机的超声测距系统,因为没有加入温度补偿所以只能在常温下测距才能比较准确。由于使用的超声波的频率为38kHz,而超声波的频率越高,传播距离越近,且使用的超声探头的发射信号的能量有限,正常的测距显示范围为6cm到5.00m左右。6、有待进一步优化的问题:
(1)定时器最小时间捕获问题:
由于发射和程序之的指令时间,使距离不可能无限近,本程序设计定时器最小的时间捕获的距离为6CM。
(2)算法问题:
由于计算距离的算法是假设在斜距与距离近似相等的基础上的,所以近距离测试有误差,而且越近误差会大。所以有待新的算法对其进行校正。
(3)测量距离问题:
采用的都是数字驱动有一个缺点,就是功率有点小。因为门电路的电流有限在一定程度上限制了发射功率,虽然可以并联、推挽等办法可以提高功率。但相对于模拟功放电路来说还很大还上升的空间。
程序附:
/****************************************
* 超声波测距 *
* CAUC *
* yaye *
****************************************/
/***************头文件******************/
#include<at89x52.h>
#include<stdio.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
sbit output=P1^0;
sbit led1=P1^7;
sbit led2=P1^6;
sbit BEEP=P3^1;
bit SentOver_flg,RecOver_flg,Disp_flg,Sentfb_flg,DispBuffer_flg,beep_flg,MeasureSuc_flg;
uchar High,Low;
uchar disp_cnt,count,count4ms,beep_cnt,cnt,i,j;
uchar P2_buffer;
uint time;
ulong sum;
uint space;
uchar disp_buffer[3];
uint value_buffer[4];
uchar code Tab1[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xbf};
uchar code Tab2[]={0xf7,0xfb,0xfd};//{0x7f,0xbf,0xdf,0xef,0xf7};
uchar code jq[4]={1,2,3,4};
void delay(void)
{
uchar a;
for(a=2;a>0;a--);
}
void Ready(void)
{
High=0;
Low=0;
RecOver_flg=0;
Disp_flg=1;
Sentfb_flg=1;
SentOver_flg=0;
beep_flg=0;
}
void FillDispBuffer(ulong wide)
{
wide=wide*17;
wide/=1000;
space=(uint)wide;
disp_buffer[0]=(uchar)(wide/100);
disp_buffer[1]=(uchar)(wide%100/10);
disp_buffer[2]=(uchar)(wide%10);
}
void SentPulse(void) //发射
{
uchar b;
for(b=0;b<4;b++)
{
output=!output; //两个方波
delay();
}
TR0=1; //定时器0开始计数
EX0=1; //允许外部中断
}
void DealSpace(void)
{
if((space<=50)&&(space>=6))
{
beep_flg=1;
beep_cnt=10;
}
if((space>50)&&(space<=150))
{
beep_flg=1;
beep_cnt=100;
}
if(space>150) beep_flg=0;
}
void main(void)
{
P0=0xff; //初始化
P2=0xff;
i=0;
j=0;
time=0;
High=0;
Low=0;
disp_cnt=0;
output=1;
count=0;
beep_cnt=0;
cnt=0;
TMOD=0x11;
TH0=0x00;
TL0=0x00;
TH1=(65535-1500)/256;
TL1=(65535-1500)%256;
EA=1;
ET1=1;
ET0=1;
EX0=0;
IT0=1; //下降沿触发中断
TR1=1;
Ready();
SentPulse();
while(1)
{
if(RecOver_flg==0)
{
if(Sentfb_flg) //45ms发射一次
{
Sentfb_flg=0;
SentPulse();
SentOver_flg=1; //发射完成标志位置1,表示发射完成
}
}
if(RecOver_flg) //接收是否完成
{
RecOver_flg=0;
time=High*256+Low;
value_buffer[j++]=time;
if(j==4)
{
j=0;
for(i=0;i<4;i++)
sum+=value_buffer[i]*jq[i];
sum/=10;
FillDispBuffer(sum);
DealSpace();
}
}
// DealSpace();
}
}
void INT0_service(void) interrupt 0 //外部中断0中断子程序
{
if(SentOver_flg) //发射完成后引起的中断才有效
{
EX0=0; //中断0关闭
TR0=0; //定时器0停止计数
High=TH0; //读取测量值
Low=TL0;
SentOver_flg=0; //发射完成标志位清0
RecOver_flg=1; //接收完成标志位置1
Disp_flg=0;
TH0=0x00; //定时器0赋初值
TL0=0x00;
}
else Ready();
}
void T0_service(void)interrupt 1 //定时器0中断子程序
{
TR0=0;
TH0=0x00;
TL0=0x00;
Ready(); //初始化
TR0=1;
}
void T1_service(void) interrupt 3 //定时器1中断子程序
{
TH1=(65535-4000)/256;
TL1=(65535-4000)%256;
P2_buffer=Tab2[disp_cnt]; //数码管位选
P2=P2_buffer;
if(Disp_flg) P0=Tab1[10];
else P0=Tab1[disp_buffer[disp_cnt]]; //数码管显示
if(beep_flg)
{
cnt++;
if(cnt>=beep_cnt)
{
cnt=0;
BEEP=!BEEP;
}
}
else BEEP=1;
disp_cnt++;
count++;
count4ms++;
if(count4ms==20)
{
count4ms=0;
Sentfb_flg=1; //45ms,发射控制位置1
}
if(disp_cnt==3) disp_cnt=0;
}