08-定时器的基本原理与应用
定时器的基本原理与应用
1、什么是定时/计数器?
在没有钟表的时候,定时的方式通过有一注香的时间,或者一桶水的时间。前者烧香不断减少是减法,后者滴水不断增加是加法。
定时/计数器,是一种能够对内部时钟信号或外部输入信号进行计数,当计数值达到设定要求时,向CPU提出中断处理请求,从而实现定时或者计数功能的外设。定时/计数器的最基本工作原理是进行计数。作为定时器时,计数信号的来源选择周期性的内部时钟脉冲;用作计数器时,计数信号的来源选择非周期性的外部输入信号。
不管是定时器还是计数器,本质上都是计数器。
定时器的工作原理与计数初值计算,可以参考以下例子:
2、51单片机的定时/计数器
51单片机有两个定时/计数器T0和T1,为16位加法计数器,由低8位TLx和高8位THx两个寄存器组成,最大计数值为65535个计数脉冲。
该加1计数器的计数脉冲来源有2个:
<1> 系统时钟振荡器输出的12分频。
<2> T0或T1引脚输入的外部脉冲信号。
每接收到一个计数脉冲,计数器就会加1,当计数值累计至全为1时(8位255,13位8191,16位65535),再输入一个计数脉冲,计数器便会溢出回零,并且计数器的溢出是TCON寄存器的TF0或TF1位置1,同时向内核提出中断请求。如果定时/计数器工作于定时模式,则表示间隔定时时间到,如果工作与计数模式,则表示计数值已满。
假设单片机的外部晶振为12MHz,那么,经过12分频后输入计数器的计数脉冲为1MHz,即每个脉冲的周期为1us。因此定时器T0的16位工作模式最大的定时时间为65535us,65.5ms。如果要定时10ms的话,计数器就不能够从0开始计数了,必须给它一个计数初值。怎么计算这个初值呢?
要定时10ms,则相当于计数10000个脉冲后计数器的值就到达65535了,那么开始计数的这个地方就是计数初值。
65535 - 10000 = 55535 = 0xd8ef
把这个计算得到的初值写入TH0和TL0寄存器即可:
TH0 = 0xd8; 或者 TH0 = (65535 - 10000) / 256;
TL0 = 0xef; 或者 TL0 = (65535 - 10000) % 256;
3、定时/计数器相关寄存器
与定时/计数器相关的寄存器除了计数初值寄存器THx和TLx之外,就是TMOD寄存器和TCON寄存器,务必掌握。
<1> TMOD模式控制寄存器,不能进行位寻址,只能字节操作。
<2> TCON中断标志寄存器,参考手册: IAP15F2K61S2_PDF_数据手册_Datasheet_规格书(semiee.com)
4、定时/计数器的编程思想
在定时/计数器的程序设计中,通常有两个函数:初始化函数和中断服务函数。
在初始化函数中,一般需要进行以下几个配置:
<1> 配置工作模式,即对TMOD寄存器编程。
<2> 计算技术初值,即对THx和TLx寄存器进行赋值。
<3> 使能定时/计数器中断,即ET0或ET1置1。
<4> 打开总中断,即EA =1。
<5> 启动定时器,即TR0或TR1置1。
在中断服务函数中,一般需要进行以下的编程:
<1> 如果不是自动重装模式,需要对THx和TLx重新赋值。
<2> 进行间隔定时到达的逻辑处理(越少越好)。
其程序框架和代码编写基本上差不多:
本次单片机为12HMZ晶振的单片机
为了大家的需求,以下以11.0592MHZ的单片机为例,12HMZ同理
1Hz:1秒内电流往返一次
晶振 11.0592MHz =11059200Hz
时钟周期 1/11059200 s(晶振的倒数)
机器周期是 12/11059200 s (标准框架下51单片机一个机器是12个时钟周期)
因为定时器是每个机器周期加1所以定时时间为 N*时钟机器周期时间=所定时间T
所以要经过的机器周期是N*(12/11059200 s)=T
N=t/(12/11059200) t为定时时间单位为s
初值等于 65536-N(因为16位的定时器65535再加1才溢出)
例如:
需要定时50ms=0.05s
0.05/(12/11059200)=0.05(11059200/12)=0.05921600=46080
快速计算只需更改这个 ↑
初值y=65536-46080=19456=0X4C00
1.晶振12M
12MHz除12为1MHz,也就是说一秒=1000000次机器周期。10ms=10000次 机器周期。
2.晶振11.0592M
11.0592MHz除12为921600Hz,就是一秒921600次机器周期,10ms=9216次机器周期。
以上单位训练代码如下:
#include <REGX52.H>
sbit L1 = P0^0;
sbit L8 = P0^7;
void _74HC138(unsigned char n) {
switch(n) {
case 4:
P2 = (P2& 0x1f) | 0x80;
break;
case 5:
P2 = (P2& 0x1f) | 0xa0;
break;
case 6:
P2 = (P2& 0x1f) | 0xc0;
break;
case 7:
P2 = (P2& 0x1f) | 0xe0;
break;
}
}
void System_Init(void) {
_74HC138(5);
P0 = 0x00;
_74HC138(4);
P0 = 0xFF;
}
void InitTimer0() {
TMOD = 0x01;
//1Hz:1秒内电流往返一次
//晶振 11.0592MHz =11059200Hz
// 时钟周期 1/11059200 s(晶振的倒数)
//机器周期是 12/11059200 s (标准框架下51单片机一个机器是12个时钟周期)
//因为定时器是每个机器周期加1所以定时时间为 N*时钟机器周期时间=所定时间T
//所以要经过的机器周期是N*(12/11059200 s)=T
// N=t/(12/11059200)
//初值等于 65536-N(因为16位的定时器65535再加1才溢出)
// THx = (65535 - N) / 256;
// TLx = (65535 - N) % 256; 11.0592MHZ = 11059200HZ
// 机器周期是N*(12/11059200) = T
// N=t/(12/11059200) t 单位s
// 50000us = 50ms
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
// 打开定时中断
ET0 = 1;
// 总中断使能
EA = 1;
// 打开定时器T0
TR0 = 1;
}
void main(void) {
InitTimer0();
_74HC138(4);
System_Init();
while(1) {
}
}
unsigned char count =0;
void Timer0_Rountine(void) interrupt 1 {
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
count++;
// 0.5s 0.5*500 = 250s
if(count % 10 == 0) {
L1 = ~L1;
}
if(count == 100) {
L8 = ~L8;
count=0;
}
}