文章目录
- 一、超声波测距原理
- 二、利用定时器实现测距
- 2.1 结合定时器实现过程
- 2.2 伪代码
- 三、代码示例
一、超声波测距原理
超声波测距是一种常用的测量距离的方法,凭借其非接触性、准确度高以及对环境因素影响小的优点,广泛应用于各类机器人、自动驾驶车辆、物体探测、避障等场景。
这种技术的基础是发送超声波并计算其返回时间。在理想情况下,超声波在空气中的速度约为343米/秒(在20°C下)。通过量化超声波单向或双向的传播时间,就可以计算出距离。
操作步骤如下:
- 发射超声波:发送器首先发射一束超声波,通常是在40kHz频率。
- 接收反射的超声波:发送出去的超声波会碰到障碍物然后反射回来,被超声波接收器接收。
- 计算传播时间:通过电路_timer_或者微控制器,计算超声波被发射和接收的时间差。
- 计算距离:最后,使用以下公式计算到障碍物的距离:距离= (超声波速度 * 时间) / 2
这种测距方法可以实现中短距离的精确测量,受环境条件影响小,适合在各种环境中使用。
二、利用定时器实现测距
2.1 结合定时器实现过程
- 设置Trig引脚高电平:通过软件使Trig引脚输出10微秒以上的高电平,这将促使超声波模块发出8个40kHz的超声波。
- 等待接收到Echo信号:然后等待Echo引脚从低电平变为高电平,当接收到Echo信号时,开始用定时器测量时间。
- 计算超声波来回时间:当Echo引脚再度变为低电平时,立即停止计时。这个时间就是超声波从发射到反射并接收回来的所有时间。
- 计算距离:将这个时间(单位应转化为秒)除以2(因为是来回的时间),然后乘以声速(在空气中为343m/s)即可得到距离。为了方便,我们通常直接把数值转成厘米,公式如下: 距离 =(时间 * 声速 / 2) * 100。
2.2 伪代码
#define Trig P2_0 // Trig接口
#define Echo P2_1 // Echo接口
#define Sound_Velocity 343 // 声速343m/svoid Timer0Init(void); // 初始化定时器
void Ultrasonic_Init(void); // 超声波初始化double Distance;
unsigned int High_Time; // 高电平时间
unsigned int Low_Time; // 低电平时间void main()
{Ultrasonic_Init();while(1){Trig = 1;delay(15); // 发出至少10us的高电平Trig = 0;while(!Echo); //等待Echo反馈TL0 = 0; TH0 = 0; // 装初值TR0 = 1; // 打开定时器while(Echo);TR0 = 0; // 关闭定时器High_Time = TH0<<8|TL0; //读取计数器值Distance = (double)High_Time * Sound_Velocity / 2 / 12;delay(50); // 延时等待超声波模块稳定}
}
三、代码示例
#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<2;i++){Tx=0;Delay13us();Tx=1;Delay13us();}//如果Rx=1或TF0=1者开始计算距离,如果Rx=0且TF0=1说明距离过远/* V1.0版本while(Rx==0); //我不知道我发完触发信号好Rx引脚会不会马上置为高电平//如果马上置为高电平,它卡在这个while语句出不来。TR0=1;while(Rx==1);*//* V1.1版本 假设它马上高电平,那我去掉那个while语句TR0=1; while(Rx==1); // 如果太近或者太远那么Rx永远不会为0,也就一直卡在这里*//* V2.0 */TR0=1;while(Rx==1 && TF0==0); // Rx=1,或者定时器还没有计数满就一直循环。if(TF0==0){TR0=0;dis=TH0*256+TL0;dis=((dis*1700)/110592);//340*100/11059200/2smg_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();}
}