URL: http://blog.csdn.net/liming0931/article/details/7517747
http://blog.csdn.net/desert2009sz/article/details/6903443
定时计数器2是一个16位定时/计数器,通过T2CON寄存器的C/T2位可以选择定时还是计数功能。定时器2 有3种操作模式:捕获、自动重新装载(递增或递减计数)和波特率发生器,这3种模式由T2CON 中的位进行选择,具体的选择方式见表1。定时器2有两个8为寄存器:TH2和TL2。在定时模式状态下,TL2寄存器每一个机器周期加1,。由于52单片机的每一个机器周期等于12的振荡周期,所以他的计数频率是振荡频率的1/12。
表1
RCLK+TCLK |
CP/RL2 |
TR2 |
MODE |
0 |
0 |
1 |
16位自重载 |
0 |
1 |
1 |
16位捕获 |
1 |
X |
1 |
波特率发生器 |
X |
X |
0 |
关 |
在计数状态下,外部引脚由1-0的负跳变是,寄存器就加1。并且在这种情况下,每当一个机器周期的S5P2的时科,单片机就对外部引脚进行采样,如果在下一个周期里信号变为低电平,则计数器加1。在下一个周期的S3P1时刻,若检测到有跳变,则计数器计数加1。识别1-0的跳变需要两个机器周期(24个振荡周期),所以计数信号的最大的频率只能是振荡频率的1/24。为了确保采样频率能够被采样,被采用的电平必须保持一个机器周期不变。
1、 捕获模式
在捕获模式,寄存器T2CON的位EXEN2有两方式可供选择:
若EXEN2=0,定时器2为16位定时/计数器,当计数溢出是,T2CON中的TF2置1,并向CPU申请中断;
若EXEN2=1,定时器2出来拥有和上述一样的功能外,还有捕获功能:即在引脚T2EX有1-0跳变的时候,RCAP2H和RCAP2L分别捕获并保存TH2和TL2的当前值(即RCAP2H=TH2,RCAP2L=TL2),另外T2EX脚的跳变也会使T2CON寄存器里的位EXF2值1,和TF2一样向CPU申请中断。
2、 自重载模式(递增/递减计数器)
定时器2可以设置为递增/递减自动重载计数器,并通过DCEN(Down Counter Enable)位来控制其模式。见表2,一旦CPU复位,DCEN被清0,意味着定时器2默认是递增计数器,当DCEN置为1时,允许定时器2递增或递减计数,由T2EX的电平来控制器计数方向。
表1
T2MOD Address = 0C9H Reset Value = XXXX XX00B |
|||||||||
Not Bit Address |
|||||||||
Bit |
- |
- |
- |
- |
- |
- |
T2OE |
DCEN |
|
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
||
Symbol |
Function |
||||||||
- |
保留 |
||||||||
T2OE |
定时器2输出使能 |
||||||||
DCEN |
DCEN=1,允许定时器2递增或递减计数 |
图1 T2捕获原理图
图2所示为定时器2自动递增模式(DCEN=0)原理图。在这种模式下由T2CON中的EXEN位选择。
当EXEN=0;当计数器向上计数到0FFFFH是就会置位溢出标志位TF2,此时,寄存器RCAP2H和RCAP2L的值会自动装载到寄存器TH2和TL2中。寄存器RCAP2H和RCAP2L的值有软件预设。
当EXEN=1;16位重载可由两个方式触发:计数溢出或T2EX引脚的负跳变。同时置位EXF2为1。在中断允许的条件下,TF2和EXTF2都可以触发中断。
图2 T2自重载模式(DCEN=0)原理图
当DCEN为1时,允许定时器2递增计数或者递减计数,就如图2所示。在这种模式下,T2EX引脚控制计数的方向。
T2EX若为逻辑“1”,定时器2递增计数,直到0FFFFH是计数器溢出,置位TF2为1,同时溢出之后,寄存器RCAP2H和RCAP2L的值会自动装载到寄存器TH2和TL2中。
T2EX若为逻辑“0”,定时器2递减计数,当寄存器TH2和TL2的值分别和寄存器RCAP2H和RCAP2L的值相等时,计数器向下溢出,同时立即置位TF2,并把定时计数器赋值为0FFFFH。
//The EXF2 bit toggles wheneverTimer 2 overflows or underflows and can be used as a 17th bit of resolution. Inthis operating mode, EXF2 does not flag an interrupt.
// (这段话不好翻译)
本文是关于52单片机定时器计数器2做为普通的16位自动重装定时器使用,类似于定时器计数器0和定时器计数器1工作在方式1下。以下程序在Keil 2和Keil 3下调时通过,下载在本校的实验板上达到预期效果。AT89C52及其以上、AT89S52及其以上、STC89C52及其以上测试正常运行。
/***********************************************************
程序功能:52系列单片机定时器计数器2使用
程序设计:燕山大学 鲁信琼
晶振选择:24MHz, 如果晶振不匹配,请修改延时函数参数;P2^6口接数码管段选控制位; P2^7口接数码管位选控制位; P1^7口作为测试指示灯
本实验注意事项:
1. 定时器2的中断使能为IE^6位,也就是ET2; 中断服务程序标号为5。
2. 定时器2工作在16为自动重装模式下,不需要在中断服务程序中重新赋初值,在程序初始化的时候我们应该给RCAP2L和RCAP2H赋值,TH2和TL2将会在中断产生时自动使TH2=RCAP2H,TL2=RCAP2L。
3. 定时器2的中断标志位TF2不能够由硬件清零,所以要在中断服务程序中将其清零,为了使定时尽量准确,我们常在终端服务程序中第一步就使TF2=0。
4. 使定时器2产生中断的有两个中断源,如果EXEN2(定时器2外部使能标志)置1的话,使定时器2进入中断的有可能是定时器2计数溢出,也可能是捕获到T2EX(单片机P1^1口)有负跳变,所以需要在中断服务程序中判断EXF2是否为1。
承接51单片机、PIC单片机程序、VB/VC++上位机程序、电子产品软硬件设计开发工作
EMail: xqlu(at)ysu.net.cn QQ: 9790335
***********************************************************/
#include
#include
#define uchar unsigned char
#define uint unsigned int
#define LED_DATA P0
sbit DULA=P2^6;
sbit WELA=P2^7;
sbit LED=P1^7;
uchar timer2_ctr,num;
uchar code table[]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x40, 0};
//24MHz晶振延时x毫秒函数
void delay_ms(uint xms)
{
uint x,y;
for(x=xms; x>0; x--)
for(y=248; y>0; y--);
}
//初始化主函数
void init_main()
{
DULA=0; //关闭数码管显示
WELA=0;
RCAP2H=(0xFFFF-50000)/256;
RCAP2L=(0xFFFF-50000)%256; //24MHz晶振下定时25ms,自动重装
TH2=RCAP2H;
TL2=RCAP2L; //定时器2赋初值
T2CON=0; //配置定时器2控制寄存器,这里其实不用配置,T2CON上电默认就是0,这里赋值只是为了演示这个寄存器的配置
T2MOD=0; //配置定时器2工作模式寄存器,这里其实不用配置,T2MOD上电默认就是0,这里赋值只是为了演示这个寄存器的配置
IE=0xA0; //1010 0000开总中断,开外定时器2中断,可按位操作:EA=1; ET2=1;
TR2=1; //启动定时器2
}
//数码管显示3位数:0-255
void display(uchar num)
{
uchar gw,sw,bw;
bw=num/100;
sw=num%100/10;
gw=num%10;
LED_DATA=0XFE; //1111 1110
WELA=1;
_nop_();_nop_();
WELA=0;
LED_DATA=table[bw];
DULA=1;
_nop_();_nop_();
DULA=0;
delay_ms(3);
LED_DATA=0XFD; //1111 1101
WELA=1;
_nop_();_nop_();
WELA=0;
LED_DATA=table[sw];
DULA=1;
_nop_();_nop_();
DULA=0;
delay_ms(3);
LED_DATA=0XFB; //1111 1011
WELA=1;
_nop_();_nop_();
WELA=0;
LED_DATA=table[gw];
DULA=1;
_nop_();_nop_();
DULA=0;
delay_ms(3);
}
void main()
{
init_main();
while(1)
{
display(num);
}
}
void timer2() interrupt 5
{
//!!!注意!!! 定时器2必须由软件对溢出标志位清零,硬件不能清零,这里与定时器0和定时器1不同!!!
TF2=0;
timer2_ctr++;
//定时25ms×40=1000ms即1秒钟,这里模拟一个60秒秒表
if(timer2_ctr>=40)
{
timer2_ctr=0;
LED=~LED;
num++;
if(num>=60)
{
num=0;
}
}
}