本文主要通过介绍定时器基本结构去学习如何使用定时器进行定时。
一、定时器基本介绍
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断,从而达到计时功能。
本文从通用定时器介绍。本文所使用芯片为 STM32F103C8T6,拥有TIM1-TIM4 四个定时器资源。
1.1、基本定时器结构
图.2为基本定时器结构
红色框选部分为时基单元。
【1】内部时钟(CK_INT)输入到PSC预分频器,预分频器会对输入时钟进行分频。如PSC=0时为1分频,即CK_CNT=CK_INT/1, PSC=1时,CK_CNT=CK_INT/2。
【2】CNT计数器:对预分频后的时钟进行计数,计时时钟每来一个上升沿,计数器+1,直到达到最大计数值,即65535。最大值后再增加则会回到0,从头开始。
【3】自动重装寄存器:存储了CNT计数器需要计数的值,当计数器计数值等于自动重装值,则会产生中断信号,并重置计数器。
【4】更新中断:即为【3】所产生的中断信号(图3蓝色框选部分)。更新中断之后就会通往NMIC,再配置好NMIC的定时器通道,更新中断就可得到CPU相应
【5】更新事件:同为【3】所产生的信号,但器不会触发中断,而是触发内部其他电路工作。
1.2、通用定时器结构介绍
【1】图四中,红色框选部分与基本定时器结构相同。但是基本定时器仅有向上计数模式,而通用定时器与高级定时器可支持向下计数与中央对齐计数。
- 向下计数:从自动重装寄存器设定值向下递减1,直到为0,,并产生中断信号从而触发更新中断或更新时间。
- 中央对齐计数:CNT从0开始计数,计数值与自动重装值相等时,申请中断,随后又向下自减至0,再次申请中断,以此循环。
【2】 输入时钟:绿色框选部分为输入时钟,对于基本定时器而言,只有内部时钟可选择。对于通用定时器,可以选择外部时钟。
1.3、定时器定时配置流程
1.4、时序描述
1.4.1、预分频器时序
【1】预分频控制寄存器:仅供读写作用,并不直接决定分频系数。
【2】缓冲寄存器:真正决定分频系数的寄存器。
当预分频控制寄存器的分频系数由0>1时,预分频缓冲器并未立即更新分频系数,而是等待本次计数周期结束时,产生更新事件后,预分频控制寄存器的分频系数的值才会被传递到预分频缓存寄存器,此时分频系数才真正变为1。
计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)。
1.4.2、计数器时序
分频系数为2,CK_CNT=72MHz。CNT_EN为时钟使能,高电平启动。
【1】CK_CNT:由于分频系数为2,因此CK_CNT=CK_INT/2=36MHz。
【2】计数器寄存器:上升沿自增,增加到0036时,发生溢出,尝产生更新事件,更短中断标志位置1,申请中断。中断响应后需手动清零标志位UIF
计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)。
例如,需要定时1s。
定时 f=1s=1Hz=72MHz / 7200 / 10000.
此时预分频值 (PSC + 1)为720,自动重装值 (ARR + 1)为1000.
二、现象代码(定时器定时中断)
以上为该例程硬件接线图
2.1、Timer.c文件
以下代码为该文件全部代码(不包含头文件)
extern int16_t NUM;
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启时钟,TIM2是APB1总线的外设
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //指定参数分频值(选择1分频),DIV22分频 DIV4 44分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//选择技术模式;
TIM_TimeBaseInitStructure.TIM_Period=10000-1;
TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); //配置时基单元
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM2,ENABLE);
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
NUM++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
2.1.1、TIM部分
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启时钟,TIM2是APB1总线的外设
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //指定参数分频值(选择1分频),DIV22分频 DIV4 44分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//选择计数模式;
TIM_TimeBaseInitStructure.TIM_Period=10000-1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler=720-1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); //配置时基单元
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
【1】TIM_InternalClockConfig():使用内部时钟函数。单片机上电默认使用内部时钟,因此可以不写改代码。
【2】TIM_ClockDivision:指定时钟分频,DIV2 2分频 DIV4 4分频 。本例中选择不分频。
滤波器主要依靠采用频率以及采用点数工作,其信号来源可以是内部时钟分频而来,而分频值即由该参数决定。此处可任意分配值。
【3】TIM_CounterMode:计数模式,继续向上、向下或对齐计数模式。本例选择向上计数模式。
【4】TIM_Period: ARR自动重装寄存器值
【5】TIM_Prescaler: PSC预分频计数器置
【6】TIM_TimeBaseInitStructure:高级定时器才拥有,因此此处给0.
【7】TIM_ClearFlag():使能中断函数。
【8】TIM_ClearFlag();引用该函数是为了解决复位立刻进中断的现象。
2.1.2、NVIC部分
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM2,ENABLE);
【1】NVIC_PriorityGroupConfig():中断分组,配置优先级分组:抢占优先级和次优先级。
【2】NVIC_IRQChannel:指定要启用或禁用的IRQ通道。
【3】NVIC_IRQChannelCmd:使能
【4】NVIC_IRQChannelPreemptionPriority:抢占优先级
【5】NVIC_IRQChannelSubPriority:响应优先级
2.1.3、中断函数
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
NUM++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
【1】TIM_GetITStatus():查看TIMx的更新事件中断标志位
3.1main.c 主程序代码
三、函数简介
3.1、时钟源选择(部分函数)
3.1.1、选择内部时钟
//定时器默认使用内部定时器,可以不用写这个函数
TIM_InternalClockConfig(TIM_TypeDef* TIMx)
效果如下图
3.1.2、选择ITRx其他定时器时钟
//参数1:选择定时器
//参数2:选择要接入那个其他定时器
TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)
效果如下图
3.1.3、选择Tlx捕获通道时钟
参数1:选择定时器
参数2:选择Tlx某个引脚
参数3:输入极性
参数4:滤波器
TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
uint16_t TIM_ICPolarity, uint16_t ICFilter);
3.1.4、选择ETR外部时钟模式1的输入时钟
//参数1:选择定时器
//参数2:外部触发预分频器---对ETR外部时钟提前做一次预分频
//参数3:极性
//参数4:滤波器
TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter)
3.1.5、选择ETR外部时钟模式2的输入时钟
//参数1:选择定时器
//参数2:外部触发预分频器---对ETR外部时钟提前做一次预分频
//参数3:极性
//参数4:滤波器
TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,
uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter
3.1.6、单独配置ETR预分频器、极性。滤波器等参数
TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter)
3.2、 时基单元
3.2.1、时基单元初始化
参数1-TIMx:选择某个定时器
参数2-TIM_TimeBaseInitStruct:结构体,内部包含了配置时基单元的基本信息
TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
3.2.2、将结构体初始化为默认值
TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
结构体内含信息:
TIM_Prescaler;
3.2.3、运行控制
//参数1:选择定时器
//参数2:使能or失能
TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
3.3、中断输出控制
//参数1:选择定时器
//参数2:选择配置那个中断输出
//参数3;使能or失能
TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
3.4、NVIC配置
详见前文
3.5、补充函数
3.5.1、单独写预分频值
//参数1:选择定时器
//参数2、写入预分频的值
//参数3、写入模式(用到再详查资料)
TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode)
3.5.2、改变计数器的计数模式
//参数2:选择新的计数器模式
TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode)
3.5.3、自动重装器预装功能配置
TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
3.5.4、计数器写入一个值
TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter)
3.5.5、自动重装器写入一个值
TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload)
3.5.6、获取当前计数器的值
TIM_GetCounter(TIM_TypeDef* TIMx)
3.5.7、获取当前预分频的值
TIM_GetPrescaler(TIM_TypeDef* TIMx)
问题解决
一上电就出现中断在 TIM_TimeBaseInit();后加上函数
TIM_ClearFlag(TIM2,TIM_FLAG_Update).
文章来源:https://www.toymoban.com/news/detail-781546.html
本文以重新优化内容排布,以后将会不定期优化更新。文章来源地址https://www.toymoban.com/news/detail-781546.html
到了这里,关于STM32—定时器(TIM)_基本定时的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!