您现在的位置是:首页 >技术杂谈 >蓝桥杯15单片机--超声波模块网站首页技术杂谈
蓝桥杯15单片机--超声波模块
目录
一、超声波工作原理
超声波时间差测距原理超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时。
超声波在空气中的传播速度为340m/s,根据计时器记录的时间t,就可以计算出发射点距障碍物的距离(s),即:s=340*t/2。这就是所谓的时间差测距法。
超声波测距的原理是利用超声波在空气中的传播速度为已知,测量声波在发射后遇到障碍物反射回来的时间,根据发射和接收的时间差计算出发射点到障碍物的实际距离。由此可见,超声波测距原理与雷达原理是一样的。测距的公式表示为:
L = C x T
式中:L为测量的距离长度;C为超声波在空气中的传播速度;T为测量距离传播的时间差(T为发射到接收时间数值的一半)。
二、超声波电路图
我们用跳线帽把N A1引脚和P10引脚连接起来,把NB1引脚和P11引脚连接起来,这样就能用P10和P11两个引脚分别操控超声波发射和接收。
如果将NA2引脚和P10引脚连接,NB2和P11引脚连接,我们使用的就是电路板上红外线的发射接收模块。
三、程序设计
1-设计思路
1、产生8个40KHz的超声波信号, 通过TX引脚发射出去。
2、启动定时器,开始计时。
3、等待超声波信号返回,如果接收到反射回来的信号,RX引脚变为低电平。
4、停止定时器,读取脉冲个数,即获得时间T。
5、根据公式,L = V*T/2m,进行距离的计算。
2-具体实现
我们默认每300ms进行一次超声波检测,这个300ms的检测我们用定时器2来完成即可。
在我们主函数中,如果检测到要开始进行超声波检测了,就要开始发送超声波信号(send_wave函数),也就是发送8次40KHZ的超声波信号。超声波信号是40KHZ,周期就是25微秒,正负周期各占一半(也就是TX口置0和置1的时间各占周期的一半,12.5微秒,13微秒即可)。所以我们要在正负信号后面加一个13微秒的延时。
但经过实际测量之后发现,由于电路中电容较多,存在误差,所以使用16微秒的延时会更好。(当然这个也不是唯一选择,可以根据自己实际情况选择)
发送完信号之后;就要开始用定时器进行计时。这里我们要用另一个定时器(定时器1),这里要注意的是:定时器时钟设置上要选择12T,其他程序用定时器选择1T即可。定时长度选择0。然后把程序中的TR1=1给注释掉(要在发送完信号之后开始计时)。
接着我们在主函数内进行检测:
如果RX没有接收到低电平(返回信号);并且检测中断标志位,没有溢出中断,就一直等待。
当检测到返回信号,或者一直没有接收到返回信号但是中断溢出了,程序就继续往下进行。首先进行判断,如果是一直没有接收到返回信号但是溢出中断了,就让距离等于9999,表示没有检测到返回信号了,数据超出范围。如果是另一种情况,也就是检测到了返回信号,
LCM_Time = TH1;
LCM_Time <<= 8;
LCM_Time |= TL1;
就读出超声波从发送到接收信号所用的时间LCM_Time,但这读出来的是定时器计数的值,所以下面我们要对其进行换算。
LCM=(uint)(LCM_Time*17/1000);
原因:定时器计数一次需要 1/1000000秒(1/12000000/12)(12M晶振),总共计数了 LCM_Time次,LCM_Time * 1/1000000 * 17000(34000/2) 距离单位是厘米。
最后,把计数值清零方便下次计数。
TL1=0X00;
TH1=0X00;
四、程序源码
#include <STC15F2K60S2.H>
#include <intrins.H>
#define uchar unsigned char
#define uint unsigned int
sbit TX = P1^0;
sbit RX = P1^1;
uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
uchar Smg_num=0;
uchar Smg[]={0,7,10,5,6,10,1,2};
unsigned int LCM_tt = 0 ;//超声波采集时间的计数 间隔多长时间进行一次超声波测量
bit LCM_Ref = 0 ;//超声波开始测量的标志位
unsigned int LCM = 0 ;//超声波测量的距离 单位:cm
unsigned int LCM_Time = 0 ;//超声波从发送到接收返回信号的时间
void Allinit();
void Delayms(uint ms);
void Timer2Init(void); //1毫秒@11.0592MHz
void Timer1Init(void); //0微秒@12.000MHz
void Delay16us(); //@12.000MHz
void Send_wave();//发送超声波信号
void main()
{
Allinit();
Timer2Init();
Timer1Init();
while(1)
{
if(LCM_Ref==1)
{
LCM_Ref=0;
Send_wave();
TR1=1;
while((RX==1)&&(TF1==0));//如果RX没有接收到低电平(返回信号),就一直等待;或者检测中断标志位,没有溢出中断
//当检测到返回信号,或者一直没有接收到返回信号但是中断溢出了,程序就继续往下进行。
TR1=0;
if(TF1==1)//这种情况是 一直没有接收到返回信号但是溢出中断了
{
TF1=0; LCM=999;//表示没有检测到返回信号了,数据超出范围
}
else
{
LCM_Time = TH1;
LCM_Time <<= 8;
LCM_Time |= TL1;//读出超声波从发送到接收信号所用的时间,但这读出来的是定时器计数的值,所以下面我们要对其进行换算
LCM=(uint)(LCM_Time*17/1000);
//定时器计数一次需要 1/1000000秒(1/12000000/12)(12M晶振),总共计数了 LCM_Time次
//LCM_Time * 1/1000000 * 17000(34000/2) 距离单位是厘米
}
TL1=0X00;
TH1=0X00;//清零方便下次计数
}
Smg[5]=LCM/100;
Smg[6]=LCM%100/10;
Smg[7]=LCM%10;
}
}
void Timer1Init(void) //0微秒@12.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x00; //设置定时初始值
TH1 = 0x00; //设置定时初始值
TF1 = 0; //清除TF1标志
//TR1 = 1; //定时器1开始计时
}
void Send_wave()//发送超声波信号
{
uchar i=8;
do
{
TX=1; Delay16us();
TX=0; Delay16us();
}
while(i--);
}
void Delay16us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 45;
while (--i);
}
void timer2() interrupt 12
{
P2|=0XC0;
P2&=0XDF;
P0=(1<<Smg_num);
P2|=0XE0;
P2&=0XFF;
P0=tab[Smg[Smg_num]];
if(++Smg_num==8) Smg_num=0;
if(++LCM_tt==699)//每三百毫秒进行一次超声波检测 999的时候数据可以上 60cm,499的时候数据可以上 50cm
{
LCM_tt=0;LCM_Ref=1;
}
}
void Timer2Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0xCD; //设置定时初始值
T2H = 0xD4; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
IE2|=0X04;EA=1;
}
void Allinit()
{
P2=0XA0;P0=0X00;
P2=0X80;P0=0XFF;
P2=0XC0;P0=0XFF;
P2=0XE0;P0=0XFF;
}
void Delayms(uint ms)
{
uint i,j;
for(i=ms;i>0;i--)
for(j=845;j>0;j--);
}