04:定时器

04:定时器

定时器

1、定时器怎么定时2、怎样实现计数?2.1、控制寄存器TCON2.2、工作模式寄存器TCOM2.3、定时器T0

3、案例:通过定时器T0控制LED间隔1s亮灭

当定时器用的时候,靠内部震荡电路数数。当配置为定时器使用时,每经过1个机器周期,计数存储器的值就加1。

1、定时器怎么定时

1、通过晶振(晶体振荡器)发出脉冲,记录脉冲的个数来进行定时的。 2、而脉冲的频率为时钟频率,此频率的倒数为震荡周期(时钟周期),也是计算机中最小的时间单位。

如图:晶体振荡器的频率为11.0592MHz,则他的时钟周期为1/11.0592MHz(秒),既一个脉冲的周期需要这么多秒。

3、机器周期为CPU周期,一个基本操作所需要的时间称为机器周期。一般情况下,一个机器周期由若干个时钟周期组成。一般情况下是12倍/6倍。

加1经过了多少时间? 当晶振频率是11.0592MHz的时候,等于11059.2KHz = 11059200Hz 机器周期 = 12 x 时钟周期 =12 x (1/时钟频率) 秒 = 12 / 时钟频率 秒 = 12 / 11059200 秒 = 12 000 000/ 11059200 微秒 = 1.085 (us) 既:当使用12倍数时,每隔1.085us,计数器就+1。

2、怎样实现计数?

通过配置相关的寄存器:如下图为定时器的相关寄存器。

如图有2中寄存器:第一种为TCON,第二种为TCOM,他们都是各8位。如图有2种定时器:第一种位定时器T0,第二种为定时器T1,他们都是各16位。

2.1、控制寄存器TCON

TF0:定时器T0溢出中断标志,当定时器0开始计数时,计数到规定的时间时,定时器产生了溢出。TF0自动由0变位1(由硬件置1)。

如果不用中断,需要手动清零。

TR0:定时器T0的控制位,当为1时,定时器T0才能计数,相当于T0的开关(由软件控制)。

2.2、工作模式寄存器TCOM

GATE:门控制位,当GATE=0时:计数条件只有TR1一个(TR1=1就计数,TR1=0就不计数)。

当GATE=1时:是否计数不仅取决于TR1还取决于INT1引脚

C/T :时钟输入选择为,为1时,时钟从外部引脚P3.5口输入;为0时,时钟从内部输入

M1 M0

0 0 :13位定时器,使用高8位和低5位

0 1 :16位定时器,全用

1 0 :8位自动重装载定时器,当溢出时将TH1存放的值自动重装入TL1.

1 1 :定时器无效

2.3、定时器T0

定时器T0一共有16位,分为高8位TH0,和低8位TL0。所以一共能计2^16个数(65536),而每计1个数的周期是1.085us,所以默认是从0开始数数,累计计时约71ms。

3、案例:通过定时器T0控制LED间隔1s亮灭

代码①:

#include

sbit LED1 = P3^7;

void main(void)

{

int cnt = 0;

LED1 = 1;//先让灯熄灭的状态

/*1、选择定时器T0,并配置为16位定时器*/

TMOD =0x01; // 0000 0001

/*

2、定一个10ms的时间,数1下需要1.085us

10ms需要数则需要数9216下,那从65536-9126=56320

从56320这里开始数,数9216下就到了65536。当超过了

65536时就报表了,控制寄存器TCON的TF0由0变为1

*/

TL0 = 0x00; //0000 0000

TH0 = 0xDC;//1101 1100

/*3、打开定时器T0*/

TR0 = 1;

TF0 = 0;//先个溢出标志清零

while(1)

{

if(TF0 == 1)//10ms报表了

{

TF0 = 0;//软件清零,现在不使用中断

TL0 = 0x00; //重新给初值

TH0 = 0xDC;

cnt++;

if(cnt == 100)//数100次,相当于1s

{

cnt = 0;

LED1 = !LED1;

}

}

}

}

【注】

每次报表后,都要给定时器重新一个初值每隔10毫秒cnt进行加1,当cnt加到100时,说明已经过了1秒了

代码优化②:

#include

sbit LED1 = P3^7;

void Timer0_Init_10ms(void)//定时器初始化10ms

{

TMOD =0x01;

TL0 = 0x00; //0000 0000

TH0 = 0xDC;//1101 1100

TR0 = 1;

TF0 = 0;

}

void main(void)

{

int cnt = 0;

LED1 = 1;//先让灯熄灭的状态

Timer0_Init_10ms();

while(1)

{

if(TF0 == 1)//10ms报表了

{

TF0 = 0;//软件清零,现在不使用中断

TL0 = 0x00; //重新给初值

TH0 = 0xDC;

cnt++;

if(cnt == 100)//数100次,相当于1s

{

cnt = 0;

LED1 = !LED1;

}

}

}

}

将定时器T0初始化封装成一个函数,当需要的时候直接调用即可。 但是使用TMOD = 0x01;这样初始化也与缺陷:

假如定时器T1正在使用,且为16位定时器。则TMOD的高4位应该为:0x1(0001)

而我们使用定时器T0时TMOD初始为0x01,则TMOD的高4位为0x0(0000),则把定时器T1变为一个13位定时器了。所以还需要改进

代码优化③:

#include

sbit LED1 = P3^7;

void Timer0_Init_10ms(void) //10毫秒@11.0592MHz

{

//AUXR &= 0x7F; //定时器时钟12T模式

TMOD &= 0xF0; //设置定时器模式

TMOD |= 0x01; //设置定时器模式

TL0 = 0x00; //设置定时初值

TH0 = 0xDC; //设置定时初值

TF0 = 0; //清除TF0标志

TR0 = 1; //定时器0开始计时

}

void main(void)

{

int cnt = 0;

LED1 = 1;//先让灯熄灭的状态

Timer0_Init_10ms();

while(1)

{

if(TF0 == 1)//10ms报表了

{

TF0 = 0;//软件清零,现在不使用中断

TL0 = 0x00; //重新给初值

TH0 = 0xDC;

cnt++;

if(cnt == 100)//数100次,相当于1s

{

cnt = 0;

LED1 = !LED1;

}

}

}

}

我们发现TMOD的初始化为:

TMOD &= 0xF0; //设置定时器模式

TMOD |= 0x01; //设置定时器模式

这样初始化有什么好处?

假如定时器T1正在使用,且为16位定时器。则TMOD的高4位应该为:0x1(0001),而要使用定时器T0,且也为16位定时器,则TMOD = 0x11;

TMOD &= 0xF0;表示TMOD = TMOD & 0xf0,则与出来的TMOD = 0x10,由此可见,这一步就是让TMOD的高4位不变,低4位清零。

TMOD |= 0x01;表示TMOD = TMOD | 0x01,则或出来的TMOD = 0x11,由此可见,这一步就是让TMOD的高4位不变,低4位初始化。

通过这样初始化,既保证了TMOD的高4位不变(不改变定时器T1的初始化),由对低4位进行了改变(对定时器T0初始化)。

当然:也可以直让TMOD = 0x11;

相关推荐

维c吃多了会怎样 det365在线平台

维c吃多了会怎样

如何游戏搬砖赚钱?新手都知道的十种赚钱方法 365在线体育投注

如何游戏搬砖赚钱?新手都知道的十种赚钱方法

文件大小怎么改 bt365在线

文件大小怎么改