超声波测距是一种常用的测量距离的方法,凭借其非接触性、准确度高以及对环境因素影响小的优点,广泛应用于各类机器人、自动驾驶车辆、物体探测、避障等场景。
这种技术的基础是发送超声波并计算其返回时间。在理想情况下,超声波在空气中的速度约为343米/秒(在20°C下)。通过量化超声波单向或双向的传播时间,就可以计算出距离。
操作步骤如下:
这种测距方法可以实现中短距离的精确测量,受环境条件影响小,适合在各种环境中使用。
#define Trig P2_0 // Trig接口
#define Echo P2_1 // Echo接口
#define Sound_Velocity 343 // 声速343m/s
void 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/2
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();
}
}