1.定时器概述
1.1.软件定时原理
使用纯软件(CPU死等)的方式实现定时(延时)功能有诸多缺点,如CPU死等、延时不精准。
void delay_us(uint32_t us)
{us *= 72;while(us--);
}
1.2.定时器定时原理
使用精准的时基,通过硬件的方式,实现定时功能定时器核心就是计数器
1.3.STM32定时器分类
1.4.STM32定时器特性表
- F1系列
- H7系列
1.5.STM32基本、通用、高级定时器的功能整体区别
2.基本定时器(以F1为例)
2.1.基本定时器简介
- 基本定时器:TIM6/TIM7
- 主要特性:
16位递增计数器(计数值:0~65535)
16位预分频器(分频系数:1~65536)
可用于触发DAC
在更新事件(计数器溢出)时,会产生中断/DMA请求
2.2.基本定时器框图
注意:事件默认产生,可以配置为不产生;中断默认不产生,可以配置为产生。
2.3.定时器计数模式及溢出条件
以下分别是递增、递减、中心对齐模式的实例说明
2.4.定时器中断实验相关寄存器
- TIM6 和TIM7 控制寄存器 1(TIMx_CR1)
用于设置ARR寄存器是否具有缓冲,使能/关闭计数器
有缓冲和没缓冲的区别
- 延时1s+延时2s:在无缓冲情况下,延时1s后要重新写ARR,这个过程消耗时间导致误差;有缓冲情况下,可以在1s延时内写ARR,不会立即生效,在1s延时结束后生效,没有误差。
- 延时1s+延时1s:不用写ARR,没有区别
- TIM6 和TIM7 DMA/中断使能寄存器(TIMx_DIER)
用于使能更新中断
- TIM6 和TIM7 状态寄存器(TIMx_SR)
用于判断是否发生了更新中断,由硬件置1,软件清零
- TIM6 和TIM7 计数器(TIMx_CNT)
计数器实时数值,可用于设置计时器初始值,范围:0~65535
- TIM6 和TIM7 预分频器(TIMx_PSC)
用于设置预分频系数,范围:0~65535,实际预分频系数等于PSC+1
- TIM6 和TIM7 自动重装载寄存器(TIMx_ARR)
用于设置自动重装载值,范围:0~65535
2.5.定时器溢出时间计算方法
2.6.定时器中断实验配置步骤
- 配置定时器基础工作参数:HAL_TIM_Base_Init()
- 定时器基础MSP初始化:HAL_TIM_Base_MspInit() 配置NVIC、CLOCK等
- 使能更新中断并启动计数器:HAL_TIM_Base_Start_IT()
- 设置优先级,使能中断:HAL_NVIC_SetPriority()、 HAL_NVIC_EnableIRQ()
- 编写中断服务函数:TIMx_IRQHandler()等 -> HAL_TIM_IRQHandler()
- 编写定时器更新中断回调函数:HAL_TIM_PeriodElapsedCallback()
关键结构体
typedef struct
{ TIM_TypeDef *Instance; /* 外设寄存器基地址 */ TIM_Base_InitTypeDef Init; /* 定时器初始化结构体*/...
}TIM_HandleTypeDef;
typedef struct
{ uint32_t Prescaler; /* 预分频系数 */ uint32_t CounterMode; /* 计数模式 */ uint32_t Period; /* 自动重载值 ARR */ uint32_t ClockDivision; /* 时钟分频因子 */ uint32_t RepetitionCounter; /* 重复计数器寄存器的值 */ uint32_t AutoReloadPreload; /* 自动重载预装载使能 */
} TIM_Base_InitTypeDef;
2.7.编程实战:定时器中断实验
- 使用定时器6,实现500ms定时器更新中断,在中断里翻转LED0
- PSC=7199,ARR=4999为例。
代码暂不贴出
3.通用定时器(以F1为例)
3.1.通用定时器简介
- 通用定时器:TIM2/TIM3 /TIM4 /TIM5
- 主要特性:
16位递增、递减、中心对齐计数器(计数值:0~65535)
16位预分频器(分频系数:1~65536)
可用于触发DAC、ADC
在更新事件、触发事件、输入捕获、输出比较时,会产生中断/DMA请求
4个独立通道,可用于:输入捕获、输出比较、输出PWM、单脉冲模式
使用外部信号控制定时器且可实现多个定时器互连的同步电路
支持编码器和霍尔传感器电路等
3.2.通用定时器框图
3.3.计数器时钟源
外部时钟模式1
外部时钟模式2
内部触发
使用一个定时器作为另一个定时器的预分频器(F1为例)
【小插曲——使用通用定时器进行定时器中断】
不同点:基本定时器只能递增计数,而通用定时器计数模式有三种
3.4.通用定时器PWM输出实验【输出比较】
3.4.1.通用定时器输出比较部分框图介绍
捕获/比较通道1的主电路—输出部分
捕获/比较通道的输出部分(通道1)
3.4.2.通用定时器输出PWM原理
假设:递增计数模式
- ARR:自动重装载寄存器的值
- CCRx:捕获/比较寄存器x的值
- 当CNT < CCRx,IO输出0
- 当CNT >= CCRx,IO输出1
总结:PWM波周期或频率由ARR决定,PWM波占空比由CCRx决定
3.4.3.PWM模式
3.4.4.通用定时器PWM输出实验配置步骤
- 配置定时器基础工作参数:HAL_TIM_PWM_Init()
- 定时器PWM输出MSP初始化:HAL_TIM_PWM_MspInit() 配置NVIC、CLOCK、GPIO等
- 配置PWM模式/比较值等:HAL_TIM_PWM_ConfigChannel()
- 使能输出并启动计数器:HAL_TIM_PWM_Start()
- 修改比较值控制占空比(可选):__HAL_TIM_SET_COMPARE()
- 使能通道预装载(可选):__HAL_TIM_ENABLE_OCxPRELOAD()
关键结构体
typedef struct
{ uint32_t OCMode; /* 输出比较模式选择 */uint32_t Pulse; /* 设置比较值 */uint32_t OCPolarity; /* 设置输出比较极性 */uint32_t OCNPolarity; /* 设置互补输出比较极性 */uint32_t OCFastMode; /* 使能或失能输出比较快速模式 */uint32_t OCIdleState; /* 空闲状态下OC1输出 */uint32_t OCNIdleState; /* 空闲状态下OC1N输出 */
} TIM_OC_InitTypeDef;
3.4.5.编程实战:通用定时器PWM输出实验
- 通过定时器输出的PWM控制LED0,实现类似手机呼吸灯的效果。
- 2KHz为例,PSC=71,ARR=499。
- 配置输出比较模式为:PWM模式1,通道输出极性为:低电平有效。
代码暂不贴出
3.5.通用定时器输入捕获实验【输入捕获】
3.5.1.通用定时器输入捕获部分框图介绍
捕获/比较通道的输入部分(通道1)
捕获/比较通道1的主电路—输入部分
3.5.2.通用定时器输入捕获脉宽测量原理
以捕获测量高电平脉宽为例,假设:递增计数模式
- ARR:自动重装载寄存器的值
- CCRx1:t1时间点CCRx的值
- CCRx2:t2时间点CCRx的值
高电平期间,计时器计数的个数:N * (ARR+1) + CCRx2
3.5.3.通用定时器输入捕获实验配置步骤
- 配置定时器基础工作参数:HAL_TIM_IC_Init()
- 定时器输入捕获MSP初始化:HAL_TIM_IC_MspInit() 配置NVIC、CLOCK、GPIO等
- 配置输入通道映射、捕获边沿等:HAL_TIM_IC_ConfigChannel()
- 设置优先级,使能中断:HAL_NVIC_SetPriority()、 HAL_NVIC_EnableIRQ()
- 使能定时器更新中断:__HAL_TIM_ENABLE_IT()
- 使能捕获、捕获中断及计数器:HAL_TIM_IC_Start_IT()
- 编写中断服务函数:TIMx_IRQHandler()等 HAL_TIM_IRQHandler()
- 编写更新中断和捕获回调函数:HAL_TIM_PeriodElapsedCallback() HAL_TIM_IC_CaptureCallback()
关键结构体
typedef struct
{ uint32_t ICPolarity; /* 输入捕获触发方式选择,比如上升、下降沿捕获 */ uint32_t ICSelection; /* 输入捕获选择,用于设置映射关系 */ uint32_t ICPrescaler; /* 输入捕获分频系数 */ uint32_t ICFilter; /* 输入捕获滤波器设置 */
} TIM_IC_InitTypeDef;
3.5.4.编程实战:通用定时器输入捕获实验
- 通过定时器5通道1来捕获按键高电平脉宽时间,通过串口打印出来。
- 1MHz计数频率为例,PSC=71,ARR=65535。
- 配置输入捕获方式:上升沿捕获、输入通道1映射在TI1上、不分频、不滤波
代码暂不贴出
3.6.通用定时器脉冲计数实验【时钟源与从模式】
3.6.1.脉冲计数实验原理
外部时钟模式1
3.6.2.通用定时器脉冲计数实验配置步骤
- 配置定时器基础工作参数:HAL_TIM_IC_Init()
- 定时器输入捕获MSP初始化:HAL_TIM_IC_MspInit() 配置NVIC、CLOCK、GPIO等
- 配置定时器从模式等:HAL_TIM_SlaveConfigSynchro()
- 使能输入捕获并启动计数器:HAL_TIM_IC_Start()
- 获取计数器的值:__HAL_TIM_GET_COUNTER()
- 设置计数器的值:__HAL_TIM_SET_COUNTER()
关键结构体
typedef struct
{ uint32_t SlaveMode; /* 从模式选择 */ uint32_t InputTrigger; /* 输入触发源选择 */ uint32_t TriggerPolarity; /* 输入触发极性 */ uint32_t TriggerPrescaler; /* 输入触发预分频 */ uint32_t TriggerFilter; /* 输入滤波器设置 */
} TIM_SlaveConfigTypeDef;
3.6.3.编程实战:通用定时器脉冲计数实验
- 将定时器2通道1输入的高电平脉冲作为定时器2的时钟,并通过串口打印脉冲数。
- PSC=0,ARR=65535
- 配置从模式:外部时钟模式1、触发选择、上升沿触发、不分频、不滤波
代码暂不贴出
4.高级定时器(以F1为例)
4.1.高级定时器简介
- 高级定时器 :TIM1/TIM8
- 主要特性:
16位递增、递减、中心对齐计数器(计数值:0~65535)
16位预分频器(分频系数:1~65536)
可用于触发DAC、ADC
在更新事件、触发事件、输入捕获、输出比较时,会产生中断/DMA请求
4个独立通道,可用于:输入捕获、输出比较、输出PWM、单脉冲模式
使用外部信号控制定时器且可实现多个定时器互连的同步电路
支持编码器和霍尔传感器电路等
重复计数器
死区时间带可编程的互补输出
断路输入,用于将定时器的输出信号置于用户可选的安全配置中
4.2.高级定时器框图
4.3.高级定时器输出指定个数PWM实验【重复计数】
4.3.1.重复计数器特性
4.3.2.高级定时器输出指定个数PWM实验原理
4.3.3.高级定时器输出指定个数PWM实验配置步骤
- 配置定时器基础工作参数:HAL_TIM_PWM_Init()
- 定时器PWM输出MSP初始化:HAL_TIM_PWM_MspInit() 配置NVIC、CLOCK、GPIO等
- 配置PWM模式/比较值等:HAL_TIM_PWM_ConfigChannel()
- 设置优先级,使能中断:HAL_NVIC_SetPriority()、 HAL_NVIC_EnableIRQ()
- 使能定时器更新中断:__HAL_TIM_ENABLE_IT()
- 使能输出、主输出、计数器:HAL_TIM_PWM_Start()
- 编写中断服务函数:TIMx_IRQHandler()等 -> HAL_TIM_IRQHandler()
- 编写更新中断回调函数:HAL_TIM_PeriodElapsedCallback()
关键结构体
typedef struct
{ uint32_t OCMode; /* 输出比较模式选择 */uint32_t Pulse; /* 设置比较值 */uint32_t OCPolarity; /* 设置输出比较极性 */uint32_t OCNPolarity; /* 设置互补输出比较极性 */uint32_t OCFastMode; /* 使能或失能输出比较快速模式 */uint32_t OCIdleState; /* 空闲状态下OC1输出 */uint32_t OCNIdleState; /* 空闲状态下OC1N输出 */
} TIM_OC_InitTypeDef;
4.3.4编程实战:高级定时器输出指定个数PWM实验
- 通过定时器8通道1实现指定个数PWM输出,用于控制LED1的亮灭
- 2Hz为例,PSC=7199,ARR=4999
- 配置输出比较模式为:PWM模式1
- 通道输出极性为:高电平有效
- 占空比:50%
代码暂不贴出
4.4.高级定时器输出比较模式实验【输出比较-翻转】
4.4.1.高级定时器输出比较模式实验原理
- 输出比较模式:翻转
- 当CNT = CCRx,OCxREF电平翻转
总结:PWM波周期或频率由ARR决定,占空比固定50%,相位由CCRx决定
4.4.2.高级定时器输出比较模式实验配置步骤
- 配置定时器基础工作参数:HAL_TIM_OC_Init()
- 定时器输出比较MSP初始化:HAL_TIM_OC_MspInit() 配置NVIC、CLOCK、GPIO等
- 配置输出比较模式等:HAL_TIM_OC_ConfigChannel()
- 使能通道预装载:__HAL_TIM_ENABLE_OCxPRELOAD()
- 使能输出、主输出、计数器:HAL_TIM_OC_Start()
- 修改捕获/比较寄存器的值:__HAL_TIM_SET_COMPARE()
关键结构体
typedef struct
{ uint32_t OCMode; /* 输出比较模式选择 */uint32_t Pulse; /* 设置比较值 */uint32_t OCPolarity; /* 设置输出比较极性 */uint32_t OCNPolarity; /* 设置互补输出比较极性 */uint32_t OCFastMode; /* 使能或失能输出比较快速模式 */uint32_t OCIdleState; /* 空闲状态下OC1输出 */uint32_t OCNIdleState; /* 空闲状态下OC1N输出 */
} TIM_OC_InitTypeDef;
4.4.3.编程实战:高级定时器输出比较模式实验
- 通过定时器8通道1/2/3/4输出相位分别为25%、50%、75%、100%的PWM
- 1KHz为例,PSC=71,ARR=999
- 配置输出比较模式为:翻转
- 通道输出极性为:高电平有效
代码暂不贴出
4.5.高级定时器互补输出带死区控制实验【互补输出、死区、刹车】
4.5.1,互补输出,带死区控制
4.5.2,带死区控制的互补输出应用之H桥
由于元器件是有延迟特性,所以需要加上死区时间控制
4.5.3,捕获/比较通道的输出部分(通道1至3)
4.5.4,死区时间计算
4.5.5,刹车(断路)功能
- 使能刹车功能:将TIMx_BDTR的BKE位置1,刹车输入信号极性由BKP位设置
- 使能刹车功能后:由TIMx_BDTR的MOE、OSSI、OSSR位,TIMx_CR2的OISx、OISxN位,TIMx_CCER的CCxE、CCxNE位控制OCx和OCxN输出状态
无论何时,OCx和OCxN输出都不能同时处在有效电平
发生刹车后的现象
- MOE位被清零,OCx和OCxN为无效、空闲或复位状态(OSSI位选择)
- OCx和OCxN的状态:由相关控制位状态决定,当使用互补输出时:根据情况自动控制输出电平,参考参考手册使用刹车(断路)功能小节
- BIF位置1,如果使能了BIE位,还会产生刹车中断;如果使能了TDE位,会产生DMA请求
- 如果AOE位置 1,在下一个 更新事件UEV时,MOE位被自动置 1
4.5.6,高级定时器互补输出带死区控制实验配置步骤
1,配置定时器基础工作参数HAL_TIM_PWM_Init()
2,定时器PWM输出MSP初始化HAL_TIM_PWM_MspInit() 配置NVIC、CLOCK、GPIO等
3,配置PWM模式/比较值等HAL_TIM_PWM_ConfigChannel()
4,配置刹车功能、死区时间等HAL_TIMEx_ConfigBreakDeadTime()
5,使能输出、主输出、计数器HAL_TIM_PWM_Start()
6,使能互补输出、主输出、计数器HAL_TIMEx_PWMN_Start()
关键结构体
typedef struct
{ uint32_t OCMode; /* 输出比较模式选择 */uint32_t Pulse; /* 设置比较值 */uint32_t OCPolarity; /* 设置输出比较极性 */uint32_t OCNPolarity; /* 设置互补输出比较极性 */uint32_t OCFastMode; /* 使能或失能输出比较快速模式 */uint32_t OCIdleState; /* 空闲状态下OC1输出 */uint32_t OCNIdleState; /* 空闲状态下OC1N输出 */
} TIM_OC_InitTypeDef;
typedef struct
{uint32_t OffStateRunMode; /* 运行模式下的关闭状态选择 */ uint32_t OffStateIDLEMode; /* 空闲模式下的关闭状态选择 */ uint32_t LockLevel; /* 寄存器锁定设置 */ uint32_t DeadTime; /* 死区时间设置 */ uint32_t BreakState; /* 是否使能刹车功能 */ uint32_t BreakPolarity; /* 刹车输入极性 */ uint32_t BreakFilter; /* 刹车输入滤波器(F1/F4系列没有) */ uint32_t AutomaticOutput; /* 自动恢复输出使能,即使能AOE位 */
} TIM_BreakDeadTimeConfigTypeDef;
4.5.7,编程实战:高级定时器互补输出带死区控制实验
- 通过定时器1通道1输出频率为1KHz,占空比为70%的PWM,使用PWM模式1
- 使能互补输出并设置死区时间控制:设置DTG为100(5.56us),进行验证死区时间是否正确
- 使能刹车功能:刹车输入信号高电平有效,配置输出空闲状态等,最后用示波器验证
- 1KHz为例,PSC=71,ARR=999
- 以H桥为例,配置通道输出极性以及互补输出极性
4.6.高级定时器PWM输入模式实验【输入捕获+从模式】
4.6.1.PWM输入模式工作原理
4.6.2.PWM输入模式时序
4.6.3.高级定时器PWM输入模式实验配置步骤
- 配置定时器基础工作参数:HAL_TIM_IC_Init()
- 定时器捕获输入MSP初始化:HAL_TIM_IC_MspInit() 配置NVIC、CLOCK、GPIO等
- 配置IC1/2映射、捕获边沿等:HAL_TIM_IC_ConfigChannel()
- 配置从模式,触发源等:HAL_TIM_SlaveConfigSynchro()
- 设置优先级,使能中断:HAL_NVIC_SetPriority()、 HAL_NVIC_EnableIRQ()
- 使能捕获、捕获中断及计数器:HAL_TIM_IC_Start_IT()、 HAL_TIM_IC_Start()
- 编写中断服务函数:TIMx_IRQHandler()等 HAL_TIM_IRQHandler()
- 编写输入捕获回调函数:HAL_TIM_IC_CaptureCallback()
typedef struct
{ uint32_t ICPolarity; /* 输入捕获触发方式选择,比如上升、下降沿捕获 */ uint32_t ICSelection; /* 输入捕获选择,用于设置映射关系 */ uint32_t ICPrescaler; /* 输入捕获分频系数 */ uint32_t ICFilter; /* 输入捕获滤波器设置 */
} TIM_IC_InitTypeDef;
typedef struct
{ uint32_t SlaveMode; /* 从模式选择 */ uint32_t InputTrigger; /* 输入触发源选择 */ uint32_t TriggerPolarity; /* 输入触发极性 */ uint32_t TriggerPrescaler; /* 输入触发预分频 */ uint32_t TriggerFilter; /* 输入滤波器设置 */
} TIM_SlaveConfigTypeDef;
4.6.4.编程实战:高级定时器PWM输入模式实验
- 通过定时器3通道2(PB5)输出PWM
- 将PWM输入到定时器8通道1(PC6),测量PWM的频率/周期、占空比等信息
- 72MHz采样频率( 精度约13.8ns ),PSC=0,ARR=65535
- 不考虑溢出情况下,测量的最长PWM周期为910.2us
代码暂不贴出
5.实验汇总
序号 | 定时器类型 | 实现功能 | 要点 |
---|---|---|---|
1 | 基础定时器 | 定时器中断 | 基础配置 |
2 | 通用定时器 | PWM输出 | 输出比较 |
3 | 通用定时器 | 输入脉冲测宽 | 输入捕获 |
4 | 通用定时器 | 脉冲计数 | 从模式(时钟源) |
5 | 高级定时器 | 输出n个PWM | 输出比较+重复计数 |
6 | 高级定时器【通用】 | 多相位PWM | 输出比较(翻转模式) |
7 | 高级定时器 | 互补输出PWM | 输出比较+死区控制(互补输出、刹车) |
8 | 高级定时器【通用】 | PWM测量 | 输入捕获+从模式 |
重要结构体汇总
- 定时器基本参数:TIM_Base_InitTypeDef
- 输出比较设置:TIM_OC_InitTypeDef
- 输入捕获设置:TIM_IC_InitTypeDef
- 从模式设置:TIM_SlaveConfigTypeDef
- 刹车与死区控制:TIM_BreakDeadTimeConfigTypeDef