任务56频率计的设计.docx
《任务56频率计的设计.docx》由会员分享,可在线阅读,更多相关《任务56频率计的设计.docx(15页珍藏版)》请在冰点文库上搜索。
![任务56频率计的设计.docx](https://file1.bingdoc.com/fileroot1/2023-5/5/9aef4eab-75c1-4058-8b63-bc98404d2cc9/9aef4eab-75c1-4058-8b63-bc98404d2cc91.gif)
任务56频率计的设计
5.6频率计的设计
5.6.1任务介绍
频率计在教学、科研、测量仪器、工业控制等方面都有广泛的应用。
在单片机应用系统中,经常需要对一个连续脉冲的频率(周期)进行测量。
在实际应用中,对于转速、位移、速度、流量等物理量的测量,一般也是先由传感器转换成脉冲信号,然后再测量频率的方式来实现。
本节的任务要求是:
开发板上有一个频率发生器,能够产生250Hz~256KHz的方波。
利用单片机的定时器测量方波的频率或者周期。
5.6.2知识准备
1、测频法
频率的定义为:
单位时间内完成周期性变化的次数,是描述周期运动频繁程度的量。
单片机要完成周期信号的频率测量,根据频率的定义,初学者首先能想到的方法是利用51单片机的1个定时/计数器产生单位时间,然后在单位时间内利用利用另外1个定时/计数器对外界脉冲进行计数。
这种方法称为“测频法”。
但测频法不是万能的,适合测量高频信号。
图5.6.1说明了测频的原理及误差产生的原因。
时基信号
待测信号
计到7个脉冲
比实际多出了0.X个脉冲.
丢失(少计一个脉冲)
图5.6.1测频法误差来源
在图5.6.1中,假设时基信号为1Hz,则用此法测得的待测信号为7Hz。
但从图中可以看出,待测信号的频率应为为7.7Hz,误差约有7/7.7=9.1%。
这个误差是比较大的。
实际上,测量的脉冲个数的误差会在±1之间。
假设测得的脉冲个数为N,则测量频率的误差最大为δ=1/(N-1)×100%。
显然,减少误差的方法,就是增大N。
举个例子,假设测频精度为0.1%,所测信号的频率为10Hz,为了达到测量的准确度,时基信号的长度超过100S,显然这是不可行的。
因此得出一个初步的结论:
测频法只适合于测量高频信号。
2、测周法
测频法不适用于低频信号的测量,低频信号的测量通常采用测周法。
测周法顾名思义就是测量脉冲信号的周期,周期与频率呈倒数的关系,求得脉冲信号的周期,频率也就求出来了。
51单片机测量脉冲信号的周期,也需要用到2个定时/计数器,其中1个定时/计数器用来对脉冲信号进行计数,另外一个定时/计数器用来测量计数时间内的时间长度。
举个例子:
定时/计数器0对外接脉冲计数,方式2,自动重装模式,TL0=246,每来10个脉冲,定时/计数器0溢出一次。
另外一个定时/计数器从溢出后开始计量时间,到下一次溢出后停止计量时间,这是时间差值就是10个脉冲的周期,然后再除以10,就是一个脉冲的周期。
有了对测频法误差来源的分析,就不难得到测周法误差的来源。
脉冲频率越低,周期越长,则测周法的精度越高。
3、频率发生器
开发板上的固定脉冲信号是由数字芯片CD4060产生的。
CD4060是14位二进制串行计数器/分频器。
开发板中CD4060的晶振是4.096MHz,经过14级分频后,输出10路分频信号(Q4~Q14)。
开发板只引出了6路分频信号(125Hz、500Hz、2KHz、8KHz、64KHz、128KHz),电路如图5.6.2所示。
图5.6.2CD4060构成的频率发生器
5.6.3任务实施
任务实施中分别给出测频法的实现程序和测周法的实现程序。
1、测频法程序实现
测频法程序的工程结构图如图5.6.3所示。
Seg7Display.c负责将测量的频率在数码管上显示,共6位数码管。
FreqMeasure.c是频率测量模块。
5.6.3测频程序工程结构图
(1)主函数
Main.c:
#include
#include"MicroDefine.h"
#include"Seg7Display.h"
#include"FreqMeasure.h"
/***************************************************************************
*函数名称:
main()
*功能:
主函数
*入口参数:
*出口参数:
*说明:
***************************************************************************/
voidmain()
{
uintCnt1Ms;//1ms计数器
DelayMs(200);
TimerInit();//定时器初始化
while
(1)
{
if(FlagSystem1Ms==1)
{
FlagSystem1Ms=0;
Seg7Display();//扫描数码管
}
}
if(++Cnt1Ms>=1000)//刷新显示缓冲区
{
Cnt1Ms=0;
FreqToBuffer(Freq);
}
}
}
}
(2)测频模块
FreqMeasure.h:
#ifndef_FREQMEASURE_H_
#define_FREQMEASRUE_H_
#include
#include"MicroDefine.h"
#include"Seg7Display.h"
//变量声明
externbitFlagSystem1Ms;//1ms时标信号
externlongintFreq;//测量频率值
externbitFlagMeasureOk;//频率测量成功标志位
//函数声明
externvoidFreqToBuffer(longintNum);//频率值更新到缓冲区
externvoidTimerInit(void);//定时器初始化
#endif
FreqMeasure.c
#include"FreqMeasure.h"
bitFlagSystem1Ms=0;//系统1ms时标信号
ucharT0OverflowCnt=0;//定时器0溢出次数计数器
longintFreq=0;//被测信号频率值
bitFlagMeasureOk=0;//频率测量成功标志位
/***************************************************************************
*函数名称:
TimerInit()
*功能:
定时器初始化
*入口参数:
无
*出口参数:
无
*说明:
定时器0用作计数,定时器1用作定时
***************************************************************************/
voidTimerInit(void)
{
TMOD=0x25;//定时器1:
0010,定时,方式2;定时器0:
0101,计数,方式1
TH0=TL0=0x00;//定时器0初值
TH1=TL1=56;//定时器1初值
ET0=ET1=EA=1;//开定时器中断
TR0=TR1=1;//开定时器
}
/***************************************************************************
*函数名称:
Num_To_DispBuff()
*功能:
待显示值传递给显示缓冲区
*入口参数:
待显示值
*出口参数:
无
*说明:
***************************************************************************/
voidFreqToBuffer(longintNum)
{
uchari,j=5;
for(i=0;i<6;i++)
{
DispBuffer[j-i]=Num%10;
Num=Num/10;
}
}
/***************************************************************************
*函数名称:
Timer0_Isr()
*功能:
定时器0中断函数
*入口参数:
无
*出口参数:
无
*说明:
计算定时器0溢出次数
***************************************************************************/
voidTimer0Isr()interrupt1
{
staticucharCnt200us=0;//200us计数器
staticuintCnt1Ms=0;//1ms计数器
uintTimer0Value;//定时器0暂存值
if(++Cnt200us>=4)//1ms到
{
Cnt200us=0;
FlagSystem1Ms=1;
if(++Cnt1Ms>=1000)//1s到
{
Cnt1Ms=0;
Timer0Value=TH0<<8+TL0;//取定时器0的计数值
TH0=TL0=0x00;//定时器0清空
Freq=T0OverflowCnt<<16+Timer0Value;//计算频率值
T0OverflowCnt=0;//定时器0溢出次数清零
FlagMeasureOk=1;//频率测量成功
}
}
}
程序解释:
①测频程序用到了2个定时/计数器,定时/计数器0用来对脉冲计数,16位计数器,方式1模式;定时/计数器1用来产生时基信号(1秒),8位定时器,方式2。
②在定时/计数器0的中断函数中,记录溢出次数,如果1S内外接脉冲个数超过65536,则定时/计数器0会溢出。
定时/计数器1主要用于产生1秒的时基信号,1秒到,则一次测频完成。
定时/计数器0的初值为0,如果定时/计数器0在1S内没有溢出,则外接脉冲的个数=TH0*256+TL0。
如果溢出了,则外接脉冲的个数=溢出次数*65536+TH0*256+TL0。
计算出频率值后,定时/计数器0的初值和溢出次数要重新置0,为下一次测频做准备,同时频率测量成功标志位置1。
刷新缓冲区函数中,频率值的分解和以前的写法不一样,初学者自己分析。
2、测周法程序实现
测周法的程序和测频法的程序结构一样,功能模块包括数码管扫描和周期测量。
数码管扫描省略。
(1)主函数
Main.c:
#include
#include"MicroDefine.h"
#include"MeasurePeriod.h"
#include"Seg7Display.h"
/***************************************************************************
*函数名称:
main()
*功能:
主函数
*入口参数:
无
*出口参数:
无
*说明:
****************************************************************************/
voidmain()
{
unsignedlongintFreq;
DelayMs(200);
TimerInit();//定时器初始化
while
(1)
{
if(FlagMeasureOk==1)//测量成功
{
FlagMeasureOk=0;
Freq=(unsignedlongint)T1Cnt*100+(T1Num-156);//100个脉冲的周期
Freq=1000000000/Freq;//换算成频率
FreqToBuffer(Freq);//刷新缓冲区
}
}
}
程序解释:
在主函数中,完成100个脉冲的周期计算,换算成频率,并更新缓冲区。
周期的计算在周期测量模块详细解释。
(2)周期测量模块
MeasurePeriod.h
#ifndef_MEASUREPERIOD_H_
#define_MEASUREPERIOD_H_
#include
#include"MicroDefine.h"
#include"Seg7Display.h"
//变量声明
externucharT1Num;//定时器1低八位暂存值
externuintT1Cnt;//定时器1溢出次数暂存值
externbitFlagMeasureOk;//周期测量完成标志位
externbitFlagSystem1Ms;//1ms时标信号
//函数声明
externvoidFreqToBuffer(unsignedlongintNum);//缓冲区刷新
externvoidTimerInit();//定时器初始化
#endif
MeasruePeriod.c:
#include"MeasurePeriod.h"
uintT1OverflowCnt=0;//定时器1溢出次数
ucharT1Num=0;//定时器1低八位暂存值
uintT1Cnt=0;//定时器1溢出次数暂存值
bitFlagMeasureOk=0;//周期测量完成标志位
bitFlagSystem1Ms=0;//系统时标信号
/***************************************************************************
*函数名称:
TimerInit()
*功能:
定时器初始化
*入口参数:
无
*出口参数:
无
*说明:
定时器0用作计数,定时器1用作定时
****************************************************************************/
voidTimerInit()
{
TMOD=0x26;//高四位:
0010,定时器1,定时模式,自动重装
//低四位:
0110,定时器0,计数模式,自动重装
TH0=TL0=156;//定时器0计数100次溢出
TH1=TL1=156;//定时器1100us溢出一次
ET0=ET1=1;
EA=1;
TR0=TR1=1;
}
/***************************************************************************
*函数名称:
FreqToBuffer()
*功能:
待显示值传递给显示缓冲区
*入口参数:
待显示值
*出口参数:
无
*说明:
***************************************************************************/
voidFreqToBuffer(unsignedlongintNum)
{
uchari,j=5;
for(i=0;i<6;i++)
{
DispBuffer[j-i]=Num%10;
Num=Num/10;
}
}
/***************************************************************************
*函数名称:
Timer0Isr()
*功能:
定时器0中断服务函数
*入口参数:
无
*出口参数:
无
*说明:
每100个脉冲,定时器0中断,记录定时器1的溢出次数和计数值
****************************************************************************/
voidTimer0Isr()interrupt1
{
T1Num=TL1;//记录定时器1的计数值
TL1=156;//定时器1赋初值
T1Cnt=T1OverflowCnt;//记录定时器1的溢出次数
T1OverflowCnt=0;//溢出次数清零
FlagMeasureOk=1;//周期测量完成标志位
}
/***************************************************************************
*函数名称:
Timer1Isr()
*功能:
定时器1中断服务函数
*入口参数:
无
*出口参数:
无
*说明:
100us溢出1次
****************************************************************************/
voidTimer1_Isr()interrupt3
{
staticucharCnt100us=0;//100us计数器
T1OverflowCnt++;//记录定时器1的溢出次数
if(++Cnt100us>=10)//1ms到
{
Cnt100us=0;
Seg7Display();//数码管扫描
}
}
程序解释:
①测周法与测频法一样,都用到了2个定时/计数器。
这两个定时/计数器都配置为自动重装模式,初值都为156,不同的是定时/计数器0是用来计脉冲个数的,作为计数器来使用,每100个脉冲(256-156=100),定时/计数器0会溢出,在其中断函数中,计算100个脉冲的累计周期。
定时/计数器1作为定时器来使用,100us溢出一次(单片机晶振为12M),在其中断函数中记录溢出次数,同时每间隔1ms,扫描数码管。
②在定时/计数器0的中断函数中,记录定时/计数器1的TL1值和定时/计数器1的溢出次数,然后把TL1复位到初值156,溢出次数清零,为一下次测量做准备,100个脉冲的周期=T1Cnt*100+(T1Num-156)。
最后,周期测量成功标志位置位,周期和频率的换算在main.c中完成。