08-定时器的基本原理与应用

定时器的基本原理与应用

1、什么是定时/计数器?
在没有钟表的时候,定时的方式通过有一注香的时间,或者一桶水的时间。前者烧香不断减少是减法,后者滴水不断增加是加法。
定时/计数器,是一种能够对内部时钟信号或外部输入信号进行计数,当计数值达到设定要求时,向CPU提出中断处理请求,从而实现定时或者计数功能的外设。定时/计数器的最基本工作原理是进行计数。作为定时器时,计数信号的来源选择周期性的内部时钟脉冲;用作计数器时,计数信号的来源选择非周期性的外部输入信号。
不管是定时器还是计数器,本质上都是计数器
定时器的工作原理与计数初值计算,可以参考以下例子:

112649npg4n9cd4f119u4r.png.thumb

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、定时/计数器相关寄存器
与定时/计数器相关的寄存器除了计数初值寄存器THxTLx之外,就是TMOD寄存器和TCON寄存器,务必掌握。
<1> TMOD模式控制寄存器,不能进行位寻址,只能字节操作。

115216kelaqaauajq4zyll.png.thumb

<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> 进行间隔定时到达的逻辑处理(越少越好)。
其程序框架和代码编写基本上差不多:

120001ebmt1mbf10pmhrlz.png.thumb

20231005164730

本次单片机为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;
	}
	
	
	
	
}
posted @ 2023-10-05 23:18  夏日清凉~  阅读(271)  评论(0编辑  收藏  举报