STM32基本定时器使用指南

实践内容:将定时器作为中断源来控制LED灯的亮灭。

定时器工作原理

如图:

 

 定时器分类

类型 实现 功能
基本定时器 TIM6 、TIM7 常⽤作定时、中断、ADC转换
通⽤定时器 TIM2-TIM5、TIM9-TIM14 具有多路独⽴通道,可用于输⼊捕获、输出⽐
较,也可用作定时功能
⾼级定时器 TIM1、TIM8 具备通用定时器的所有功能,还具有互补信号输
出,刹车输⼊(电机控制)

基本定时器

概念:

STM32F407 基本定时器由时钟源、控制器、时基单元组成。 有两个基本定时器 TIM6 和 TIM7,它们的功能完全相同,资源是完全独立的,可以同时使用。

结构组成:

定时器由时钟源控制器时基单元三个部分组成。如图:

时钟源

 定时器的核心是计算器,要实现计数功能,首先要给它一个时钟源。基本定时器时钟挂载在APB1总线,所以它的时钟来自于APB1总线,但是基本定时器时钟不是直接由APB总线直接提供,而是先经过一个倍频器。 

当APB1的预分频器系数为1 时,这个倍频器系数为1,当APB1的预分频器系数≥2分频时,这个倍频器系数就为2 。

控制器

控制定时器复位、使能、计数等功能之外,还可以用于触发 DAC 转换。

时基单元

构成时基单元的三个组要部分PSC、CNT、ARR的具体功能在文章开篇的图中就已经给出了,这里不再说明。需要说明的概念是影子寄存器

这里假设我们给ARR的值是5,也就是说CNT从0、1、2…..一直数到5算是一个周期(设定CNT的计数模式为递增计数);给PSC的分配大小是2,当CNT数到3(也就是一个周期没数完)时,我们将PSC的大小修改为3,此时CNT不会受到影响,而是等当前周期结束才会发生改变,这个就是影子寄存器的作用。同样,如果我们不改变PSC的大小,而是改变ARR的值,比如改为6,那么CNT也不会立即从数到5结束改为数到6结束,而是在当前周期数到5,下个周期才数到6,所以ARR同样也拥有影子寄存器。

也就是说,PSC和ARR都有两个寄存器,影子寄存器是实际起作用的寄存器,不可直接访问。当更新事件发生时(周期结束),值才写入影子寄存器。PSC的影子寄存器和ARR的影子寄存器有区别:前者不可配置,后者可配置。

CNT的计数模式和溢出条件

计数器模式 溢出条件
递增计数模式 CNT == ARR
递减计数模式 CNT == 0
中心对齐模式 CNT == ARR-1   &&  CNT == 1

溢出时间计算

我们需要定时500ms,该如何计算:
我们的基本定时器未分频之前的频率为:84MHZ,我们设置分频系数为8400, 即写入预分频寄存
器的值为 8399,那么 fCK_CNT=84MHz/8400=10KHz。这样就得到计数器的计数频率为10KHz,即计数器 1 秒钟可以计 10000 个数。我们需要 500ms的中断周期,所以我们让计数器计数 5000 个数就能满足要求,即需要设置自动重载寄存器的值为 4999。

对于定时器的预分频和重载值,通常是因为计数器是从 0 开始的,所以在设置寄存器时需要减1。

对于预分频器,如果设置为 N,则实际的预分频为 +1这是因为预分频器的作用是将输入频率分频为 N+1。所以,如果要实现 N 的预分频,就需要设置为 N−1。同样,对于重载寄存器,如果设置为 M,则实际的重载值为 M+1。这是因为计数器是从 0 开始的,所以为了达到 M 的计数,需要设置为 M−1。

实践

#include "stm32f4xx.h"  // Device header

void TIM6_DAC_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM6,TIM_IT_Update) == SET)
	{
		GPIO_ToggleBits(GPIOF,GPIO_Pin_9);
		GPIO_ToggleBits(GPIOF,GPIO_Pin_10);
		
		/*清除中断标志*/
		TIM_ClearITPendingBit(TIM6,TIM_IT_Update);
	}
}

int main()
{
	/*点灯使能*/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
	/*定时器使能*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
	
	/*初始化定时器结构体*/
	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = TIM6_DAC_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&NVIC_InitStruct);
	
	/*初始化LED灯结构体*/
	GPIO_InitTypeDef GPIO_InitTypeDefStruct;
	GPIO_InitTypeDefStruct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitTypeDefStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitTypeDefStruct.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_9;
    GPIO_InitTypeDefStruct.GPIO_Speed = GPIO_Fast_Speed;
	GPIO_SetBits(GPIOF,GPIO_Pin_10);
	GPIO_SetBits(GPIOF,GPIO_Pin_9);
	GPIO_Init(GPIOF,&GPIO_InitTypeDefStruct);
	
	/*时基单元*/
	
	TIM_TimeBaseInitTypeDef TIM_InitStruct;
	/*预分频系数*/
	TIM_InitStruct.TIM_Prescaler = 8399;
	/*重装载值*/
	TIM_InitStruct.TIM_Period = 4999;
	
	TIM_TimeBaseInit(TIM6,&TIM_InitStruct);

	/*定时器中断配置*/
	TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);
	
	/*定时器中断使能*/
	TIM_Cmd(TIM6,ENABLE);
	
	TIM6_DAC_IRQHandler();

	
	while(1)
	{
	}
	
}

输出结果:STM32F407ZG开发板上的两个LED灯会规律性的亮灭。

注意事项

①我们必须在中断服务函数里把该位清零。如果中断到来后,不清除中断标志,那么系统就会⼀直进入中断服务函数。

②中断函数不要放入循环体中,因为CNT到达ARR设定的值后会自行重置,达到一直循环效果。

物联沃分享整理
物联沃-IOTWORD物联网 » STM32基本定时器使用指南

发表评论