【51单片机学习记录】超声波测距

一、超声波测距概述

(1)超声波时间差测距原理

  • 超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时。
  • 超声波在空气中的传播速度为340m/s,根据计时器记录的时间t,就可以计算出发射点距障碍物的距离(s),即:s=340*t/2。这就是所谓的时间差测距法。
  • 超声波测距的原理是利用超声波在空气中的传播速度为已知,测量声波在发射后遇到障碍物反射回来的时间,根据发射和接收的时间差计算出发射点到障碍物的实际距离。由此可见,超声波测距原理与雷达原理是一样的。测距的公式表示为:L=C✖️T(式中L为测量的距离长度;C为超声波在空气中的传播速度;T为测量距离传播的时间差(T为发射到接收时间数值的一半))

(2)超声波应用

  • 超声波测距主要应用于倒车提醒、机器人、建筑工地、工业现场等的距离测量,虽然目前的测距量程上能达到百米,但测量的精度往往只能达到厘米数量级。
  • 超声波易于定向发射、方向性好、强度易控制、与被测量物体不需要直接接触的优点,是作为液体高度测量的理想手段。

二、超声波测距原理

(1)超声波发射电路

(2)超声波接收电路

(3)超声波/红外选择跳线

  • N A1-P10 N B1-P11可以使用P10和P11操作超声波发射模块
  • N A2-P10 N B2-P11使用的红外

三、超声波测距应用

(0)编写逻辑

  1. 产生8个40KHz的超声波信号,通过TX引脚发射出去。
  2. 启动定时器,开始计时。
  3. 等待超声波信号返回,如果接收到反射回来的信号,RX引脚变为低电平
  4. 停止定时器,读取脉冲个数,即获得时间T.
  5. 根据公式,L=V*T/2 m,进行距离的计算。

(1)变量

(2)函数

(每14us发射一次,发射八次)

(3)主函数

(4)完整代码

#include<STC15.H>
#include<intrins.H>

sbit TX = P1^0 ;//超声波发射引脚
sbit RX = P1^1 ;
	
unsigned char LED_Bit=0XFF;
unsigned char Actuator_Bit=0X00;

#define LEDx_ON(n) 	{ LED_Bit&=_crol_(0XFE,n-1); P0=LED_Bit; P2|=0X80;	P2&=0X9F;	P2&=0X1F;}
#define LEDx_OFF(n) { LED_Bit|=_crol_(0X01,n-1); P0=LED_Bit; P2|=0X80;	P2&=0X9F;	P2&=0X1F;}

#define Buzzer_ON 	Actuator_Bit|=0x40; P0=Actuator_Bit;	P2|=0XA0;	P2&=0XBF; P2&=0X1F;		
#define Buzzer_OFF 	Actuator_Bit&=0XBF; P0=Actuator_Bit;	P2|=0XA0;	P2&=0XBF;	P2&=0X1F;
#define Relay_ON 		Actuator_Bit|=0x10; P0=Actuator_Bit;	P2|=0XA0;	P2&=0XBF;	P2&=0X1F;
#define Relay_OFF 	Actuator_Bit&=0XEF; P0=Actuator_Bit;	P2|=0XA0;	P2&=0XBF;	P2&=0X1F;

unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
unsigned char KEY_Value = 0 ;
unsigned char DigCom=0;
unsigned char DigBuf[8] = {10,10,10,10,10,10,10,10};

unsigned char LED = 1 ;
unsigned int LED_tt =0;
bit LED_Ref = 0 ;

unsigned int SEG_tt =0;		//定义一个数码管计数时间标识位
bit SEG_Ref = 0 ;					//定义一个数码管刷新标识位
bit SEG_Run = 0 ;					//定义一个控制数码管运行标识位
unsigned int Num = 999 ;

unsigned int LCM_tt = 0 ;//超声波计数时间标识位
bit LCM_Ref = 0 ;				 //超声波刷新标识位
unsigned int LCM = 0 ;	 //存储超声波测距
unsigned int LCM_Time = 0 ;//定时器计时超声波从发出到返回的时间

void ALL_Init(void);
void Delay_MS(unsigned int MS);
void KeyScan(void);
void ArrKeyScan(void);
void Timer0Init(void);		//1毫秒@11.0592MHz
void Send_wave(void);
void Timer1Init(void);

void main(void)
{
	IO_Init();
	ALL_Init();
	Timer0Init();
	Timer1Init();
	EA=1;ET0=1;
	
	while(1)
	{
		KeyScan();
//		ArrKeyScan();
		if(KEY_Value==7){KEY_Value=0;SEG_Run = 1 ;}
		if(KEY_Value==6){KEY_Value=0;SEG_Run = 0 ;}
		if(KEY_Value==5){KEY_Value=0;LEDx_ON(1);Buzzer_ON;}
		if(KEY_Value==4){KEY_Value=0;LEDx_OFF(1);Buzzer_OFF;}	
		
		if(LCM_Ref==1)//timer0计时达到300ms
		{
			LCM_Ref = 0 ;
			Send_wave();
			TR1 = 1; //发送超声波之后定时器开始计时
			while((RX == 1)&&(TF1 == 0));//没有接收到信号 没有产生溢出中断 当无论是采集到数据或者定时器1溢出 开始执行
			TR1 = 0;//清楚定时器的计时值
			if(TF1 == 1) //产生中断 溢出
			{
				TF1 = 0 ;//清除中断、溢出
				LCM = 9999 ;//表示没有采集到数据
			}
			else 
			{
				LCM_Time = TH1 ;//读出定时器中的高八位数据
				LCM_Time <<= 8 ;
				LCM_Time |= TL1 ;//读出十六位数据
				LCM = (unsigned int)(LCM_Time*17/921.6); //  1/11059200HZ/12分频=  1/921600(计一个数的时间)    LCM_Time*17000(cm) * (1/921600)
				//LCM = (unsigned int)(LCM_Time*0.017); 如果比赛要求使用12MHZ
			}
			TL1 = 0x00;		//设置定时初始值 清零便于下次计时
			TH1 = 0x00;		//设置定时初始值
		}
		DigBuf[5] = LCM/100;
		DigBuf[6] = LCM%100/10;
		DigBuf[7] = LCM%10;  
	}
}



void Timer1Init(void)		//0毫秒@11.0592MHz
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x00;		//设置定时初始值
	TH1 = 0x00;		//设置定时初始值
	TF1 = 0;		//清除TF1标志
//	TR1 = 1;		//定时器1开始计时
}


void Delay14us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 45;
	while (--i);
}

void Send_wave(void)
{
	unsigned char i = 8 ;
	do
	{
		TX = 1 ;  Delay14us();
		TX = 0 ;  Delay14us();
	}
	while(i--);
}

void KeyScan(void)
{
	if(P30==0)
	{
		Delay_MS(10);
		if(P30==0)KEY_Value = 7 ;		
		while(!P30);
	}
	else if(P31==0)
	{
		Delay_MS(10);
		if(P31==0)KEY_Value = 6 ;		
		while(!P31);
	}	
	else if(P32==0)
	{
		Delay_MS(10);
		if(P32==0)KEY_Value = 5 ;		
		while(!P32);
	}	
	else if(P33==0)
	{
		Delay_MS(10);
		if(P33==0)KEY_Value = 4 ;		
		while(!P33);
	}	
}

void Timer0(void) interrupt 1
{
	P0=0X00;
	P2|=0XC0;  // P2=P2|0XC0;   XXXX XXXX | 1100 0000 = 11XX XXXX
	P2&=0XDF;	 // P2=P2&0XDF;   11XX XXXX & 1101 1111 = 110X XXXX	
	P2&=0X1F;		//关闭所有的74HC573锁存器	
	
	P0=tab[DigBuf[DigCom]];	
	P2|=0XE0;			//	P2=P2|0XE0;   XXXX XXXX | 1110 0000 = 111X XXXX
	P2&=0XFF;		 	// P2=P2&0XDF;   11XX XXXX & 1101 1111 = 110X XXXX	
	P2&=0X1F;			//关闭所有的74HC573锁存器
	
	P0=(0X01<<DigCom); 	//然后选中第一个数码管
	P2|=0XC0;  // P2=P2|0XC0;   XXXX XXXX | 1100 0000 = 11XX XXXX
	P2&=0XDF;	 // P2=P2&0XDF;   11XX XXXX & 1101 1111 = 110X XXXX	
	P2&=0X1F;		//关闭所有的74HC573锁存器

	if(++DigCom == 8)DigCom = 0 ;
	
	LED_tt++;
	if(LED_tt == 999) {LED_tt = 0 ; LED_Ref = 1 ;}

	if(++SEG_tt==1000){SEG_tt=0;SEG_Ref=1;}
	if(++LCM_tt==300){LCM_tt = 0 ; LCM_Ref = 1 ;}//假设每300ms进行一次测量
}

void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初始值
	TH0 = 0xD4;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}




void Delay_MS(unsigned int MS)
{
	unsigned i,j;
	for(i=0;i<MS;i++)
		for(j=853;j>0;j--); 
}

void ALL_Init(void)
{
	P0 =0X00;		//先设置关闭蜂鸣器继电器的P0输出值(全关)
	P2|=0XA0;		// 将P27 P25 设置为1 其他位保持不变
	P2&=0XBF; 	// 将P26设置为0 其他位保持不变
	P2&=0X1F;		//关闭所有的74HC573锁存器

	P0 =0XFF;		//先设置关闭所有的LED的P0输出值(全关)
	P2|=0X80;		// 将P27设置为1 其他位保持不变
	P2&=0X9F;		// 将P26 P25设置为0 其他位保持不变
	P2&=0X1F;		//关闭所有的74HC573锁存器
	
	P0 =0X00;		//先设置选择数码管位选的P0输出值(全不选)
	P2|=0XC0;		// 将P27 P26 设置为1 其他位保持不变
	P2&=0XDF;		// 将P26设置为0 其他位保持不变
	P2&=0X1F;		//关闭所有的74HC573锁存器
}

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值