第11章 实战练习二Word文件下载.docx
《第11章 实战练习二Word文件下载.docx》由会员分享,可在线阅读,更多相关《第11章 实战练习二Word文件下载.docx(34页珍藏版)》请在冰点文库上搜索。
在“AVR-51多功能实验开发板”的K区有一个方波信号源。
该区模块使用一个2.048MHz的晶体振荡器,经过CD4060的分频后,提供了占空比为50%,125Hz~128KHz之间10种不同频率的标准方波脉冲信号。
下面我们介绍2个基本的频率测量实例,实现对这些不同频率的信号进行测量。
11.1.2测频法测量频率
测频法的基本思想,就是采用在已知限定的时间内对被测信号输入的脉冲个数进行计数的方法来实现对信号频率的测量。
当被测信号的频率比较高时,采用这种方法比较适合,因为在一定时间内,频率越高,计数脉冲的个数也越多,测量也越准确。
例11.1采用测频法的频率计设计与实现
1)硬件电路
硬件电路的显示部分与图9-7相同,PA口为8个LED数码管的段输出,PC口控制8个LED数码管的位扫描。
使用T/C0对被测信号输入的脉冲个数进行计数,被测频率信号由PB0(T0)输入。
2)软件设计
我们首先给出系统程序,然后做必要的说明。
/*********************************************
Filename:
demo_11_1.c
Chiptype:
ATmega16
Programtype:
Application
Clockfrequency:
4.000000MHz
Memorymodel:
Small
ExternalSRAMsize:
0
DataStacksize:
256
*********************************************/
#include<
mega16.h>
flashcharled_7[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
flashcharposition[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
chardis_buff[8];
//显示缓冲区,存放要显示的8个字符的段码值
charposit;
bittime_1ms_ok,display_ok=0;
chartime0_old,time0_new,freq_time;
unsignedintfreq;
voiddisplay(void)//8位LED数码管动态扫描函数
{
PORTC=0xff;
PORTA=led_7[dis_buff[posit]];
if(posit==5)PORTA=PORTA|0x80;
PORTC=position[posit];
if(++posit>
=8)posit=0;
}
//Timer2outputcompareinterruptserviceroutine
interrupt[TIM2_COMP]voidtimer2_comp_isr(void)
time0_new=TCNT0;
//1ms到,记录当前T/C0的计数值
time_1ms_ok=1;
display_ok=~display_ok;
if(display_ok)display();
voidfreq_to_disbuff(void)//将频率值转化为BCD码并送入显示缓冲区
chari,j=7;
for(i=0;
i<
=4;
i++)
{
dis_buff[j-i]=freq%10;
freq=freq/10;
}
dis_buff[2]=freq;
voidmain(void)
chari;
DDRA=0xFF;
//LED数码管驱动
DDRC=0xFF;
//T/C0初始化,外部计数方式
TCCR0=0x06;
//外部T0脚下降沿触发计数,普通模式
TCNT0=0x00;
OCR0=0x00;
//T/C2初始化
TCCR2=0x0B;
//内部时钟,32分频(4M/32=125KHz),CTC模式
TCNT2=0x00;
OCR2=0x7C;
//OCR2=0x7C(124),(124+1)/125=1ms
TIMSK=0x80;
//允许T/C2比较匹配中断
for(i=0;
=7;
i++)dis_buff[i]=0;
time0_old=0;
#asm("
sei"
)//开放全局中断
while
(1)
if(time_1ms_ok)
{//累计T/C0的计数值
if(time0_new>
=time0_old)freq=freq+(time0_new-time0_old);
elsefreq=freq+(256-time0_old+time0_new);
time0_old=time0_new;
if(++freq_time>
=100)
{
freq_time=0;
//100ms到,
freq_to_disbuff();
//将100ms内的脉冲计数值送显示
freq=0;
}
time_1ms_ok=0;
}
};
程序中LED扫描形式函数desplay(),以及脉冲计数值转换成BCD码并送显示缓冲区函数freq_to_disbuff()比较简单,请读者自己分析。
在该程序中,使用了两个定时计数器。
T/C0工作在计数器方式,对外部T0引脚输入的脉冲信号计数(下降沿触发)。
T/C2工作在CTC方式,每隔1ms中断一次,该定时时间即作为LED的显示扫描,同时也是限定时间的基时。
每一次T/C2的中断中,都首先记录下T/C0寄存器TCNT0当前的计数值,因此前后两次TCNT0的差值(time0_new–time0_old)或(256-time0_old+time0_new)就是1ms时间内T0脚输入的脉冲个数。
为了提高测量精度,程序对100个1ms的脉冲个数进行了累计(在变量freq中),即已知限定的时间为100ms。
读者还应该注意频率的连续测量与LED扫描、BCD码转换之间的协调问题。
T/C2中断间隔为1ms,因此在1ms时间内,程序必须将脉冲个数进行的累计、BCD码转换和送入显示缓冲区,以及LED的扫描工作完成掉,否则就会影响到下一次中断到来后的处理。
在本实例的T/C2中断中,使用了display_ok标志,将LED扫描分配在奇数ms(1、3、5、7、……),而将1ms的TCNT0差值计算、累积和转换等处理放在主程序中完成。
另外由于计算量大的BCD码转换是在偶数ms(100ms)处理,所以程序中LED的扫描处理和BCD码转换处理不会同时进行(不会在两次中断间隔的1ms内同时处理LED扫描和BCD码转换),这就保证了在下一次中断到达时,前一次的处理已经全部完成,使频率的连续测量不受影响。
该实例程序的性能和指标为(假定系统时钟没有误差=4MHz):
✓频率测量绝对误差:
±
10Hz。
由于限定的时间为100ms,而且T/C0的计数值有±
1的误差,换算成频率为±
✓被测最高频率值:
255KHz。
由于T/C0的长度8位,所以在1ms中,TO输入的脉冲个数应小于255个,大于255后造成T/C0的自动清另,丢失脉冲个数。
✓测量频度:
10次/秒。
限定的时间为100ms,连续测量,所以为10次/秒。
✓使用资源:
两个定时器,一个中断。
3)思考与实践
根据上面采用测频法的思路,如何修改程序提高测量精度和被测最高频率?
参考提示如下:
✓延长限定的时间,如采用1s,可提高频率的测量精度。
但测量频度减小,同时注意变量freq应定义为长整型变量。
✓将T/C0换成16位的T/C1,可以提高被测最高频率值。
注意此时time0_new、time0_old应定义为整型变量。
11.1.3测周法测量频率
测周法的基本思想,就是测量在限定的脉冲个数之间的时间间隔,然后再换算成频率(需要时)。
当被测信号的频率比较低时,采用这种方法比较适合,因为频率越低,在限定的脉冲个数之间的时间间隔也也长,因此定时计数的个数也越多,测量也越准确。
例11.2采用测周法的频率计设计与实现
被测频率信号由PB0(T0)输入。
demo_11_2.c
//显示缓冲区,存放要显示的8个字符的段码值
bitfreq_ok=0;
chartime2_new;
unsignedintfreq;
unsignedlongintfreq_temp;
voiddisplay(void)//8位LED数码管动态扫描函数
PORTC=0xff;
PORTA=led_7[dis_buff[posit]];
if(posit==5)PORTA=PORTA|0x80;
PORTC=position[posit];
if(++posit>
//T/C0比较匹配中断服务,250个计数脉冲中断一次
interrupt[TIM0_COMP]voidtimer0_comp_isr(void)
time2_new=TCNT2;
TCNT2=0;
TIFR|=0x02;
freq_temp=freq;
freq=0;
freq_ok=1;
//T/C2比较匹配中断服务,500us一次
freq++;
#asm("
)//开中断,允许中断嵌套,T/C0中断可打断该中断服务
display();
voidfreq_to_disbuff(void)//频率值转化为BCD码送显示缓冲区
chari,j=7;
for(i=0;
{
dis_buff[j-i]=freq_temp%10;
freq_temp=freq_temp/10;
}
chari;
//LED数码管
//T/C2初始化
TCCR2=0x0A;
//内部时钟,8分频(4M/8=500KHz),CTC模式,
//基时为2us
OCR2=0xF9;
//OCR2=0xF9(249),(249+1)/500=0.5ms
//T/C0初始化
TCCR0=0x0E;
//外部T0脚下降沿触发计数,CTC模式
OCR0=0xF9;
//OCR0=0xF9(249),(249+1)=250
TIMSK=0x82;
//允许T/C2、T/C0比较匹配中断
i++)dis_buff[i]=0;
)//开放全局中断
if(freq_ok)
freq_temp=freq_temp*250+time2_new;
//累计250个脉冲的时间间隔
freq_temp=12500000000/freq_temp;
//换算成频率
freq_to_disbuff();
//频率值送显示
freq_ok=0;
};
在该程序中,同样使用了两个定时计数器。
T/C2仍旧工作在CTC方式,每隔500us中断一次,该定时时间即作为LED的显示扫描,同时也用于时间累计。
在每一次T/C2的中断中,将累计中断的次数(在freq中),然后马上开放全局中断(由于在进入T/C0中断时,系统硬件已经自动关闭了全局中断允许),保证系统能及时响应T/C0的中断。
该程序的核心是T/C0的中断。
T/C0工作在CTC方式,它负责对外部T0引脚输入的脉冲信号计数(下降沿触发),一旦计数值(限定脉冲个数)到达250产生中断。
进入T/C0中断后,立即记录当前T/C2寄存器TCNT2的值(在time2_new中),然后清零TCNT2和T/C2的中断标志位,为下一次计时做初始化准备。
接下来同样需要把T/C2产生中断的次数累计值备份到freq_temp中,此时变量freq_temp和time2_new中的值就是T0输入的250个限定脉冲之间的时间间隔。
当T/C0中断产生后,系统应该立即响应,马上读取T/C2的值。
由于T/C2的计时过程不会停止,所以拖延T/CO中断的响应时间就会影响测量的精度。
因此需要把T/C2的中断服务程序设计成能够支持中断嵌套的方式,使系统尽可能的立即响应T/C0中断。
计算250个限定脉冲之间的时间间隔是在主程序中完成的。
计算公式为:
250个脉冲之间的时间间隔=T/C2中断次数*250+T/C2当前值(计时时基个数);
1计时时基个数=2us(注:
T/C2计时时基=4M/8)。
换算成频率值:
1000000/(250个脉冲之间的时间间隔*2us/250)*100=12500000000/250个脉冲之间的时间间隔,单位为Hz。
乘上100是为了保留2位小数。
程序中全部使用了整数运算,它比采用浮点数运算的速度要快的多,同时也保证了在T/C0两次中断的间隔中,能全部完成频率换算、LED扫描等处理任务,不造成对频率连续测量的影响。
✓周期测量绝对误差为±
(2us/250)。
如果不考虑中断响应时间的影响,由于T/C2的计数值有±
1的误差,所以周期测量绝对误差为±
如果考虑中断响应时间的影响时,周期测量绝对误差在±
(2~5/250)us。
✓被测最低频率值为8Hz。
考虑freq的长度为16位,最大计数值为65535,所以可以记录的250个脉冲之间的时间间隔最大为65535*250*2us=32767500us。
那么最长1个脉冲周期为32767500us/250=131070us,换算成频率为1/131070=7.63Hz。
与被测频率有关。
如被测频率为125Hz,测量频度=1次/2秒;
被测频率为250Hz,测量频度=1次/秒;
被测频率为2K,测量频度=8次/秒。
两个定时器,两个中断,其中一个支持中断嵌套。
下面我们进一步讨论测量的精度问题,在测频法中,由于频率测量的绝对误差是±
10Hz,因此被测频率越高(仅受系统时钟限制),测量精度也就越好,这一点是明显的。
而在测周法中,由于其周期测量绝对误差是固定的,因此被测频率越低,精度越好。
这一特点不容易直接看出,我们以测量1K频率和4K频率为例,分别计算出它们的精度结果,并进行比较。
首先我们取测周法的周期测量绝对误差为±
(2us/250),即±
0.008us。
对于1K频率,其标准周期为1000us。
考虑测量误差:
1000.008us~999.992us,对应频率为:
999.992Hz~1000.008Hz,有效位数为6位。
而对于4K频率,其标准周期为250us。
250.008us~249.992us,对应频率为:
3999.872Hz~4000.128Hz,此时有效位数降为5位了。
可见,当被测频率越高时,有效位数越少,测量的精度也越差了。
11.1.4频率测量小结
以上我们介绍了两种频率的测量方法,通过分析我们知道,频率的测量还是比较复杂的。
如果设计制作一个频率计,要能满足在被测频率范围比较宽,变化大时使用的话,单一的使用某一种测量方法都是不能达到需要的。
所以,一个完善的频率计,要设计一个智能的测量过程,即其系统程序能够根据每次的测试数据,自动转换使用正确的测量方法,以及能够自动调节限定的时间(测频法),或调节限定脉冲数(测周法),或调整计时的时间基时等。
这样经过几次自动的调整后,系统测出的频率达到最高的测量精度。
此外,上面的频率测量方法都必须占用MCU的2个硬件资源,这也是一般单片机测频所采用的方法(或采用1个T/C加1个外部中断,同样占用2个硬件资源)。
AVR单片机的T/C1增加了捕捉功能,利用该功能进行频率的测量时,不但只需要使用1个硬件资源T/C1就能完成周期的测量,而且还能获得更好的测量的精度。
11.2基于T/C1捕捉功能实现高精度的周期测量
在第8章第4节中我们介绍了AVR定时计数器的一个非常有特点的功能――T/C1的输入捕捉功能。
该功能可以应用于精确捕捉一个外部事件的发生,记录事件发生的时间印记(Time-stamp)。
当一个输入捕捉事件发生,如外部引脚ICP1上的逻辑电平变化时,T/C1计数器TCNT1中的计数值被实时的写入到输入捕捉寄存器ICR1中,并置位输入捕获标志位ICF1,产生中断申请。
因此,利用输入捕捉功能可以实现对周期的精确测量。
采用输入捕捉功能进行精确周期测量的基本原理比较简单,实际上就是将被测信号作为ICP1的输入,被测信号的上升(下降)沿作为输入捕捉的触发信号。
T/C1工作在常规计数器方式,对设定的已知系统时钟脉冲进行计数。
在计数器正常工作过程中,一旦ICP1上的输入信号由低变高(假定上升沿触发输入捕捉事件)时,TCNT1的计数值被同步复制到了寄存器ICR1中。
换句话将,当每一次ICP1输入信号由低变高时,TCNT1的计数值都会再次同步复制到ICR1中。
如果能及时的将两次连续的ICR1中数据记录下来,那么2次ICR1的差值乘上已知的计数器计数脉冲的周期就是输入信号一个周期的时间。
由于在整个过程中,计数器的计数工作没有受到任何影响,捕捉事件发生的时间印记也是由硬件自动同步复制到ICR1中的,因此所得到的周期值是非常精确的。
下面,我们把“AVR-51多功能实验开发板”K区提供有占空比为50%、125Hz~128KHz之间10种不同频率的标准方波脉冲信号作为被测信号源,给出仅采用一个T/C1,配合输入捕捉功能的应用,实现一个高精度的周期(频率)测试计的设计应用。
例11.3基于T/C1捕捉功能的可变量程频率计的设计与实现
图11-1基于T/C1捕捉功能的可变量程频率计电路图
本例的硬件电路如图11-1所示,PA口为6个LED数码管的段输出,PC口是6个LED数码管的位扫描控制口。
6位LED构成频率计的结果显示。
被测脉冲信号由ICP1(PD6)输入。
需要注意的是,为了提高测量的精度,系统时钟应该采用外部晶体,同时系统时钟频率原则上越高越好。
本例中采用外部4M晶体,因此系统时钟频率为4M,周期为0.25us(图中未画出外部晶体部分的电路和8个段限流电阻)。
尽管采用输入捕捉功能进行精确周期测量的基本原理比较简单,但是实际实现起来却不是那么简单的。
因为系统中需要LED扫描显示,频率值的换算也需要大量的计算,而且在系统的运行的过程中,还必须确保T/C1每次捕捉中断产生后马上把寄存器ICR1中的时间印记读出,以及T/C1计数过程是否溢