本文简单阐述了怎么使用51的定时器/计数器。
如果不在意细节,可以直接看“五、应用实例”。
一、原理(简略)
定时器/计数器实质是加1计数器,该计数器由两个寄存器存储着计数的值(每一个有8位),将其称之为高8位、低8位寄存器;意即高8位、低8位的数值总和即为计数总和。
当高8位、低8位寄存器全满时(即16位全为1,等同于216),若再计数一次,定时器/计数器会产生一次“溢出”,将高8位、低8位寄存器清0,并向单片机发生中断请求。所以只要设定了寄存器的初值,就可以控制啥时候溢出了。
然而,什么时候计数一次呢?脉冲下降沿。而脉冲有两个来源:一是系统的时钟振荡器,二是T0或T1引脚输入的外部脉冲源。一般情况下,使用系统的时钟源即可满足需求。
二、寄存器
1.控制寄存器TCON
位: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
字节地址:88H | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
各标志位功能如下:(仅讲4位与定时器有关的)
- TF1——定时器1的溢出标志位。当加1计数器达到最大值时,则在下一次脉冲时产生溢出,此时由硬件将TF1置1,发出中断请求;响应中断后,该位由硬件清0。【注:软件也可以对它进行操作】
- TR1——定时器1的运行控制位。设定为1时,定时器开始工作;为0时,定时器停止工作。
- TF0、TR0——分别是定时器0的溢出标志位、运行控制位,功能与上述相同。
2.工作方式寄存器TMOD
位: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
字节地址:89H | GATE | C/T | M1 | M0 | GATE | C/T | M1 | M0 |
各标志位功能如下:(低4位控制T0,高4位控制T1;此处仅以高4位为例)
- GATE——门控位。设定为0时,定时器/计数器T1的运行启动仅受TCON的TR1控制;为1时,不但需要TR1=1,还需要外部引脚INT0=1。
- C/T——工作模式选择位。设定为0时,T1是定时器;为1时,T1是计数器。
- M1、M0——工作方式控制位。设定为00,对应方式0;为01,则方式1;为10,则方式2;为11,则方式3。
3.加1计数器的寄存器THx和TLx
- TH0、TL0是T0的计数器,TH1、TL1是T1的计数器。TH是高8位,TL是低8位。
- 当我们需要设定初值时,就可以对THx和TLx进行赋值,而后定时器/计数器会从这个值开始累加,直至216。
三、如何设定初值
由于常使用工作方式1,所以下面以T0为例,展示在工作方式1的情况下如何设定初值。
-
计数器模式:
设初值为X、计算次数为M,则
X = 65536 − M X=65536-M X=65536−M -
定时器模式:
设初值为X、定时为t微秒,时钟频率为f MHz、时钟周期为T微秒(12分频后,T=12/f),则
X = 65536 − t / T = 65536 − t ∗ f / 12 X=65536-t/T=65536-t*f/12 X=65536−t/T=65536−t∗f/12
放入数值:
//提示:2的8次方等于256
TH0=X/256;
TL0=X%256;
四、定时器/计数器的编程(使用中断)
初始化
//使用T1
TMOD=0x10; //GATE=0,C/T=0,工作方式为1
赋初值
//想要计数50000次,则设定初值为15536
TH1=15536/256;
TL1=15536%256;
开中断
EA=1; //总中断
EX0=1; //开定时器中断
TR1=1; //使能定时器
写中断服务程序
void time() interrupt 1 //1是定时器T0中断序号
{
write something
}
五、应用实例
利用中断、定时器,实现精准延时1s和延时t s,让LED每2s取反一次:
/*功能:通过中断延时,令LED1的闪烁间隔为2s。(使用T0)*/
#include <reg52.h>
#define uint unsigned int
sbit led1=P1^0;
uint num=0;
/**函数功能:精准延时1s**/
void delay_1s(){
while(num<=20);
num=0;
}
/**函数功能:精准延时。单位:s**/
void delay(uint t){
while(num<=20*t);
num=0;
}
/**函数功能:初始化T0**/
void init_T0(){
TMOD=0x01; //受TR0控制、定时器、方式1
//想要计数50000次,则设定初值为19456(f=11.059)
TH0=19456/256;
TL0=19456%256;
}
void main()
{
init_T0();
led1=0;
EA=1; //开总中断
ET0=1; //开定时器中断
TR0=1; //使能定时器
while(1){
delay(1);
delay_1s();
led1=~led1;
}
}
void time() interrupt 1 //T0中断序号为1
{
num++;
}