主要简单讲解关于STM32定时器的基本定时使用及方法
定时器分为三类:(根据所需可以选择定时器使用)
基本定时器:基本的定时功能,主要用于驱动DAC
通用定时器:具备基本定时器功能、捕获/比较通道、输入捕获、PWM模式
高级定时器:具备通用定时器的功能、互补输出和死区插入
如何选择使用哪一个定时器,可以通过ST官网给的芯片手册去选择:
我这边整理出三者区别图片:
基本定时器的主要特性
基本定时器的特性包括:
1、16 位自动重载递增计数器
2、16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数
介于 1 和 65536 之间
3、用于触发 DAC 的同步电路
4、发生如下更新事件时会生成中断/DMA 请求:计数器上溢
如何使用定时器去配置1s定时?
首先要了解基本定时器的基本结构:
由图分析可得:
1、时钟源:只有一种时钟源,挂在APB时钟线上,并且为84MHz(F401时钟树)。
2、能通过触发控制器输出信号控制DAC。
3、具备主模式功能。
4、自动重载寄存器,PSC预分频寄存器是有影子寄存器的。
5、自动重载寄存器,PSC预分频寄存器不是真正起作用,而是影子寄存器。
6、自动重载寄存器,PSC预分频寄存器只有在更新事件时才会把值传递给它们各自的影子。
7、基本定时器只有向上计数,不存在向下计数。
注:我们程序中能够访问的是自动重装载寄存器,而芯片中实际工作的是影子寄存器,也就是每次与计数器进行比较的寄存器是影子寄存器,我们设定在自动重装载寄存器中的值在每次更新事件发生时传入影子寄存器,预分频器和影子寄存器的关系也是如此。
基本定时器的三个寄存器(时基单元):
计数器寄存器 (TIMx_CNT) :16 位计数器从 0 累加计数到自动重装载数值(TIMx_ARR寄存器),然后重新从 0 开始计数并产生一个计数器溢出事件。
预分频器寄存器 (TIMx_PSC) :对时钟源进行分频,它有缓冲器,即影子寄存器。
自动重载寄存器 (TIMx_ARR):决定计数器一个周期计数的次数,即定时器的周期,它也有缓冲器,即影子寄存器。
计数器寄存器是用于计数的,我们要获得1S的定时,必须要设置好预分频器的值与自动重装载寄存器的值,定时的时间公式:
定时时间=(PSC+1)*(ARR+1)/Fck_psc;
定时时间计算:已知定时器的时钟为 84Mhz,如果分频系数为8400,分频后的计数频率为 84Mhz/8400=10KHz,然后计数器如果计数到10000,那么所得时长为 10000(hz)/10000(cnt)=1s,也就是 1000ms
通过以上的计算得到结论:
1、将预分频器寄存器 TIM6->PSC进行分频8400,因为该寄存器默认已经+1,时间设置的值为8399,也就是 TIM6->PSC=8399
经过TIM6->PSC分频后的计数频率为 84Mhz/8400=10KHz。即10KHz=10000,也就是计数到 10000就是1s,因为该寄存器默认已经+1。所以自动重装载寄存器的值TIM6->ARR=9999。按照标准库配置以下定时器的代码:
由于STM32F401RET6的定时器没有TIM6-TIM7-TIM8所以我这边用TIM3通用定时器去实现基本定时器功能。
#include "tim3.h"
void tim3_init(int psc,int arr)
{
TIM_TimeBaseInitTypeDef TIM3_init; //定时结构体
NVIC_InitTypeDef NVIC_TIM3_Init; //中断结构体变量
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //采用组别2中断分组
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //开启tim3时钟
TIM3_init.TIM_Prescaler = psc -1 ; //分频系数 可以直接写8399
TIM3_init.TIM_Period = arr -1; //自动重载值 可以直接写9999
TIM3_init.TIM_CounterMode = TIM_CounterMode_Up ; //向上计数模式,从0开始数
TIM3_init.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频因子(不分频)
TIM_TimeBaseInit(TIM3, &TIM3_init); //tim3初始化
TIM_ClearFlag(TIM3,TIM_FLAG_Update); //更新中断
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //使能TIM3 UG位更新
TIM_Cmd(TIM3,ENABLE); //使能tim3工作
NVIC_TIM3_Init.NVIC_IRQChannel=TIM3_IRQn;//中断源
NVIC_TIM3_Init.NVIC_IRQChannelCmd=ENABLE;//使能中断
NVIC_TIM3_Init.NVIC_IRQChannelPreemptionPriority=0; //抢占优先级
NVIC_TIM3_Init.NVIC_IRQChannelSubPriority=0;//响应优先级
NVIC_Init(&NVIC_TIM3_Init);
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除TIM3的中断标志位
printf("1s定时时间到\r\n");//最好不要在中断里加输出函数,需要时间执行。为了效果添加
}
}
验证一下代码:
每1S就会进一次中断执行一次打印函数,基本的定时功能实现。可用于定时使用执行某些任务,或者用于计时。