MEGA16定时器0
T/C0 是一个八位定时器,主要有定时、外部事件计数、产生PWM波形这几个功能,我们在使用这些功能之前,首先要设置T/C0 工作在合适的工作模式下。T/C0 有四种工作模式,分别是普通模式、CTC模式、快速PWM、相位可调的PWM 模式四种。模式设置通过T/C0 的控制寄存器TCCR0 来完成。
1.普通模式
在此模式下,T/C0 的计数寄存器TCNT0 在时钟的驱动下不停累加。当计满后(计数值达到最大,8 位寄存器最大
计数值为0xff),由于数值的溢出寄存器清零重新开始累加。当计数器溢出后,TIFR 中的溢出标志位TOV0 会置
位,也可触发中断。所以我们可以通过查询或中断的方式得知定时器的溢出从而进行相关处理。此模式适合定时
与计数。关于定时和计数,这里的定时功能是T/C0 在对时钟计数达到一定的值后引发中断,达到了定时功能,
然而本质的过程是计数工作。那么这里所说的计数功能是外部事件计数。
实例:T/C0 定时实验,将T/C0 设置为普通模式,对1024 分频的系统时钟进行计数,计满发生中断,40 次中断
递增一个计数用的变量,主函数则不停显示这个变量。
第一步:开总中断,SREG |= 0X80;
第二步:开T/C0 溢出中断
第三步:模式设置、分频设置、匹配输出模式设置
T/C0 控制寄存器用于设置工作模式,时钟分频和波形输出模式。这里T/C0设置为普通模式,WGM00-WGM01
设置为00。此模式下定时器的TOP 值,也就是能够达到的最大计数值为0xFF。TOV0 在计数器计满后置位,也
就是计到MAX,八位的定时器计数达到255 为计满。
低三位设置定时器时钟。T/C0在系统时钟的分频或外部时钟的驱动下递增或递减。系统时钟也就是晶振的大小
是11.0592MHZ。此实验中,设置为1024 分频。11.0592MHZ 的周期是其倒数,那么1024分频后的时钟周期就
是1024*(1/11.0592),大约等于92.6。单位是微秒,一秒等于十的六次方微秒。定时器在此时钟的一个周期内增
一,也就是92.6us 增加一次,计满需要255 个时钟周期,也就是说计满需要23613us 左右,从而定时器中断一次时间为23ms左右。时钟也可以从T0 引脚输入,T0 为PB0 第二功能,此情况一般用于外部事件计数。
匹配输出模式:
T/C0 可以用作波形输出,那么OC0 就是其波形输出引脚,是PB3 引脚第二功能。波形输出功能可以使用芯片成
为波形发生器,可以驱动外围部件,比如常用的电机的驱动,也可以作为外部器件的时钟。普通模式下一般不使
用此功能,效率不是很高,所以这里不使用此功能,设置为COM01-COM00 为00。
综上所述:TCCR0 的设置为0B00000101,也就是0x05,FOC0 为强制匹配位,仅在非PWM 模式下有效,也就
是CTC 模式和普通模式,定时器在工作时,对该位写‘1’会产生匹配,但是这种匹配只更新OC0 引脚的输出。
PWM 模式下写TCCR0 时,为了保证与未来器件兼容,要对其写0。关于匹配的概念,会在CTC 模式中讲解,
在讲解普通模式和CTC 模式时,强制匹配功能都未使用,设置控制寄存器时也应写入0。
#include "avr16.h"
unsigned int num_a;
unsigned int num_b;
void Display(short int num);
#pragma interrupt_handler fun_timer0_ov:10
(中断号可以从中断一章的图中查询)
void fun_timer0_ov(void)
{
if(num_a++ > 40)
{
num_a=0;
num_b++;
if(num_b==20) (20s后显示清零,重新开始)
num_b=0;
}
}
void main()
{
num_a=0;
num_b=0;
DDRB = 0XFF;
DDRD = 0XFF; //设置为输出
CLR_PORTD(BUZZER); //关蜂鸣器
SREG|=0X80; //开总中断
TIMSK|=0x01; //开溢出中断
TCCR0 = 0X05; //普通模式/1024分频/OC0不连接
while(TRUE)
{
Display(num_b);
}
}
2.CTC 模式
此模式下,TCNT0 计数达到匹配寄存器OCR0 设置的值后清零,匹配就是说两者值相等。可以看出,和普通模
式的区别就是计数能够达到的最大值可以改变,注意不是上限值。这种模式便于我们控制输出波形的频率。匹配
后TIFR 寄存器的匹配标志位OCF0 置位,可以通过中断或查询的方法得知匹配事件发生,从而进行相关处理。
实例:T/C0 定时器CTC 模式实验
这个例子和上一小节的实验没有多大出入,只是采用了OCR0 匹配,匹配值120,num_a 上限改成100,也是秒
计数器。
第一步:开总中断
第二步:开匹配中断
此模式下,通常设置的匹配值是小于计数上限的,就无法产生溢出中断,所以要使用匹配中断。
TIMSK|=(1<<1);
第三步:模式设置、时钟设置、匹配输出模式设置
模式设置:设置为CTC 模式,此模式下TOP 值为OCR0 的值,TOV0 在计数达到MAX 置位。OCR0 立即更新,
意思是在定时器工作过程中我们修改了OCR0 的值,OCR0 就会立即更新。通常在中断程序中更新这个值,建议
不要将此值更新为和BOTTOM 接近的值,BOTTOM 是寄存器能够达到的最小值,一般为0。如果更新的值过于
接近BOTTOM,有可能写入的OCR0 的值小于当前TCNT0 的值,这样将失去一次匹配机会,定时器将计满后
清零,然而在PWM 模式下可以不关心这一点,因为PWM 模式下OCR0 是双缓冲。
时钟设置:1024 分频
匹配输出模式:
COM01-COM00 位可以设置当匹配发生时管脚OC0 的动作,从而在OC0 上产生特定的波形。
要使用波形输出,首先将OC0 端口的方向设置为输出。
#include "avr16.h"
unsigned int num_a;
unsigned int num_b;
//动态显示函数
void Display(short int num);
#pragma interrupt_handler fun_timer0_ov:20
(中断号可在中断一章的图中查询)
void fun_timer0_ov(void)
{
if(num_a++ > 100)
{
num_a=0;
num_b++;
if(num_b==20)
num_b=0;
}
}
void main()
{
num_a=0;
num_b=0;
DDRB = 0XFF;
DDRD = 0XFF; //设置为输出
CLR_PORTD(BUZZER); //关蜂鸣器
SREG|=0X80; //开总中断
TIMSK|=(1<<1); //开匹配中断
OCR0 = 0x78; //十进制120
TCCR0 = 0X0D; //CTC模式/1024分频/OC0不连接
while(TRUE)
{
Display(num_b);
}
}
3.快速PWM 模式
PWM,Pulse Width Modulation,意即脉冲宽度可调。此模式下可输出脉宽可调的波形,占空比可调。定时器从
BOTTOM 开始计数,通常是0,然后计满后清零重新开始。通过设置匹配输出模式,当定时器与OCR0 匹配时,
OC0 管脚发生相应变化。
这种模式采用的是单斜坡工作方式,因为定时器从0 开始计数,计满后一下回到0。
快速PWM 模式的OCR0 不会立即更新,因为它采用的是双缓冲,我们可以随时修改OCR0,修改OCR0的时候只是将值保存在了缓冲用的OCR0 中,这样可以避免输出错误的波形。输出波形频率公式:
F=Fclk/(n*256)
n是变频因子,另外在使用OC0作为波形输出时,首先要设置其方向为输出。
设置OC0 管脚为输出。
4.相位修正的PWM 模式
此模式下定时器重复得从BOTTOM 计数达到MAX,然后又从MAX 倒退返回到BOTTOM。那么OC0 的输出将
在第一个上升斜坡匹配时变化一次,在第二个下降斜坡匹配时变化一次。
此模式也是使用双缓冲的OCR0。可以看出相位修正模式和快速PWM模式在相同的时钟驱动下,相位修正模式
输出的波形频率更低一些。因为快速PWM 模式下,一个时钟周期内OC0 可以发生两次电平变化,而相位修正
模式只能变化一次。此模式下也可以使用溢出中断与匹配中断,相关实验代码大家可参考上一小节的参考代码进
行修改。
关于T/C0 定时器的四种模式就介绍到这里,最后还要注意一些地方。CPU 对读写TCNT0 有较高的优先级,在
任何模式下写TCNT0 都会在下一个时钟周期内阻止比较匹配,所以将TCNTO 设置为与0CR0 相等的值,都会
失去一次匹配的机会,造成不正确的波形。