0%

定时器/计数器的原理及使用

定时器计数器也可以简称定时器,是单片机内与CPU独立的一个硬件,是单片机的重点内容之一

CPU时序

  • 振荡周期:为单片机提供实时信号震荡源的周期(晶振周期或外加震荡周期);

    • 状态周期:两个振荡周期;
  • 机器周期:六个机器周期;

  • 指令周期:完成一条指令的全部时间,以机器周期为单位。

    当外接晶振频率为12M时:
    振荡周期:1/12M=1/12微秒
    状态周期:1/6us
    机器周期:1us
    指令周期:1~4us

51单片机定时器结构

定时器计数器实质是加1计数器(16位),由高八位和低8位两个寄存器组成,工作时先向低8位累加,加满后再向高8位累加,高8位溢出后发出中断信号。TMOD是工作方式寄存器,确定工作方式与功能,TCON是控制寄存器,前面已经讲过。
定时器结构

TMOD寄存器

TMOD是定时器计数器的工作方式寄存器,低四位控制定时器T0,高四位控制定时器T1。
TMOD寄存器

  • GATE:门控位,GATE=0,定时器计数器的启动与停止仅受TCON寄存器中的TR0/TR1,GATE=1时,受TR0/TR1与外部中断引脚(INT0/INT1)上的电平共同控制‘’
  • C/T:定时器模式和计数模式选择位,C/T=1为计数器模式,C/T=0为定时器模式;
  • M1M0:工作方式选择位,每个定时器都有四种工作方式,如下表:
M1M0 工作方式
00 方式0,为13位定时器计数器
01 方式1,16位定时器计数器
10 方式2,8位初值自动重装的8位定时器计数器
11 方式3,仅适用于T0,分成两个8位计数器,T1停止计数

定时器计数器工作方式

在这里我们以方式1为例。
定时器0方式1的逻辑结构如图:

定时器0方式1 逻辑结构

当GATE=0,TR0=1,低8位TL0在机器周期的作用下开始加1计数,当TL0计满后,向TH0进位,直到TH0也满,此事计数器溢出,TF0置1,向CPU请求中断。
那么如何让定时器定时自己想要的时间呢?
定时器每执行一次+1需要一个机器周期,即12个振荡周期,在时钟频率为12MHz的单片机中,1个机器周期为1us,那么计满计数器需要2^16个机器周期,大约65.5ms。如果我们要定时50ms,就要给TL0TH0装一个初值,在这个初值上加50000个数后,定时器计数器溢出,就是50ms中断一次。当需要1s中断一次时,我们只需要编写程序,使定时器产生20个50ms的中断后执行中断程序。
如何计算初值呢?
当我们要定时50ms,那初值应该是2^16-50000=15536。15536/256=60装入高8位,15536%256=176装入低8位。

定时器程序编写

使用定时器前需对寄存器进行初始化:

  1. 对TMOD赋值,确定T0/T1工作方式
  2. 计算初值,填入TH0/TL0;
  3. 对IE0赋值,开放中断;
  4. 使TR0/TR1置位,启动计数。

接着我们编写程序,目的是使第一个发光二极管以2s为周期闪烁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<reg52.h>

#define uchar unsigned char
#define uint unsigned int

sbit led=P2^0;
uint num=0;

void main(){
EA=1;
ET0=1;
led=0;
TR0=1;
TMOD=0x01;
TH0=0xFC;
TL0=0x18;
while(1);
}
void time0() interrupt 1{
TH0=0xFC;
TL0=0x18;
num++;
if(num==1000){
num=0;
led=~led;
}
}