1.优化分析
昨天我在看原理图的发现超声波模块的反馈引脚P11刚好可以使用PCA模块0的捕获功能,我就想着把PCA功能留给超声波,然后测频功能还是改成定时器0来完成,然后前后台功能改成定时器1。
至于我为什么要这么改呢,看一下我原来封装的超声波代码就知道了,下图高亮部分,如果一直没有接收到反馈信号,程序就会一直等待65ms,严重吃MCU资源,而且会导致数码管闪动。如果换成PCA模块捕获功能来做的话,我们只需初始化一下,然后在每个下降沿捕获中断里面获取距离就行,这大大提高了代码效率!
2.代码示例
STC15使用CCP功能驱动超声波模块
#include "wave.h"#define Wave_TX P10 //超声波发送引脚
#define Wave_RX P11 //超声波信号接收反馈引脚float Distance=0; //单位:cmvoid 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/CCP0CCON = 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; //单位:cmvoid System_Init(void);
void Timer1_Init(void);void main()
{System_Init();Timer1_Init();Capture_Init();Wave_Init();while(1){if(KeyScan_Flag){ //50HZKeys_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=0P04=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=0P0=0XFF;P25=0;P26=0;P27=0;//锁存数据
}