1、定时器简介
STM32中,定时器的应用非常广泛,涉及计时、信号检测、电机控制等等,并且定时器章节的介绍在STM32F1的手册里面也占据了大量的篇幅,足以看出定时器的重要性。
我将会做5个实验来学习TIM定时器的使用:
(1)实验目录
2、模式简述
根据官方手册可以看到,TIM的模式有很多:
- 计数器模式:计时模式
- 输入捕获模式:捕获输入的信号电平,捕获发生在影子寄存器上,然后再复制到预装载寄存器中。
- PWM输入模式:输入捕获的一个特例。
- 输出比较模式:预装载寄存器的内容被复制到影子寄存器中,然后影子寄存器的内容和计数器进行比较。
- 强制输出模式:输出比较信号)能够直接由软件强置为有效或无效状态,而不依赖于输出比较寄存器和计数器间的比较结果。
- PWM模式:由内部ARR和CCR寄存器控制端口输出确定占空比的PWM信号。
- 单脉冲模式:允许计数器响应一个激励,并在一个程序可控的延时之后,产生一个脉宽可程序控制的脉冲。
加粗的都是比较常用和重要的模式。
此外,TIM1和TIM8不仅具有通用定时器的所有功能,并且还具备控制交直流电机的功能(输出6路互补带死区的信号,刹车功能等)。
定时器总共分为三种:基本定时器、通用定时器、高级定时器
图片来源:零死角玩转STM32(库函数版)刘火良 图31-1
图片来源:STM32官方手册 第六章 RCC部分
特别提醒:除非APB1在预分频的时候被配置为=1的数,那么定时器TIM2-TIM7的时钟为APB1的2倍,也就是72MHz
从上图可以看出,如果没有特别设定RCC的话,所有定时器的时钟均为72MHz
3、初始化结构体
typedef struct
{
uint16_t TIM_Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock.
This parameter can be a number between 0x0000 and 0xFFFF */
uint16_t TIM_CounterMode; /*!< Specifies the counter mode.
This parameter can be a value of @ref TIM_Counter_Mode */
uint16_t TIM_Period; /*!< 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. */
uint16_t TIM_ClockDivision; /*!< Specifies the clock division.
This parameter can be a value of @ref TIM_Clock_Division_CKD */
uint8_t TIM_RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounter
reaches zero, an update event is generated and counting restarts
from the RCR value (N).
This means in PWM mode that (N+1) corresponds to:
- the number of PWM periods in edge-aligned mode
- the number of half PWM period in center-aligned mode
This parameter must be a number between 0x00 and 0xFF.
@note This parameter is valid only for TIM1 and TIM8. */
} TIM_TimeBaseInitTypeDef;
TIM_Period:配置ARR,重装载值
TIM_Prescaler:预分频值
TIM_CounterMode:计数方法,向上、向下、中央对齐三种
TIM_ClockDivision:设置定时器时钟与数字滤波器之间的分频比例(与输入捕获相关)
TIM_RepetitionCounter:重复计数,也就是重复多少次才发生计数溢出中断。看到官方注释里面这个数只与TIM1和TIM8有关
4、定时器计时周期计算
计数频率 = 总线频率/[(预分频因子+1)*(重装载值+1)]
f = f总/[(PSC+1)*(ARR+1)]
计时周期 T = 1/f
例3-1:
TIM3实现500ms定时,挂载在APB1上 总线频率为72MHz
T = [(PSC+1)*(ARR+1)]/f总
0.5 = [(PSC+1)*(ARR+1)]/72M
PSC=7199,ARR=4999或者其他配置只要满足等式均可。
5、代码示例
//TIM3 基本定时配置
void TIM3_Config(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//TIM3基础配置
//计时器时钟 = APB总线时钟/分频因子
// psc
TIM_TimeBaseStructure.TIM_Period = arr;//重装载值/最大计数值
TIM_TimeBaseStructure.TIM_Prescaler = psc;//预分频值
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//TIM3中断使能
//中断优先级配置 优先级:2 0
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3,ENABLE); //使能TIM3
}
/*
*TIM3 中断服务函数
*/
//LED1单独闪三次,第四次LED1闪的同时LED0变灯
int a=0;
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET) //再次检测是否有中断
{
a++;
if(a == 4)
{
LED0 = !LED0;
a=0;
}
LED1 = !LED1;
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}