STM32F4的定时器分布如下:
- 其中基本定时器包括TIM6、TIM7,其结构最简单,也具有最基本的定时功能,一是用于基本定时、产生时基、二是用于驱动DAC数模转换器。
- 其中通用定时器包括TIME2-TIME5,TIME9-TIME14共10个;通用定时器除了包含基本定时器的功能外还有输入捕获、输出比较和PWM功能等。
- 其中高级定时器包括TIM1、TIM8;
定时器的相关常用寄存器功能如下:
定时器的时钟源有4个:
- 内部时钟(CK_INT)
- 外部时钟模式1:外部输入脚(TIx)
- 外部时钟模式2:外部触发输入(ETR),仅适用于TIM2、TIM3、TIM4
- 内部触发输入(ITRx):使得A定时器作为B定时器的预分频器(A为B提供时钟)
这是通过设置TIMx_SMCR的相关位来选择的。其中内部时钟(CK_INT)来自于APB1或APB2总线。
该寄存器用于对时钟进行分频,然后提供给计数器,作为计数器的时钟。
其中16位空间存储分频系数。
它存储了定时器当前的计数值。
该寄存器在物理结构上对应着2个寄存器,一个是程序员可以操作的,另一个是看不到且不能操作的ARM把它叫做影子寄存器。实际上真正起作用的是影子寄存器。
根据 TIMx_CR1 寄存器中 APRE 位的设置: APRE=0 时,预装载寄存器的内容可以随时传送到影子寄存器,此时 2 者是连通的;而 APRE=1 时,在每一次更新事件(UEV)时,才把预装载寄存器( ARR) 的内容传送到影子寄存器。
这里我们只用最后一位:更新中断使能(UIE:update interrupt enable),改为置1用来允许由更新事件产生的中断。
简单应用中,我们只需要使用最后一位:计数器使能位(CEN:counter enable),改为必须置1才能使计数器开始计数。
接下来我们使用定时器产生定时中断,根据配置定时器的实际步骤,以TIM3为例解析配置过程。
定时器相关的库函数主要集中在固件库文件 stm32f4xx_tim.h 和 stm32f4xx_tim.c 文件中。 定时器配置步骤如下:
TIM3挂载在APB1下,所以要通过使能APB1总线的使能函数来使能TIM3的时钟源。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); ///使能 TIM3 时钟
配置定时器相关参数。
void TIM_TimeBaseInit(
TIM_TypeDef *TIMx,
TIM_TimeBaseInitTypeDef *TIM_TimeBaseInitStruct
);
第一个参数是指定哪个定时器;
第二个参数是定时器配置参数结构体;
typedef struct{
uint16_t TIM_Prescaler; //分频系数
uint16_t TIM_CounterMode; //计数方式(向上、向下、中央对其)
uint16_t TIM_Period; //自动重载计数值(即定时时间)
uint16_t TIM_ClockDivision; //时钟分频因子????
uint8_t TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef;
实际的:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //声明初始化参数结构体变量
TIM_TimeBaseStructure.TIM_Period = 5000; //以下开始填充
TIM_TimeBaseStructure.TIM_Prescaler =7199;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //执行初始化
库函数TIM_ITConfig用来设置打开中断
void TIM_ITConfig(TIM_TypeDef* TIMx, //指定哪个定时器
uint16_t TIM_IT, //指定中断类型(更新中断、触发中断等等)
FunctionalState NewState); //使能还是失能
实际的:
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能更新中断
既然使用中断,就必须设置NVIC,使用NVIC_Init 函数设置。这里就不多讲了,很常用。
配置好后要使能定时器,使其开始工作,使用TIM_Cmd函数:
void TIM_Cmd(TIM_TypeDef* TIMx, //指定定时器
FunctionalState NewState); //指定状态
实际的:
TIM_Cmd(TIM3, ENABLE); //使能 TIM3 外设
最后还是要编写中断函数来处理定时器产生的相关中断。流程为:
在中断产生后:通过状态寄存器的值来判断此次中断属于什么类型->执行相关操作->清除SR寄存器的中断标志。
另外,固件库中还提供了两个函数用来判断定时器的状态和清除定时器状态标志函数:TIM_GetFlagStatus 和 TIM_ClearFlag,它们的作用和上面两个相似,不过它们要先判断中断是否使能,然后再判断中断标志位,而TIM_GetITStatus直接判断中断标志位。
实际的:
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //判断中断状态
{
//
//do sth here. //执行操作
//
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除中断标志