一,定时器介绍
STC89C51RC/RD+系列单片机的定时器0和定时器1,与传统8051的定时器完全兼容,当在定时器1做波特率发生器时,定时器0可以当两个8位定时器用。
STC89C51RC/RD+系列单片机内部设置的两个16位定时器/计数器TO和T1都具有计数方式和定时方式两种工作方式。对每个定时器/计数器(TO和T1),在特殊功能寄存器TMOD中都有一控制位―CT来选择TO或T1为定时器还是计数器。定时器/计数器的核心部件是一个加法(也有减法)的计数器,其本质是对脉冲进行计数。只是计数脉冲来源不同:如果计数脉冲来自系统时钟,则为定时方式,此时定时器/计数器每12个时钟或者每6个时钟得到一个计数脉冲,计数值加1;如果计数脉冲来自单片机外部引脚(TO为P3.4,T1为P3.5),则为计数方式,每来一个脉冲加1。
当定时器/计数器工作在定时模式时,可在烧录用户程序时在STC-ISP编程器中设置(如下图所示)是系统时钟/12还是系统时钟/6后让TO和T1进行计数。当定时器/计数器工作在计数模式时,对外部脉冲计数不分频。
定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号,每隔“一秒”,计数单元的数值就增加一,当计数单元数值增加到“设定的闹钟提醒时间”时,计数单元就会向中断系统发出中断申请,产生“响铃提醒”,使程序跳转到中断服务函数中执行
二,四种工作模式
STC89C52的T0和T1均有四种工作模式:
模式0:13位定时器/计数器
模式1:16位定时器/计数器(常用)
模式2:8位自动重装模式
模式3:两个8位计数器
模式1:
此模式下,定时器配置为16位定时器/计数器,由TL0的8位和TH0的8位所构成。TL0的8位溢出向TH0进位,THO计数溢出置位TCON中的溢出标志位TF0。
SYSclk:系统时钟,即晶振周期,本开发板上的晶振为12MHz
那么1毫秒 溢出一次的晶振次数怎么计算呢?
STC89C51RC/RD+系列单片机的定时器有两种计数速率:一种是12T模式,每12个时钟加1,与传统8051单片机相同;另外一种是6T模式,每6个时钟加1,速度是传统8051单片机的2倍。TO的速率在烧录用户程序时在STC-ISP编程器中设置。
STC89C52RC 的时钟频率是12MHz。
12MHz就是 1秒钟 晶振次数 是 12000000次,
12000000/12/1000(毫秒)=1000 (次/毫秒)
也就是说我们 要让定时器没1毫秒溢出一次,就得让晶振震动1000次后溢出。而溢出的时候TH0和TL0 合并起来的值是65536
所以我们把 定时器的初始值TH0和TL0的合并值设置为TIMS=65536-1000=64536
赋值
TL0=64535%256;(TL0=TIMS; [TL0只有8位,所以高位不会赋值过去,只有地位有效])
TH0=64536/256;(TH0=TIMS>>8;TH0也只有8位,TIMS右移8位后然低位溢出,高位就自动在低位了)
每次中断发生后,都需要重新将TH0和TL0重新初始化。(在中断函数中重新赋值TH0和TL0)
三,如何开启定时器/计数器中断
3.1 开启中断 interrupt 1 (定时器Timer0/计数器 触发中断 实现LED闪烁)
如下图。要开启标红的这一路。配置还是比较多。不要嫌麻烦。挨着来。走一遍后,你会觉得像是打开了任督二脉。
按照图,还是从下往从右往左一次配置。
PX0: 优先级系统默认是最高级,不管
EA:全局中断开关合上 EA=1
ET0:允许Timer0/TF0 的中断进入。ET0=1;
我们再单独分析定时器器/计数器,
TR0:定时器开始运行;TR0=1;
TMOD:采用模式1(16位)
#include <REGX52.H>
/*宏定义定时器的初始值*/
#define TIMS (65536-12000000/12/1000)
unsigned int count=1000;//计数器 默认1000
void main()
{
TMOD=0x01; //设置模式1
TL0=TIMS; //设置定时器的低8位
TH0=TIMS>>8;//设置定时器的高8位
TR0=1; //让定时器开始运行
ET0=1; //允许定时器发生中断溢出
EA=1; //打开全局中断
while(1); //主程序停止在此
}
/**
* 函 数:定时器中断函数
* 参 数:无
* 返 回 值:无
*/
void timer0_interrupt() interrupt 1
{
TL0=TIMS; //重新初始化低位
TH0=TIMS>>8; //重新初始化高位
if(count--==0) //1毫秒*1000=1秒
{
count=1000; //重置计数
P2_0=!P2_0; //第一个LED 每秒熄亮一次
}
}
效果
3.2 开启中断 interrupt 3 (定时器Time1/计数器 触发中断 实现LED闪烁)
还是模式1,同样的,只是几个开关的名字变了
PX0: 优先级系统默认是最高级,不管
EA:全局中断开关合上 EA=1
ET1:允许Timer0/TF0 的中断进入。ET1=1;
TR1:定时器开始运行;TR1=1;
TMOD:采用模式1(16位)不过这里和上面有区别,要设置为0x10
#include <REGX52.H>
/*宏定义定时器的初始值*/
#define TIMS (65536-12000000/12/1000)
unsigned int count=1000;//计数器 默认1000
void main()
{
TMOD=0x10; //设置模式1
TL1=TIMS; //设置定时器的低8位
TH1=TIMS>>8;//设置定时器的高8位
TR1=1; //让定时器开始运行
ET1=1; //允许定时器发生中断溢出
EA=1; //打开全局中断
while(1); //主程序停止在此
}
/**
* 函 数:定时器中断函数
* 参 数:无
* 返 回 值:无
*/
void timer1_interrupt() interrupt 3
{
TL1=TIMS; //重新初始化低位
TH1=TIMS>>8; //重新初始化高位
if(count--==0) //1毫秒*1000=1秒
{
count=1000; //重置计数
P2_0=!P2_0; //第一个LED 每秒熄亮一次
}
}
效果 与上面一样