锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

实现超声波测距并语音播报

时间:2024-05-16 05:07:10

基于AT89S52的超声波测距实验
更多内容欢迎访问我的技术记录博客共同讨论学习
(地址:http://blog.sina.com.cn/aftermind)


超声波测距原理:单片机IO口接超声波模块TX引脚,由IO口产生40KHz频率方波发送给TX用以超声波模块发送超声波,同时打开单片机,超声波遇到障碍后返回,模块接收头接收到超声波后产生信号由电路滤波整形放大后在RX引脚输出高电平,RX接单片机的P3^2(51内核单片机的外部中断),在中断服务程序中停止,对所计数值进行处理得到超声波往返所用时间再乘以风速即得测量距离。由于超声波属于声波范围,其速度与温度有关,不同温度下超声波在空气中传播速度随温度变化关系:V=331.4+0.61T。所以要是测量结果更加精确需另加温度补偿模块(本实验中采用上的DS18B20完成温度补偿)。外围可添加显示(本实验采用开发板1602LCD)和语音播报模块(本实验采用4004语音模块)。


源程序
// *********************单片机实验室******************************/
// *文件名称 :csbspk.c
// *功能 : 实现超声波测距并语音播报 (测量范围:4~80cm)
// *引脚连接 : ISD4004 SS接P1.2 MOSI接P1.0 MISO接P1.1 SCLK接P1.3
// * 超声波模块 TX接P3.1 RX接P3.2 J7接上插冒
// *当前版本 :1.0
// *作者 : 刘松
// *完成日期 :2010.11.11
// ****************************************************************/
#include
#include
#include"lcd.h" // 液晶显示
#include"ds18b20.h" //温度
sbit P3_1=P3^1;
sbit key1=P2^1; //定义按键
sbit SS=P1^2; //以下四行定义ISD4004引脚
sbit MOSI=P1^0;
sbit MISO=P1^1;
sbit SCLK=P1^3;
uchar addr; //语音地址全局变量
uchar s; //语音所对应数字
int VD; //扩大十倍的声速
int D; //测量的距离
int temp; //超声波反射时间
void timer() //初始化计数器
{
TMOD=0x10;
TH1=0;
=0;
EA=1;
EX0=1;
}

void delay25us_40KHz(unsigned char us) //产生方波用于超声波发射
{

TR1=1;
while(us--)
{
P3_1= 0;
_nop_();_nop_();
_nop_();_nop_();
_nop_();_nop_();
_nop_();_nop_();
_nop_();_nop_();
_nop_();
P3_1= 1;
_nop_();_nop_();
_nop_();_nop_();
}
P3_1= 1;
}

rec() interrupt 0 //计算超声波反射时间
{
TR1=0;
EA=0;
temp=TH1*256+TL1;
}

void delayms(uchar ms) // 延时子程序用于语音播放上电等待
{
uchar j;
while(ms--)
{
for(j = 0; j < 120; j++);
}
}

void delay2(int m) //长延时用于语音播放
{
int l,j;
for(l=0;l<30001;l++)
for(j=0;j }

////////////////////////////液晶显示子函数//////////////////////////////////
void display()
{
float V;//声速
V=331.4+0.61*T; VD=V*10;
D=temp*V/2000-29;
displaystring(0,0,"Dis=");
displaychar(4,0,(D/100)+0x30);
displaychar(5,0,(D0/10)+0x30);
displaychar(6,0,'.');
displaychar(7,0,(D)+0x30);
displaystring(8,0,"cm");
displaystring(0,1,"T=");
displaychar(5,1,(TD)+0x30);
displaychar(4,1,'.');
displaychar(3,1,(TD0/10)+0x30);
displaychar(2,1,(TD/100)+0x30);
displaychar(6,1,0xdf);
displaychar(7,1,'C');
displaystring(9,1,"V=");
displaychar(11,1,(VD/1000)+0X30);
displaychar(12,1,(VD00/100)+0X30);
displaychar(13,1,(VD0/10)+0X30);
displaychar(14,1,'.');
displaychar(15,1,(VD)+0X30);
}
///////////////////////////////////////////////////////////////


////////////////放音部分子程序,放音地址由A决定////
void play(addr)
{
uchar y;
SS=0;
MOSI=0;//发送开始
SCLK=0;
for(y=0;y<8;y++)
{
SCLK=0;
if((0x20>>y)&0x01)MOSI=1; //上电命令
else MOSI=0;
_nop_();
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
_nop_();
}//发送结束
SS=1;//上电结束
delayms(50);
SS=0;
MOSI=0;//发送地址
SCLK=0;
for(y=0;y<16;y++)
{
SCLK=0;
if((addr>>y)&0x01)MOSI=1;
else MOSI=0;
_nop_();
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
_nop_();
}//发送地址结束
MOSI=0;//放音
SCLK=0;
for(y=0;y<8;y++)
{
SCLK=0;
if((0xe0>>y)&0x01)MOSI=1; //指定地址放音命令
else MOSI=0;
_nop_();
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
_nop_();
}
SS=1;
SS=0;
MOSI=0;
SCLK=0;
for(y=0;y<8;y++)
{
SCLK=0;
if((0xf0>>y)&0x01)MOSI=1; //忽略地址放音命令(连贯播放后续空间)
else MOSI=0;
_nop_();
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
_nop_();
}
SS=1;
}
///////////////////////////////////////////////////////////////

///////////////////读数字子函数///////////////////////////////
void speaknum()
{
if(s==1) play(0x01);
if(s==2) play(0x0a);
if(s==3) play(0x14);
if(s==4) play(0x1e);
if(s==5) play(0x28);
if(s==6) play(0x32);
if(s==7) play(0x3c);
if(s==8) play(0x46);
if(s==9) play(0x50);
if(s==0) play(0x6e);
}
////////////////////////////////////////////////////////////////

///////////////////读书显示结果子函数////////////////////////////
void read()
{
play(0xdc);
delay2(50000);
delay2(50000);
s=D/100;
if(s==1)
{
play(0x5a);
delay2(50000);
}
if(s>1)
{
speaknum();
delay2(50000);
play(0x5a);
delay2(50000);
}
s=D0/10;
if(s!=0)
{
speaknum();
delay2(50000);
}
play(0x64);
delay2(50000);
s=D;
speaknum();
delay2(50000);
play(0xbe);
delay2(50000);
play(0xf0);
delay2(50000);
delay2(50000);
s=TD/100;
if(s==1)
{
play(0x5a);
delay2(50000);
}
if(s>1)
{
speaknum();
delay2(50000);
play(0x5a);
delay2(50000);
}
if(s!=0)
{
s=TD0/10;
speaknum();
delay2(50000);
}
play(0x64);
delay2(50000);
s=TD;
speaknum();
delay2(50000);
play(0xC8);
delay2(50000);
delay2(50000);
play(0xe6);
delay2(50000);
delay2(50000);
s=VD/1000;
speaknum();
delay2(50000);
play(0xfa);
delay2(50000);
s=VD00/100;
speaknum();
delay2(50000);
play(0x5a);
delay2(50000);
s=VD0/10;
speaknum();
delay2(50000);
play(0x64);
delay2(50000);
s=VD;
speaknum();
delay2(50000);
play(0xd2);
}
////////////////////////////////////////////////////////////

void main()
{
initlcd() ; //初始化LCD1602
while(1)
{
timer();
readtemp(); //读温度
delay25us_40KHz(15);
display();
if(key1==0) read();
}
}
以下是温度传感器头文件ds18b20.h
sbit DQ=P2^2;
uchar tempdata[2];
uchar k=0;
int TD;
float T;
void delay1(uchar i)
{
while(i--);
}
void initDS18B20() //初始化DS18B20
{
DQ = 1; //DQ复位
delay1(8); //稍做延时
DQ = 0; //单片机将DQ拉低
delay1(80); //延时 大于 480us
DQ = 1; //拉高总线
delay1(30);
}
uchar readchar() //向DS18B20读取一字节
{
uchar i = 0 ;
uchar dat = 0 ;
for (i = 8 ; i > 0 ; i--)
{
DQ = 0 ;
dat >>= 1 ;
DQ = 1 ;
if(DQ)
dat |= 0x80 ;
delay1(4) ;
}
return (dat) ;
}
void writecmd(uchar cmd) //向DS18B20写入一字节
{
uchar i ;
for (i = 8 ; i > 0 ; i--)
{
DQ = 0 ;
DQ = cmd&0x01 ;
delay1(5) ;
DQ = 1 ;
cmd>>=1 ;
}
}

void readtemp()
{
initDS18B20() ;
writecmd(0xCC) ; // 跳过读序号列号的操作
writecmd(

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章