定时器

本贴最后更新于 502 天前,其中的信息可能已经沧海桑田

概述

image.png

清 0 则用作定时器(对内部系统时钟进行计数),置 1 用作计数器(对引脚 T0/P3.4 外部脉冲进行计数)

定时功能:内部时钟的频率,再结合计数,就可以计算这段时间所用的时间。

寄存器

辅助寄存器 1(AUXR)

image.pngimage.png

默认都是 12T。

中断与时钟输出控制寄存器(INTCLKO)

image.png

如果选择时钟输出,必须要将对应的 IO 口初始化。

单位

==1M 是 1 百万,就是 1000000。==

计数单位应包含整数部分和小数部分两大块,并按以下顺序排列:京、千兆、百兆、十兆、兆、千亿、百亿、十亿、亿、千万、百万、十万、万、千、百、十、个(一)、十分之一、百分之一、千分之一。

M 的英文全称是 million ,意思是百万,1M 就是 1 百万,就是 1000000,通常商业中说的 M 就是十进制的 M,即一百万。另外我们通常所说的流量中的 M 不是 1 百万,而是 1024KB,因为我们流量的计算用的是二进制。

  • 1GHz=1000MHz,1MHz=1000kHz,1kHz=1000Hz
  • 1s=1000ms,1 ms=1000μs,1μs=1000ns
  • s(秒)、ms(毫秒)、μs(微秒)、ns(纳秒)---

时钟频率 时钟周期

  • 5MHz 200ns
  • 10MHz 100ns
  • 20MHz 50ns
  • 25MHz 40ns
  • 33MHz 30ns
  • 40MHz 25ns
  • 50MHz 20ns
  • 66MHz 15ns
  • 80MHz 12ns
  • 100MHz 10ns
  • 120MHz 8.3ns
  • 133MHz 7.5ns

时钟周期与时钟频率互为倒数, 我们可以找出以下关系:

  • 时钟频率 时钟周期
  • 1Hz 1s
  • 1KHz 1ms
  • 1MHz 1μs
  • 1GHz 1ns---

知道这些,我们就能很快换算周期与频率.

  • 比方 10KHz, 那么就是 1/10 = 0.1ms, 即 100μs.

  • 比方 100ns, 那么就是 1/100 = 0.01GHz, 即 10MHz.

定时器初值计算

1、时钟周期,也称为振荡周期:定义为时钟脉冲的倒数,在单片机中也就等于晶振的倒数。
51 单片机中把一个时钟周期定义为一个节拍(用 P 表示),2 个节拍定义为状态周期(用 S 表示)
时钟周期是单片机中最小的时间单位。
eg:12M 晶振的单片机,时钟周期=振荡周期=1/12 us。

2、机器周期:定义为完成一项基本操作所需要的时间,称为机器周期。
在计算机中,为了方便管理,把一条指令的执行过程分为若干个阶段,每个阶段去执行一项基本操作。
如:取指令,存储器读,存储器写等。
在 51 单片机中 1 个机器周期由 6 个状态周期组成,也就是 12 个时钟周期=12 x 1/12 us =1 us
定义机器周期是因为时钟周期时间太短,根本做不了什么。

3、指令周期:定义为执行一条指令所需的时间。
通常,包含一个机器周期的指令称为单周期指令,比如 MOV 指令,CLR 指令等。
包含两个机器周期的指令称为双周期指令。
另外还有四周期指令。

相比于delay计时,delay是要直接让单片机做空循环,死等。而定时器则是利用定时器的溢出间隔,如果时间上不够,可以在溢出中断中配合软件计数器来实现。 前者浪费cpu,后者更高效

最大频率

image.png

如果是 24M 的晶振,最大值为 2M;

  1. 51 单片机入门 - 定时/计数器原理及结构(T0 和 T1)
  2. 51 单片机定时器初值的计算

定时器(外部脉冲计数)

image.png

image.png

自动重新装载 VALUE 的值,当来了一个脉冲加一,溢出产生中断。

计算公式

定时器周期

image.png

定时器频率

image.png

定时计数

**12T:**65535-系统时钟/12/定时周期

程序

参考程序

#include	"STC8A_Timer.h"
#include	"STC8A_NVIC.h"

/******************** 主函数**************************/
void main(void)
{

	Timer_config();
	EA = 1;

	while (1);
}


/************************ 定时器配置 ****************************/
void	Timer_config(void)
{
	TIM_InitTypeDef		TIM_InitStructure;						//结构定义
	TIM_InitStructure.TIM_Mode      = TIM_16BitAutoReload;	//指定工作模式,   TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
	TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T;		//指定时钟源,     TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
	TIM_InitStructure.TIM_ClkOut    = DISABLE;				//是否输出高速脉冲, ENABLE或DISABLE
	TIM_InitStructure.TIM_Value     = 65536UL - (MAIN_Fosc / 100000UL);		//初值,
	TIM_InitStructure.TIM_Run       = ENABLE;					//是否初始化后启动定时器, ENABLE或DISABLE
	Timer_Inilize(Timer0,&TIM_InitStructure);					//初始化Timer0	  Timer0,Timer1,Timer2,Timer3,Timer4
	NVIC_Timer0_Init(ENABLE,Priority_0);		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
}

//========================================================================
// 函数: Timer0_ISR_Handler
// 描述: Timer0中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-23
//========================================================================
void Timer0_ISR_Handler (void) interrupt TIMER0_VECTOR		//进中断时已经清除标志
{
	P27 = ~P27;
}

测高电平脉宽

只有定时器 0 和定时器 1 可以设置 GATE 位。

image.png

image.png

  1. 配置辅助和控制寄存器,清空计数寄存器。
  2. 等待低电平结束,高电平触发时,开启计数
  3. 启用下降沿中断,进入中断程序,执行对应的功能

定时器做波特率发生器

image.pngimage.png

串口和定时器解决方法

image.png

image.png

串口与定时器的重要关系_单片机串口必备基础知识

51 单片机的定时器 0 和串口同时使用问题

定时器 + 计数器

u8 timer_count=0;				//定时器计数
u8 isFlag=0;					//显示标志位
double ttl_count=0;				//一秒钟有多少个周期数
double temp_freq=0;				//暂时周期数

void main()
{
	Timer_config();
	EA = 1;
	while(1)
	{
		if(isFlag == 1)
		{
			LCD_DISPLAY_NUM(0,0,temp_freq);
			//temp_freq=0;
			DigDisplayNum((long)(temp_freq));
			isFlag=0;
		}
	}
}

void	Timer_config(void)
{
	//P34
	TIM_InitTypeDef		TIM_InitStructure;						//结构定义
	TIM_InitStructure.TIM_Mode      = TIM_16BitAutoReload;	//指定工作模式,   TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
	TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_12T;		//指定时钟源,     TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
	TIM_InitStructure.TIM_ClkOut    = DISABLE;				//是否输出高速脉冲, ENABLE或DISABLE
	TIM_InitStructure.TIM_Value     = 65536UL - (MAIN_Fosc / (50UL * 12 ));		//初值,
	TIM_InitStructure.TIM_Run       = ENABLE;					//是否初始化后启动定时器, ENABLE或DISABLE
	Timer_Inilize(Timer0,&TIM_InitStructure);					//初始化Timer0	  Timer0,Timer1,Timer2,Timer3,Timer4
	NVIC_Timer0_Init(ENABLE,Priority_2);		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3

	//P12
	TIM_InitStructure.TIM_Mode      = TIM_16BitAutoReload;	//指定工作模式,   TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
	TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_Ext;		//指定时钟源,     TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
	TIM_InitStructure.TIM_ClkOut    = DISABLE;				//是否输出高速脉冲, ENABLE或DISABLE
	TIM_InitStructure.TIM_Value     = 0;					//初值,
	TIM_InitStructure.TIM_Run       = ENABLE;				//是否初始化后启动定时器, ENABLE或DISABLE
	Timer_Inilize(Timer2,&TIM_InitStructure);				//初始化Timer0	  Timer0,Timer1,Timer2,Timer3,Timer4
	NVIC_Timer2_Init(ENABLE,Priority_3);		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
}

void Timer0_ISR_Handler (void) interrupt TIMER0_VECTOR		//进中断时已经清除标志
{
	timer_count ++;
	if(timer_count == 50)
	{
		temp_freq = (long)(ttl_count*65536+TH2*256+TL2);	//取出脉冲数
		isFlag=1;				//显示标志位
		timer_count=0;			//定时计数清0
		ttl_count=0;			//脉冲计数
		//对值进行清零前,需要停止计数
		Timer2_Stop();

		TH2 =0;
		TL2 =0;
	
		//清完零之后继续计数
		Timer2_Run(1);
		T2_Load(0);
	
		LCD_Clear();
	}
}
void Timer2_ISR_Handler (void) interrupt TIMER2_VECTOR		//进中断时已经清除标志
{
	T2_Load(0);
	ttl_count++;
}

注意事项

  1. 一定要记得==EA=1==
  2. 使用时钟输出时,要配置 IO 口。
  3. 修改定时器计数器的值的时候,需要关闭计数器,之后再重新装载初始值,开启计数器。

其他想法

  1. 定时器的输出口,可以连接 LED 灯,方便调试。

相关帖子

回帖

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...