一、超声波测距原理
超声波测距是一种常用的测量距离的方法,凭借其非接触性、准确度高以及对环境因素影响小的优点,广泛应用于各类机器人、自动驾驶车辆、物体探测、避障等场景。
这种技术的基础是发送超声波并计算其返回时间。在理想情况下,超声波在空气中的速度约为343米/秒(在20°C下)。通过量化超声波单向或双向的传播时间,就可以计算出距离。
操作步骤如下:
- 发射超声波:发送器首先发射一束超声波,通常是在40kHz频率。
- 接收反射的超声波:发送出去的超声波会碰到障碍物然后反射回来,被超声波接收器接收。
- 计算传播时间:通过电路_timer_或者微控制器,计算超声波被发射和接收的时间差。
- 计算距离:最后,使用以下公式计算到障碍物的距离:距离= (超声波速度 * 时间) / 2
这种测距方法可以实现中短距离的精确测量,受环境条件影响小,适合在各种环境中使用。
二、利用定时器实现测距
2.1 结合定时器实现过程
- 设置Trig引脚高电平:通过软件使Trig引脚输出10微秒以上的高电平,这将促使超声波模块发出8个40kHz的超声波。
- 等待接收到Echo信号:然后等待Echo引脚从低电平变为高电平,当接收到Echo信号时,开始用定时器测量时间。
- 计算超声波来回时间:当Echo引脚再度变为低电平时,立即停止计时。这个时间就是超声波从发射到反射并接收回来的所有时间。
- 计算距离:将这个时间(单位应转化为秒)除以2(因为是来回的时间),然后乘以声速(在空气中为343m/s)即可得到距离。为了方便,我们通常直接把数值转成厘米,公式如下: 距离 =(时间 * 声速 / 2) * 100。
2.2 伪代码
void Timer0_Init(void) //100微秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x00; //设置定时初始值
TH0 = 0x00; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0开始计时
}
// 用这个代码前,需要配置定时器0工作在1T模式下,16位非自动重装载
void csb_test()
{
unsigned char i=0;
for(i=0;i<8;i++){
Tx=1;
Delay13us();
Tx=0;
Delay13us();
}
/* V2.0 */
TR0=1;
while(Rx==1 && TF0==0); // Rx=1,或者定时器还没有计数满就一直循环。
if(TF0==0){
TR0=0;
dis=TH0*256+TL0;
dis=((dis*1700)/110592);
smg_display[5]=dis/100;
smg_display[6]=dis/10%10;
smg_display[7]=dis%10;
}
else{
TF0=0;
TR0=0;
smg_display[6]=18;
smg_display[7]=18;
smg_display[8]=18;
}
TH0=0;
TL0=0;
}
三、利用CCP模块实现超声波
void Delay12us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 38;
while (--i);
}
u16 csb_test()
{
u8 i=0;
u16 temp;
CMOD&=0x00; // 12T计数模式,相当于T0的12T计数
CCON&=0x00; // 关闭
CL=0; // 计数清零
CH=0;
for(i=0;i<8;i++)
{
TX=1;
Delay12us(); // 12us不好,就改为13us,再不好就改Delay中的i值,比如我就从33改为38
TX=0;
Delay12us();
}
while(RX==0);
CR=1;
while(RX==1 && CF==0); // 当声波还没回传回来,且计数没有溢出
CR=0; // 停止计时
if(CF==1)
{
// 如果没有溢出
CF=0;
temp=0xffff; // 赋一个异常数据
}
else
{
temp=(CH<<8)|CL;
}
return temp;
}
四、代码示例
#include <stc15f2k60s2.h>
#include <intrins.h>
//#include <smg.h>
sbit Tx=P1^0;
sbit Rx=P1^1;
unsigned long dis;
unsigned char code dat[]={0xc0, 0xf9, 0xa4, 0xb0, 0x99,
0x92, 0x82, 0xf8, 0x80, 0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,
0xbf,0x7f,0xff};
unsigned char smg_display[]={18,18,18,18,18,18,18,18}; //保存数码管显示的数字
void Delay2ms() //@12.000MHz
{
unsigned char i, j;
i = 24;
j = 85;
do
{
while (--j);
} while (--i);
}
void selectHC573(unsigned char num)
{
switch(num)
{
case 4:
P2=(P2 & 0x1f) | 0x80;
break;
case 5:
P2=(P2 & 0x1f) | 0xa0;
break;
case 6:
P2=(P2 & 0x1f) | 0xc0;
break;
case 7:
P2=(P2 & 0x1f) | 0xe0;
break;
case 0:
P2=(P2 & 0x1f) | 0x00;
break;
}
}
void display_SMG_Bit(unsigned char dat, unsigned pos)
{
/*消影法1*/
// selectHC573(6);
// P0=0x01<<(pos-1);
// selectHC573(7);
// P0=dat;
//
// delay(100);
// P0=0xff;
/*消影法2*/
P0=0xff;
selectHC573(7);
selectHC573(0);
P0=0x01<<(pos-1);
selectHC573(6);
selectHC573(0);
P0=dat;
selectHC573(7);
selectHC573(0);
}
void display_D_SMG()
{
display_SMG_Bit(dat[smg_display[0]],1);
Delay2ms();
display_SMG_Bit(dat[smg_display[1]],2);
Delay2ms();
display_SMG_Bit(dat[smg_display[2]],3);
Delay2ms();
display_SMG_Bit(dat[smg_display[3]],4);
Delay2ms();
display_SMG_Bit(dat[smg_display[4]],5);
Delay2ms();
display_SMG_Bit(dat[smg_display[5]],6);
Delay2ms();
display_SMG_Bit(dat[smg_display[6]],7);
Delay2ms();
display_SMG_Bit(dat[smg_display[7]],8);
Delay2ms();
}
void system_Init()
{
selectHC573(5);
P0=0x00;
selectHC573(0);
}
void Delay13us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 36;
while (--i);
}
void Timer0_Init(void) //100微秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x00; //设置定时初始值
TH0 = 0x00; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0开始计时
}
void csb_test()
{
unsigned char i=0;
for(i=0;i<8;i++){
Tx=1;
Delay13us();
Tx=0;
Delay13us();
}
/* V2.0 */
TR0=1;
while(Rx==1 && TF0==0); // Rx=1,或者定时器还没有计数满就一直循环。
if(TF0==0){
TR0=0;
dis=TH0*256+TL0;
dis=((dis*1700)/110592);
smg_display[5]=dis/100;
smg_display[6]=dis/10%10;
smg_display[7]=dis%10;
}
else{
TF0=0;
TR0=0;
smg_display[6]=18;
smg_display[7]=18;
smg_display[8]=18;
}
TH0=0;
TL0=0;
}
void main()
{
system_Init();
Timer0_Init();
while(1){
csb_test();
display_D_SMG();
}
}