第十五届蓝桥杯单片机组——超声波测距(利用CCP模块节省定时器资源,附带可直接运行代码)

一、超声波测距原理

超声波测距是一种常用的测量距离的方法,凭借其非接触性、准确度高以及对环境因素影响小的优点,广泛应用于各类机器人、自动驾驶车辆、物体探测、避障等场景。
这种技术的基础是发送超声波并计算其返回时间。在理想情况下,超声波在空气中的速度约为343米/秒(在20°C下)。通过量化超声波单向或双向的传播时间,就可以计算出距离。

操作步骤如下:

  1. 发射超声波:发送器首先发射一束超声波,通常是在40kHz频率。
  2. 接收反射的超声波:发送出去的超声波会碰到障碍物然后反射回来,被超声波接收器接收。
  3. 计算传播时间:通过电路_timer_或者微控制器,计算超声波被发射和接收的时间差。
  4. 计算距离:最后,使用以下公式计算到障碍物的距离:距离= (超声波速度 * 时间) / 2

这种测距方法可以实现中短距离的精确测量,受环境条件影响小,适合在各种环境中使用。

二、利用定时器实现测距

2.1 结合定时器实现过程

  1. 设置Trig引脚高电平:通过软件使Trig引脚输出10微秒以上的高电平,这将促使超声波模块发出8个40kHz的超声波。
  2. 等待接收到Echo信号:然后等待Echo引脚从低电平变为高电平,当接收到Echo信号时,开始用定时器测量时间。
  3. 计算超声波来回时间:当Echo引脚再度变为低电平时,立即停止计时。这个时间就是超声波从发射到反射并接收回来的所有时间。
  4. 计算距离:将这个时间(单位应转化为秒)除以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();
	}
}
  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值