蓝桥杯备战——12.超声波与测频代码优化

1.优化分析

昨天我在看原理图的发现超声波模块的反馈引脚P11刚好可以使用PCA模块0的捕获功能,我就想着把PCA功能留给超声波,然后测频功能还是改成定时器0来完成,然后前后台功能改成定时器1。
蓝桥杯备战——12.超声波与测频代码优化_第1张图片
蓝桥杯备战——12.超声波与测频代码优化_第2张图片
至于我为什么要这么改呢,看一下我原来封装的超声波代码就知道了,下图高亮部分,如果一直没有接收到反馈信号,程序就会一直等待65ms,严重吃MCU资源,而且会导致数码管闪动。如果换成PCA模块捕获功能来做的话,我们只需初始化一下,然后在每个下降沿捕获中断里面获取距离就行,这大大提高了代码效率!
蓝桥杯备战——12.超声波与测频代码优化_第3张图片

2.代码示例

STC15使用CCP功能驱动超声波模块

#include "wave.h"

#define Wave_TX P10	//超声波发送引脚
#define Wave_RX P11	//超声波信号接收反馈引脚

float Distance=0;	//单位:cm

void Send_Vave()	//发出超声波脉冲
{
	u8 i=8;
	while(i--)
	{
		Wave_TX=1;
		_nop_();_nop_();_nop_();
		Wave_TX=0;
		_nop_();_nop_();_nop_();
	}
}

void Wave_Init()
{
	P_SW1 &=0XCF;	//清除CCP_S1,CCP_S0位
	P_SW1 |=0X00;	//CCP在P11/CCP0
	CCON = 0;     //清除CF标志 PCA定时器停止 清除模块0/1/2中断标志
	CL = 0;CH = 0;	//复位PCA计数值
	CCAP0L = 0;CCAP0H = 0;	//清除捕获值
	CMOD = 0x01; //设置PCA时钟源:系统时钟/12,允许PCA溢出中断
	CCAPM0 = 0x11; //PCA模块0允许下降沿捕获,开捕获中断
	CR = 1;	//启动PCA计数器阵列计数
	EA = 1; //开总中断
}

void PCA_isr() interrupt 7
{
	static u8 count=0;
	if (CF){ //每65.536ms发生溢出中断
		CF = 0;
		CR=0;
		CL = 0;CH = 0; 	//复位PCA计数值
		CCAP0L = 0;CCAP0H = 0; //清除捕获值
		if(++count==8) count=0;
		Send_Vave(); 
		CR=1;	//启动PCA计数阵列
  }
	if (CCF0)	//发生下降沿捕获中断
  {
		CCF0 = 0;
		if(count==4) //65*8ms采样一次,防止数值频繁变动
			Distance = (CCAP0H<<8 | CCAP0L)*0.017;	//返回距离
  }
}

定时器0外部脉冲输入测频

#include "capture.h"

u8 Overflow=0;

//定时器0对P34输入脉冲计数
void Capture_Init()
{
	TMOD |= 0x04;			//定时器0外部脉冲计数,16自动重装载
	TL0 = 0x00;				//设置自动重装载值
	TH0 = 0x00;
	TF0 = 0;	//清除TF0标志
	ET0 = 1;
	EA = 1;
	TR0 = 1;	//定时器0开始计时
}

void Timer0_Isr(void) interrupt 1
{
	Overflow++;
}

//每1S获取一次计数值,即频率
u32 Get_Frequency()
{
	u32 count = (Overflow<<16) | (TH0<<8) |TL0;
	TR0=0;	//先关定时器再清零
	TH0 = 0;
	TL0 = 0;
	Overflow=0;
	TR0=1;
	return count; //返回计数值(频率),单位HZ
}

定时器1前后台

#include "main.h"

bit KeyScan_Flag=0;
u32 frequency=0;
extern float Distance;	//单位:cm

void System_Init(void);
void Timer1_Init(void);

void main()
{
	System_Init();
	Timer1_Init();
	Capture_Init();
	Wave_Init();
	while(1)
	{
		if(KeyScan_Flag){ //50HZ
			Keys_Scan();
			KeyScan_Flag=0;
		}
		//前四位显示超声波获取距离
		Nixie_Display(1,((u8)Distance%100)/10);
		Nixie_Display(2,(u8)Distance%10);
		Nixie_Display(2,16);	//小数点
		Nixie_Display(3,(u8)(Distance*10)%10);
		Nixie_Display(4,(u8)(Distance*100)%10);
		
		//后四位显示频率
		Nixie_Display(5,(frequency%10000)/1000);	
		Nixie_Display(6,(frequency%1000)/100);	
		Nixie_Display(7,(frequency%100)/10);	
		Nixie_Display(8,frequency%10);

	}
}

void Timer1_Isr(void) interrupt 3 //1ms中断一次
{
	static u8 count1=0,count2=0;
	static u16 counter3=0;
	
	if(++count1==20){	//20ms扫描一次按键
		KeyScan_Flag=1;
		count1=0;
	}
	if(++count2==250){	//LED8一秒闪四次
		P12=!P12;
		Set_Leds(8,P12);
		count2=0;
	}
	if(++counter3==1000)
	{
		frequency = Get_Frequency();
		counter3=0;
	}
}

void Timer1_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;
	TMOD &= 0x0F;
	TL1 = 0x18;
	TH1 = 0xFC;
	TF1 = 0;
	ET1 = 1;
	EA = 1;
	TR1 = 1;
}

void System_Init()//系统上电初始化
{
	//先锁存蜂鸣器,继电器所在573输出低电平,防止上电乱叫
	P25=1;P26=0;P27=1; //74HC138-->Y5=0,else=1-->Y5C=1,else=0
	P04=0;P06=0;	//ULN2003输入经过非门送入达林顿管,低电平有效
	P25=0;P26=0;P27=0;//锁存数据
	
	//关闭所有LED灯
	P25=0;P26=0;P27=1; //74HC138-->Y4=0,else=1-->Y4C=1,else=0
	P0=0XFF;
	P25=0;P26=0;P27=0;//锁存数据
}

你可能感兴趣的:(蓝桥杯单片机备战笔记,蓝桥杯,单片机,嵌入式硬件)