简介
C51中的定时器和计数器是同一个硬件电路支持的,通过寄存器配置不同,就可以将他当做定时器或者计数器使用。
确切的说,定时器和计数器区别是致使他们背后的计数存储器加1的信号不同。当配置为定时器使用时,每经过1个机器周期,计数存储器的值就加1。而当配置为计数器时,每来一个负跳变信号(信号从P3.4 或者P3.5引脚输入),就加1,以此达到计数的目的。
标准C51有2个定时器/计数器:T0和T1。他们的使用方法一致。C52相比C51多了一个T2。
时钟周期与机器周期
定时器的本质原理就是:每经过1个机器周期,计数存储器的值就加1。因此当使用定时器时,就必须掌握时钟周期和机器周期的关系。
时钟周期 :晶振频率的倒数。如果使用的是11.0592M的晶振,那么就是 1 / (11.0592x10^6) 秒
注:1MHz = 10^6Hz
机器周期 :标准51下,机器周期 =12倍的时钟周期。即:12 / (11.0592x10^6) 秒 。有的增强51单片机,1个机器周期等于4倍的时钟周期,还有的更短。
计数存储寄存器THx&TLx
定时器和计数器工作,都依赖于 计数。计数则是由计数存储器THx和TLx这2个8位寄存器完成的。
对于计数器,每来一个负跳变信号(信号从P3.4 或者P3.5引脚输入),就加1,以此达到计数的目的。
对于定时器,每隔1个机器周期 加 1,假如(只是假如)一个机器周期为 1ms , 当加到1000次时,我们就认为经过了1s,这就是定时器定时依据。
T0和T1都拥有一对8bit计数存储寄存器。他们的复位值都是0。
T0 对应:TH0 ,TL0
T1 对应 : TH1 , TL1
sfr TL0 = 0x8A; // TL中的L是LOW的意思,代表低位,同理H代表HIGH高位。2个8位组合起来就形成了一个16位的计数器。当然也可以配置为仅仅当做8bit计数存储器用。
sfr TL1 = 0x8B;
sfr TH0 = 0x8C;
sfr TH1 = 0x8D;
当计数器加满后,再加1,就溢出了,溢出后自动归0。且溢出时,溢出标识位TFx 就会自动变为1(T0的溢出标志位TF0,T1的溢出标志位TF1)。如果启用了对应的中断,单片机会调用中断处理函数。
若TH0 和 TL0 以 16位 模式工作,那它的计数范围为 [0 , 65535 ] , 也就是累加 65536次发生溢出。 每累加一次是 12 / (11.0592x10^6) 秒。
那么从 0 累加到溢出 历时 ≈ 0.071s = 71ms 。
可以延时 10的整数倍ms,这样就避免了误差,以便用倍数控制更长的延时时间。所以,我么要给 TH0 和 TL0赋一个初始值,使他们的溢出周期(TH0,TL0从初始值到溢出所用的时间)减少到 10ms。
就像一个瓶子,开始装了2/3,再来就只能装1/3就溢出了。通过比例式计算:
12 / (11.0592x10^6) s ----- 1 次
10x 10-3 s ------ x 次 (求出 x = 9216次 ,计数9216次后溢出)
65536 - 9216 = 56320 = 二进制( 11011100 00000000)
也就是 TH0 = 11011100 , TL0 = 00000000
工作模式寄存器TMOD
通过TMOD来配置T0和T1的工作模式。
注意,TMOD寄存器不可位寻址(例如sbit led = P0^0 就是P0寄存器位寻址的例子),因此对它的配置需要对这个8bit寄存器整体赋值。
注:51中有些特殊功能寄存器不支持位寻址。只有寄存器的地址值能够被8整除的(即以数字0或者8结尾的地址,如0xA8, 0xD0),才能支持位寻址。不支持位寻址的,只能整体赋值。
小技巧:在对寄存器整体赋值时,要注意只修改我们想修改的位而不影响其它无关位的值,避免影响了之前对这个寄存器的配置。
TMOD |= 0x01; //仅仅修改TMOD的最低位,其他位保持不变。
C/T:计数器,定时器功能选择位。 1为计数器模式, 0 为定时器模式。
M0和M1:
GATE:门控位。
解释说明:
②处 C/T = 0 表示为定时器模式,触发信号为①处的单片机内部时钟信号。(若②处CT = 1,则触发信号为Tn脚)
③处表明,信号能触发使加法计数器加1,还得受④处控制。不然时钟信号是不能让加法计数器累加的。 ④处这个是与门,所以TRx(TR0和TR1)必须为1,表明我们要开启定时器。同时当,GATE为0,通过非门后为1,再通过或门,也是1,那么就让③处控制起来了。若GATE为1,那么,定时器的启动停止受 TRx和 INTx 共同控制。 INTx脚为1且TRx为1才能启动定时器/计数器。
于是在一般情况下使用定时器,我们需要如下配置:
TRx 为 1
GATE 为 0
INTx 任意
控制寄存器TCON
控制寄存器就是用来控制定时器/计数器 启动和停止的,以及溢出标志位的查询和修改。TFx是计数存储器溢出标志位,只要一溢出,就马上置为1。
TF1:定时器/计数器1的溢出标志位。1表示计数存储器溢出,0表示计数存储器正常计数。
清0方式:①通过代码修改TF1为0
②当通过中断机制来使用定时器/计数器1时,进入中断处理函数后自动归0
TR1:定时器/计数器1的启动和停止位。1表示启动,0表示停止。
TF0:定时器/计数器0的溢出标志位。1表示计数存储器溢出,0表示计数存储器正常计数。
清0方式:①通过代码修改TF0为0
②当通过中断机制来使用定时器/计数器0时,进入中断处理函数后自动归0
TR0:定时器/计数器0的启动和停止位。1表示启动,0表示停止。
低4位与外部中断INT0和INT1有关,与定时器/计数器无关。这里不做介绍。
查询法使用T0作为定时器
程序1:P0_0连接驱动的LED小灯,用T0作为16位定时器,完成间隔为1s 的 blink程序。
#include #include"binary.h" #include"int51.h" /******************************/ void timer0_init(void); void timer0_delay(uint16_t dly); // P0_0驱动LED小灯 #define LEDpin P0_0 void main(void) { LEDpin = 0; timer0_init(); TR0 = 1; for(;;) { LEDpin = 1; timer0_delay(1000); //延时1000ms LEDpin = 0; timer0_delay(1000); //延时1000ms } } /************************* T0作为定时器的初始化 **************************/ void timer0_init(void) { TMOD |= B0000_0001; //定时器0,16位存储计数器模式 TH0 = B1101_1100; //TH0 TL0 形成数是 56320 。这样,一次溢出代表经过10ms TL0 = B0000_0000; } /********************** 参数: dly,延时的毫秒数,只能是10的整数倍 ***********************/ void timer0_delay(uint16_t dly) { while(dly) { if(TF0){ TF0 = 0; TH0 = B1101_1100; TL0 = B0000_0000; dly -= 10; //溢出一次代表10ms } } } 程序2:通过T0定时器的8位重装模式,使得P0_0输出PWM信号,LED为呼吸灯效果。 #include #include"binary.h" #include"int51.h" /******************************/ void timer0_init(void); void timer0_delay(uint16_t dly); void pwm_duty(uint16_t d); // P0_0驱动LED小灯 #define LEDpin P0_0 void main(void) { uint16_t i; LEDpin = 0; timer0_init(); TR0 = 1; for(;;) { for(i=0;i<=500;++i) pwm_duty(i); for(i=500;i>0;--i) pwm_duty(i); } } /************************* T0作为定时器的初始化 **************************/ void timer0_init(void) { TMOD |= B0000_0010; //定时器0,8位重装模式 TH0 = 250; //一次溢出代表经过6.51us TL0 = 250; } /********************** 一次溢出代表经过6.51us 参数 c乘以6.51us 就是这个函数延时的时间 ***********************/ void timer0_delay(uint16_t c) { while(c) { if(TF0){ TF0 = 0; //因为是自动重装,因此不用给计数存储器赋值。 --c; } } } /************* 参数d 的范围是[0,500]。d / 500 即为 pwm输出的占空比,控制LED灯的暗亮程度 **************/ void pwm_duty(uint16_t d) { LEDpin = 1; timer0_delay(d); LEDpin = 0; timer0_delay(500-d); } 注:如果需要精确的延时,使用8位自动重装模式最好,因为硬件装值(赋值给TH0)比软件装值快。但8位自动重装模式不宜做单次长时间延迟。毕竟溢出周期短。长时间延迟需要多个溢出周期,也挺消耗资源的。 尽量让溢出周期 越长越好。溢出周期为10ms 的优于 1ms 的。因为,在同样的延时时间下,如100ms,溢出周期为10ms 的 只需要溢出10次,为TH0 和 TL0重新赋值10次,而溢出周期为1ms的要溢出100次,为TH0 和 TL0重新赋值100次。减少溢出次数和赋值次数,可以减轻单片机的负担,提高定时的准确性。
上一篇:非常稳定可靠的单片机按键消抖程序
下一篇:谈51单片机实物与仿真差异
推荐阅读最新更新时间:2024-11-12 16:15
设计资源 培训 开发板 精华推荐
- LTC2637-LMX8 四路、8 位数模转换器的典型应用
- DVP测试板
- 8*8RGB点阵
- LTC2908IDDB-B1、12V、3.3V、2.5V、1.8V、1.5V、1.2V六电源监视器的典型应用电路
- LTC2633-LO10 双路 10 位数模转换器的典型应用
- LT6559 的典型应用 - 采用 3mm x 3mm QFN 封装的低成本 5V/±5V 300MHz 三路视频放大器
- 使用 Panasonic 的 AN32054B 的参考设计
- LT8390IUFD 98% 效率、48W、12V/4A 微型降压-升压稳压器的典型应用电路
- ESP32并口墨水屏驱动-修改自GitHub开源项目epdiy
- 基于STBB3J的2A,2MHz,Vout=3.3V,高效双模降压-升压DC-DC转换器