蓝桥杯单片机-国赛3——已更正:基于pca方式的超声波传感器操作(CX20106A)

本文基于小蜜蜂编程风格,并结合往期编程代码模板


        由于在国赛中,如果同时考到LM555与超声波,会产生定时计数器不够用现象,因此我们可以将采用PCA方式来实现超声波的计数功能。

1. PCA简介

PCA方式全称为:Programmable Counter Array。我们不需要搞懂其内部的原理,只需要掌握其具备的计数功能,从而便于我们使用。

PCA计数的过程,与定时计数器相似,只不过定时计数器可以在中断服务函数中响应计数溢出,PCA没有中断服务函数,而直接进行计数值的读取。

在配置时,我们将PCA与定时计数器的相关寄存器和位,类比来看,便可快速掌握:

定时计数器PCA计数器作用
TMODCMOD定义计数模式
TCONCCON控制计数器
THx,TLxCH,CL计数值寄存器
TFxCF溢出标志位
TRxCR启动或暂停标志

以上便是配置PCA计数器会用到的所有标志,我们要做的就是记下来,知道是什么东西。

2. 定义特殊寄存器和特殊位变量

        如果头文件是stc15f2k60s2.h , 则不需要此步骤,因此寄存器在这个头文件中都有了

        如果头文件是reg52.h , reg51.h , REGX52.H :则需要添加特殊寄存器地址和位:

不用背!!看这里:

        这些东西在stc-isp里面都可以查到,此外AUXR,P4等也是可以查出来的

3. 实现关键步骤

        初始化:

        读取过程(使用0x08):(可以看出读取过程与平时使用定时计数器完全一样,只是位变量名不同)

          读取过程(使用0x01):(需要配置,设置计数值达到某一定量时,退出循环,避免程序卡死)

4. 参考代码

#include <REGX52.H>
#include <intrins.h>

sfr AUXR = 0x8e;
sfr CMOD = 0xd9;
sfr CCON = 0xd8;
sfr CL = 0xE9;   //0000,0000 PCA计数器低字节
sfr CH = 0xF9;   //0000,0000 PCA计数器高字节

sbit CF = CCON^7;
sbit CR = CCON^6;



sbit TX = P1^0;
sbit RX = P1^1;

void flash_SMG ();

unsigned int distance = 0;
unsigned char sonic_flag = 0; //500ms刷新一次超声波数据标志位
unsigned char code duanma[20] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
                                 0x88,0x83,0xc6,0xc0,0x86,0x8e,0xbf,0xc7,0x89,0x8c};

//锁存器通道选择函数
void select_HC573 ( unsigned char channal )
{
	switch ( channal )
	{
		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 state_SMG ( unsigned char pos_SMG , unsigned char value_SMG )
{
	select_HC573 ( 0 );
	P0 = 0x01 << pos_SMG;select_HC573( 6 );
	select_HC573 ( 0 );
	P0 = value_SMG;select_HC573( 7 );
	select_HC573 ( 0 );
}

//全位数码管静态显示
void state_SMG_all ( unsigned char value_SMG_all )
{
	select_HC573 ( 0 );
	P0 = 0xff;select_HC573( 6 );
	select_HC573 ( 0 );
	P0 = value_SMG_all;select_HC573( 7 );
	select_HC573 ( 0 );
}	

//初始化系统,关闭继电器和蜂鸣器
void init_sys ()
{
	select_HC573 ( 0 );
	P0 = 0xff;select_HC573 ( 4 );
	select_HC573 ( 0 );
	P0 = 0x00;select_HC573 ( 5 );
	select_HC573 ( 0 );
}

//延时函数生成13us,然后把变量值改成38效果最佳
void Delay13us()		//@12.000MHz
{
	unsigned char i;

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

void init_pca ()
{

	CMOD=0x01;//设置定时器时钟
	//0x00可以正常使用,但是感觉发出去的波形不是垂直的,带有一定的弧角,最大测量132cm
	//0x01效果更佳,最大实测到了305cm,数据比较稳定,但题目复杂时,while循环等待太久单片机会死机,因此需要根据CH的值推出循环
	//0x08效果积极稳定,实测最大可以到93cm,且最终距离数据需要除以12后使用。数据稳定度最佳。
	//综合比较之后,在国赛中,如果测距小于90则用0x08,大于90用0x01,并使用我调试过的超声波程序。
		
    CCON=0x00;//将溢出位cf(溢出标志位)置零cr(启停位)置零停止计数	
}

void send_sonic ()
{
	unsigned char i;
	for ( i=0 ; i<8 ; i++ )
	{
		TX = 1;
		Delay13us();
		TX = 0;
		Delay13us();
	}
}


void recive_sonic ()
{
	if ( sonic_flag == 1 ) //刷新标志位
	{
		unsigned int time = 0;
		CF = 0;		
		CL = 0x00;
		CH = 0x00;	
		
		EA = 0;
		send_sonic ();
		EA = 1;
		CR = 1;

		while ( (CH<0xb0) && (RX == 1) );  //CH的数据需要根据比赛时调整,我测试时感觉没有定值。14届国赛中我用的0x40,可以测量到265cm,但这里0x40不行,看来是和程序的量有关系的,毕竟单片机i性能有限
		CR = 0;
		if ( CH>=0xb0 )
		{
			distance = 999;
			CF = 0;
		}
		else 
		{
			time = CH;
			time = (time<<8)|CL;
			distance = (unsigned int)(time*0.0172);
		}
		
		sonic_flag = 0;
	}
}

void init_timer0(void)		//5微秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x02;		//设置定时器模式
	TL0 = 0xFB;		//设置定时初始值
	TH0 = 0xFB;		//设置定时重载值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	ET0 = 1;
	EA = 1;
}

unsigned char count_50us = 0;
unsigned char count_10ms = 0;
unsigned char flash_count = 0;
void timer0_service () interrupt 1
{
	if ( ++count_50us == 200 )
	{
		count_50us = 0;
		if ( ++count_10ms == 50 )
		{
			count_10ms = 0;
			sonic_flag = 1;
		}	
	}
	
	if ( count_50us % 100 == 0 )
	{
		if ( ++flash_count == 6 )
		{
			flash_count = 0;
		}
		flash_SMG ();
	}
}

void flash_SMG ()
{
	state_SMG_all ( 0xff );
	switch ( flash_count )
	{
		case 0:
			state_SMG ( 0 , duanma[12] );break;
		case 1:
			state_SMG ( 1 , 0xc7 );break;
		case 2:
			if ( distance > 999 )
			{
				state_SMG ( 4 , duanma[distance/1000%10] );
			}
			else 
			{
				state_SMG ( 4 , 0xff );
			}
			break;
		case 3:
			if ( distance > 99 )
			{
				state_SMG ( 5 , duanma[distance/100%10] );
			}
			else 
			{
				state_SMG ( 5 , 0xff );
			}
			break;
		case 4:
			if ( distance > 9 )
			{
				state_SMG ( 6 , duanma[distance/10%10] );
			}
			else 
			{
				state_SMG ( 6 , 0xff );
			}
			break;		
		case 5:
				state_SMG ( 7 , duanma[distance%10] );break;		
	}
}	

void main ()
{
	init_pca ();
	init_timer0 ();
	init_sys ();
	while ( 1 )
	{
		recive_sonic ();
	}
}

  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* CX20106A 超声波发送与接受程序 40KHz脉冲由单AT89S52单片机P1.0口送出,由P3.2(INT0)采用中断方式接收。 定时器0,定时器1中断方式工作,T1为8位自动重装模式(定时12.5us),T0为16位定时器(定时约65ms) 超声波接受采用外部中断INT0,接受到返回脉冲后,在外部中断程序中计算距离。 65ms超声波传播距离约65×10^(-3) × 340m/s =22.1m,距离足够了,远超CX20106A的测量范围。 40KHz对应波周期T=1/40KHz =25us,方波高占空比50%,高低电平宽度分别占0.5T=12.5us。 定时器T1采用8位自动重装模式(定时12.5us), 在单片机采用12MHz晶振的前提下,(2^8-X)×12/12 us =12.5us (1) 当X=0xF3时,2^8-X=13, (2) 当X=0xF4时,2^8-X = 12, 所以,取X=0xF3,0xF4均可以满足计时要求。 距离显示在4位数码管上,单位为cm。 */ /* 单片机P2口接74HC138(三八译码器)P2.3--74HC138:/EI、P2.2--74HC138:A2、P2.1--74HC138:A1、P2.0--74HC138:A0 译码器输出 Y0,Y1、Y2、Y3、Y4、Y5、Y6、Y7均低电平有效,分别选通1~8个数码管。包括2个四位一体数码管LG3641BH,共2x4=8个数码管。 数码管数据口为P0口。数码管为共阳4位一体数码管。 功能: 译码器输出为1——8个数码管的段选信号,轮流选择1——8数码管。 dispaly(uint d)将d(distance)的千、百、十、个依次显示在1~3号数码管上。 显示原理: 1、送出要显示的段数 2、P2译码,选择要显示的位 3、延时1——2ms,时间不能太长,否则会闪烁,也不能太短,否则会很暗。 4、取消段选,消隐! 若要显示多段,重复以上4步! */

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值