51单片机/计数器基础知识介绍
一、基本概念
1、89C51有两个计数器T0和T1,89C52还有一个T2。每个计数器都是由两个8位的RAM
单元组成的,即每个计数器都是16 位的计数器,最大的计数容量是2 16 =65536,记住是从0-65535。
2、提供给定时器的计数源又是从哪里来的呢?就是由单片机的晶振经过12 分频后获得的一个脉冲源。一个12M 的晶振,它提供给计数器的脉冲时间间隔是就是1us。
3、预置数计数法。如果每个脉冲是1微秒,则计满65536个脉冲需时65.536毫秒。但是如果只需要10毫秒就可以了,怎么办?只要在计数器里预先放进55536,这样只需要计数65536-55536=10000次,也就是10毫秒了。
二、相关寄存器
特殊功能寄存器TMOD(89H)
用于T1
用于T0
GATE C/T M1 M0
GATE C/T M1
M0
GATE:0用于内部脉冲;1用于外部脉冲。
C/T:0用于定时器;1用于计数器。
M1M0:工作方式
M1,M0 范围
特性
0,0工作方式0 13位,8192次
为了和51 的前辈48系列兼容。
0,1工作方式1 16位,65536次
16位,其他特性与工作方式0相同,比较常用。
1,0工作方式2 8位,256次
自动再装入预置数,预置数放在T0(或T1)
的高8位中,只有低8
位参与计数,通常用于
波特率发生器。
1,1工作方式3 8位,256次
TH0只能作为定时器用,TL0可作定时器或计数
器。溢出标记:TL0
还是用原来的T0的标记,
而TH0则借用T1的标记,因此只有在T1 以工
作方式2
运行时,才让T0 工作于方式3。
特殊功能寄存器TCON(88H)
用于定时/计数器
用于中断
TF1
TR1 TF0
TR0
IE1 IT1
IE0
IT0
TR0/TR1:定时器 的开关。
TF0/TF1:计数溢出后由0变为1
IT0/IT1:定时器/计数器中断允许位。
在今天的分享中我们学习下单片机/计数器的使用,在前面的分享中我们接触到了单片机时钟周期、机器周期和指令周期的概念,我们再温习下:
1时钟周期
= 1/晶振频率M
1机器周期
= 12( 51系列为12时钟周期,有的改进型单片机是1时钟周期 )× 时钟周期=12(1)
× (1/晶振频率M)=1us(1/12us,如采用12M晶体)。
如果12MHZ晶振工作在51单片机12T模式下,需要使用定时器进行50ms定时操作,定时器工作在方式1,那么我们该怎样编写程序呢?
我们知道:
12M的晶振每秒(s)可产生1M(10
6 us)个机器周期。
50ms就需要50
× 1000us×
1us(1机器周期)个机器周期=50000个机器周期。
如果定时器在方式1工作,是16位计数器,最大值为65536(2 16),也就是能进行最大65536次计数。而50ms定时操作需要50000个机器周期,1个机器周期=1us,所以需要50000次计数操作。
为了计数器定时器工作,需要预先填充定时器初值(初值=定时器计数最大计数次数-所需定时计数次数)。所以需设置定时器初值 15536=65536-50000,即3CB0H(10进制15536转换成16进制数3CB0),所以TH0=0x3c,TL0=0xb0,高位就是 TH0的值,低位为TL0的值。
如果使用11.0592MHZ的晶振,其他条件不变,11.0592M的晶振每秒可产生0.9216M个机器周期,50ms就需要46080 个机器周期。定时器在方式1工作,是16位计数器,最大值为65536,所以需设置初值19456=65536-46080,即4C00H,所以 TH0=0x4c,TL0=0x00。
由上面的分析,我们可以得出推导16位定时器/计数器初值设定高8位TH0,低TL0的公式为:
TH0=(65536-所需计数次数)/256=初值/256;
TL0=(65536-所需技术次数)%6=初值%6;
公式中的256是什么意思呢?我们的计时器是两个8位组成的,那么要把那些差值装进这两个8位,计数从低8位开始,那么低8位最多能装256 个机器周期,那么256计满了就用高8位的,就是说低8位满一次高8位加1,那么高8位装多少,低8位就满了几次,算法就是用差值除一下256取其整数, 剩下的,就是还剩了小于256次数的就放在低8位,就是差值的余数。
下面我们看个定时器/计数器0,产生定时中断的例程。
晶振频率12M,其程序如下:
#include
void timer0_init()
{
TMOD = 0x01;
//定时器在方式1工作,是16位计数器,最大值为65536
TL0 = 0xb0;
//给TL0赋计数初值0xb0
TH0 = 0x3c;
//给TH0赋计数初值0x3c
TR0 = 1;
//定时器开始计数
ET0 = 1;
//定时器中断允许
EA = 1;
//开总中断
}
void main()
{
timer0_init();
w hile(1);
}
void timer0()
interrupt 1
{
TH0=(65536-50000)/256; //在中断处理函数中需要重新给TH0赋初值。
TL0=(65536-50000)%6; //在中断处理函数中需要重新给TL0赋初值。
加上我们希望的语句。
}
上面给大家看了一段例程,讲的是如何用定时器/计数器0实现中断。单片机一般还有一个定时器/计数器1,它的编程和定时器/计数器0差不多。
另外,单片机定时器/计数器的使用不单单体现在定时器中断方面,但它们的使用都万变不离其综,大家掌握了一种用法,对于其它的应用也就不难掌握了。