以前学了好几次单片机,都是半途而废,这次要把基础打好点才行。
话说定时器还是很重要的。。。
对51单片机来说,其实定时器和计数器是一样的东西,下面把它们统称为定时器了。
51单片机有两个定时器,它们的核心是两个16位的加1计数器T0和T1,它们又被分为两个8位的计数器TH0,TL0,TH1,TL1。
当作为计数器使用时,计数脉冲来自外部引脚P3.4(T0)和P3.5(T1)。当该脚的输入信号发生由高到低的负跳变时,读数器TH、TL的值就加1。
定时器其实也是计数,只不过计数的脉冲来源的内部时钟。
程序是怎样知道定时器的时间到了呢?用中断啦。。。
定时器使用的是加法计数,而且只在计数溢出时才申请中断,因此,要实现自定义定时或计数,需要自己计算计数的起点,并将它们填到TH、TL中。
也就是说,如果我要记1000个时钟脉冲,我就将TH和TL的值设到距离最大值还差1000的位置。
假设计数的最大值是MAX(工作模式不同,这个值不同),则起点X的计算方法如下:
在计数方式下,X=MAX-计数值
在定时方式下,X=MAX-定时值/T,其中T为单片机的机器周期。如当机器周期=0.5us时,如果定时器工作于模式0,MAX = 2^13 * 0.5us = 4.096ms;如果工作于模式1,则最大定时值为MAX = 2 ^ 16 * 0.5us = 32.768ms。
在注意的是,在溢出后,除了模式2之外,程序都要重新装入初值!
使用定时器的步骤:
1. 指定工作模式,即TMOD寄存器;
2. 装入初始值,即对TH和TL赋值;
3. 启动定时器中断,通过赋值IE和优先级寄存器IP来实现,如果不使用中断,则忽略此步骤;
4. 启动定时器,即置位TR0或TR1。
模式0:
此模式为13位计数器,使用TH及TL中的低5位组成,此模式主要是为了向前兼容而设计的;在此模式下,当TL的低5位溢出时,向TH进位,当TH溢出时,计数器清零,同时TF置1,另外发出中断请求。
模式1:
此模式为16位计数器,使用TH和TL中的所有位,此模式方便计算初值,而模式0中要由TH和TL中的5位组成一个13位的数,麻烦。
模式2:
此模式是8位自动重新装入的计数器,其中TH作为计数初值寄存器,初值在程序中设置,程序初始化时,TL=TH,当TL溢出时,自动设置TL=TH,重新计数,TF标志置1,TH中的数不受影响。溢出信号还将送到串行通信系统,产生串口通讯的波特率。
模式3:
此模式是将TL和TH分成两个独立的计数器。T1没有模式3,只有T0有模式3。如果T0工作在方式3下,那么T1就只能工作在0、1、2方式下,因为TR1及TF1已经被T0借用。
可以通过TMOD和TCON两个寄存器控制它们。
TMOD
---------------------------------------------------------
用于T1 | 用于T0
---------------------------------------------------------
GATE | C/T | M1 | M0 | GATE | C/T | M1 | M0 |
TCON
------------------------------------------------------------
用于定时/读数器 | 用于中断
------------------------------------------------------------
TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
------------------------------------------------------------
TF是溢出的标志,TR是运行控制位,当置TR0=1时,定时器1即启动。
IT是外部中断触发方式选择位,0是低电平触发,1是负跳变触发。
IE是外部中断请求位。
定时/计数器有四种工作方式,TMOD中的M1和M0即为指定工作方式;
C/T决定是工作于定时还是计数方式;
GATE可控制定时器的启动,当GATE=0时,定时器仅由TR控制,当GATE=1时,除TR置1外,还必须等待外部脉冲输入端P3.4或P3.5有个高电平,定时器才能启动。若外部输入低电平,则定时器关闭,这样可由外部控制定时器的启停。
初值计算举例(以T0为例):
模式0, 6MHz的晶振,单片机的机器周期为12/6MHz=2us=0.002ms,如果要定时1ms,则有算式:1ms = (2^13-X)*0.002,解出X=7692=0x1E0C,转化为2进制为1111000001100,这里面低5位要放到TL中,即TL0=01100=0xC,其余放到TH中,即TH0=11110000=0xF0;
模式1, 12MHz的晶振,单片机的机器周期为12/12MHz=1us=0.001ms,如果要定时10ms,则有算式: 10ms=(2^16-X)*0.001,解出X=55536=0xD8F0,则TH0=0xD8,TL0=0xF0;
模式3, 6MHz的晶振,机器周期为2us=0.002ms,如果要定时200us,则有200=(2^8-X)*2,解出X = 156 = 0x9C, 则TL0 = 0x9C
程序举例:
T0工作于方式1,定时时间50ms,输出周期为1000ms的方波,晶振为11.0592MHz
机器周期为12/11.0592us,最大值为2^16=65536,X=0x4C00
程序如下:
#include "reg51.h"
sbit P0_1 = P0^1;
char i = 0;
void main()
{
TMOD = 0x01; //T0方式1
TL0 = 0x00; //TL0的初值
TH0 = 0x4C; //TH0的初值
ET0 = 1; //打开定时器0的中断允许开关
EA = 1; //开中断
TF0 = 0;
TR0 = 1;
while(1);
}
void Int_T0() interrupt 1 using 2
{
TL0 = 0x00; //重新装入初值
TH0 = 0x4C;
i++;
if (i==10)
{
P0_1 = !P0_1;
i = 0;
}
}
下面这段中断的程序还须进一步研究,呵呵
|