STM32:定时器
- TIM(Timer)定时器
- 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
- 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时72/65536/65536
- 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
- 类型 编号 总线 功能
- 高级定时器 TIM1、TIM8 APB2 拥有通用定时器全部功能,并额外具有重 复计数器、死区生成、互补输出、刹车输入等功能
- 通用定时器 TIM2、TIM3、TIM4、TIM5 APB1 拥有基本定时器全部功能 并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能
- 基本定时器 TIM6、TIM7 APB1 拥有定时中断、主模式触发DAC的功能
- STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4
- 基本定时器:基准时钟->预分频器->计数器
- 预分频器
- 如果预分频器写0,不分频,输出频率=输入频率=72MHz
- 如果预分频器写1,二分频,输出频率=输入频率/2=36MHz
- 如果预分频器写,三分频,输出频率=输入频率/3=24MHz
- 最大值可以写65535也就是65536分频,输出频率=72/65536
- CNT计数器
- 对预分频后的始终进行计数,计数时钟每来一个上升沿,计数器的值就加
- 自动重装寄存器,当计数值等于自动重装值时,代表计时时间到,会产生中断信号,并且清零计数器。(图中向上箭头:更新中断;更新中断通往NVIC)(图中向下箭头:更新时间,更新事件不睡出发中断,但是可以触发内部其他电路的工作)
- 主模式触发DAC的功能:主模式把更新事件映射到 触发输出TRGO的位置,TRGO直接接到DAC的触发转换引脚上,直接触发DAC,不需要软件的参与,实现了硬件的自动化。
- 预分频器
- 通用定时器:
- 除了向上计数,通用定时器和高级定时器还支持向下计数模式和中央对齐模式
- 向下计数模式:从重装值开始,向下自减。
- 中央对齐模式:从0开始,先向上自增,到重装值,申请中断,然后向下自减到0 再次申请中断。
- 内外时钟源选择:
- 第一个外部时钟:TIMx_ETR引脚(PA0)上的外部时钟。两个输出:1.ETRF进入触发控制器,进而到时基单元,这一路也叫外部时钟模式2;2.TRGI:用作触发输入使用,触发输入和从模式,以后课程讲。这一路叫外部时钟模式1.
- ITRx(ITR0~ITR3)信号来来源于其他定时器,主模式的TRGO可以通向其他定时器。
- 表格意思为:例如:TIM2定时器的ITR0信号来自于上一个时钟(TIM1)
- 定时器级联功能,比如:先初始化TIM3,然后使用主模式把它的更新事件映射到TRGO上,然后再初始化TIM2,这里算则ITR2,对应的就是TIM3的TRGO
- 时钟还能通过CH1获得,ED是边沿的意思,可以是上升沿可以是下降沿。
- last :时钟还能通过TI1FP1和TI2FP2获得。
- 总结:外部时钟模式1的引脚可以是ETR引脚、(ITR)其他定时器、CH1引脚的边沿、CH1和CH2引脚的TI1FP1和TI2FP2获得
- 右下角是输出比较电路,共有四个通道,分别对应CH1到CH4的引脚,可以用于输出PWM波形,驱动电机。
- 左下角是输入捕获电路,也有四个通道。对应的也是CH1到CH4的引脚,可以用于侧输入方波的频率等。
- 中间是捕获/比较寄存器,是输入捕获和输出比较电路共用的。因为输入捕获和输出比较不能停驶使用,所以寄存器共用,引脚共用。之后再具体分析。
- 高级定时器:
- 申请中断的地方加了一个重复次数计数器,可以实现每隔几个计数周期,才发生一次更新事件和更新中断。
- 定时中断基本结构图:
- 中断输出控制(即,中断输出允许位):解决定时器模块有很多地方都要申请中断,看是否需要这个中断,如果需要就允许,如果不需要这个中断,就禁止。(更新会申请中断,触发信号(TRGO)也会申请中断、输入捕获和输出比较匹配时也会申请中断)
- 时基单元运行细节问题:
- 预分频时序:
- 计数器计数频率:CK_CNT= CK_PSC/(PSC + 1)
- CK_PSC:预分频器的输入时钟。一般为72Mhz
- CNT_EN:计数器使能,高电平计数器正常运行,低电平计数器停止。
- CK_CNT:计数器时钟,即时分频器的时钟输出,也是计数器的时钟输入。
- 一个计时周期结束时,产生了更新事件,预分频(控制)寄存器的值才会杯传递到缓冲器里去,才会生效。
- 计数器时序:
- 计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR +1)=CK_PSC / (PSC +1) / (ARR +1)
- 计数器无预装时序:
- 计数器有预装时序:
- RCC时钟树:
- P13 TIM定时中断,44分钟。
- 无论什么定时器,内部基准时钟都是72Mhz。
- void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);初始化时基单元;
- void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct); 把结构体变量赋一个默认值;
- void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);使能计数器;
- void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);使能中断输出信号;TIM_IT 选择配置哪个中断输出,NewState使能还是失能。
- 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捕获通道的时钟。TIM_TIxExternalCLKSource选择TIx的某个引脚;TIM_ICPolarity输入的极性;ICFilter滤波器。
- void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);选择ETR通过外部时钟模式1输入的时钟。TIM_ExtTRGPrescaler外部触发预分频器:可以对ETR的外部时钟再提前做一个分频;
- 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);写预分频值;TIM_PSCReloadMode选择模式:1.听从安排等待更新事件生效,2.在写入后,手动产生一个更新事件,让这个值立即生效。
- void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);用来改变计数器的计数模式。
- void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);自动重装器预装功能配置
- 定时器代码如下:
-
#include "stm32f10x.h" // Device header extern uint16_t Num; void Timer_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启时钟 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;//预分频器的值 72MHz/7200/10000=1 TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值(高级计数器才需要,目前不需要用给0即可) TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//时基单元配置完毕 更新事件和更新中断是同时发生的, TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清除更新事件带来的更新中断标志位的变化,否则会导致上电立刻进入中断 TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断;开通更新中断到NVIC的通路 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;//定时器2在NVIC里的通道 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); } }