什么是定时器?什么是计数器?
定时器,字面意思就是定时的。手机的闹钟就是个定时器,定个每天早上7点的闹钟。
计数器,字面意思计时统计个数的,来一个就加一个,一直累加着。
其实定时器和计数器里面的内容是一样的,区别在于,定时器是在数内部的时钟,计数器是数外面的脉冲。
STC89C51RC单片机的定时器/计数器
定时器/计数器0
定时器/计数器1
定时器/计数器2
其实传统的51单片机就只有定时器/计数器0和定时器/计数器1这两个,STC的51单片机自己加了一个定时器/计数器2。
定时器/计数器的核心内容就是一个加法计数器,对脉冲进行计数,来一个脉冲计数器就加1.
用作定时的时候,单片机是在数自己的系统时钟脉冲;
用作计数的时候,单片机是在数从外面的脉冲,这个外面的脉冲通过计数器绑定的引脚传给单片机,
T0对应的引脚是P3.4,T1对应的引脚是P3.5;
是用来定时还是用来计数,可以通过设置定时器模式寄存器TMOD的C/T位来决定。
定时器/计数器0的工作模式
模式0:13位定时器/计数器
模式1:16位定时器/计数器
模式2:8位自动重装模式
模式3:两个8位定时器/计数器
定时器/计数器1的工作模式
模式0:13位定时器/计数器
模式1:16位定时器/计数器
模式2:8位自动重装模式
定时器/计数器0、定时器/计数器1相关的寄存器
定时器控制寄存器TCON
TF1:定时器/计数器T1溢出标志位。当T1被允许计数后,就开始不断+1计数,计数计到最大值的时候,TF1位的值就自动变成1了,这也叫做硬件置1。如果这个时候定时器中断被允许了,那就向CPU请求中断,当CPU响应了中断之后,TF1位的值就自动变成0了。
TR1:定时器T1的运行控制位。TR1位要由软件来置位或者清零。TR1相当于计数使能信号,但是这个计数使能信号有个前提:
当TMOD计数器的第7位那个GATE =0的时候,TR1 =1,开始计数,TR1=0,禁止计数;
当TMOD计数器的第7位那个GATE =1的时候,TR1 =1,然后INT1为高电平的时候才开始计数
TF0:跟TF 1的功能是一样的,用于定时器/计数器0;
TR0:跟TR1的功能是一样的,用于定时器/计数器0;
IE1、IT1、IE0、IT0主要用于外部中断,这里就不介绍,免得引起混乱。
定时器模式寄存器TMOD
BIT7、BIT6、BIT5、BIT4是控制定时器1的
GATE =0的时候,TR1 =1,开始计数,TR1=0,禁止计数;
GATE =0的时候,GATE =1的时候,TR1 =1,然后INT1为高电平的时候才开始计数
C/T = 1的时候用于计数功能,C/T = 0的时候用于定时功能;
BIT3、BIT2、BIT1、BIT0是控制定时器0的
定时器0的数据寄存器TH0、TL0
定时器1的数据寄存器TH1、TL1
定时器0和定时器1工作在模式1的模型
定时器0和定时器1定时功能的C语言实现
#include <STC89C5xRC.H>
#define FOSC 11059200L
/*把T_MS的值写进TH和TL寄存器,TH是高八位,TL是低八位
**65535 - FOSC/12/1000,算一下,到定时器溢出刚好1ms
*/
#define T_MS (65535 - FOSC/12/1000)
unsigned int count0 = 0;
unsigned int count1 = 0;
void main()
{
//TMOD = 0x01;//定时器0工作在模式1,16位模式,GATE==0
TMOD = 0x11; //定时器0和定时器1都工作在模式1,16位模式
/*把倒计时1ms的值装进数据寄存器*/
TH0 = T_MS / 256;
TL0 = T_MS % 256;
TH1 = T_MS / 256;
TL1 = T_MS % 256;
TR0 = 1; //定时器0开启计数
TR1 = 1; //定时器1开启计数
ET0 = 1; //定时器0中断使能
ET1 = 1; //定时器1中断使能
EA = 1; //中断总开关使能
while(1);
}
//定时器0的中断服务函数
void timer0_ISR() interrupt 1
{
TH0 = T_MS/256; //装载高八位的数据
TL0 = T_MS %256; //装载低8位的数据
count0++; //每次中断+1
if(count0 == 1000) //1000次就是1秒钟
{
count0 = 0;
P00 = !P00; //P00挂个LED,就能看到1秒的闪烁
}
}
//定时器1的中断服务函数
void timer1_ISR() interrupt 3
{
TH1 = T_MS/256; //装载高八位的数据
TL1 = T_MS %256; //装载低8位的数据
count1++;
if(count1 == 500) //500ms
{
count1 = 0;
P01 = !P01; //P01挂个LED就能看到500ms的闪烁
}
}
定时器0和定时器1的模式1(16位定时器)是用的比较多的,其实我们都知道51单片机是8位的单片机,所谓的16位,也是两个8位的寄存器拼接起来的。
在模式1,定时器中断服务程序中都要把TH(TH0、TH1)寄存器和TL(TL0、TL1)寄存器的值重新写入一遍,这样有点麻烦。就像你定闹钟一样,闹钟响之后,你还得重新设置一下。我想定个每天7点的闹钟,只设置一次可不可以,当然是可以的。这个就涉及到定时器的自动重装模式
定时器0和定时器1的模式2(自动重载)
所谓自动重载就是,定时器溢出中断产生后,不用在中断服务程序中再次设定TH和TL的值;
当溢出产生时,将TH中存放的值自动的装入TL中,显然自动重载模式计数最大值只有8位了,因为只有一个寄存器来计数,8位最大值就是255,到256就溢出,所以最多也就0.28ms就溢出中断了
定时器0模式2自动重装C语言实现
#include <STC89C5xRC.H>
unsigned int count0 = 0;
sbit TEST_LED = P0^0;
void main()
{
TMOD = 0x02; //定时器0工作在模式2,8位自动重载
TL0 = TH0 = 0; //256*12/11059200 = 0.28ms
TR0 = 1; //定时器0开启计数
ET0 = 1; //定时器0中断使能
EA = 1; //中断总开关使能
while(1);
}
void timer0_ISR() interrupt 1
{
count0++;
if(count0 == 1000) //280ms的闪烁
{
count0 = 0;
TEST_LED = !TEST_LED;
}
}