定时器理解

Posted 旭日初扬

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了定时器理解相关的知识,希望对你有一定的参考价值。

一、定时器分类

1.1、通用定时器

TIM2~TIM5是一个向上/向下计数的定时器。

功能:可以定时、输出比较、输入捕捉、每个定时器有四个外部IO。

1.2、基本定时器

TIM6、TIM7  是一个16位的只能向上计数的定时器,没有外部IO口只能定时。

1.3、高级定时器

TIM1和TIM8

16位向上/向下计数的定时器

功能:输出比较、输入捕捉、三相电机互补输出信号、每个定时器有8个外部IO

 二、定时器相关概念

2.1、内部时钟

定时器时钟:TIMxCLK

内部时钟:INTCLK

 定时器时钟TIMxCLK即内部时钟CK_INT,经过APB1预分频后提供

如果预分频系数为1,则频率不变,否则频率*2

库函数中APB1的预分频系数是2,即PCLK1=36M,即定时器2~7的时钟频率(CK_INT)为72M

1MHz = 1000KHz = 1000 000 Hz

  • CLK :AHB总线时钟,由系统时钟SYSCLK 分频得到,一般不分频等于系统时钟,HCLK是高速外设时钟,是给外部设备的,比如内存,flash
  • PCLK1:低速APB时钟(PCLK1)
  • PCLK2:高速APB时钟(PCLK2)

自定义所需的时钟(例)

  • 库函数默认配置系统时钟为72M。
  • SYSCLOCK(系统时钟)=HCLK(AHB总线时钟)     库函数的配置     AHB预分频器1分频。
  • APB1预分频器8分频 得PCLK1的时钟,72/8=9M,即PCLK 1(APB1外设时钟)=9M
  • TIM2~TIM7的时钟(TIMxCLK):由于APB1分频器此处为8分频,因此TIM2~TIM7的时钟频率*2,TIMxCLK =2PCLK1=18M

RCC_PCLK1Config(RCC_HCLK_Div8);  
RCC_PCLK2Config(RCC_HCLK_Div8);

定时器TIM2~TIM7的时钟频率为:18M,即内部时钟频率=定时器时钟频率=18M

假定

//  CNT计数器计数周期  
TIM_TimeBaseStructure.TIM_Period =1000; 

//  指定用于除TIM时钟的预分器值                   
TIM_TimeBaseStructure.TIM_Prescaler = 9-1;  

CK_CNT(计数器时钟 )= 内部时钟/内部时钟预分频器的值+1 = 18/9 = 2MHz

CNT计数周期:1000      计数器计数到1000时,如果使能定时器中断,会产生中断溢出(更新)

CNT计数频率:f=1/T = 1/1000

计数器计数一次的时间:1/CK_CNT = 1/2 微妙(us)

中断时间=period*(prescaler+1)/TIMxCLK = 1000*9000 000 /18000 000 =500微妙

2.2、 计数器时钟(CNT)

CNT是一个16位的计数器,只能向上计数,计数值为:0xFFFF(65535),

当计数器达到自动重装载寄存器的时,产生中断事件,并清零重新计数。

CK_CNT(计数器时钟)=内部时钟(CK_INT)/(TIM_Prescaler+1)

2.3、自动重装载寄存器

/*
 Specifies the period value to be loaded into the active
 Auto-Reload Register at the next update event.
This parameter must be a number between 0x0000 and 0xFFFF.
*/ 
TIM_TimeBaseInitStructure.TIM_Period=6000;  

自动重装载寄存器ARR是一个16位的寄存器,这里装载着计数器能计数的最大值,当计数到这个值时,如果使能了中断,定时器就会产生溢出中断。

2.5、定时时间计算

定时器的定时时间 =定时器中断周期*中断次数

计数器在CK_CNT在内部时钟的驱动下,计一个数的时间是CK_CLK的倒数

计一个数的时间 = 1/(TIMxCLK/(PSC+1))   即   psc+1 / TIMxCLK

产生一次中断的时间:1/(分频系数*计数周期)

中断服务函数中定义一个变量T,用于记录中断次数。则定时时间 = 1/CK_CLK*(ARR+1)*T

三、代码

3.1、初始化函数

void TIM3Init(u16 per,u16 psc)
{
   //  一、使能时钟
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM4时钟
	
	//  二、初始化定时器参数,包含自动重装载的值,分频系数,计数方式
  TIM_TimeBaseInitStructure.TIM_Period=per;                       //   自动装载值       定时周期
	TIM_TimeBaseInitStructure.TIM_Prescaler=psc;                    //   分频系数         定时器预分频率
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;       //   一分频           时钟分频  
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;   //   设置向上计数模式 计数模式
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);              //   初始化定时器3
	
	//  三、设置定时器中断类型,并使能
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);                        //开启定时器中断
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
	
	//  四、设定定时器中断优先级,使能定时器中断通道
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;          //  定时器中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;  //  抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		     //  子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			     //  IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	
	
	//  五、开启定时器
	TIM_Cmd(TIM3,ENABLE); //使能定时器	
}

3.2、中断服务函数

void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update))  //  TIM3更新(溢出)中断是否产生
	{
		//  更新中断  中需要执行的操作
	}
   // Clears the TIMx's interrupt pending bits.
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);	
}

设计一个1s的定时器中断

// 定时器产生中断的时间 = (预分频系+1数)*(CNT计数周期)/INT定时器时钟
void TIM3Init(1000,72000-1);

72000 000Hz /72MHz  = 1s

以上是关于定时器理解的主要内容,如果未能解决你的问题,请参考以下文章

如何理解这段代码片段中的两对括号?

如何在使用片段和计时器的选项卡式活动上更新 UI

测试片段不执行定时器或示例超时

精心收集的 48 个 JavaScript 代码片段,仅需 30 秒就可理解

前端面试题之手写promise

精心收集的 48 个 JavaScript 代码片段,仅需 30 秒就可理解!(转载)