频率计模块在国赛和省赛中都出现过,所以这是一个非常重要的知识点。该模块非常占用定时器资源,下面是代码编写时定时器的使用情况:
定时器0 | 定时器1 | 定时器2 |
---|---|---|
用作P34输入捕获,得到方波的高电平个数 | 50ms中断,循环20次得到1s的时间基数 | 代替不使用频率计时定时器0,即给数码管、按键、led等外设或状态机提供定时操作 |
- 从上面的表格很容易看出:STC15F2K60S2的所有定时器资源被占据,且P34作为脉冲输入管脚也被使用。
- 因此,我有下列两个推断:(1)需要额外占用定时器资源的模块将不会同时考察到,比如超声波模块和串行通信模块等。(2)和P34管脚相连的按键将不会被使用,但不代表不会考察矩阵键盘。
下面是我本人书写的代码,亲测有效。代码注释都放在代码后面了,请自行食用。
/**********************蓝桥杯频率计模板**********************/
#include "STC15F2K60S2.h"
#define u8 unsigned char
#define u16 unsigned int
u8 code smg_du[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00}; //0-9
u8 code smg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
unsigned int paulse_count=0;//存放高电平次数
u8 over_flag=0;//存放1s溢出标志位
u8 smg_freq[8];//存放频率数组
//定时器0;16位自动重装载;1T模式//
void Timer0Init(void) //该定时器只用来计数
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD = 0x04; //设置计数模式//特别注意,需要自己写0x04
TL0 = 0xff; //设置定时初值//特别注意,需要自己写0xff
TH0 = 0xff; //设置定时初值//一加就溢出//特别注意,需要自己写0xff
TF0 = 0; //溢出标志位清0
TR0 = 1; //启用T0计时器
ET0 = 1; //别忘了使能定时器中断
EA=1;//打开总中断
}
//定时器1;16位自动重装载;12T模式;12.000MHz;50ms//
void Timer1Init(void)
{
AUXR &= 0xBF;
TMOD &= 0x0F;
TL1 = 0xB0;
TH1 = 0x3C;
TF1 = 0;
TR1 = 1;
ET1 = 1;//别忘了使能定时器中断
EA=1;//打开总中断
}
//定时器2;16位自动重装载;1T模式;12.000MHz;1ms//
void Timer2Init(void)
{
AUXR |= 0x04;
T2L = 0x20;
T2H = 0xD1;
AUXR |= 0x10;
IE2 |= (1<<2);//别忘了使能定时器中断
EA=1; //打开总中断
}
void freq_handle(void)
{
int freq;
if(over_flag)
{
over_flag=0;
freq=paulse_count;
paulse_count=0;//切记要进行清0操作
smg_freq[0]=smg_du[freq/10000];
smg_freq[1]=smg_du[freq/1000%10];
smg_freq[2]=smg_du[freq/100%10];
smg_freq[3]=smg_du[freq/10%10];
smg_freq[4]=smg_du[freq%10];
ET0=1;
ET1=1;
TR0=1;
TR1=1;//前面四句使能与频率计数相关的定时器寄存器,以保证定时的精度。
}
}
void main(void)
{
P2=0XA0;P0=0X00;P2=0X00;
P0=~0X00;P2=0X80;P2=0X00;
Timer0Init();
Timer1Init();
Timer2Init();//不要忘了调用定时器中断函数
while(1)
{
freq_handle();
}
}
void timer2() interrupt 12 //定时器2扫描按键以及数码管
{
static int smg_count=0,i=0;
smg_count++;
if(smg_count==2)
{
smg_count=0;
P2=0xc0;P0=0;P2=0;
P2=0xe0;P0=~smg_freq[i];P2=0;
P2=0xc0;P0=smg_wei[i];P2=0;
i++;
if(i==8) i=0;
}
}
void timer0() interrupt 1 //定时器0用作计数(检测P34),paulse_count指的是1s内高电平的个数,也就是频率!
{
paulse_count++;
}
void timer1() interrupt 3 //定时器1用作频率计定时,相当于定时了20*50ms=1s
{
static u8 t1_count=0;
t1_count++;
if(t1_count==20)
{
t1_count=0;
ET0=0;
ET1=0;
TR0=0;
TR1=0;//前面四句失能与频率计数相关的定时器寄存器,以保证定时的精度。
over_flag=1;//说明1s的时长定时完毕
}
}