
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)详解 - 宋马](https://pic.songma.com/blogimg/20250715/c440f3640b514b40bc81ccc83c14a683.png)
计数器寄存器(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);
}
}
















暂无评论内容