1.定时器介绍(51单片机和某些增强型51)
STC89C52含有三个定时器:0,1,2.
51单片机一定含有两个基本的定时器0,1.
1.1cpu时序
1.振荡周期:为单片机提供定时信号的振荡元的周期,称为晶振周期或者外加振荡周期.
2.状态周期:2个振荡周期为一个状态周期,用S表示.振荡周期又被称为S周期或者时钟周期.
3.机器周期:12个振荡周期(6个状态周期)为一个机器周期.
4.指令周期:完成一条指令所占用的全部时间,以机器周期为单位.
例子:外接晶振是50MHz,相关周期值为:
振荡周期:0.02us.
状态周期:0.04us.
机器周期:0.24us.
指令周期:0.24~0.96us.
学习定时器/计数器之前要明白的几点
1.定时器/计数器和单片机的CPU是互相独立的,定时器/计数器的工作过程不需要CPU的参与.
2.定时器/计数器是根据机器内部的时钟或者外部的脉冲信号对寄存器中的数据+1.
3.把简单重复的+1工作交给定时器/计数器去处理,让CPU处理一些更为复杂的事情.
单片机定时器原理
定时器的原理是一个十六位的加一计数器,由高八位和第八位两个寄存器THx和TLx组成,每次来一个脉冲,计数器就自动加一,当加到计数器全为一时,再输入一个脉冲就会使计数器归零,计数器的溢出使相应的中断标志位置1,向CPU发出中断请求.
如果定时器工作于定时模式,则说明时间已到;如果工作于计数模式,则证明计数已满,由此可见,由溢出时计数器的值减去计数器初值才是计数器的计数值.
内部结构:T0 T1对应于P3.4 P3.5管脚.
工作方式:由两个sfr(special function register)特殊功能寄存器控制,TMOD是工作方式寄存器--timer mode,TCON--timer control是控制寄存器,控制T0和T1的启动和停止以及设置溢出标志.
1.TMOD
低四位用于T0,高四位用于T1.
GATE是门控位,GATE用于控制定时器的启动是否受到外部中断源信号的影响.GATE=0时,只要使TR0或TR1为1就可以启动定时器.当GATE为1时,不仅要满足上面的条件,还要外部中断引脚INT0/1为高电平.
C/T:定时/计数模式选择,count-timer
MIMO:工作方式设置位.
2.TCON
低四位用于控制外部中断,高四位用于控制定时器的启动和中断申请.
TF1:T1溢出中断请求标志位,T1溢出时TF1为1,CPU响应中断后TF1由硬件清零.也可以由软件置一或者清零,与硬件置一或者清零的效果一样.
TR1:为一时,T1开始工作,为零时,T1停止工作.可以由软件控制.
TF0:类似TF1.
TR0:类似TR1.
2.定时器工作方式
1.方式0
13位计数,由TL0的低五位和TH0的八位组成.TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断.
可以看出,GATE的低位很特殊.当GATE为零时,经过反相后或门输出为1,此时由TR0来控制与门的开启.如果GATE为1,此时由外中断引脚信号和TR0共同控制,可以用来测试外中断引脚上的正脉冲的宽度.
计数模式时,计数脉冲是T0引脚上的外部脉冲,计数初值与计数个数的关系:X=2^13-N.(此关系后面再作理解)
2.方式1
十六位加一计数器,方式1的计数位数是16位,TL0作低八位,TH0作高八位.
计数初值与计数个数的关系:X=2^16-N.
3.方式2
适用于作较为精确的脉冲信号发生器,自动重装初值的8位计数方式.
计数初值与计数个数的关系:X=2^8-N.
4.方式3
仅仅适用于定时器/计数器T0,定时器T1在方式3下时,TR1=0.停止计数.
方式3将T0分为两个独立的8位计数器TL0和TH0.
多用方式1和方式2,定时器通常用的是方式1(16位),而串口通信通常用的是方式2(8位).
3.定时器配置(timer configuration)
完成以下几点就可以,无论顺序.
1.对TMOD赋值,确定是使用T0还是T1,使用哪一个就对哪个配置.
2.计算初值并放入TH0,TL0或者TH1,TL1.
3.使用中断需要开放EA,对EA赋值.
4.对TR0或者TR1置位,启动定时器/计数器.
例子:
外部晶振的频率是12MHz,单片机内部的时钟频率就是1MHz,机器周期就是1us,如果想要定时1ms,就是1000个计数点,初值为65535-1000+1=64536,也就是FC18H.所以初值就为THx=0XFCH,TLx=0X18H.
由于定时器的位数有限,肯定是不可能通过初值定下来一个很长的定时时间,比如1s(1000ms).通过初值来定时,上限也就是600ms左右(0.6s).如果想要实现1s的定时,可以通过初值设置1ms,每当累计1ms,再次赋初值,累计到一千次的时候,就是1s了.
这样,就可以用定时器来精确的延时从而代替之前的delay_10us或者是delay_1ms这种函数了(纯软件实现).
void time0_init(void)
{
TMOD = 0X01;//选定定时器0模式,工作方式1
TH0 = 0XFC;//定时1ms,赋初值
TL0 = 0X18;//同上
ET0 = 1;//打开定时器0中断允许
EA = 1;//打开总中断
TR0 = 1;//打开定时器
}
如果是定时器1,TMOD=0X10?另外还要将其他的0改为1.
通过定时器0和LED模块可以实现D1指示灯间隔1秒闪烁,定时器0属于51单片机内部资源,只使用到了开发板上的LED模块的D1.一个可能的实验代码如下:
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit LED0=P2^0;
/*void delay_10us(u16 ten_us)
{
while(ten_us--);
}
*/未使用的代码段
void time0_init(void) //initialize初始化,time0是函数名,可以自选
{
TMOD = 0X01;//选定定时器0模式,工作方式1
TH0 = 0XFC;//定时1ms,赋初值
TL0 = 0X18;//同上
ET0 = 1;//打开定时器0中断允许
EA = 1;//打开总中断
TR0 = 1;//打开定时器
}
void main()
{
time0_init();
while(1)
{
}
}
void time0() interrupt 1 //中断器0中断函数
{
static u16 i; //i=0
TH0 = 0XFC;//定时1ms,赋初值
TL0 = 0X18;//同上
i++;
if(i==1000)
{
i=0;
LED0=!LED0;
}
}
假如晶振是11.0592MHz,定时时间为1ms,根据软件来计算初值.
注:开发板使用外部晶振的频率不一样,换算的初值自然也不一样,应该引起重视.