Stm32定时器
本文讲解了在Stm32常用的定时器相关知识,并带有部分示例代码。若有错误,欢迎指出
文章目录
类型 | 编号 | 总线 | 功能 |
---|---|---|---|
高级定时器 | TIM1、TIM8 | APB2 | 拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能 |
通用定时器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能 |
基本定时器 | TIM6、TIM7 | APB1 | 拥有定时中断、主模式触发DAC的功能 |
一些概念解释
死区生成
通常大功率电机、变频器等,末端都是由大功率管、IGBT等元件组成的H桥或3相桥。每个桥的上半桥和下半桥是绝对不能同时导通的,但高速的PWM驱动信号在达到功率元件的控制端时,往往会由于各种各样的原因产生延迟的效果,造成某个半桥元件在应该关断时没有关断,造成功率元件烧毁。
PWM输出时的Dead Zone(死区)作用是在电平翻转时插入一个时间间隔,避免关闭前一个设备和打开后一个设备时因为开关速度的问题出现同时开启状态而增加负荷的情况(在没有彻底关闭前打开了后一个设备),尤其是电流过大时容易造成短路等损坏设备
刹车输入
STM32的安全措施,TIMx_BRK引脚或者来自CSS(时钟安全系统)控制pwm输出。
定时器的时钟频率
定时器的时钟频率默认都是72MHz。虽然有部分时钟挂接在APB1总线上(APB1总线经过分频只有系统时钟的一半,36MHz),但是从系统时钟树可以得知,挂接APB1的时钟又经过一次倍频,变回了72MHz。
高级控制定时器框图
一些介绍
通道
TIMx_CH1,TIMx_CH2,TIMx_CH3,TIMx_CHy就是通道引脚,通道引脚在输入捕获模式下用作输入,在输出比较模式下用作输出,但同时只能用作一种模式。
重要的寄存器
寄存器 | ||
---|---|---|
自动重装器 | ARR | |
预分频器 | PSC | |
重复计数器 | RCR | 仅高级定时器有 |
计数器 | CNT | |
捕获/比较寄存器 | CCRx | x=1,2,3,4(因为有四个通道) |
定时器模式
输出比较
输出比较模式就是用计数器寄存器
的值和比较寄存器
进行比较,然后按照模式让对应通道引脚输出高/低电平。
输出比较的八种模式
模式 | TIM_OCMode | 描述 |
---|---|---|
冻结 | Timing | CNT=CCR时,REF保持为原状态 |
匹配时置有效电平 | Active | CNT=CCR时,REF置有效电平 |
匹配时置无效电平 | Inactive | CNT=CCR时,REF置无效电平 |
匹配时电平翻转 | Toggle | CNT=CCR时,REF电平翻转 |
强制为无效电平 | ForcedAction_Active | CNT与CCR无效,REF强制为无效电平 |
强制为有效电平 | ForcedAction_InActive | CNT与CCR无效,REF强制为有效电平 |
PWM模式1 | PWM1 | 向上计数:CNT<CCR时,REF置有效电平,CNT≥CCR时,REF置无效电平 向下计数:CNT>CCR时,REF置无效电平,CNT≤CCR时,REF置有效电平 |
PWM模式2 | PWM2 | 向上计数:CNT<CCR时,REF置无效电平,CNT≥CCR时,REF置有效电平 向下计数:CNT>CCR时,REF置有效电平,CNT≤CCR时,REF置无效电平 |
输入捕获
输入捕获模式当输入通道有电平跳变的时候,将计数器寄存器
的值保存到对应通道的捕获寄存器
。
注意
在高级定时器(TIM1、TIM8等)中,如果要使用输出比较模式输出PWM的话,需要额外配置
- 使能主输出,配置 TIMx_BDTR 寄存器的 MOE 位
- MOE: 主输出使能 (Main output enable) 一旦刹车输入有效,该位被硬件异步清’0’。根据AOE位的设置值,该位可以由软件清’0’或被自 动置1。它仅对配置为输出的通道有效。
- 0:禁止OC和OCN输出或强制为空闲状态
- 1:如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。
- MOE: 主输出使能 (Main output enable) 一旦刹车输入有效,该位被硬件异步清’0’。根据AOE位的设置值,该位可以由软件清’0’或被自 动置1。它仅对配置为输出的通道有效。
- 配置 TIM_OCInitTypeDef.TIM_OCIdleState 成员值
- TIM_OCInitTypeDef.TIM_OCIdleState:指定空闲状态期间TIM输出比较引脚状态。
- 本质是配置 TIMx_CR2 寄存器的 OISx(x=通道号)
- OISx:输出空闲状态x(OCx输出) (Output Idle state x)
- 0 (TIM_OCIdleState_Reset):当MOE=0时,如果实现了OC1N,则死区后OC1=0
- 1 (TIM_OCIdleState_Set):当MOE=0时,如果实现了OC1N,则死区后OC1=1
- OISx:输出空闲状态x(OCx输出) (Output Idle state x)
//...配置结构体其他成员
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM1,ENABLE);
使用实例
基础定时中断功能
void Timer_Init(void)
{
//使能TIM2的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
//选择使用内部时钟,可省略,因为默认就是使用内部时钟
TIM_InternalClockConfig(TIM2);
/*
定时器基础配置
计数器溢出频率计算: CK_CNT_OV = CK_PSC / (PSC + 1) / (ARR + 1)
下面的配置是 1s 溢出进入中断一次
*/
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中,当配置完之后会置更新事件标志位,在定时器启动之后就直接进入中断了
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
//配置中断:使能更新中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
//设置优先级配置分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//初始化 TIM2 中断通道
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
//启动定时器
TIM_Cmd(TIM2, ENABLE);
}
//TIM2 中断函数
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
外部引脚触发计数器
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//配置PA0,因为PA0复用为TIM2_CH1_ETR
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //手册建议配置为浮空输入,但上拉输入也可以
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*
配置使用外部时钟模式2,通过ETR引脚输入时钟信号
TIM_ETRClockMode2Config 函数介绍
TIM_TypeDef* TIMx :配置的定时器
uint16_t TIM_ExtTRGPrescaler:外部触发预分配器,TIM_ExtTRGPSC_OFF 为不分频
uint16_t TIM_ExtTRGPolarity: 外部触发的极性,TIM_ExtTRGPolarity_NonInverted 高电平或上升沿有效
uint16_t ExtTRGFilter:外部触发滤波器,0x0F为采样频率fSAMPLING=fDTS/32,N=8
*/
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);
//其他内容和 基础定时中断功能 大差不差
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 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_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE);
}
输出PWM波
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//使用内部时钟
TIM_InternalClockConfig(TIM2);
//定时器基础配置,频率是 1K hz
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//定时器输出通道1配置
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure); //因为是局部变量,内存数据不确定,因此要给结构体赋初始值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:有效电平为高电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
TIM_OCInitStructure.TIM_Pulse = 30; //CCR,在PWM模式中决定输出的占空比
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
/*
TIM_OC2Init(TIM2, &TIM_OCInitStructure); //可以配置通道2输出
实际上因为四个通道共用一个计数器,因此四个通道输出pwm波的频率一致,但是CCR寄存器不一样可以输出不同占空比的pwm
*/
TIM_Cmd(TIM2, ENABLE);
}
//设置占空比
void PWM_SetCompare(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare); //更改通道1的CCR寄存器
}
输入捕获
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
TIM_Cmd(TIM3, ENABLE);
}
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
输入捕获之PWMI(测量PWM的频率与占空比)
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM3);
//定时器基础配置,72分频,每过1us计数器加一,自动重装载的值要尽可能大。
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
//配置输入捕获
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //通道1
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
TIM_Cmd(TIM3, ENABLE);
}
//获取频率
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
//获取占空比
uint32_t IC_GetDuty(void)
{
return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}