1.三种STM32定时器区别
定时器种类 | 位数 | 计数器模式 | 产生DMA请求 | 捕获/比较通道 | 互补输出 | 特殊应用场景 |
---|---|---|---|---|---|---|
高级定时器(TIM1,TIM8) | 16 | 向上,向下,向上/下 | 可以 | 4 | 有 | 带死区控制盒紧急刹车,可应用于PWM电机控制 |
通用定时器(TIM2~TIM5) | 16 | 向上,向下,向上/下 | 可以 | 4 | 无 | 通用。定时计数,PWM输出,输入捕获,输出比较 |
基本定时器(TIM6,TIM7) | 16 | 向上,向下,向上/下 | 可以 | 0 | 无 | 主要应用于驱动DAC |
2.通用定时器功能特点描述
3.计数器模式
4.通用定时器工作过程
计数器时钟可以由下列时钟源提供:
①内部时钟(CK_INT)
默认调用Systemlnit函数情况下:
SYSCLK=72M
AHB时钟=72M
APB1时钟=36M
所以APB1的分频系数=AHB/APB1时钟=2。所以,通用定时器时钟CK_INT=2*36M=72M
②外部时钟模式1:外部输入脚(TIx)
③外部时钟模式2:外部触发输入(ETR)
④内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。
5.定时器中断实验相关寄存器
计数器当前值寄存器TIMx_CNT
预分频寄存器TIMx_PSC
自动重装载寄存器TIMx_ARR
控制寄存器TIMx_CR1
DMA中断使能寄存器
6.常用库函数
void TIMx_TimeBaseInit(TIM_TypeDef*TIMx,TIMx_TimeBaseInitTypeDef*TIMx_TimeBaseInitStruct);
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;
void TIM_Cmd(TIM_TypeDef*TIMx,FunctionalState NewState);
void TIM_ITConfig(TIM_TypeDef*TIMx,unit_16 TIM_IT,FunctionalState NewState);
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);
7.定时器中断实现步骤
RCC_APB1PeiphClockCmd();
TIM_TimeBaseInit();
void TIM_ITConfig();
NVIC_Init();
TIM_Cmd();
TIMx_IRQHandler();
在输出模式下,TIMx_CCRx寄存器的值与CNT的值比较,若CCRx的值大于CNT的值,则产生高电平,反之则为低电平,故通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽。
以通道1为例:
CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值。CCMR1:OC1M[2:0]位:
对于PWM方式下,用于设置PWM模式1【110】或者PWM模式2【111】
CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。
CCER:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。
2.相关寄存器
PWM模式:脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。
在TIMx_CCRx寄存器中的OCxM位写入’110’(PWM模式1)或’111’(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。必须设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器,最后还要设置TIMx_CR1寄存器的ARPE位,(在向上计数或中心对称模式中)使能自动重装载的预装载寄存器。
void TIM_OC2PreloadConfig(TIM_TypeDefTIMx,uint16_t TIM_OCPreload);
void TIM_ARRPreloadConfig(TIM_TypeDefTIMx,FunctionalState NewState);
TIMx_CR1寄存器的ARPE位1时,ARR立即生效,APRE=0时,ARR下个比较周期生效。
3.STM32定时器3输出通道引脚
复用功能 | TIM3_REMAP[1:0]=00(没有重映像) | TIM3_REMAP[1:0]=10(部分重映像) | TIM3_REMAP[1:0]=11(完全重映像) |
---|---|---|---|
TIM3_CH1 | PA6 | PB4 | PC6 |
TIM3_CH2 | PA7 | PB5 | PC7 |
TIM3_CH3 | PB0 | PB0 | PC8 |
TIM3_CH4 | PB1 | PB1 | PC9 |
(其他定时器的引脚通过查找Datasheet表格可知)
4.PWM输出库函数
//初始化
void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
typedef struct
{
uint16_t TIM_OCMode; //PWM模式1或者模式2
uint16_t TIM_OutputState; //输出使能
uint16_t TIM_OutputNState;
uint16_t TIM_Pulse;//比较值,写CCRx
uint16_t TIM_OCPolarity;//比较输出极
uint16_t TIM_OCNPolarity;
uint16_t TIM_OCIdleState;
uint16_t TIM_OCNIdleState;
} TIM_OCInitTypeDef;
//设置比较值函数
void TIM_SetCompareX(TIM_TypeDef*TIMx,uint16_t Compare2);
5.PWM输出配置步骤
一句话总结工作过程:通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升浴下降沿)的时候,将当前太时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器 (TIMxCCRx)里面,完成一次捕获
1.设置输入捕获滤波器
输入捕获 1 滤波器 IC1F[3:0],这个用来设置输入采样频率和数字滤波器长度。其中, f C L K _ I N T f_{CLK\_INT} fCLK_INT是定时器的输入频率(TIMxCLK),一般为 72Mhz,而 f D T S f_{DTS} fDTS则是根据 TIMx_CR1 的 CKD[1:0]的设置来定的,如果 CKD[1:0]设置为 00,那么 f D T S = f C L K _ I N T f_{DTS}=f_{CLK\_INT} fDTS=fCLK_INT。N 值就是滤波长度,举个简单的例子:假设 IC1F[3:0]=0011,并设置 IC1 映射到通道 1 上,且为上升沿触发,那么在捕获到上升沿的时候,再以 f C L K _ I N T f_{CLK\_INT} fCLK_INT的频率,连续采样到 8 次通道 1 的电平,如果都是高电平,则说明却是一个有效的触发,就会触发输入捕获中断(如果开启了的话)。这样可以滤除那些高电平脉宽低于 8 个采样周期的脉冲信号,从而达到滤波的效果。
2.设置输入捕获极性(通道1为例)
CCER寄存器的位1
3.设置输入捕获映射通道(通道1为例)
CCMR1寄存器的位[1:0]
一般情况下通道1就映射到IC1,通道2映射到IC2。
4.设置输入捕获分频器(通道1为例)
5.捕获到有效信号可以开启中断
1.输入捕获通道初始化函数
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
typedef struct
{
uint16_t TIM_Channel; //捕获通道1-4
uint16_t TIM_ICPolarity; //捕获极性
uint16_t TIM_ICSelection; //映射关系
uint16_t TIM_ICPrescaler; //分频系数
uint16_t TIM_ICFilter; //滤波器
} TIM_ICInitTypeDef;
2.通道极性设置独立函数
void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
跟上面初始化函数中设置通道极性有什么区别呢?
3.获取通道捕获值
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
4.输入捕获配置的一般步骤
①初始化定时器和通道对应IO的时钟
②初始化IO口,模式为输入:GPIO_Init();
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//PA0输入
③初始化定时器ARR,PSC
TIM_TimeBaseInit();
④初始化输入捕获通道
TIM_ICInit();
⑤如果要开启捕获中断
TIM_ITConfig();
NVC_Init();
⑥使能定时器:TIM_Cmd();
⑦编写中断服务函数:TIMx_IRQHandler();
考虑溢出