STC单片机timer2捕获模式测频率

9 篇文章 0 订阅
5 篇文章 0 订阅

在使用STC单片机测频率最常用的方法是在一定时间内计算脉冲个数,这种方式一般需要一个计数器和一个定时器配合,而且对低频信号也不太准确,下面我们可以用到timer2的捕获模式通过测量两个下降沿的时间,来计算频率,这样做仅使用timer2就好了,而且对低频信号测量准确,经实际测试,在100Hz一下时,精度可达0.05Hz。

下面先介绍一下STC51 timer2的捕获模式:

在捕获模式中,通过T2CON中的EXEN2设置两个选项,如果EXEN2=0,定时器作为一个16位的定时器或计数器,溢出时置位TF2。该位可用于产生中断(ET2=1)。如果EXEN2=1,就增加了一个特性,即外部输入T2EX(P11)有下降沿时,将timer2中的TH2和TL2当前值各自捕获到RCAP2L和RCAP2H。另外,T2EX的负跳变使T2CON中的EXF2置位,EXF2也想TF2一样来产生中断(其向量与timer2溢出中断相同,timer2的中断服务通过查询TF2和EXF2来确定引起的中断事件),若是T2EX中断,进来后TH2和TL2不会重新装载值,会继续以当前计数往上计数,除非你确实想改变TH2和TL2的值,如需要重新计数。



下面介绍下程序:

因为外部跳变和溢出均可以进入中断,我们可以利用这一特性来做对两个脉冲之间的时间测量,初始时设置TH2和TL2值为0,如果发生溢出中断,我们的计时变量就自加65536,如果进入外部跳变中断,则我们读取RCAP2L和RCAP2H的值并与前面的计时变量相加即可得到这个跳变与上一跳变的时间,注意测量结束后要清空计时变量以及H2和TL2,方便下一次的重新计数。

初始化程序如下:

//定时器2设置为捕获模式,用户计算速度
void Timer2Init()
{
	char i;
	EXEN2 = 1;//timer2 outside enable
	CP_RL2 = 1;//enable capture mode
	TH2 = TL2 = 0;
	RCAP2H = RCAP2L = 0;
	TR2 = 1;//enable timer2
	ET2=1; //enable timer2 interrupt
	
	//将计时器存储区设置的很大,也就是频率先接近0 
	for(i=0;i<5;i++)
	{
		plus_length[i] = 6553600;
	}
}
中断服务程序如下,在这里keil对long型的数据计算有点问题,需要格外注意

/*******************************************************************************
* 函 数 名 :Timer2Int
* 函数功能 :定时器2中断函数 , 捕获模式
* 输    入 :无
* 输    出 :无 
*******************************************************************************/
void Timer2Int() interrupt 5
{
	static volatile long plus_length_temp=0;
	static char index=0;
	if(TF2 == 1)//overflow int
	{
		TF2 = 0;
		TH2 = 0;
		TL2 = 0;
		RCAP2H = 0;
		RCAP2L = 0;
		plus_length_temp = plus_length_temp + 65536;
		if(plus_length_temp > 6553600) 
		{
			plus_length[index] = plus_length_temp;//对最近5个求平均值
			index++;
			if(index == 5) index = 0;
			plus_length_temp = 0;
		}
	}
	if(EXF2 == 1)//capture int
	{
		long temp;
		TH2 = 0;
		TL2 = 0;//WTF!!!  clear TH2 and TL2,not TH0 and TH1
		EXF2 = 0;
		temp = ((long)(RCAP2H<<8) + RCAP2L) & 0xffff; //奇怪的问题,如果不加0xffff,temp高位会全为ff,从而产生负数
		RCAP2H = 0;
		RCAP2L = 0;
		temp = plus_length_temp + temp;//在对long计算时要小心,一步一来
		plus_length_temp = temp;
		plus_length[index] = plus_length_temp;//对最近5个求平均值
		index++;
		if(index == 5) index = 0;
		plus_length_temp = 0;//read calc next plus

	}
}

最后就是主函数部分内容,每隔500ms求平均值并打印一次当前频率:

		calc_plength = 0;
		Delayms(500);
		for(count = 0;count<5;count++)
		{
			calc_plength += plus_length[count];
		}
		calc_plength = calc_plength/5;
		freq = (float)3990000/calc_plength;//read real frequence
		printf("freq=%f\r\n",freq);

这种方法对低频情况下比较有效,但频率较高时如达到上k的频率,误差比较大,有明显的偏高,至于原因,还等待进一步研究。


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值