目录
STM32系列芯片具有多个定时器供使用者选择,其中包括TIM1和TIM8等高级定时器,TIM2到TIM5等通用定时器,还有TIM6和TIM7等基本定时器。定时器在单片机系统中地位十分重要,本文中可能无法全面展开。
基本定时器TIM6 和TIM7 是一个16 位的只能向上计数的定时器,只能定时,没有外部IO
通用定时器TIM2/3/4/5 是一个16 位的可以向上/下计数的定时器,可以定时,可以输出比较,
可以输入捕捉,每个定时器有四个外部IO
高级定时器TIM1/8 是一个16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有8 个外部IO
介绍,我们先做一个基本了解,日后笔者可能还会有定时器相关的内容呈现给大家。所以,本文以通用定时器作为引导,大致了解一下STM32的定时器系统。
0x01、基本定时器简介
0x0001、时钟源
定时器时钟TIMxCLK,即内部时钟CK_INT,经APB1 预分频器后分频提供,如果APB1 预分频
系数等于1,则频率不变,否则频率乘以2,库函数中APB1 预分频的系数是2,即PCLK1=36M,
所以定时器时钟TIMxCLK=36*2=72M。
0x0002、计数器时钟
定时器时钟经过PSC 预分频器之后,即CK_CNT,用来驱动计数器计数。PSC 是一个16 位的预
分频器,可以对定时器时钟TIMxCLK 进行1~65536 之间的任何一个数进行分频。具体计算方式
为:CK_CNT=TIMxCLK/(PSC+1)。
0x0003、计数器
计数器CNT 是一个16 位的计数器,只能往上计数,最大计数值为65535。当计数达到自动重装
载寄存器的时候产生更新事件,并清零从头开始计数。
0x0004、自动重装载寄存器
自动重装载寄存器ARR 是一个16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到
这个值的时候,如果使能了中断的话,定时器就产生溢出中断。
0x0005、定时时间的计算
定时器的定时时间等于计数器的中断周期乘以中断的次数。计数器在CK_CNT 的驱动下,计一
个数的时间则是CK_CLK 的倒数,等于:1/(TIMxCLK/(PSC+1)),产生一次中断的时间则等于:1/(CK_CLK * ARR)。如果在中断服务程序里面设置一个变量time,用来记录中断的次数,那么就可以计算出我们需要的定时时间等于:1/CK_CLK* (ARR+1)*time。
0x02、定时器初始化结构体详解
typedef struct
{
uint16_t TIM_Prescaler; // 预分频器
uint16_t TIM_CounterMode; // 计数模式
uint16_t TIM_Period; // 定时器周期
uint16_t TIM_ClockDivision; // 时钟分频
uint8_t TIM_RepetitionCounter; // 重复计算器
} TIM_TimeBaseInitTypeDef;
(1) TIM_Prescaler:定时器预分频器设置,时钟源经该预分频器才是定时器时钟,它设定TIMx_PSC寄存器的值。可设置范围为0 至65535,实现1 至65536 分频。
(2) TIM_CounterMode:定时器计数方式,可是在为向上计数、向下计数以及三种中心对齐模式。
基本定时器只能是向上计数,即TIMx_CNT 只能从0 开始递增,并且无需初始化。
(3) TIM_Period:定时器周期,实际就是设定自动重载寄存器的值,在事件生成时更新到影子寄
存器。可设置范围为0 至65535。
(4) TIM_ClockDivision:时钟分频,设置定时器时钟CK_INT 频率与数字滤波器采样时钟频率分
频比,基本定时器没有此功能,不用设置。
(5) TIM_RepetitionCounter:重复计数器,属于高级控制寄存器专用寄存器位,利用它可以非常容
易控制输出PWM 的个数。这里不用设置。
虽然定时器基本初始化结构体有5 个成员,但对于基本定时器只需设置其中两个就可以,想想使
用基本定时器就是简单。
0x03、库函数
由于定时器相关的寄存器数量众多,介绍复杂,所以这里我们就不详细介绍了,具体的可以查看官方文档。
定时器设置的一般步骤可以总结为以下几步:
1、定时器时钟使能
2、初始化定时器,设置自动重装值,分频系数,计数方式等
3、允许更新中断
4、设置定时器中断优先级
5、使能定时器
6、编写中断服务函数
0x0001、初始化函数
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
函数功能:根据TIM_TimeBaseInitStruct中指定的参数初始化定时器外围设备。
参数1:TIM_TypeDef* TIMx —> 选择TIM外围设备。
参数2:TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct —> 指向包含指定TIM外围设备的配置信息的TIM_TimeBaseInitTypeDef结构体的指针。
返回值:无
0x0002、初始化TIMx外设为默认重置值函数
void TIM_DeInit(TIM_TypeDef* TIMx)
函数功能:将TIMx外围寄存器反初始化为其默认重置值。
参数1:TIM_TypeDef* TIMx —> 选择TIM外围设备。
返回值:无
0x0003、是否允许改变定时器计数值。
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
函数功能:启用或禁用ARR上的TIMx外围预加载寄存器。
参数1:TIM_TypeDef* TIMx —> 选择TIM外围设备。
参数2:FunctionalState NewState —>TIMx外围预加载寄存器的新状态
返回值:无
这个函数要重点说一下,如果我们不需要在程序运行中改变定时器的计数值,我们可以不用该函数,如果需要在程序运行中改变定时器的定时时间,我们可以使用该函数开启该功能。然后通过TIM_PrescalerConfig函数重新配置定时器。
0x0004、配置TIMx预分频器。
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode)
函数功能:配置TIMx预分频器。
参数1:TIM_TypeDef* TIMx —> 选择TIM外围设备。
参数2:Prescaler —> 指定预分频器寄存器值
参数3:TIM_PSCReloadMode —> 指定预分频器重新加载模式
此参数可以是以下值之一:
TIM_PSCReloadMode_Update: 预分频器在更新事件中加载。
TIM_PSCReloadMode_Immediate: 预分频器立即加载。
返回值:无
0x0005、中断使能函数
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
函数功能:启用或禁用指定的TIM中断。
参数1:TIM_TypeDef* TIMx —> 选择TIM外围设备。
参数2:uint16_t TIM_IT —>指定TIM中断要启用或禁用的源。
参数3:FunctionalState NewState —>定时器中断的新状态
返回值:无
0x0006、定时器使能函数
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
函数功能:启用或禁用指定的TIM外围设备。
参数1:TIM_TypeDef* TIMx —> 选择TIM外围设备。
参数2:FunctionalState NewState —>定时器的新状态
返回值:无
0x0007、定时器中断判断函数
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT)
函数功能:检查TIM中断是否发生。
参数1:TIM_TypeDef* TIMx —> 选择TIM外围设备。
参数2:uint16_t TIM_IT —> 指定要检查的TIM中断源。
返回值:定时器中断的新状态
0x0008、清除中断标志位
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
函数功能:检查TIM中断是否发生。
参数1:TIM_TypeDef* TIMx —> 选择TIM外围设备。
参数2:uint16_t TIM_IT —> 指定要清除的TIM中断源。
返回值:无
0x0009、定时器计数值设定函数
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter)
函数功能:设定计数器的计数值
参数1:TIM_TypeDef* TIMx —> 选择TIM外围设备。
参数2:uint16_t TIM_IT —> 指定计数器寄存器的新值。
返回值:无
0x04、编写函数
/**
*@brief TIM6定时器1s定时
*@param 无
*@return 无
*/
void TIM6_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); // 使能定时器6时钟
// 定时器6初始化 TIM2频率为72MHz
TIM_TimeBaseStructure.TIM_Period = 9999; // 定时时间为计数1000次,即1s
TIM_TimeBaseStructure.TIM_Prescaler = 7199; // 分频系数7200,频率为72000000/7200 = 10000,即每秒计数10000次
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); // 初始化定时器
/* 使能TIM6全局中断 */
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ClearFlag(TIM6, TIM_FLAG_Update); // 清除溢出中断标志位
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); // 定时器6溢出中断开启
TIM_Cmd(TIM6, ENABLE); // 定时器6使能
}
/**
*@brief TIM6中断函数
*@param 无
*@return 无
*/
void TIM6_IRQHandler(void)
{
if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM6, TIM_FLAG_Update); // 清除定时器T6溢出中断标志位
if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_10) == 1)
{
GPIO_ResetBits(GPIOC,GPIO_Pin_10);
}
else
{
GPIO_SetBits(GPIOC,GPIO_Pin_10);
}
}
}
0x05、源程序下载地址
该程序利用定时器6产生1S定时,是led灯每隔1s翻转一次