一、前言
参考硬石科技的教程,实现定时器同步-脉冲计数。TIM1发送PWM脉冲,TIM2计算TIM1发送PWM脉冲的数量。以往想要计算TIM1实际发送了多少PWM脉冲,需要让TIM1每产生一个脉冲时进入一次中断。在STM32H7上,可以使用定时器的主从关系,实现TIM2计算TIM1发送PWM脉冲的数量。这样,计算PWM脉冲数就不需要TIM1频繁进入中断了。
在手册RM0433中的介绍:
二、CubeMX
2.1、Clock Configuration
定时器之类的外设,挂载在哪个时钟总线上。通过查看手册RM0433的100页能找到。
2.2、主定时器TIM1 - Mode and Configuration
2.3、主定时器TIM1 - Parameter Settings
TIM1产生PWM脉冲的频率 = 240M / (Prescaler + 1 ) / (Counter Period + 1) = 240M / 240 / 50000 = 1M / 50000 = 20Hz。
PWM脉冲占空比 = (Pulse + 1) / (Counter Period + 1 ) = 25000 / 50000 * 100% = 0.5 * 100% = 50%。
使能TRGO,开启TIM的主从模式。TIM1作为主定时器,使用TRGO作为触发输出给从定时器。 触发的方式Comapre Pulse,相当于CNT计数器 = CCR1时触发(即PWM脉冲中间低电平切换高电平的地方)。实际上,Trigger Output Parameter就是配置TIM1控制器寄存器2(TIMx_CR2)。
2.4、从定时器TIM2 - Mode and Configuration
从手册RM0433看到,TIM1与TIM2的内部触发连接是ITR0。比如TIM3与TIM2的内部触发连接是ITR1。
2.5、从定时器TIM2 - Parameter Settings
基本不用修改。
2.6、生成代码
三、代码
3.1、tim.c
在函数MX_TIM2_Init()里添加用户代码:
/* USER CODE BEGIN TIM2_Init 2 */
HAL_TIM_Base_Start(&htim2); /* 启动TIM2 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); /* 开启TIM1发送PWM脉冲 */
/* USER CODE END TIM2_Init 2 */
四、DEBUG
4.1、现场表达式查看内存
在现场表达式上添加结构体变量htim2,再从结构体成员里找到Instance,里面看到CNT寄存器的值。从下图看到,CNT=461,表示TIM1已经发了461个PWM脉冲。
使用HAL库时,每一个外设的结构体变量(也称为句柄),都有成员Instance。通过Instance可以很方便查看外设的寄存器。
4.2、TIM2上CNT寄存器的值真的等于TIM1的PWM脉冲数吗?
参考笔记配置PWM中断:
STM32H743+CubeMX-定时器TIM输出PWM(PWM Generation模式)+ 中断
TIM1每发送一个PWM脉冲,进入一次定时器溢出中断,计算PWM脉冲的总数。如何在中断里计算的PWM脉冲总数等于TIM2的CNT寄存器的值的话,就能证明了。
从下图可以看到,main_Value等于CNT。证明了TIM2上的CNT寄存器的值真的等于TIM1的PWM脉冲数。
五、细节补充
5.1、为什么选择TIM2计算PWM脉冲的总数
从下图看到,TIM2与TIM5的CNT寄存器32位的,其他定时器的CNT寄存器都是16位。32位寄存器的计数范围是 0 ~ 4294967295,实际工作上使用它来计算步进电机的步距角非常方便,因为32位的寄存器很难溢出。
其他定时器的CNT寄存器是16位,计数范围是0 ~ 65535。用它来计算步进电机的步距角的话,非常容易溢出,计算起来稍微麻烦一些。
5.2、Update Event 与 Compare Pulse(OC1)的区别
经过实际测试,触发方式改为Update Event的效果是一样的。只是细节上稍微有一点不一样而已。
严格来说,触发模式改为Update Event才对的。因为PWM脉冲的结束位置是CNT = ARR,而不是CNT = CCR1。当然无论选择Update Event还是Compare Pulse,计算出来的PWM总数都是一样,除非TIM1在PWM模式下只发送了PWM脉冲的一半(这个应该是不可能的)。