定时器

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

概述

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 灯,方便调试。

相关帖子

回帖

欢迎来到这里!

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

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