51单片机课程设计 超声波测距仪文档格式.docx
《51单片机课程设计 超声波测距仪文档格式.docx》由会员分享,可在线阅读,更多相关《51单片机课程设计 超声波测距仪文档格式.docx(20页珍藏版)》请在冰点文库上搜索。
![51单片机课程设计 超声波测距仪文档格式.docx](https://file1.bingdoc.com/fileroot1/2023-5/7/21e77fb6-e189-4073-8df6-e6a9abac0007/21e77fb6-e189-4073-8df6-e6a9abac00071.gif)
20
30
40
50
60
100
声速(m/s)
313
319
325
332
338
344
350
356
361
367
388
二、设计框图
超声波测距仪系统结构如下图所示。
它主要由单片机、超声波发射及接收电路、超声波传感器、温度传感器、键盘、LED显示电路及电源电路组成。
系统主要功能包括:
1.超声波的发射、接收,并根据计时时间计算测量距离;
2.检测空气温度用于距离计算的补偿;
3.LED显示器显示距离、温度;
4.键盘接收用户命令并处理;
5.当系统运行不正常时,用电平式开关与上电复位电路复位。
三、方案设计
测量距离方法有很多种,短距离可以用尺,远距离有激光测距等,超声波测距适用于高精度中长距离测量。
因为超声波在标准空气中传播速度为331.45米/秒,由单片机负责计时,单片机使用12.0M晶振,所以此系统测量精度理论上可以达到毫米级。
目前比较普遍的测距的原理:
通过发射具有特征频率的超声波对被摄目标的探测,通过发射出特征频率的超声波和反射回接受到特征频率的超声波所用的时间,换算出距离,如超声波液位物位传感器,超声波探头,适合需要非接触测量场合,超声波测厚,超声波汽车测距告警装置等。
由于超声波指向性强,能量消耗缓慢,在介质中传播距离远,因而超声波可以用于距离测量。
利用超声波检测距离,设计比较方便,计算处理也较简单,并且在测量精度方面也能达到要求。
由于超声波易于定向发射、方向性好、强度易控制、与被测量物体不需要直接接触的优点,是作为液体高度测量的理想手段。
在精密的液位测量中需要达到毫米级的测量精度,但是目前国内的超声波测距专用集成电路都是只有厘米级的测量精度。
通过分析超声波测距误差产生的原因,提高测量时间差到微秒级,以及用温度传感器进行声波传播速度的补偿后,我们设计的高精度超声波测距仪能达到毫米级的测量精度。
目前超声波测距已得到广泛应用,国内一般使用专用集成电路根据超声波测距原理设计各种测距仪器,但是专用集成电路的成本较高、功能单一。
而以单片机为核心的测距仪器可以实现预置、多端口检测、显示、报警等多种功能,并且成本低、精度高、操作简单、工作稳定、可靠。
以8051为内核的单片机系列,其硬件结构具有功能部件齐全、功能强等特点。
尤其值得一提的是,出8位CPU外,还具备一个很强的位处理器,它实际上是一个完整的位微计算机,即包含完整的位CPU,位RAM、ROM(EPROM),位寻址寄存器、I/O口和指令集。
所以,8051是双CPU的单片机。
位处理在开关决策、逻辑电路仿真、过程测控等方面极为有效;
而8位处理则在数据采集和处理等方面具有明显长处。
根据设计要求并综合各方面因素,可以采用AT89C51单片机作为主控制器,它控制发射触发脉冲的开始时间及脉宽,响应回波时刻并测量、计数发射至往返的时间差。
利用软件产生超声波信号,通过输出引脚输入至驱动器,经驱动器驱动后推动探头产生超声波;
超声波信号的接收采用锁相环LM567对放大后的信号进行频率监视和控制。
一旦探头接到回波,若接收到的信号频率等于振荡器的固有频率(此频率主要由RC值决定),则其输出引脚的电平将从“1”变为“0”(此时锁相环已进入锁定状态),这种电平变化可以作为单片机对接收探头的接收情况进行实时监控。
可对测得数据优化处理,并采用温度补偿,使测量误差降到更低限度;
AT89C51还控制显示电路,用动态扫描法实现LED数字显示。
四、程序流程图及分析
系统上电后,首先系统初始化,不断扫描按键k1,若按键k1按下,则开始测量空气温度,然后将P1.0置位,使定时器T0开始定时,控制超声波传感器发出超声波,同时使定时器T1开始定时。
CPU循环检测P3.3引脚,当P3.3为低电平时接收到回波,立即使T1停止工作,保存定时器的计数值。
然后根据温度和传输时间计算距离,温度补偿措施使测量精度有了明显提高,计算出距离后调用距离显示子程序,LED显示距离。
最后检测按键k2,若k2闭合,则调用温度显示子程序,LED显示温度(温度并非测量距离时用于补偿的温度,而是当前温度)5s后恢复显示本次测量距离;
若按键k2没有闭合,则显示器恒定显示最新一次的测量结果;
若要进行下一次测量,则先要按下k3重新开始,再按下按键k1才执行新一次测量。
由于不需输入数据,键盘只设置了3个按键,用于开始测量距离并显示温度功能设置等。
五、系统仿真
六、制作和调试
虽说在仿真时温度传感器DS18B20是可视调节,且全为整数,但LED显示时当温度达到一定范围便会出现小数误差。
例如当DS18B20显示是28℃时,而LED显示是28.4℃;
而当DS18B20显示是25℃时,而LED显示仍是25℃;
而仿真表明随着温度的升高其误差大小也并不一致,且全都控制在1℃以内。
说明这并不是固有误差,很难避免,可以忽略,其对距离测量的影响也微乎其微,并不会使距离测量精度明显降低。
根据超声波的特性,距离测量时必须满足条件:
①被测目标必须垂直于超声波测距仪。
②被测目标表面必须平坦。
③测量时在超声波测距仪周围没有其他可反射超声波的物体。
因此在测量过程中稍不小心就会接收不到超声波,而导致没有测量结果。
由于超声波的往返时间由单片机AT89C51的定时器T1来记,定时器T1工作在方式1,其最大定时时间为65.536ms,可得出在常温下最大的测量距离在10m以内。
且因为发射功率有限,测距仪也无法测量10m外的物体。
我们知道C语言程序有利于实现较复杂的算法,汇编语言程序则具有较高的效率且容易精细计算程序运行的时间,而超声波测距仪的程序既有较复杂的计算(计算距离时),又要求精细计算程序运行时间(超声波测距时),所以控制程序可采用C语言和汇编语言混合编程。
因为本设计对时间要求精度较高的部分全部由单片机内部的定时器完成,而虽然温度传感器的读写对时间精度要求也高,但经详细计算所得出的C程序已被广泛应用,故直接借用已有程序也能作到对温度的准确读取,所心本设计全部使用C语言编程,这样能使设计中所用到的公式能方便快捷的体现和实现,又缩短了论文的篇幅。
软件采用模块化设计方法,由主程序、超声波发生子程序、超声波接收中断子程序、温度测量子程序、距离计算子程序、显示子程序、键盘扫描处理程序等模块组成。
七、心得体会
利用51系列单片机设计的测距仪便于操作、读数直观。
经实际测试证明,该类测距仪工作稳定,能满足一般近距离测距的要求,且成本较低、有良好的性价比。
由于该系统中锁相环锁定需要一定时间,测得的距离有误差,在汽车雷达应用中可忽略不计;
但在精度要求较高的工业领域如机器人自动测距等方面,此误差不能忽略,可以通过改变一些硬件的应用实现对超声波的快速锁定或根据自己的需要在程序中加入测距软件补偿的代码,使误差进一步减小,可以满足更高要求。
本设计完整地做出之后可测量十米以内的距离。
因为超声波的特性,测距时保证传感器与被测物间,以及测量轴线上没有障碍物;
且要尽量保证传感器轴线与被测物表面垂直;
实际测距范围与被测物表面材料等因素有关,一般不要测量表面为毛料的物体表面。
八、源程序
#include<
reg51.h>
stdio.h>
math.h>
intrins.h>
#defineunintunsignedint
#defineucharunsignedchar
#defineLEDP1//际温度值输出端口定义
#defineNOP_nop_()
sbittem_in=P1^1;
sbitk1=P3^7;
sbitk2=P3^6;
sbitk3=P3^5;
sbitsend=P1^0;
sbitrecieve=P3^2;
uchartemp_h,temp_l;
//温度值变量
floattemnum;
//当前温度值
floatt;
//超声波往返所占用的时间
bitsetb;
bitb;
//测距成功标志位,当b=1时标志测距成功
ucharflag1;
//正负标志位
ucharcodeledcode[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
//数码显示数据:
0,1,2,3,4,5,6,7,8,9,-,消隐
uchardispbuf[4]={0,0,0,0},tembuf[4]={0,0,0,0};
///////////////////////////////////////////////////////////////
voiddelay(unsignedintcount)
{
uninti;
while(count)
{
i=38;
while(i>
0)i--;
count--;
}
}
voiddelay10ms(unsignedintn)
unsignedintj,k;
while(n--!
=0)
for(j=0;
j<
10;
j++)
for(k=0;
k<
72;
k++)
;
}
voiddelay_us(ucharn)
uchari;
i=0;
while(i<
n)
{i++;
return;
voiddsreset(void)//DS18B20重设
unsignedinti;
tem_in=0;
i=103;
while(i>
tem_in=1;
i=4;
ucharreadbyte(void)//直接读一字节程序
uchari,k;
i=8;
k=0;
while(i--)
{
tem_in=1;
delay_us
(1);
tem_in=0;
k=k>
>
1;
NOP;
if(tem_in)k|=0x80;
//tem_in为1时,则该位也为1
delay_us(4);
return(k);
voidtmpwrite(unsignedchardat)//函数功能:
向B20写一字节
{unsignedinti;
unsignedcharj;
bittestb;
for(j=1;
=8;
{testb=dat&
0x01;
dat=dat>
if(testb)
{tem_in=0;
i++;
tem_in=1;
i=8;
while(i>
}
else
{
tem_in=0;
//////////////////////////////////////////////////////////////
voidtmpchange(void)
dsreset();
//复位
delay
(1);
tmpwrite(0xcc);
//跳过序列号命令
tmpwrite(0x44);
//转换命令
////////////////////////////////////////////////////////////
voidtmp(void)//温度采集及转换
{
intm,n=0;
floattemnum1=0;
tmpwrite(0xbe);
temp_l=readbyte();
//低位在前
temp_h=readbyte();
//高位在后
flag1=temp_h&
0xf8;
if(flag1)
{n=flag1;
temp_h=~temp_h;
if(temp_l==0)temp_h++;
//若低8位全为0且温度为负,取补时就要向高位进1
temp_l=~temp_l+1;
temnum1=(temp_h*256+temp_l)/16;
if(temnum1<
10)
{tembuf[3]=11;
tembuf[2]=11;
tembuf[1]=(uchar)temnum1;
tembuf[0]=(uchar)(temnum1*10)%10;
if(temnum1>
=100)
tembuf[3]=(uchar)temnum1/100;
m=(int)temnum1%100;
tembuf[2]=(uchar)m/10;
tembuf[1]=(uchar)m%10;
tembuf[0]=(uchar)(temnum1*10)%10;
100&
&
temnum1>
=10)
tembuf[2]=(uchar)temnum1/10;
tembuf[1]=(uchar)temnum1%10;
if(n==0xf8)tembuf[3]=10;
temnum=temnum1;
//////////////////////////////////////////////////////////
voiddis(void)//温度显示
uchari;
ucharj=0xfe;
for(i=0;
i<
4;
i++)//输送显示数据
{
P0=0xff;
P0=ledcode[tembuf[i]];
if(i==1)P0=ledcode[tembuf[i]]+0x80;
//小数点显示
P2=j;
delay(15);
j=(j<
<
1)+0x01;
///////////////////////////////////////////////////////
voiddistance(void)//计算测量得到的距离
doubleradical,dist;
if(b!
radical=sqrt(1+(temnum+273)/273);
dist=165.7*t*radical;
dist=dist+0.005;
//四舍五入并留两位小数
if(dist>
0&
dist<
{dispbuf[3]=11;
dispbuf[2]=(uchar)dist;
dispbuf[1]=(uchar)(dist*10)%10;
dispbuf[0]=(uchar)(dist*100)%10;
=10&
=0)//测量距离大于10米或小于0显示"
----"
也有出错的意思
dispbuf[3]=10;
dispbuf[2]=10;
dispbuf[1]=10;
dispbuf[0]=10;
if(dist<
dist>
{dispbuf[3]=(uchar)dist/10;
dispbuf[2]=(uchar)dist%10;
else
{//当T1溢出时,则测量时间无效
}
voiddis1(void)//距离显示
0;
i++)/*输送显示数据*/
P0=ledcode[dispbuf[i]];
if(i==2)P0=ledcode[dispbuf[i]]+0x80;
delay10ms
(1);
voiddis2(void)
dispbuf[3]=11;
dispbuf[2]=11;
dispbuf[1]=11;
dispbuf[0]=0;
voidtimer1(void)interrupt3
TR1=0;
TH1=0x00;
TL1=0x00;
voidtimer0(void)interrupt1
send=!
send;
TH0=0x1f;
TL0=0xf4;
voidint1(void)interrupt2
if(TH1!
=0x00&
TH0!
=0x00)
b=1;
TR0=0;
t=TH1*256+TL1;
t=t/1000000;
b=0;
main()
EA=1;
//开中断
TMOD=0x10;
//设定时器0、定时器1都工作在定时状态,T0方式0,T1方式1
ET0=1;
//定时器0中断允许
ET1=1;
//定时器1中断允许
IT1=0;
//外部中断1低电平有效
send=1;
receive=1;
k1=1;
k2=1;
////////////////////////////////////////////////////////////////
while
(1)
dis2();
if(k1!
=1)//判断k1是否按下,按下则开始执行温度转换和测距操作
delay(100);
//消抖
=1)
tmpchange();
//启动温度转换
tmp();
EX1=1;
//外部中断1中断允许
TR0=1;
//T0定时开始
TR1=1;
//T1定时开始
delay10ms(7);
distance();
EX1=0;
dis1();
if(k2!
=1)
for(i=0;
200;
i++)