提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
本节先只讲解定时器的定时中断,内外中断源选择。
一、定时器介绍
TIM(Timer)定时器
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断。
16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时。
不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能。
根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型。
定时器类型
注:开启时钟时注意,高级定时器连接APB2总线,通用与基本定时器连接APB1总线。
基本定时器
16位计数器、预分频器、自动重装寄存器构成了最基本的计时计数电路,叫做时基单元。
基本定时器只能选择内部时钟。
预分频器:写0,输入频率=输出频率=72MHZ;写1,二分频 ,输出频率=输出频率/2=32MHZ;
写n,输出频率=输入频率/(n+1)。(预分频器是16位的,故写入值不得大于65535)
计数器:16位寄存器;每来一个上升沿,计数器的值加1,自增到目标值时产生中断。
自动重装寄存器:16位寄存器;写入值为固定值,是我们的目标值,当计数值等于自动重装值时,产生中断信号,清零计数器。
上箭头代表会产生中断信号。
下箭头代表会产生“更新事件”。(不会触发中断,但会触发其他内部电路的工作)。
工作流程:时钟信号从基准时钟,到预分频器,再到计数器。计数器计数自增,并不断的与自动重装值进行比较,相等时,产生一个更新中断,更新事件,CPU响应定时中断,完成定时中断的任务。
主模式触发DAC:将定时器的更新事件,映射到TRGO的位置,TRGO接到DAC的触发引脚上,TRGO会直接去触发DAC,实现了硬件自动化。
通用定时器
拥有基本定时器的功能。
通用定时器拥有向上自增,向下自减,中央对齐。(基本定时器,只有向上模式)
内外时钟源选择:基本定时器只能选择内部时钟源(系统频率72MHz),通用定时器还可以选择外部时钟,外部时钟模式2(ETR外部时钟),外部时钟模式1(ERT外部时钟、ITRx其他定时器-可定时器级联、TIx捕获通道)。
外部时钟使用时注意外部时钟的引脚,STM32最小系统板的TIM的外部时钟接在PA0引脚上。(查看引脚定义表)
高级定时器
拥有通用定时器的功能。
重复次数计数器:可以实现每隔几个周期才发生一次更新事件和更新中断,相当于对更新的输出信号作了一次分频。
定时中断的基本结构
在定时中断中,ETR的外部中断1与外部中断2无区别。
中断输出控制:定时器中含有多种中断(如定时中断,输入捕获,输出比较),需要中断输出控制进行判断是否需要。
时序图介绍
我们通过时序图,来更深入了解一下定时器定时中断时的工作原理。
CK_PSC:预分频器的输入时钟。
CNT_EN:计数器使能。
CK_CNT定时器时钟:CK_PSC/(PSC+1)。
CNT_EN置1后,计数器使能,计数器开始工作,预分频器的系数为1(写0,系数为1;写,系数为2),CK_CNT前半段频率=CK_PSC(若内部时钟作为时钟源的话,CK_CNT=72MHZ)。
之后,预分频器系数为2,此时预分频缓冲器保留之前的系数,定时器时钟CK_CNT频率暂未改变,当计数器值自增到目标值时,产生一个更新事件,并且在下一个时钟来临时清零计数器;当产生更新事件后,预分频缓冲器的值为1,预分频计数器按照二分频的工作模式工作,CK_PSC不变,CK_CNT周期,计数周期为原来的两倍。
缓存器的作用:值的变化与计数周期同步发生,在控制寄存器的值突然改变时,定时仍按原来的方式工作一个计数周期后,再改变,避免更改数值造成错误。
可知 更新中断后,需要再中断函数内手动清零中断标志位。
二,配置定时器
第一步:配置RCC,打开时钟。
第二步:选择定时器时钟单元(不配置,默认为内部时钟)。
第三步:配置时基单元。
第四步:配置输出中断控制,允许更新中断到NVIC
第五步:配置NVIC,在NVIC中打开中断通道,配置优先级。
最后,使能定时器,开始运行。
定时器库函数(本节)
void TIM_DeInit(TIM_TypeDef* TIMx);//恢复缺省配置
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);//时基单元初始化;需结构体后,作为参数传递。
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);//时基单元结构体变量赋默认值。
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);//使能计数器CNT;对应操作上图运行控制位。
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);//使能中断输出信号,ITConfing即使能外设的中断输出;对应操作上图中断输出控制。
//时钟源选择
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);//内部时钟
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);//选择ITRx其他定时器的时钟
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
uint16_t TIM_ICPolarity, uint16_t ICFilter);//选择TIX捕获通道的时钟。
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
uint16_t ExtTRGFilter);//选择ETR通过外部时钟模式1,输入的时钟。
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,
uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);//选择ETR通过外部时钟模式2,输入的时钟
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
uint16_t ExtTRGFilter);//单独用来配置ETR引脚的极性,滤波器,预分频器等参数。
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);//单独修改预分频值;参数1:定时器x;参数2:写入的预分频器的值;参数三:预分频器的模式(对应上文,预分频器的缓存器)
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);//修改计数器的模式
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);//修改预装值
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);//获得计数器的值
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);//获得预分频器的值
//获取或清除标志位(上节介绍过EXTI,类似)
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
配置过程
第一步:配置RCC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//开启TIM2的时钟,TIM2连接APB1总线
第二步:选择定时器时钟源
TIM_InternalClockConfig(TIM2);//内部时钟,不配置,默认也是内部时钟
第三步:时基单元初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
定时器中滤波器工作原理:在固定的频率f下,进行采样,如果n个采样点都输出相同的电平,即信号稳定;相反,则不稳定,这时保持上次输出,或低电平。时钟的滤波频率由结构体参数TIM_ClockDivisio配置的。
第四步:配置中断输出控制
TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除定时器更新标志位
//TIM_TimeBaseInit函数末尾,手动产生了更新事件
//若不清除此标志位,则开启中断后,会立刻进入一次中断
//如果不介意此问题,则不清除此标志位也可
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启TIM2的更新中断
配置中断输出控制为更新中断。
第五步:配置NVIC
/*NVIC中断分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
//即抢占优先级范围:0~3,响应优先级范围:0~3
//此分组配置在整个工程中仅需调用一次
//若有多个中断,可以把此代码放在main函数内,while循环之前
//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //选择配置NVIC的TIM2线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //指定NVIC线路的抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
最后启动定时器文章来源:https://www.toymoban.com/news/detail-847059.html
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
中断函数
在启动文件中查找中断函数文章来源地址https://www.toymoban.com/news/detail-847059.html
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)//检验标志位
{
//中断函数执行内容
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除标志位
}
}
到了这里,关于STM32——定时器——定时中断的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!