找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7133|回复: 10
打印 上一主题 下一主题
收起左侧

[讨论]超声波测距

[复制链接]
跳转到指定楼层
楼主
ID:15556 发表于 2009-12-9 21:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
请教有关超声波测距的问题,有经验的可以交流下
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:21971 发表于 2010-3-6 15:30 | 只看该作者

目前,现有的超声波发生器有40KHz,48KHz,58KHz等频率。根据声波在空气中(25摄氏度时)的速度340米每秒,来计算距离。其中一关键数据是超声波从发射到返回之间的时间(除以2),以此来计算时间;从而得到距离,之后再进行距离方面的提示工作,现有的倒车雷达便是如此。以上请知悉......

回复

使用道具 举报

板凳
ID:22031 发表于 2010-3-20 19:53 | 只看该作者
正在等程序,新手,谁搞过的共享一下程序啊- -
回复

使用道具 举报

地板
ID:26649 发表于 2010-11-2 20:32 | 只看该作者
我也等!!!!
回复

使用道具 举报

5#
ID:60076 发表于 2014-4-5 04:10 | 只看该作者
这个程序在分的很细,可以看超声部分或温湿检测部分程序。
程序如下:
#include <reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define Data  P1   //LCD1602的数据口
#define NOP() {_nop_();_nop_();_nop_();_nop_();} //用于延时

//LCD1602控制引脚定义
//sbit RS = P2^6;
//sbit RW = P2^5;
//sbit E = P2^7;
sbit RS = P2^0; //复位端
sbit RW = P2^1; //写数据端
sbit E = P2^2; //使能端
//温湿DHT11的数据引脚定义
sbit DHT=P2^3;
//这些数组用于数据的缓存
uchar wendu_char[]=" temperature";//12  用于提示的字符
uchar shidu_char[]="  humidity";//10   用于提示的字符
uchar  wendu[] ="wen:00.00 d";//11  数据格式,当读取的数据会保存到数组的相应的位上
uchar  shidu[]="shi:00.00 RH";//12  //同上一句
uchar table[]={" make ^!^ in  "};//14   //用于提示
uchar table1[]={" 2013-12-20 "};//12   //用于提示
//uchar qingxu1[]={"   ^!^    "};//11
//uchar qingxu2[]={"good weather"};//12
//uchar qingxu3[]={"   -_-!    "};//12
//uchar qingxu4[]={"bad weather!"};//12
unsigned char shiZ,shiX,wenZ,wenX,check;  //用于存读出传感器的数据,因为读出的是整型数据,之后用于转换成字符存于上面的数组中
unsigned char shiH,shiL,wenH,wenL;  //
unsigned char flag;  //定义一个标志位
unsigned int n=20,m;   //定义一些会在下面用到的全局变量
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void delay(uint a); //超声波模块和温湿模块的公用延时函数
void delay_10us() ;
void delay_1ms(unsigned int i) ;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//超声波部分的函数
/////////////////////////////////////////////////////
sbit Tx=P3^3;    //超声波模块发射脉冲的引脚定义
sbit Rx=P3^2;    //超声波模块接收回波的引脚定义
uchar code table2[]={"Distance Test:"}; //14   //用于提示
uchar temp_dis[]= {"000.0 cm"};// 8       //用于显示数据的缓冲数组
long int t;//读出的数据现存于这些变量,再转换成字符赋给上面的数组
double distance;
uchar cache[4]={0,0,0,0};  //用于装入分离的数据的各个位
//外部中断0用于计算超声波模块接收到回波的时间,用于计算距离
void init0() //外部中断0在接收到Rx脚的高电平触发定时器计时,当高电平回波结束时是下降沿
{//定时器0的初始化
TMOD=0x01;  
TH0=0;
TL0=0;

//外部中0的初始化
EX0=1; //外部中断的
IT0=1;      //设置为低电平触发,下降沿有效

//打开总中断
//EA=1;
}

//超声波模块初始化
void HC05_Init()
{ //依据模块的资料,把发射脚拉高大于10us,再把发射脚拉低,模块就会自动发送探测的脉冲
  EA=1;
  Tx=1;  
  NOP();NOP();NOP();NOP(); //用于延时,保持大于8us的要求
  Tx=0;  //发射脚拉低
  while(!Rx);  //当RX为零时等待
  TR0=1;       //开启计数
  while(Rx);   //当RX为1计数并等待
  TR0=0;    //关闭计数
  //TR0=1; //打开定时器0,以便从发送脉冲开始计时,到接收到外部中断0后关闭
  distance=0.17*t;  //计算距离的公式
// distance=(340*t)/2;
}

//数值转换
void distance_convert(long int dat)
{  
  //把得到的数据分离出个,十,百等位,装入数组中
//0.17*t知道测量的值有两个小数点,且该超声波模块可以测量到几百厘米,所以,得到的数据格式位000.00cm,
//我们要保留1为小数,又因为\,%的运算为整数,则先把数据乘以10,再求出各个对应的位放到对应的数组
  //dat=dat*10;
  cache[0]=dat/1000; //实际对应原数据的百位,因为把数据*10处理了,向高位移了一位
  cache[1]=dat/100;
  cache[2]=dat/10;
  cache[3]=dat; //
  //装入数组,加'0'是将整型的数据转换成字符数据
  temp_dis[0]=cache[0]+'0'; //数组的格式位uchar temp_dis[]= {"000.0 cm"};
  temp_dis[1]=cache[1]+'0';
  temp_dis[2]=cache[2]+'0';
  temp_dis[4]=cache[3]+'0';
}

//温度度部分的函数(DHT11)
////////////////////////////////////

//延时函数1ms
void delay_1ms(unsigned int i)
{
  unsigned int j=88;
  for(;i>0;i--)
  {
  while(j>0)j--;
  }
}
//延时函数10us
void delay_10us()
{
  unsigned char i;
  i--;
  i--;
  i--;
  i--;
  i--;
  i--;
}
//延时函数可调
void delay(uint a)
{
uint y;
for(;a>0;a--)
  for(y=100;y>0;y--);
}


//读取DHT11的数据,其为单总线通讯,只用一条线,已经定义为DHT,区别于I2C通讯
char read_data()
{
  unsigned char i,num,temp;
  num=0;
  for(i=0;i<8;i++)
  {
  flag=2;
  while((!DHT)&&flag++); //判断从机是否发出80us的低电平相应信号是否结束
  delay_10us();
  delay_10us();
  delay_10us();
   if(DHT==1)
   {
    temp=1;
    flag=2;
    while(DHT&&flag++);   
   } //超时则跳出
  else
   temp=0;
   num<<=1; //一位一位的读出存入变量num中
   num|=temp;
  }
  return(num); //读8个位的数据,为一个字节
}

//读取DHT11的40位数据函数//////////////////////////////////////////////////////////////////////////////
void read_init()
{
  DHT=0;   //主机拉低21ms
  delay_1ms(21);
  DHT=1;    //总线由上拉电阻拉高40us
  delay_10us();
  delay_10us();
  delay_10us();
  delay_10us();
  DHT=1; //主机设为输入 判断从机相应信号
  if(!DHT)  //判断从机是否把总线拉低
  {
   flag=2;
   while((!DHT)&&flag++); //等待从机把总线拉低
   flag=2;
   while(DHT&&flag++); //判断从机是否拉低总线,即响应
    //接收数据
   shiH=read_data();//因为read_data()只读出一个字节,而DHT读出的是连续的5个字节,所以不用for()
   shiL=read_data();
   wenH=read_data();
   wenL=read_data();
   check=read_data();
   DHT=1;
  }      
}

//DH11数据处理
void DHT11dada()
{
unsigned char temp;
read_init();
  temp=shiH+shiL+wenH+wenL; //检验也为8位的二进制,等于前面的数据之和
  if(check==temp)
  {  //检验数据对了就赋给另外几个变量来转换
    shiZ=shiH;
    shiX=shiL;
    wenZ=wenH;
    wenX=wenL;
  }
  wendu[4]='0'+wenZ/10; //分离出各个位,并转换成字符数据,依据上面的数组定义wendu[] ="wen:00.00 d";的数据格式,把对应的数据写到对应的位
  wendu[5]='0'+wenZ;  //分理出的是温度的个位,在数组中的第六个位置,所以写入该位更新,以便显示
  wendu[8]='0'+wenX/10;  //第七位为 .
  wendu[9]='0'+wenX;
  shidu[4]='0'+shiZ/10; //同理,湿度的格式为shidu[]="shi:00.00 RH";
  shidu[5]='0'+shiZ;
  shidu[8]='0'+shiX/10;
  shidu[9]='0'+shiX;
}


//LCD1602部分函数     各个函数依据LCD1602的时序编写
////////////////////////////////////////////////////////

//LCD1602写指令函数
void lcd_write_com(uchar c)   
{
  delay_1ms(5);
  E=0;
  RS=0;
  RW=0;
  _nop_();
  E=1;
  Data=c;
  E=0;
}

//LCD1602写数据函数
void lcd_write_dat(uchar c)  
{
  delay_1ms(5);
  E=0;
  RS=1;
  RW=0;
  _nop_();
  E=1;
  Data=c;
  E=0;
  RS=0;
}

//LCD1602初始化
void lcd_init()   
{
  delay_1ms(5);
  lcd_write_com(0x38);
  lcd_write_com(0x38);
  lcd_write_com(0x38);
  lcd_write_com(0x06);
  lcd_write_com(0x0c);
  lcd_write_com(0x01);
}
//LCD1602清屏函数
void qingping()
{
lcd_write_com(0x01);
delay(5);
}

//显示开始标题
void disp(void)    //显示子函数
{ uchar i,j;
lcd_write_com(0x80);//往第一行写入字符串,写完一个字符会自动调到第二个地址写入数据
  for(i=0;i<13;i++)
  {
   lcd_write_dat(table[ i]);
  }
lcd_write_com(0x80+40);//往第二行写入日期
for(j=0;j<11;j++)
  {
   lcd_write_dat( table1[j]);
  }
  delay(3000);//显示的时间长短
  qingping();//清屏
}

//显示温湿函数
void display_DHT11()
{ uchar h,n,e,m;
//uchar x,y;
lcd_write_com(0x80);
  for(e=0;e<12;e++)  //写入温度数据
   {
    lcd_write_dat(wendu_char[e]);
   }
  lcd_write_com(0x80+40);
  for(n=0;n<11;n++)  //写入温度数据
   {
    lcd_write_dat(wendu[n]);
   }
  delay(3000);
  qingping();//清屏
  lcd_write_com(0x80);
  for(h=0;h<10;h++) //写入湿度数据
   {
    lcd_write_dat(shidu_char[h]);
   }
  lcd_write_com(0x80+40);
  for(m=0;m<12;m++) //写入湿度数据
   {
    lcd_write_dat(shidu[m]);
   }
  delay(3000);
  qingping();

//  //情绪表达部分   //因为51内存写满了,只能舍去这部分
//  if(shiZ>=16&&shiZ<=28)
//  {
//   lcd_write_com(0x80);
//   for(y=0;y<11;y++)
//   {
//    lcd_write_dat(qingxu1[y]);
//   }
//  lcd_write_com(0x80+0x40);
//  for(x=0;x<12;x++)
//   {
//    lcd_write_dat(qingxu2[x]);
//   }
//   delay(3000);
//   qingping();
//  }
//  if(shiZ<=16&&shiZ>=28)
//  {
//   lcd_write_com(0x80);
//   for(y=0;y<12;y++)
//   {
//    lcd_write_dat(qingxu3[y]);
//   }
//  lcd_write_com(0x80+0x40);
//  for(x=0;x<12;x++)
//   {
//    lcd_write_dat(qingxu4[x]);
//   }
//   delay(3000);
//   qingping();
//  }
}

//显示超声波数据
void display_HC05()
{  
  uchar k,w;
  lcd_write_com(0x80);//超声波测距显示部分:K,W
  for(k=0;k<14;k++)
   {
    lcd_write_dat(table2[k]);
   }
  lcd_write_com(0x80+0x40);
  for(w=0;w<8;w++)
   {
    lcd_write_dat(temp_dis[w]);
   }
  delay(3000);
  qingping();
}
////不写在一起是为了及时将数据输出,因为读完传感器才输出,有的传感器的数据已经变化了
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//主函数
void main()
{  uchar x,s;
  lcd_init();
  init0();
  Tx=0;//超声波发送口初始化,
  while(1)
  {
  disp();//显示开始的字符
  for(x=0;x<2;x++)
  {
   DHT11dada();//温湿的数据
  }
  display_DHT11();//显示温湿的数据
  for(s=0;s<2;s++)
  {
   HC05_Init(); //需要放到while(1)中 因为要不断触发超声波模块的脉冲得出距离
   distance_convert(distance);
  }
  display_HC05();
}
}


//外部中断0的中断函数,记回波的时间,即发送测量脉冲开始计时,到接收到回波时产生外部中断,把得到的时间赋给t
void int0() interrupt 0
{  EA=0;
  t=(TH0*256+TL0);  //读取定时器的时间
  TH0=0; //清空定时器
  TL0=0;
}
回复

使用道具 举报

6#
ID:61326 发表于 2014-5-2 19:50 | 只看该作者
谢谢分享
回复

使用道具 举报

7#
ID:56795 发表于 2014-5-3 17:02 来自手机 | 只看该作者
几块钱的超声波测距模决是不是测距不稳定,我做的测同一距离会测出不同的数据。误差有几个毫米
回复

使用道具 举报

8#
ID:56795 发表于 2014-5-3 17:04 来自手机 | 只看该作者
我不知道是程序有问题或是超声波模块有问题
回复

使用道具 举报

9#
ID:28571 发表于 2015-4-18 14:12 | 只看该作者
好东西,学习一下,谢谢!
回复

使用道具 举报

10#
ID:128255 发表于 2016-6-30 15:36 | 只看该作者
卖的模块,普遍测量角度都在15度以内,分离模块能达到多大的角度?
回复

使用道具 举报

11#
ID:223039 发表于 2017-8-3 18:35 | 只看该作者
学习一下,楼主分享的很好!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表