网站颜色:

超声波测距传感器超声波接收模块

  • 品牌:Embedream

    (如需要购买配套的发射、控制模块,请用购物车

     发射模块:http://picimg.witdes.cn/pic/nantong.witdes.cn/shop/c109/t5eddc9d6b1.html

     控制模块:http://picimg.witdes.cn/pic/nantong.witdes.cn/shop/c109/t5eddc956d1.html)

    此处的介绍为本产品的主要细节,至于如何使用?精度如何?等详细介绍请下载如下资料,所有问题都能找到解答:

    http://picimg.witdes.cn/pic/embedream.com/doc/qsmx-USSensor(Hardware).pdf

    http://picimg.witdes.cn/pic/embedream.com/doc/qsmx-USSensor(Software).pdf

    http://picimg.witdes.cn/pic/www.embedream.com/qsmx/2009-01-08/72.html

    http://picimg.witdes.cn/pic/www.embedream.com/qsmx/2009-04-21/78.html

    http://picimg.witdes.cn/pic/embedream.com/doc/qsmx-USSEN-3.pdf

    这是第三代超声波测距传感器的接收部分,其主要特点是使用专用的超声波信号检出电路TL852,这块芯片的最大优势是方便的变增益控制,同时有选频电路,使得回波检测可靠。

    变增益对于超声波的回波检测尤为重要,如果是恒定增益,就很难在灵敏度和可靠性之间取舍,为了测量远距离,必须增加灵敏度,但这样会被近距离的干扰信号所破坏。如果能根据发射后的时间逐步提升增益将会使回波检出不至于误判。

    接收模块由 5V 供电,需要 5 根控制线,一根信号输出线(一共 8线):

    增益控制线4根(GCA、GCB、GCC、GCD):由这 4根线控制TL852,实现 11 级增益,可以直接由MCU的I/O口控制。因为 TL852是 5V 供电,如果所用的 MCU是3.3V的,建议使用开漏输出,TL852内部有上拉电阻。

    输出信号复位线(SOU):TL852 支持一个特殊的功能,即将其输出电容放电,实现继续测量,此功能十分有意义,可以和软件配合实现一次发射,得到多个不同距离的回波。此控制线可以直接用 MCU的I/O口控制,但必须设置为开漏模式。也可以用 NPN 三极管控制。

    (注:已经修改 PCB,包含实现OC门的三极管,使得用 Arduino及其它一些不支持 OC 输出的 MCU 控制更加方便。)

    信号输出线(Sig):此信号为运放的比较器输出信号,有效信号为低电平,高电平为3.3V。可以直接输入 MCU的外部中断口。

    用Arduino UNO 控制:

    因Arduino不支持 OC输出,所以接收模块控制需做如下处理:

    用 Arduino 控制1个发射模块、2个接收模块的示例程序:(可以得到更准确、稳定的测量结果,采用定时器计时,中断方式采集;而不是 pulseIn 函数的软件循环查询计时。可以支持2个接收,实现障碍定位。也可以用对射方式实现灵活多样的测距应用)

/*****************************************************************
      Ultrasonic Sensor 1 Send 2 Rcv Demo
      超声波一发二收 Arduino 驱动示例程序
            20140328 by Embedream
*****************************************************************/
#include <TimerOne.h>

// 系统时间
unsigned long g_ulRunTime;

// 数字输出
int LED = 13;         // Pin No, for LED

//工作指示
boolean  g_bLED_On;        // LED 状态   
int      g_iDisplayTimeCnt;// LED 闪烁时间,对 1ms 计数
#define  DISPLAY_TIME  1000 // 1000ms 闪烁一次 


int ULTRASONIC_IN1 = 0;   // 超声波输入引脚 1, INT0, PIN2
int ULTRASONIC_IN2 = 1;   // 超声波输入引脚 2, INT1, PIN3

int GAIN_CTLA = 8;        // TL852增益控制输出, 5V 电平!!!
int GAIN_CTLB = 7;
int GAIN_CTLC = 6;
int GAIN_CTLD = 5;

int TL852_INHIBIT1 = 9;         //输出电容放电控制,需要接三极管,实现OC控制!!
int TL852_INHIBIT2 = 10;

unsigned int  ga_uiGainTime[11] = {2380,2740,2750,2740,2740,2740,2750,2740,5490,5480,5490};
unsigned int  ga_uiTimeCnt[16] = {0,2380,5120,7870,10610,13350,16090,18840,21580,27070,32550,38040,43530,49020,54510,60000};
unsigned char gi_ucGainNo;
boolean g_bRcvFinish;

#define TIME_OUT 15

unsigned int g_uiMeaResult1;
unsigned int g_uiMeaResult2;

#define INHIBIT_TIME 880            // 最短允许距离 30cm 对应的时间

// for Send
// StartKey
int START_KEY = 4;

int ULTRASONIC_OUTPUT = 11;  // 超声波输出引脚
int CUT_OFF = 12;            // 余波抑制输出引脚,输出电压必须和发射器供电电压一致,否则需要用OC输出!

int g_iSendStat;

/*********************************************************************************
 **  setup()
 **  Initialize the Arduino and setup serial communication.
 **  Input:  None
 **  Output: None
 *********************************************************************************/
 void setup()

  // Initialize Serial Port With The Default Baud Rate
  pinMode(GAIN_CTLA,OUTPUT);
  pinMode(GAIN_CTLB,OUTPUT);
  pinMode(GAIN_CTLC,OUTPUT);
  pinMode(GAIN_CTLD,OUTPUT);
 
  pinMode(TL852_INHIBIT1,OUTPUT);
  pinMode(TL852_INHIBIT2,OUTPUT);
 
  digitalWrite(TL852_INHIBIT1,HIGH);
  digitalWrite(TL852_INHIBIT2,HIGH);
   
  attachInterrupt(ULTRASONIC_IN1, rcv1isr, FALLING);
  attachInterrupt(ULTRASONIC_IN2, rcv2isr, FALLING);
 
  // ----- for send ----------
  pinMode(ULTRASONIC_OUTPUT,OUTPUT);
  digitalWrite(ULTRASONIC_OUTPUT,LOW);     // Must set to LOW!!!!!!!!!!!!!
  pinMode(CUT_OFF,OUTPUT);
  digitalWrite(CUT_OFF,HIGH);              // Must set to HIGH!!!!!!!!!!!!!
  g_iSendStat = 0;

  pinMode(START_KEY,INPUT);
  digitalWrite(START_KEY,HIGH);           // Input_Up
   
  //--------------------------------   
  Serial.begin(115200);            
  Serial.flush();

  g_ulRunTime = millis();

  // init Display
  pinMode(LED,OUTPUT);
  g_bLED_On = true;
  digitalWrite(LED,g_bLED_On);
  g_iDisplayTimeCnt = DISPLAY_TIME; 

  delay(2000);          // (咨询特价)
   
  Serial.println("I'm Ready");
}

/*********************************************************************************
 **  loop()
 **  The main loop.  This loop runs continuously on the Arduino.  It
 **  Input:  None
 **  Output: None
 *********************************************************************************/
void loop()
{  
  int iTemp1;
   
  // LED Display ,
  iTemp1 = deltaTime();                          
  if(iTemp1 != 0)                                      // 时基处理
  {
    g_iDisplayTimeCnt -= iTemp1;                       // LED 指示处理
    if(g_iDisplayTimeCnt <= 0)
    {
      g_iDisplayTimeCnt = DISPLAY_TIME;
      g_bLED_On = !g_bLED_On;
      digitalWrite(LED,g_bLED_On);
    }
  }

  if((digitalRead(START_KEY) == 0)&&(g_iSendStat ==0))
  {
    Serial.println("already Send");
    digitalWrite(LED,HIGH);
    sendUltrasonic(10);
    g_iSendStat = 1;

    // ---- Start Rcv Proc ----------
    startRcvWork();
//    Serial.println("In Checking Ultrasonic!");
   
    while(g_bRcvFinish == false)
    {
      if(g_uiMeaResult1 != 0)
      {
        if(g_uiMeaResult1 < INHIBIT_TIME)
        {
          g_uiMeaResult1 = 0;
          digitalWrite(TL852_INHIBIT1,LOW);
        }
      }
     
      if(g_uiMeaResult2 != 0)
      {
        if(g_uiMeaResult2 < INHIBIT_TIME)
        {
          g_uiMeaResult2 = 0;
          digitalWrite(TL852_INHIBIT2,LOW);
        }
      }
     
      if((g_uiMeaResult1 !=0)&&(g_uiMeaResult2 !=0))
      {
        Timer1.stop();
        Timer1.detachInterrupt();
       
        gi_ucGainNo = 0;
        setGain(gi_ucGainNo);
        digitalWrite(TL852_INHIBIT1,HIGH);
        digitalWrite(TL852_INHIBIT2,HIGH);
        g_bRcvFinish = true;      
      }
    }
    Serial.print("RCV 1 Distance:");
    if(g_uiMeaResult1 != 65535)
    {
      Serial.println(g_uiMeaResult1*0.17);
    }
    else
    {
      Serial.println("None");
    }
    Serial.print("RCV 2 Distance:");
    if(g_uiMeaResult2 != 65535)
    {
      Serial.println(g_uiMeaResult2*0.17);
    }
    else
    {
      Serial.println("None");
    }
   
    delay(500);
  }

  if(g_iSendStat == 1)
  {
    if(digitalRead(START_KEY) == 1)
    {
      g_iSendStat = 0;
      delay(1000);
    }
  }   
}

// 系统时间采集,返回两次采集经过的时间
int deltaTime(void)
{
  unsigned long ulCurrent;
  int delta;
 
  ulCurrent = millis();
  delta = int(ulCurrent - g_ulRunTime);
  g_ulRunTime = ulCurrent;
 
  return(delta);
}

//启动超声波接收检测
void startRcvWork(void)
{
  gi_ucGainNo = 0;
  g_bRcvFinish = false;
  g_uiMeaResult1 = 0;
  g_uiMeaResult2 = 0;
   
  Timer1.initialize(ga_uiGainTime[gi_ucGainNo]);
  setGain(gi_ucGainNo);
  Timer1.attachInterrupt( timerIsr ); // attach the service routine here

  digitalWrite(TL852_INHIBIT1,LOW);
  digitalWrite(TL852_INHIBIT2,LOW);
 
}

// setting TL852 GAIN
void setGain(unsigned char ucGainNo)
{
  switch (ucGainNo)
  {
    case 0:
    {
      digitalWrite(GAIN_CTLA,LOW);
      digitalWrite(GAIN_CTLB,LOW);
      digitalWrite(GAIN_CTLC,LOW);
      digitalWrite(GAIN_CTLD,LOW);
      break;
    } 
    case 1:
    {
      digitalWrite(GAIN_CTLA,HIGH);
      digitalWrite(GAIN_CTLB,LOW);
      digitalWrite(GAIN_CTLC,LOW);
      digitalWrite(GAIN_CTLD,LOW);
      break;
    } 
    case 2:
    {
      digitalWrite(GAIN_CTLA,LOW);
      digitalWrite(GAIN_CTLB,HIGH);
      digitalWrite(GAIN_CTLC,LOW);
      digitalWrite(GAIN_CTLD,LOW);
      break;
    } 
    case 3:
    {
      digitalWrite(GAIN_CTLA,HIGH);
      digitalWrite(GAIN_CTLB,HIGH);
      digitalWrite(GAIN_CTLC,LOW);
      digitalWrite(GAIN_CTLD,LOW);
      break;
    } 
    case 4:
    {
      digitalWrite(GAIN_CTLA,LOW);
      digitalWrite(GAIN_CTLB,LOW);
      digitalWrite(GAIN_CTLC,HIGH);
      digitalWrite(GAIN_CTLD,LOW);
      break;
    } 
    case 5:
    {
      digitalWrite(GAIN_CTLA,HIGH);
      digitalWrite(GAIN_CTLB,LOW);
      digitalWrite(GAIN_CTLC,HIGH);
      digitalWrite(GAIN_CTLD,LOW);
      break;
    } 
    case 6:
    {
      digitalWrite(GAIN_CTLA,LOW);
      digitalWrite(GAIN_CTLB,HIGH);
      digitalWrite(GAIN_CTLC,HIGH);
      digitalWrite(GAIN_CTLD,LOW);
      break;
    } 
    case 7:
    {
      digitalWrite(GAIN_CTLA,HIGH);
      digitalWrite(GAIN_CTLB,HIGH);
      digitalWrite(GAIN_CTLC,HIGH);
      digitalWrite(GAIN_CTLD,LOW);
      break;
    } 
    case 8:
    {
      digitalWrite(GAIN_CTLA,LOW);
      digitalWrite(GAIN_CTLB,LOW);
      digitalWrite(GAIN_CTLC,LOW);
      digitalWrite(GAIN_CTLD,HIGH);
      break;
    } 
    case 9:
    {
      digitalWrite(GAIN_CTLA,HIGH);
      digitalWrite(GAIN_CTLB,LOW);
      digitalWrite(GAIN_CTLC,LOW);
      digitalWrite(GAIN_CTLD,HIGH);
      break;
    } 
    case 10:
    {
      digitalWrite(GAIN_CTLA,LOW);
      digitalWrite(GAIN_CTLB,HIGH);
      digitalWrite(GAIN_CTLC,LOW);
      digitalWrite(GAIN_CTLD,HIGH);
      break;
    } 
   
    default:
    {
      digitalWrite(GAIN_CTLA,HIGH);
      digitalWrite(GAIN_CTLB,HIGH);
      digitalWrite(GAIN_CTLC,LOW);
      digitalWrite(GAIN_CTLD,HIGH);
      break;
    } 
  }
}
void sendUltrasonic(unsigned char ucPulsNum)
{
  int i;
  digitalWrite(CUT_OFF,HIGH);  
  for(i = 0; i<ucPulsNum; i++)
  {
    digitalWrite(ULTRASONIC_OUTPUT,HIGH);
    delayMicroseconds(8);                     // 实测值,需要用示波器标定!
    digitalWrite(ULTRASONIC_OUTPUT,LOW);
    delayMicroseconds(9);                     // 实测值,需要用示波器标定!
  }
 
  digitalWrite(ULTRASONIC_OUTPUT,LOW);        // For safe
 
  delayMicroseconds(20);
  digitalWrite(CUT_OFF,LOW);                  // 短路变压器初级,消耗变压器中所储存的能量
}

//  ISR Timer Routine
void timerIsr()
{
  gi_ucGainNo++;
  if(gi_ucGainNo < 11)
  {
    Timer1.setPeriod(ga_uiGainTime[gi_ucGainNo]);
    setGain(gi_ucGainNo);
  }
  else
  {
    if(gi_ucGainNo < TIME_OUT)
    {
      setGain(11);
    }
    else
    {
      // TIME_OUT
      Timer1.stop();
      Timer1.detachInterrupt();
     
      gi_ucGainNo = 0;
      setGain(gi_ucGainNo);

      if(g_uiMeaResult1 == 0)
      {
        g_uiMeaResult1 = 65535;
      }
      if(g_uiMeaResult2 == 0)
      {
        g_uiMeaResult2 = 65535;
      }
    }
  }
}

// 超声波接收 1 中断服务
void rcv1isr(void)
{
  g_uiMeaResult1 = word(Timer1.read()) + ga_uiTimeCnt[gi_ucGainNo];
  digitalWrite(TL852_INHIBIT1,HIGH);
}

// 超声波接收 1 中断服务
void rcv2isr(void)
{
  g_uiMeaResult2 = word(Timer1.read()) + ga_uiTimeCnt[gi_ucGainNo];
  digitalWrite(TL852_INHIBIT2,HIGH);
}

 

    你可能会问:单独买个接收模块有什么用?

    如果你想学习超声波测距,如果你的课程中涉及到传感器,那么随便找一个你熟悉的单片机学习板,甚至是实验室中的试验箱,只要有I/O口,即可编程控制这个模块,以体验超声波测距之原理,这比买现成的传感器更易理解,因为你可以掌控。也比自己做硬件来得快捷,因为这部分硬件设计没有什么新东西,没有必要耗费这个精力。即使你有创新的想法,也应该是在消化了最基本的电路之后。

    至于性能,因为这是侧重学习的,所用参数及程序均为示范性质,目前距离不用调试可达 5M,如需要再远,用户可以自己优化参数,电路设计上应该可以支持更远,因为使用了变压器升压驱动发射,发射功率足够,通过提高接收灵敏度即可。

    第二代超声波测距传感器(详见“蝙蝠的启示”一文)问世一年来,收到大量的客户反馈,在肯定其性能之余,也有些许遗憾,主要意见是“其结构限制了其用途”,客户有许多需求与“瞄准”无关,给使用带来了困扰。

    为此,在第二代基础上,结合客户所提出的建议,设计了第三代超声波测距传感器。

    关于温度补偿,硬件上设计了18B20,软件上也已将温度值读出,存放在内存中,用户如需要可方便的实现温度补偿!只需焊上18B20及相关件(一个4.7k电阻、一个104电容),在程序中计算距离算法上增加温度修正即可。

    第三代设计的主要改进是

    将超声波发射、超声波接收、单片机控制三个部分分离,分别构成独立模块,如下图:

    

    

   
    发射、接收模块所选用的控制信号插座均为标准的2.54mm间距,可以方便的连接到万能试验PCB板上,为同学们自己尝试提供了方便。
 

    

    这样,客户可以根据需要组合成:

    1)标准的测距传感器,一发一收模式,相当于第一代,如下图所示:
 

    

    2)能瞄准的测距传感器,一发二收模式(相当于第二代),如下图所示:
 

    

    上图所示安装关系只是一个示意,使用时不一定受此限制。因为模块之间的连接设计为软线,这样用户可以根据安装需要布置接收和发射模块,以达到最佳的测距效果:
 

    

    所提供的软线长度为15cm,一般小车上应用绰绰有余,如不够可以自己酌情加长。

    一个客户用这个传感器做的避障:

    http://picimg.witdes.cn/pic/blog.ednchina.com/exbot/1970462/message.aspx

    3)多个同步测距传感器,即用一个控制器实现多个标准的测距传感器。

    首先,请仔细看前面的控制模块图,设计上,控制模块可以同时处理4个接收模块的信号,即可以同时接 4 个接收模块。
再仔细看发射模块图,发射模块设计了级联插座位置,可以通过级联方式,接多个发射模块,如下图所示:

    

    这样,用户可以用4个发射和 4个接收构建4组超声波测距,布置在小车四周,实现同步测距,等于装了4个超声波测距传感器。(注意:级联发射时最好不要用 USB 的电源供电,以免损坏USB口!)

    用4个独立的测距传感器如果不同步发射,将产生相互干扰;为了可靠,必须轮流工作,会大大降低采样速率。

    4)三维瞄准

    第二代测距传感器因为只有2路接收,所以只能判断二维的目标位置。

    此次设计的控制器可以最多接4个接收模块,因此,可以用一个发射和3个或4个接收组合,构成3维瞄准,实现对空间目标定位。

    这应该是不错的编程素材,通过控制2个舵机还可以实现对一个空中目标的跟踪。

    除了组合方式灵活外,将控制器分离,用户就有了使用其它MCU控制的可能。

    因为本超声波测距传感器设计目的是为了学习单片机的同学提供素材,所以不应限制MCU的使用。我设计的控制器可以作为同学们的参考,而同学们可以选用自己熟悉的、想要学习的MCU来控制接收和发射模块,实现测距功能。

    很多同学偏爱AVR、PIC等 MCU,或者有些同学想尝试 ARM,这些在此次的改进设计上都很容易实现。

    如果自己选择MCU构成控制部分,所需要的资源如下:

    控制发射模块,只需要占用MCU的一个定时器和2个输出口,注意:一个最好是推挽输出(即高、低电平均有驱动能力,而不是标准51口那种只有低电平驱动能力的);另一个输出最好是开漏模式。对于新型的MCU,这些均不成问题,通常其I/O口都有4种模式。

    控制接收模块,需要占用MCU的一个定时器和6个I/O口,其中4个输出用于控制TL852的增益;一个输入用于接收超声波信号,必须支持负跳中断;还有一个输出用于控制TL852的信号检测电容,以实现无效信号的屏蔽和多重距离检测,此口最好是开漏输出模式。

    如果要接多个接收模块,4个增益控制用输出端可以并联,但另外2个输入、输出端必须独立,也就是说,如果接4个接收模块,共需要12个I/O口,其中4个支持输入负跳中断。

    为了便于计时,最好选择带PCA(可编程计数器阵列)的MCU,计时比较准确,控制也比经典的定时器灵活。现在新的MCU上多配备有PCA,ARM系列更是如此。

    关于电路和软件,基本没有变化,只是围绕多路接收做了一些调整,基本原理未变,所以在此不再赘述。


    为了调试、测试方便,PC上的测试程序也作了相应的修改,支持4路信号采集,如下图所示:

    

拓展内容:

    1)控制器硬件上设计了18B20温度测量部分,因为声波速度受温度影响,应该根据温度修正。

    2)控制器硬件上设计了RFM12B无线模块,可以实现无线通讯,目的有二:

    其一:作为传感器数据远程采集的通道。因为一般安装传感器的位置均为人不易到达的地方,至少人待着比较别扭,直接在传感器上显示数据似乎有些不妥。通过无线通讯将传感器的数据传至PC上,人可以方便观察,也便于存贮。

    其二:作为收、发分离的同步通道。有一些应用需要将收、发分离,当距离较远,或者有一方需要移动时,电缆连接就不太方便了,此时需要通过无线通讯实现同步,才能达到测量的目的。

    希望这些改进设计能帮助同学们更好的学习单片机应用。

   附:模块外形尺寸  


 

    

    

    

热门设计服务