我们在了解八位数码管的时候,提到了定时器的概念,因为后面很多情况都会涉及到,所以就来认真学习一下啦
基本介绍
MCS51系列的单片机通常有2个16位可编程定时/计数器,即定时器0和1
(MCS52系列还有一个定时/计数器2)
- 可编程的意思是指其功能(如工作模式、定时时间、启动方式等)可由指令来确定和改变。通常都是赋值指令给相关的寄存器。
- 与定时/计数器相关的有两个特殊功能寄存器(模式控制寄存器TMOD和控制寄存器TCON)。且定时器往往在中断中使用,以便当时间到了完成相应处理
MCS51单片机定时/计数器工作原理示意图
联系该图,我们可以看到
定时器
- 每个16位定时/寄存器又分别由两个8位专用寄存器组成
e.g.TH0、TL0(对应定时器0),其访问地址为8AH-8CH - 它们可单独访问,主要用于装载定时或计数的初始值
正常工作前提
需要先设置好8位模式控制寄存器TMOD(89H)和8位控制寄存器TCON(88H)
- TMOD主要用于设定定时/计数器的工作模式
- TCON主要用于控制定时/计数器的启动/停止,保存T0、T1的溢出和中断标志
(当定时器工作在计数方式时,外部事件可通过引脚P3^4 (对应T0)或P3^5(对应T1)进行输入)
工作原理
实质:加1计数器
当定时器/计数器为定时工作方式时,计数器的加1信号由振荡器的12分频信号产生;每过一个机器周期,计数器加1,直至计满溢出为止
(定时器的定时时间与系统的振荡频率有关)
计数周期
一个机器周期等于12个振荡周期
所以计数频率fcount=1/12osc
如果晶振为12MHz,则计数周期为:T=1/(12×106)Hz×1/12=1μs
这是最短计数周期
补充:
- 当CPU用软件给定时器设置了某种工作方式之后,定时器就会按设定的工作方式独立运行,不再占用CPU的操作时间,除非定时器计满溢出,才可能中断CPU当前操作。CPU也可以重新设置定时器工作方式,以改变定时器的操作
- 在定时器/计数器开始工作之前,CPU必须将一些命令(称为控制字)写入定时/计数器。将工作模式控制字写入模式控制寄存器,工作状态字(或相关位)写入控制寄存器,并给定时/计数器赋初值
定时器赋初始值计算
以方式1为例
举个例子--------------需要定时为50MS
计算如下:
如果晶振是12MHZ,则机器周期为12MHz除以12,就是1MHz,每秒1000000次机器周期,那么50ms就是50000次机器周期
65536-50000=15536(3cb0),
TH0=0x3c,(高位)
TL0=0xb0。 (低位)
而若是1ms
1ms就是1000次机器周期
(65536-1000)/256是高位
(65536-1000)%256是低位
TMOD TCON
TMOD寄存器的设置依据
TCON寄存器的设置依据
我们下面开始介绍这几种方式:
-
方式0:
13位的定时器,它的低位TL0是五位的,所以它的总值是28*25=8192
可以用来做短时间中断
(e.g. 装入5ms:
TH0(8192-5000)/32;TL0(8192-5000)%32;
32是5位寄存器的容量。所以要中断200次才能达到1s) -
方式1:
16位的定时器/计数器
一次溢出也就是65536us
前面的例子就是采用方式1 -
方式2:
方式0和方式1,当计数溢出后,计数器变为0,所以要反复重新装填初值,这会影响定时精度。但是方式2可以解决这个问题
其中低位TL0是8位定时器,而TH0是常数缓冲器,当低位TL0溢出时,在溢出标志位TF0置1的同时,自动将高位TH0的常数重新装入TL0中,让TL0从初值开始重新计数,这样就不用人为软件重新装入初值带来的误差,从而提高精度。
不用再求模求余 -
方式3:
它只能用于T0,也就是定时器0,
和方式2差不多,也是把TL0、TH0分成两个独立的寄存器,但是TH0也参与计数,也就是两个独立的8位定时器/计数器
定时器T1一定不要用在有中断的场合,当然,T1同样可以正常工作在方式0、1、2下。通常这种情况,T1都被用来当做串行口的波特率发生器
中断
概念:
CPU在处理某一事件A时,发生了另一事件B请求CPU迅速去处理(中断发生);CPU暂时中断当前的工作,转去处理事件B(中断响应和中断服务);待CPU将事件B处理完毕后,再回到原来事件A被中断的地方继续处理事件A(中断返回)的这一过程
中断源名称 | 中断序号 | 默认优先级别 | 中断服务程序入口地址 |
---|---|---|---|
外部中断0 | 0 | 最高 | 0003H |
定时/计数器0中断 | 1 | 第2 | 000BH |
外部中断1 | 2 | 第3 | 0013H |
定时/计数器1中断 | 3 | 第3 | 001BH |
串行口中断 | 4 | 第4 | 0023H |
相关寄存器
- 中断允许控制寄存器IE
位号 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
位名称 | EA | – | – | ES | ET1 | EX1 | ET0 | EX0 |
取值 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
其中:
- 在用到中断时,必须要开总中断EA,即EA=1。
- EX0(EX1):外部中断允许控制位。
EX0=1开外部0号中断,
EX0=0关闭外部0号中断。 - ET0(ET1):定时中断允许控制位。ET0=1,开内部定时器0号中断;ET0=0关闭定时器中断0号开关。
- ES: 串口中断允许控制位。ES=1,开串口中断;ES=0 关闭串口中断。
- 中断优先控制寄存器IP
– | – | – | PS | PT1 | PX1 | PT0 | PX0 |
---|
其中:
-
PS:串行口中断优先级控制位。PS=1设定串行口为高优先级中断;PS=0为低优先级中断。
-
PT1:T1中断优先级控制位。PT1=1设定定时器T1为高优先级中断;PT1=0为低优先级中断。
-
外部中断1优先级控制位。PX1=1设定定时器外部中断1为高优先级中断;PX1=0为低优先级中断。
-
PT0:T0中断优先级控制位。PT0=1设定定时器T0为高优先级中断;PT0=0为低优先级中断。
-
PX0:外部中断0优先级控制位。PX0=1设定定时器外部中断0为高优先级中断;PX0=0为低优先级中断。
代码
我们上面已经了解了基本的一些知识,那我们在实际使用的使用,是如何编写代码的呢
定时/计数器初始化基本流程
部分代码如下:
TMOD = 0x01; //寄存器0,方式1
ET0 = 1; //开启定时器中断
TH0 = ( 65535 - 1000 ) / 256; //定时器高8位设置
TL0 = ( 65535 - 1000 ) % 256; //定时器低8位设置
TR0 = 1; //启动定时器
EA = 1; //打开总的中断
这是我们学习数码管的时候的部分代码,现在来看是不是觉得很简单了呢