STM32H7定时器TIM1-TIM17中断、PWM实现
STM32H7 支持的定时器有点多,要简单的区分下。STM32H7 支持 TIM1-TIM8,TIM12-TIM17 共14 个定时器,而中间的 TIM9,TIM10,TIM11 是不存在的,这点要注意。
高级定时器硬件框图
我们直接看最复杂的高级定时器 TIM1&TIM8 框图:
通过这个框图,我们可以得到如下信息:
TIMx_ETR 接口
外部触发输入接口。ETR 支持多种输入源:输入引脚(默认配置)、比较器输出和模拟看门狗。
截图左侧的 TIMx_CH1,TIMx_CH2,TIMx_CH3 和 TIMx_CH4 接口
这四个通道主要用于输入捕获,可以计算波形频率和脉宽。
TIMx_BKIN 和 TIMx_BKIN2 接口
断路功能,主要用于保护由 TIM1 和 TIM8 定时器产生的 PWM 信号所驱动的功率开关
TRGO 内部输出通道
主要用于定时器级联,ADC 和 DAC 的定时器触发。
6 组输出比较单元 OC1 到 OC6
OC1 到 OC4 有对应的输出引脚,而 OC5 和 OC6 没有对应的输出引脚,主要用于内部控制。
截图右侧的输出比较通道 TIMx_CH1,TIMx_CH1N,TIMx_CH2
TIMx_CH2N,TIMx_CH3,
TIMx_CH3N 和 TIMx_CH4
主要用于 PWM 输出,注意 CH1 到 CH3 有互补输出,而 CH4 没有互补输出。
定时器模式
时基
定时器要工作就需要一个基本时基单元,而基本的时基单元是由下面几个寄存器组成的:
预分频器寄存器 (TIMx_PSC)
用于设置定时器的分频,比如定时器的主频是 200MHz,通过此寄存器可以将其设置为 100MHz,
50MHz,25MHz 等分频值。
注:预分频器有个缓冲功能,可以让用户实时更改,新的预分频值将在下一个更新事件发生时被采用
(以递增计数模式为例,就是 CNT 计数值达到 ARR 自动重装寄存器的数值时会产生更新事件)。
计数器寄存器 (TIMx_CNT)
计数器是最基本的计数单元,计数值是建立在分频的基础上面,比如通过 TIMx_PSC 设置分频后的频
率为 100MHz,那么计数寄存器计一次数就是 10ns。
自动重载寄存器 (TIMx_ARR)
自动重装寄存器是 CNT 计数寄存器能达到的最大计数值,以递增计数模式为例,就是 CNT 计数器达
到 ARR 寄存器数值时,重新从 0 开始计数。
注,自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预
装载寄存器的内容既可以立即传送到影子寄存器(让设置立即起到效果的寄存器),也可以在每次发
生更新事件时传送到影子寄存器。简单的说就是让 ARR 寄存器的数值立即更新还是更新事件发送的
时候更新。
重复计数器寄存器 (TIMx_RCR)
以递增计数模式为例,当 CNT 计数器数值达到 ARR 自动重载数值时,重复计数器的数值加 1,重复
次数达到 TIMx_RCR+ 1 后就,将生成更新事件。
注,只有 TIM1,TIM8,TIM15,TIM16,TIM17 有此寄存器。
比如我们要配置定时器实现周期性的中断,主要使用这几个寄存器即可。
输出PWM
使用定时器时基单元的那几个寄存器仅仅能设置周期,还不能设置占空比。针对这个问题,还需要比
较捕获寄存 CCR 的参与,这样就可以设置占空比了。
为了方便大家理解,以 PWM 边沿对齐模式,递增计数配置为例:
当计数器 TIMx_CNT < 比较捕获寄存器 TIMx_CCRx 期间,PWM 参考信号 OCxREF 输出高电平。
当计数器 TIMx_CNT >= 比较捕获寄存器 TIMx_CCRx 期间,PWM 参考信号 OCxREF 输出低电平。
当比较捕获寄存器 TIMx_CCRx > 自动重载寄存器 TIMx_ARR,OCxREF 保持为 1。
当比较捕获寄存器 TIMx_CCRx = 0,则 OCxRef 保持为 0。
定时器输入捕获
与 PWM 一样,使用定时器实现输入捕获,仅靠时基单元的那几个寄存器是不行的,我们需要一个寄
存器来记录发生捕获时的具体时间,这个寄存器依然由比较捕获寄存器 TIMx_CCRx 来实现。
比如我们要测量一路方波的周期:
配置定时器为输入捕获模式,上升沿触发,设置分频,自动重装等寄存器,比如设置的 CNT 计数器计数 1 次是 1 微秒。
当有上升沿触发的时候,TIMx_CCRx 寄存器就会自动记录当前的 CNT 数值,然后用户就可以通过CC 中断,在中断复位程序里面保存当前的 TIMx_CCRx 寄存器数值。等下次再检测到上升沿触发,两次时间求差就可以得到方波的周期。
不过这里要特别注意一点,如果 CNT 发生溢出(比如 16 位定时器,计数到 65535 就溢出了)
就需要特别处理下,将 CNT 计数溢出考虑进来。
TIM1-TIM17的中断配置
/*
TIM¶¨Ê±ÖжϷþÎñ³ÌÐò·¶Àý£¬±ØÐëÇåÖжϱêÖ¾
void TIM6_DAC_IRQHandler(void)
{
if((TIM6->SR & TIM_FLAG_UPDATE) != RESET)
{
TIM6->SR = ~ TIM_FLAG_UPDATE;
//Ìí¼ÓÓû§´úÂë
}
}
*/
void bsp_SetTIMforInt(TIM_TypeDef* TIMx, uint32_t _ulFreq, uint8_t _PreemptionPriority, uint8_t _SubPriority)
{
TIM_HandleTypeDef TimHandle = {
0};
uint16_t usPeriod;
uint16_t usPrescaler;
uint32_t uiTIMxCLK;
/* ʹÄÜTIMʱÖÓ */
bsp_RCC_TIM_Enable(TIMx);
/*-----------------------------------------------------------------------
bsp.c ÎļþÖÐ void SystemClock_Config(void) º¯Êý¶ÔʱÖÓµÄÅäÖÃÈçÏÂ:
System Clock source = PLL (HSE)
SYSCLK(Hz) = 400000000 (CPU Clock)
HCLK(Hz) = 200000000 (AXI and AHBs Clock)
AHB Prescaler = 2
D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)
D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)
D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)
因为 APB1 prescaler != 1, 所以 APB1 上的 TIMxCLK = APB1 x 2 = 200MHz;
因为 APB2 prescaler != 1, 所以 APB2 上的 TIMxCLK = APB2 x 2 = 200MHz;
APB4 上面的 TIMxCLK 没有分频,所以就是 100MHz;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14,LPTIM1
APB2 定时器有 TIM1, TIM8 , TIM15, TIM16,TIM17
APB4 定时器有 LPTIM2,LPTIM3,LPTIM4,LPTIM5
----------------------------------------------------------------------- */
if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM15) || (TIMx == TIM16) || (TIMx == TIM17))
{
/* APB2 定时器时钟 = 200M */
uiTIMxCLK = SystemCoreClock / 2;
}
else
{
/* APB1 定时器 = 200M */
uiTIMxCLK = SystemCoreClock / 2;
}