1.简介
51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成定时器作用:
- 用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
- 替代长时间的Delay,提高CPU的运行效率和处理速度
- ……
定时器个数:3个(T0、T1、T2),T0和T1与传统的51单片机兼容,T2是STM89C52单片机增加的资源。
注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的。
2.定时器
STC89C52的T0和T1均有四种工作模式:
模式0:13位定时器/计数器
模式1:16位定时器/计数器(常用)
模式2:8位自动重装模式
模式3:两个8位计数器工作
其中最常用的模式1框图如下:
定时器/2-1.png)
16位定时器可表示的最大数字为65535,每隔65535个时钟脉冲,定时器就会向中断系统发出中断申请。基于此,我们可以设置初值,来实现任意时长的定时效果。初值的大小可以在TH0与TL0寄存器中设置。下面是对模式1框图的一些讲解:
定时器/2-2.png)
3.中断系统
由于整个过程涉及到中断系统,因此在写对应函数时,需要加上对应的中断号。对应关系如下图所示:
定时器/3-1.png)
定时器/3-2.png)
一些相关的寄存器如下图所示:
定时器/3-3.png)
4.定时器初始化函数编写
在写实际代码的时候,通常将定时器以单独文件保存,对于任何一个定时器,我们都需要对它进行初始化,来配置一些最基础的参数。
首先配置TMOD(定时器模式寄存器),下面是每一位的具体含义:
定时器/4-1.png)
由于模式一默认使用定时器0,因此对于TMOD我们只需要操作其末四位:
末两位M1和M0用于选择定时器模式,我们常用模式1则该两位置01。
CT位用于确认使用定时器还是计数器,我们使用定时器则该位置0。
GATE门控位,置0时只使用TR寄存器就可以控制定时器开关,置1时还需要配置INT0才可控制定时器开关,我们将该位置0。
由此得到最终的结果:TMOD的低四位置0001。
由于TMOD不可位寻址,因此我们需要对TMOD整体赋值。同时,为了只改变定时器0的配置而不影响定时器1的配置(只操作低四位),我们使用与操作和或操作来完成:
1 | TMOD&=0XF0; //低四位清零,高四位不变 |
然后设置初值,我们设定定时器的时长为10ms,则对应的计算过程和最终结果如下:
1 | TH0=0XDC; //11.0592MHZ的晶振频率,12分以后为0.9216MHZ,约1.08mius晶振一次 |
根据模式1框图可知,定时器是通过累计脉冲次数产生溢出,从而触发中断,并执行中断程序,在触发中断时会将TF位置1,我们在初始化时将其置0。
同时,由于我们将GATE门控位置0,我们只需要将TR0置1即可启动定时器。
两者的配置代码如下:
1 | TF0=0; |
参考STC89C52系列中断系统结构图可知,想要Timer0执行中断,还需要将ET0(允许Timer0发生中断)和EA(允许中断的总开关)置1,将PT0(用于控制中断优先级,默认置0,即低优先级)置0,即:
1 | ET0=1; |
这样,一个定时器初始化函数就写好了:
1 | void Timer0_Init() |
5.定时器中断函数编写
我们在配置好定时器以后,还需要对中断函数进行配置。定时器初始化函数相当于定好了一个闹钟,而定时器中断函数则相当于制定了“闹钟响后做什么事情”的计划表,这样才是一个完成的流程。
下面先给出模板代码,然后再进行讲解:
1 | void Timer0_Routine() interrupt 1 |
我们在定时器初始化函数中,设定该定时器为一个“每过10ms中断一次的定时器”,假设我们需要实现每过500ms亮或灭一次LED灯,那么可以通过设置静态变量T0Count来实现。每过10ms,定时器执行该中断程序,使得T0Count自增1。需要注意的是,每次中断执行时需要重新设定初值,否则定时器将从0开始累计脉冲,无法正常工作。
当中断执行10次,即过了500ms以后,执行反转P2_0的操作。同时将T0Count归零,进入下一个循环。
以上只是一个示例,具体在初始化时设定定时器大小为多少,中断函数需要执行几次定时中断才触发对应事件均可自行更改完成。