首页  /  单片机教程  /  超声波模块  /  

超声波模块

点击打开在线编译器,边学边练

1.超声波模块型号

超声波模块是一种常用的测距工具,一般用在避障小车,水位监控系统中,本教程使用的模块型号为HC-SR04,外观形状大体如下

9.3.png

模块除了两个电源引脚外,还有TRIG,ECHO引脚,这两个引脚分别接我们开发板的P2.0和P2.1。

工作原理就是起初先给这两个引脚都拉低,然后让TRIG引脚拉高10微秒以上再拉低产生一个脉冲起始信号(程序中我们是拉高20微秒)。起始信号一开启,ECHO引脚就会被拉高的同时,超声波开始发射,ECHO引脚检测到反射回来的信号时就会被拉低,因为声速为340m/s。那么测出的距离就是

(ECHO引脚高电平持续的时间*340m/s)/2。

中学学过用声波测海底深度,时间*声速=来回的距离,所以需要除以2才是真正的深度,超声波模块也一样。

 

2.软件分析

计算ECHO引脚高电平的持续时间就用定时器的计数功能完成,如果定时器计数溢出,证明测的距离太远,超出模块的测距范围(最多4米),我们就在数码管上显示999表示距离太远。在测量范围内我们的数码管就显示测出的厘米数。

比如说定时器的计数为9216,那么高电平的持续时间就是9216*(12/11059200)=0.01s

测出的距离就是0.01*340/2=1.7m

数码管就显示170。

不过为了简化单片机的计算过程,我们可以这样算

“( (X*12)/11059200 )*340*100/2”就是厘米数,化简约为“X/54”,X就是定时器的计数值。

本讲代码需要用到“#include<intrins.h >”的“_nop_();”,这个表示延时1微秒左右,请参考《手把手教你学51单片机》文档14.2节后半段文字。


3.代码

#include <reg52.h> 
#include <function.h> //详见第六章第8讲
#include <timer.h>    //详见第八章第11讲
#include <intrins.h> 

sbit TRIG = P2^0; 
sbit ECHO = P2^1; 
u8   FLAG = 0;
void delay_20us() 
{
    _nop_();_nop_();_nop_();_nop_();_nop_(); 
    _nop_();_nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();_nop_();
}
 
void main()
{  
    u16 time_data,CM_data;
    TRIG = 0; 
    ECHO = 0;

    LED_Init();        //初始化LED硬件模块
    EA = 1;            //闭合总中断开关
    TIM1_Init(1000,0); //定时1ms,用来刷新数码管显示,定时精度要求不高可不微调

    TMOD &= 0xF0;
    TMOD |= 0x01; 
    ET0  = 1;
    while(1)
    {   
        TH0  = 0; 
        TL0  = 0; 
        FLAG = 0;      //上次如果是超出测量范围,FLAG被置1,这次再测就要清0

        //启动发射声波
        TRIG = 1;    
        delay_20us();
        TRIG = 0;

        while(!ECHO);              //声波开始发射,等待ECHO引脚拉高退出这个循环
        TR0 = 1;                   //ECHO引脚一拉高,就打开定时器进行计数 
        while(ECHO==1 && FLAG==0); //收到声波返回来的信号ECHO引脚就拉低,退出这个循环;如果定时器溢出,就会进入中断函数执行“FLAG=1;”
                                   //也就是测量的距离太远,一直没有收到反射回来的信号,不满足“FLAG==0”的条件只能结束这个循环语句  
        TR0 = 0;                   //关闭定时器结束计数

        time_data =TH0;
        time_data=(time_data<<8)|TL0;                //把两个八位的寄存器里的值组成一个16位变量的值,也就是定时器计数值
        CM_data = time_data/54;                      //得到厘米的表达式

        if(FLAG==1){ShowNumber(999); delay_ms(100);} //超出测量范围显示999,延时的目的:比如测得5cm到6cm之间,数码管会频繁在5跟6之间显示,加入延时就会让它们显示的没有那么频繁   
        else {ShowNumber(CM_data); delay_ms(100);}     
    }
}
 
void TIM0_IRQHandler()  interrupt 1   
{
    FLAG=1;
}

void TIM1_IRQHandler()  interrupt 3
{
    TH1 = T1RH;  //重新加载重载值
    TL1 = T1RL;
    SEG_Scan();
}

本文固定URL:https://www.dotcpp.com/course/384

上一课:舵机与按键
第一章 单片机入门
第二章 LED
第三章 蜂鸣器
第四章 数码管
第五章 独立按键
第六章 多文件编程
第七章 外部中断
第八章 定时器
第九章 舵机与超声波模块
第十章 串口通信
第十一章 1602液晶屏
第十二章 IIC通信
第十三章 红外遥控与温度传感器
第十四章 AD与DA
第十五章 混合例程
第十六章 完结
Dotcpp在线编译      (登录可减少运行等待时间)