通用定时器(TIM2~5_TIM12~17)详解

1、General-purpose timers 介绍

STM32H562 的各个通用定时器特性介绍如下表

定时器 计数器位数 计数模式 预分配系数 捕获/比较通道 互补输出通道 定时最大频率(MHz)
TIM2/TIM5 32 递增/递减 /中心对齐 1 ~ 65536 4 250
TIM3/TIM4 16 递增/递减/中心对齐 1 ~ 65535 4 250
TIM12/TIM15 16 递增 1 ~ 65536 2 1 250
TIM13/TIM14
TIM16/TIM17
16 递增 1 ~ 65536 1 1 250

以 TIM2/TIM3/TIM4/TIM5 的框图为例来学习定时器内部框图,对之后的编程会有一个清晰的思路。如下图:

1、时钟源

通用定时器的输入时钟可以选择如下四类时钟源之一:

1、内部时钟(tim_ker_ck)

2、外部时钟模式

3、外部时钟模式2:外部触发输入(tim_etr_in)

4、内部触发输入(tim_itr):使用一个定时器作为另一个定时器的预分频器

通用定时器时钟源的设置方法如下所示:

内部时钟(tim_ker_ck):设置TIMx_SMCR寄存器的SMS=000,即TIMx_CR1寄存器的CEN,DIR位与TIMx_EGR寄存器的UG位是实际的控制位,只能通过软件更改(UG位除外,它会自动清零)。一旦CEN=1,即选择内部时钟(tim_ker_ck)驱动预分频器;

外部时钟模式1:设置TIMx_SMCR寄存器的SMS=111;

外部时钟模式2:设置TIMx_SMCR的ECE=1;

内部触发输入:该配置参考《STM32H5xx参考手册》的39.4.23小节

2、控制器

控制器包括:从模式控制器、编码器接口和触发控制器(TRGO)。从模式控制器可以控制计数器复位、启动、递增/递减、计数。编码器接口针对编码器计数。触发控制器用来提供触发信号给别的外设,例如为其它定时器提供时钟或者为DAC/ADC的触发转换提供信号。

3、时基单元

该单元包括:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR)。通用定时器的计数模式有三种:递增计数模式、递减计数模式和中心对齐模式;三种工作模式如下图所示:

4、输入捕获

图中第4部分是输入捕获,一般与第5部分一起完成信号测量功能。常用的测量有:测量输入信号的脉冲宽度、测量PWM输入信号的频率与占空比等。TIMx_CH1~TIMx_CH4表示定时器的4个通道,这些通道可独立工作。以通道1为例,对于信号的输入捕获详解如下图所示:

当待测量信号到达TIMx_CH1后,首先会经过一个滤波器,由ICF[3:0]位来设置滤波方式,也可设置不使用滤波器。之后会经过边沿检测器,可设置上升沿或者下降沿检测。由CC1P位来设置。CC1NP是配置互补通道的边沿检测,仅有高级定时器才有,通用定时器没有;

然后经过输入捕获映射选择器,可映射到tim_ti1_fp1、tim_ti2_fp1或tim_trc,由CC1S[1:0]位设置。紧接着会经过输入捕获1预分频器,由ICPS[1:0]来设置预分频系数;

最后通过设置CCIE位为1来使能输入捕获功能,IC1PS即分频后的捕获信号。

5、输入捕获与输出比较公用部分

输入捕获/输出时,该部分功能如下图所示:

6、输出比较

关于该部分主要功能如下图所示:

7、ocxref清除信号

这些输入可用于清除tim_ocxref信号,通常用于硬件逐周期脉宽控制。

8、定时器中断信号与DMA请求信号

2、TIM2~5寄存器介绍

控制寄存器1(TIMx_CR1)


GEN位:用于使能计数器,该位置1,计数器才会开始计数

DIR位:用于控制计数器方向,0表示递增计数,1表示递减计数;

CMS[1:0]位:用于设置边沿对齐或中心对齐模式;

ARPE位:用于控制自动重载寄存器是否进行缓冲,若ARPE位置1,ARR起缓冲作用,即仅当有更新事件发生时才会把ARR的值写入影子寄存器;若ARR位置0,当修改自动重载寄存器值时,该值会立即被写入影子寄存器,从而立即生效;

从模式控制寄存器(TIMx_SMCR)

SMS[3:0]位:用于从模式选择,即选择计数器输入时钟的来源;

TIMx DMA/中断使能寄存器(TIMx_DIER)

该寄存器主要用于是否使能触发DMA请求、捕获/比较中断以及更新中断;

UIE位:更新中断是否使能,1:开启;0:关闭;

状态寄存器(TIMx_SR)

该寄存器都是一些中断标志位,如更新中断标志位、捕获/比较中断标志位等。这些位都由硬件置位,由软件清零;

TIMx 事件生成寄存器(TIMx_EGR)

TIMx捕获/比较模式寄存器(TIMx_CCMR1)图片[1] - 通用定时器(TIM2~5_TIM12~17)详解 - 宋马
计数器寄存器(TIMx_CNT)

TIM3/TIM4的计数器是16位的,对应位CNT[15:0]。可直接写位[15:0]设置计数器的初始值,也可读取位CNT[15:0]获取计数器的值;

预分频寄存器(TIMx_PSC)

该寄存器表示预分频值,范围为0~65535;分频系数为该值+1;

自动重载寄存器(TIMx_ARR)

当DITHEN为0(即非抖动模式)时,该寄存器保存的为自动重装载值;当DITHEN为1(即抖动模式),该寄存器ARR[19:4]位域存储整数部分,ARR[3:0]位域则包含抖动部分;

3、代码实战测试

本实验使用PWM波控制LED实现呼吸灯的效果,硬件如下图:

新建tim.c与tim.h文件,tim.c的代码如下:

#include "tim.h"

TIM_HandleTypeDef   Pwm_TimHandle;
TIM_OC_InitTypeDef  Pwm_OcHandle;

/**
 * @brief Pwm_Init
 * @note 通用定时器的时钟来自APB1,APB1为250M,所以定时器时钟 = 250MHz
 * 
 * @param arr :自动重装载值
 * @param psc :时钟预分频数
 */
void Pwm_Init(uint16_t arr, uint16_t psc)
{
            
    Pwm_TimHandle.Instance = TIM3;                                              //定时器x
    Pwm_TimHandle.Init.Prescaler = psc;                                         //定时器分频
    Pwm_TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;                        //向上计数模式
    Pwm_TimHandle.Init.Period = arr;                                            //自动重装载值
    HAL_TIM_PWM_Init(&Pwm_TimHandle);                                           //初始化PWM

    Pwm_OcHandle.OCMode = TIM_OCMODE_PWM1;                                      //模式选择PWM1
    Pwm_OcHandle.Pulse = arr/2;                                                 //设置占空比 50%
    Pwm_OcHandle.OCPolarity = TIM_OCPOLARITY_LOW;                               //输出比较极性为低
    HAL_TIM_PWM_ConfigChannel(&Pwm_TimHandle, &Pwm_OcHandle, TIM_CHANNEL_1);    //配置PWM通道1

    HAL_TIM_PWM_Start(&Pwm_TimHandle, TIM_CHANNEL_1);                           //开启PWM通道1
}


/**
 * @brief HAL_TIM_PWM_MspInit
 * 
 * @param htim 
 */
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
            
    if(htim->Instance == TIM3)
    {
            
        GPIO_InitTypeDef GPIO_Initval;

        __HAL_RCC_GPIOB_CLK_ENABLE();                                           //开启GPIOB通道时钟
        __HAL_RCC_TIM3_CLK_ENABLE();                                            //开启TIM3定时器时钟

        GPIO_Initval.Pin = GPIO_PIN_4;                                          //定义GPIO引脚
        GPIO_Initval.Mode = GPIO_MODE_AF_PP;                                    //复用推挽输出
        GPIO_Initval.Pull = GPIO_PULLUP;                                        //上拉
        GPIO_Initval.Speed = GPIO_SPEED_FREQ_HIGH;                              //高速

        GPIO_Initval.Alternate = GPIO_AF2_TIM3;                                 //定时器x通道y的GPIO口复用
        HAL_GPIO_Init(GPIOB, &GPIO_Initval);                                    //初始化GPIO
    }
}

tim.h文件如下图:

#ifndef __TIM_H__
#define __TIM_H__
#include "stm32h5xx_hal.h"
#include "stm32h5xx_hal_tim.h"
#include "stm32h5xx_hal_tim_ex.h"

extern TIM_HandleTypeDef   Pwm_TimHandle;
extern TIM_OC_InitTypeDef  Pwm_OcHandle;

void Pwm_Init(uint16_t arr, uint16_t psc);

#endif

最后在main.c中添加测试代码如下:

#include "stm32h5xx_hal.h"
#include "sys_freq.h"
#include "adc.h"
#include "uart.h"
#include "tim.h"
// uint32_t sysclk_val = 0;
// uint32_t hclk_val = 0;
// uint32_t apb1clk_val = 0;
// uint32_t apb2clk_val = 0;
// uint32_t apb3clk_val = 0;
// uint16_t temprow = 0;
// float tempvolt = 0;
// uint8_t tx_msg[] = "STM32H562 UART DMA Ready
";
// uint8_t rx_data[128];
// uint16_t rx_len = 0;

uint8_t dir = 1;
uint16_t dutyval = 0;

int main(void)
{
            
    HAL_Init();
    sys_clock_init();
    // uart_init(115200);
    Pwm_Init(500 - 1, 250 - 1);

    while(1)
    {
            
        if(dir)
        {
            
            dutyval++;
        }else{
            
            dutyval--;
        }

        if(dutyval > 300)dir = 0;
        if(dutyval == 0)dir = 1;
        __HAL_TIM_SET_COMPARE(&Pwm_TimHandle, TIM_CHANNEL_1, dutyval);
        
        HAL_Delay(10);
    }
}
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容