注:本文为 "STM32 定时器" 相关合辑。
图片清晰度受引文原图所限。
略作重排,未整理去重。
如有内容异常,请看原文。
STM32 定时器配置(TIM1、TIM2、TIM3、TIM4、TIM5、TIM8)------高级定时器与普通定时器定时计数模式总结
posted @ 2018-08-16 21:54 竹风清
一、定时器基本介绍



定时器时基单元
1. 时钟源
定时器时钟 TIM x CLK \text{TIM}x\text{CLK} TIMxCLK(即内部时钟 CK_INT \text{CK\_INT} CK_INT)由 APB1 预分频器分频提供:
- 若 APB1 预分频系数为 1 1 1, TIM x CLK \text{TIM}x\text{CLK} TIMxCLK 频率与 APB1 频率一致;
- 若 APB1 预分频系数 ≠ 1 \neq 1 =1, TIM x CLK \text{TIM}x\text{CLK} TIMxCLK 频率为 APB1 频率的 2 2 2 倍。
示例 :若 APB1 预分频系数为 2 2 2、 PCLK1 = 36 M \text{PCLK1}=36\text{M} PCLK1=36M,则 TIM x CLK = 36 M × 2 = 72 M \text{TIM}x\text{CLK}=36\text{M} \times 2=72\text{M} TIMxCLK=36M×2=72M。
2. 计数器时钟
定时器时钟经 PSC 预分频器后得到 CK_CNT \text{CK\_CNT} CK_CNT,作为计数器的驱动时钟。
- PSC 为 16 16 16 位预分频器,可对 TIM x CLK \text{TIM}x\text{CLK} TIMxCLK 进行 1 ∼ 65536 1 \sim 65536 1∼65536 范围内的分频;
- 计算公式: CK_CNT = TIM x CLK PSC + 1 \text{CK\_CNT} = \frac{\text{TIM}x\text{CLK}}{\text{PSC}+1} CK_CNT=PSC+1TIMxCLK。
3. 计数器
计数器 CNT \text{CNT} CNT 为 16 16 16 位向上计数器,最大计数值为 65535 65535 65535。
- 当计数达到自动重装寄存器的值时,触发更新事件,并清零后重新开始计数。
4. 自动重装载寄存器
自动重装载寄存器 ARR \text{ARR} ARR 为 16 16 16 位寄存器,存储计数器的最大计数值。
- 当计数器计数至 ARR \text{ARR} ARR 的值时,若使能中断,定时器将产生溢出中断。
5. 定时时间的计算
定时时间 = 计数器的中断周期 × \times × 中断次数。
- 计数器在 CK_CNT \text{CK\_CNT} CK_CNT 驱动下,计数 1 1 1 次的时间为 CK_CNT \text{CK\_CNT} CK_CNT 的倒数,即: 1 TIM x CLK PSC + 1 \frac{1}{\frac{\text{TIM}x\text{CLK}}{\text{PSC}+1}} PSC+1TIMxCLK1;
- 单次中断的时间为: 1 CK_CNT × ARR \frac{1}{\text{CK\_CNT}} \times \text{ARR} CK_CNT1×ARR;
- 若在中断服务程序中用变量 time \text{time} time 记录中断次数,则总定时时间为: 1 CK_CNT × ( ARR + 1 ) × time \frac{1}{\text{CK\_CNT}} \times (\text{ARR}+1) \times \text{time} CK_CNT1×(ARR+1)×time。
二、普通定时器详细介绍(TIM2-TIM5)
2.1 时钟来源
计数器时钟可由以下时钟源提供:
- 内部时钟 (CK_INT)
- 外部时钟模式 1:外部输入引脚 (TIx)
- 外部时钟模式 2:外部触发输入 (ETR)
- 内部触发输入 (ITRx):将一个定时器配置为另一个定时器的预分频器,例如可将 TIM1 配置为 TIM2 的预分频器。
本章节聚焦基础定时功能,故采用内部时钟作为计数时钟源。TIM2-TIM5 的时钟并非直接取自 APB1 总线,而是来源于以 APB1 为输入的倍频器,该倍频器的工作规则为:
- 当 APB1 预分频系数为 1 时,倍频器不工作,定时器时钟频率等于 APB1 频率(36 MHz);
- 当 APB1 预分频系数为 2、4、8 或 16 时,倍频器生效,定时器时钟频率为 APB1 频率的 2 倍。
时钟频率计算示例
设 APB1 预分频系数为 2,则 APB1 频率为 36 MHz,此时 TIM2-TIM5 的倍频器生效,定时器输入时钟频率为 2 × 36 MHz = 72 MHz 2 \times 36 \ \text{MHz} = 72 \ \text{MHz} 2×36 MHz=72 MHz。
不同预分频系数下的时钟频率计算如下:
- APB1 1 分频: f TIM = 36 MHz f_{\text{TIM}} = 36 \ \text{MHz} fTIM=36 MHz
- APB1 4 分频: f TIM = 72 MHz 4 × 2 = 36 MHz f_{\text{TIM}} = \frac{72 \ \text{MHz}}{4} \times 2 = 36 \ \text{MHz} fTIM=472 MHz×2=36 MHz
- APB1 8 分频: f TIM = 72 MHz 8 × 2 = 18 MHz f_{\text{TIM}} = \frac{72 \ \text{MHz}}{8} \times 2 = 18 \ \text{MHz} fTIM=872 MHz×2=18 MHz
- APB1 16 分频: f TIM = 72 MHz 16 × 2 = 9 MHz f_{\text{TIM}} = \frac{72 \ \text{MHz}}{16} \times 2 = 9 \ \text{MHz} fTIM=1672 MHz×2=9 MHz
c
// 系统时钟初始化配置
void RCC_Configuration(void)
{
// 定义错误状态变量
ErrorStatus HSEStartUpStatus;
// 将 RCC 寄存器重置为默认值
RCC_DeInit();
// 使能外部高速时钟晶振
RCC_HSEConfig(RCC_HSE_ON);
// 等待外部高速时钟晶振稳定
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
// 设置 AHB 时钟 (HCLK) 等于系统时钟
RCC_HCLKConfig(RCC_SYSCLK_Div1);
// 设置 APB2 时钟等于 HCLK 时钟
RCC_PCLK2Config(RCC_HCLK_Div1);
// 设置 APB1 时钟为 HCLK 的 2 分频(TIM2-TIM5 输入时钟为 72 MHz/2×2=72 MHz)
RCC_PCLK1Config(RCC_HCLK_Div2);
// 设置 FLASH 访问延时
FLASH_SetLatency(FLASH_Latency_2);
// 使能预取指缓存
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
// 配置 PLL 时钟:HSE 1 分频,9 倍频(8 MHz × 9 = 72 MHz)
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
// 使能 PLL
RCC_PLLCmd(ENABLE);
// 等待 PLL 稳定
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
// 设置 PLL 为系统时钟源
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
// 确认 PLL 已作为系统时钟
while(RCC_GetSYSCLKSource() != 0x08);
}
// 使能 TIM2 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
// 使能 GPIOB 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
}
APB1 分频配置的设计初衷为:APB1 需为多个外设提供时钟,倍频器可保证在 APB1 低频工作时,TIM2-TIM5 仍能获得较高时钟频率,满足定时精度需求。
2.2 计数器模式
TIM2-TIM5 支持三种计数模式:
- 向上计数模式:计数器从 0 计数至自动重装值(TIMx_ARR),溢出后重置为 0 并产生更新事件;
- 向下计数模式:计数器从自动重装值计数至 0,溢出后重置为自动重装值并产生更新事件;
- 中央对齐模式(向上/向下计数) :计数器从 0 计数至 ARR − 1 \text{ARR}-1 ARR−1 产生溢出事件,再向下计数至 1 产生溢出事件,随后重复上述过程。
2.3 编程步骤
定时器基础配置流程如下:
- 配置系统时钟;
- 配置嵌套向量中断控制器(NVIC);
- 配置通用输入输出端口(GPIO);
- 配置定时器(TIMER),具体包含:
(1) 调用TIM_DeInit()函数将定时器寄存器重置为默认值;
(2) 调用TIM_InternalClockConfig()函数选择内部时钟源;
(3) 通过TIM_Prescaler设置预分频系数;
(4) 通过TIM_ClockDivision设置时钟分割比;
(5) 通过TIM_CounterMode设置计数器模式;
(6) 通过TIM_Period设置自动重装值;
(7) 调用TIM_ARRPreloadConfig()函数配置自动重装预装载缓冲器;
(8) 调用TIM_ITConfig()函数使能定时器中断。
其中步骤 (3)-(6) 的参数由 TIM_TimerBaseInitTypeDef 结构体定义,参数说明如下:
- 预分频系数 :定时器工作时钟频率计算公式为 KaTeX parse error: Expected 'EOF', got '' at position 12: f{\text{CK_̲CNT}} = \frac{f...,其中 KaTeX parse error: Expected 'EOF', got '' at position 12: f{\text{CK_̲INT}} 为内部时钟频率,
TIM_Prescaler取值范围为 0~65535; - 时钟分割比:定义定时器时钟与数字滤波器(ETR、TIx)采样时钟的分频比例,参数说明见表 2-1。
表 2-1 时钟分割比参数说明
| TIM_ClockDivision | 描述 | 二进制值 |
|---|---|---|
| TIM_CKD_DIV1 | t DTS = T ck_tim t_{\text{DTS}} = T_{\text{ck\_tim}} tDTS=Tck_tim | 0 x 00 0\text{x}00 0x00 |
| TIM_CKD_DIV2 | t DTS = 2 × T ck_tim t_{\text{DTS}} = 2 \times T_{\text{ck\_tim}} tDTS=2×Tck_tim | 0 x 01 0\text{x}01 0x01 |
| TIM_CKD_DIV4 | t DTS = 4 × T ck_tim t_{\text{DTS}} = 4 \times T_{\text{ck\_tim}} tDTS=4×Tck_tim | 0 x 10 0\text{x}10 0x10 |
数字滤波器的作用为滤除 ETR/TIx 输入信号中的高频噪声,确保采样信号频率不超过阈值。
- 自动重装预装载缓冲器 :
- 禁用时:写入 TIMx_ARR 的值直接更新至影子寄存器;
- 使能时:写入 TIMx_ARR 的值需在更新事件(UEV)发生时,才从预装载寄存器同步至影子寄存器。
预装载寄存器(preload register)与影子寄存器(shadow register)的设计目的为:保证多通道定时器的寄存器更新同步,避免因软件逐寄存器写入导致的时序不同步问题。
三、定时器代码实例
定时周期计算公式:
T out = ( arr + 1 ) × ( psc + 1 ) f Tclk T_{\text{out}} = \frac{(\text{arr}+1) \times (\text{psc}+1)}{f_{\text{Tclk}}} Tout=fTclk(arr+1)×(psc+1)
其中:
- arr \text{arr} arr:自动重装值;
- psc \text{psc} psc:预分频系数;
- f Tclk f_{\text{Tclk}} fTclk:定时器输入时钟频率;
- T out T_{\text{out}} Tout:定时周期。
3.1 定时器 1 配置
配置前提:APB2 时钟 1 分频,即 f APB2 = 72 MHz f_{\text{APB2}} = 72 \ \text{MHz} fAPB2=72 MHz(配置代码见 RCC_Configuration() 函数中 RCC_PCLK2Config(RCC_HCLK_Div1))。
定时周期计算:
T out = ( 100 − 1 + 1 ) × ( 7200 − 1 + 1 ) 72 × 10 6 = 0.1 s = 100 ms T_{\text{out}} = \frac{(100-1+1) \times (7200-1+1)}{72 \times 10^6} = 0.1 \ \text{s} = 100 \ \text{ms} Tout=72×106(100−1+1)×(7200−1+1)=0.1 s=100 ms
c
// 定时器 1 计数初始化(置于主函数初始化流程)
void Timer1CountInitial(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 使能 TIM1 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
// 配置定时器时基参数
TIM_TimeBaseStructure.TIM_Period = 100-1; // 自动重装值(定时 100 ms)
TIM_TimeBaseStructure.TIM_Prescaler = 7200-1; // 时钟预分频系数
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分割比 1
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 重复计数器值(高级定时器专用)
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);
// 清除更新标志位
TIM_ClearFlag(TIM1,TIM_FLAG_Update);
// 使能更新中断
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);
// 使能 TIM1
TIM_Cmd(TIM1, ENABLE);
}
// TIM1 更新中断服务函数
void TIM1_UP_IRQHandler(void)
{
if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)
{
// 行程开关去抖程序
if(XingChengTickNum_QuFantan < 1000)
{
XingChengTickNum_QuFantan++;
}
// 清除中断挂起位
TIM_ClearITPendingBit(TIM1,TIM_IT_Update);
}
}
3.2 定时器 2 配置
配置前提:APB1 时钟 2 分频,即 f TIM2 = 72 MHz f_{\text{TIM2}} = 72 \ \text{MHz} fTIM2=72 MHz(配置代码见 RCC_Configuration() 函数中 RCC_PCLK1Config(RCC_HCLK_Div2))。
定时周期计算:
T out = ( 4 − 1 + 1 ) × ( 36000 − 1 + 1 ) 72 × 10 6 = 2 ms T_{\text{out}} = \frac{(4-1+1) \times (36000-1+1)}{72 \times 10^6} = 2 \ \text{ms} Tout=72×106(4−1+1)×(36000−1+1)=2 ms
c
// TIM2 中断初始化
void TIM2_Int_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 使能 TIM2 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 重置 TIM2 寄存器
TIM_DeInit(TIM2);
// 配置定时器时基参数
TIM_TimeBaseStructure.TIM_Period = 4 - 1; // 自动重装值
TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1; // 预分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分割比 1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 清除更新标志位
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
// 使能更新中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
// 使能 TIM2
TIM_Cmd(TIM2, ENABLE);
}
// TIM2 中断服务函数
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
interrupt_rtc(); // 执行自定义函数
// 清除中断挂起位
TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);
}
}
3.3 定时器 3 配置
配置前提:APB1 时钟 2 分频,即 f TIM3 = 72 MHz f_{\text{TIM3}} = 72 \ \text{MHz} fTIM3=72 MHz。
定时周期计算:
T out = ( 4 − 1 + 1 ) × ( 36000 − 1 + 1 ) 72 × 10 6 = 2 ms T_{\text{out}} = \frac{(4-1+1) \times (36000-1+1)}{72 \times 10^6} = 2 \ \text{ms} Tout=72×106(4−1+1)×(36000−1+1)=2 ms
c
// 通用定时器 3 中断初始化
// arr:自动重装值;psc:时钟预分频数
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能 TIM3 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// 配置定时器时基参数
TIM_TimeBaseStructure.TIM_Period = arr; // 自动重装值
TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分割比 1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// 使能更新中断
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
// 配置 NVIC 中断优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; // 中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// 抢占优先级 0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 响应优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStructure);
// 使能 TIM3
TIM_Cmd(TIM3, ENABLE);
}
// TIM3 中断服务程序
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 清除中断挂起位
LED1 = !LED1; // LED 状态翻转
}
}
3.4 定时器 4 配置
配置前提:APB1 时钟 4 分频,即 f TIM4 = 36 MHz f_{\text{TIM4}} = 36 \ \text{MHz} fTIM4=36 MHz(配置代码:RCC_PCLK1Config(RCC_HCLK_Div4))。
定时周期计算:
T out = ( 4 − 1 + 1 ) × ( 36000 − 1 + 1 ) 36 × 10 6 = 4 ms T_{\text{out}} = \frac{(4-1+1) \times (36000-1+1)}{36 \times 10^6} = 4 \ \text{ms} Tout=36×106(4−1+1)×(36000−1+1)=4 ms
c
// TIM4 中断初始化
void TIM4_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能 TIM4 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
// 配置定时器时基参数
TIM_TimeBaseStructure.TIM_Period = arr; // 自动重装值
TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分割比 1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
// 使能更新中断
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
// 配置 NVIC 中断优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; // 中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// 抢占优先级 0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 响应优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStructure);
// 使能 TIM4
TIM_Cmd(TIM4, ENABLE);
}
// TIM4 中断服务程序
void TIM4_IRQHandler(void)
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update); // 清除中断挂起位
LED0 = !LED0; // LED 状态翻转
// Get_Angle(); // 自定义角度获取函数
}
}
3.5 定时器 5 配置
配置前提:APB1 时钟 1 分频,即 f TIM5 = 36 MHz f_{\text{TIM5}} = 36 \ \text{MHz} fTIM5=36 MHz(配置代码:RCC_PCLK1Config(RCC_HCLK_Div1))。
定时周期计算:
T out = ( 4 − 1 + 1 ) × ( 36000 − 1 + 1 ) 36 × 10 6 = 4 ms T_{\text{out}} = \frac{(4-1+1) \times (36000-1+1)}{36 \times 10^6} = 4 \ \text{ms} Tout=36×106(4−1+1)×(36000−1+1)=4 ms
c
// TIM5 初始化
void TIM5_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能 TIM5 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
// 配置定时器时基参数
TIM_TimeBaseStructure.TIM_Period = arr; // 自动重装值
TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分割比 1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
// 使能更新中断
TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE);
// 配置 NVIC 中断优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; // 中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// 抢占优先级 0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 响应优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStructure);
// 使能 TIM5
TIM_Cmd(TIM5, ENABLE);
}
// TIM5 中断服务程序
void TIM5_IRQHandler(void)
{
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM5, TIM_IT_Update); // 清除中断挂起位
LED1 = !LED1; // LED 状态翻转
}
}
STM32-定时器详解
辰哥单片机设计 已于 2023-08-04 22:49:25 修改
前言
定时器作为微控制器的标准外设,在 STM32 系列微控制器中同样具备广泛应用场景。多数初学者在学习定时器相关内容时,常会降低对 STM32 学习的积极性,甚至产生放弃的想法,究其原因在于该部分知识体系相对复杂。但如果学习者已熟练掌握 GPIO、串口通信、外部中断等外设的相关知识,那么学习定时器这一新外设的难度会显著降低。
本章共计 1 万余字,将从 STM32 定时器的工作原理、寄存器说明、定时器配置方法,以及定时器若干常用功能(如定时器中断、定时器输出比较 PWM 波形、定时器输入捕获测量电平时长、定时器编码器模式应用等)的实现方式展开讲解,帮助学习者掌握定时器外设的使用方法。
一、定时器基本介绍
1. STM32 定时器
定时器是具备定时功能的硬件模块,作为外设集成于 STM32 单片机内部。STM32 系列单片机配备 8 个定时器,具体分类为:2 个高级定时器(TIM1、TIM8)、4 个通用定时器(TIM2、TIM3、TIM4、TIM5)以及 2 个基本定时器(TIM6、TIM7),具体如下图所示:

三类定时器的功能差异如下:

具体而言:高级定时器包含捕获/比较通道与互补输出功能;通用定时器仅配备捕获/比较通道;基本定时器则无上述两类功能模块。
2. 通用定时器功能和特点
在 STM32 各类定时器中,高级定时器与通用定时器的应用频次最高,且高级定时器通常也可配置为通用定时器模式运行。以下以通用定时器为例,说明其功能与特性:
- 挂载于低速 APB1 总线(APB1);
- 具备 16 位向上计数、向下计数、向上/向下(中心对齐)计数模式,配置有自动装载计数器(TIMx_CNT);
- 配备 16 位可编程(支持实时修改)预分频器(TIMx_PSC),可将计数器时钟频率的分频系数设置为 1 ∼ 65535 1 \sim 65535 1∼65535 范围内的任意数值;
- 包含 4 个独立通道(TIMx_CH1~4),各通道可实现以下功能:
① 输入捕获;
② 输出比较;
③ PWM 生成(边缘对齐或中心对齐模式);
④ 单脉冲模式输出; - 支持通过外部信号(TIMx_ETR)实现定时器控制,以及定时器间互连(可通过一个定时器控制另一个定时器)的同步电路;
- 当发生以下事件时,可触发中断/DMA 请求(配置 6 个独立的 IRQ/DMA 请求生成器):
① 更新事件:计数器向上溢出/向下溢出、计数器初始化(通过软件或内部/外部触发);
② 触发事件:计数器启动、停止、初始化,或由内部/外部触发计数;
③ 输入捕获;
④ 输出比较;
⑤ 支持面向定位应用的增量(正交)编码器与霍尔传感器接口电路;
⑥ 触发输入可作为外部时钟源,或用于周期性电流管理; - STM32 通用定时器可应用于:测量输入信号的脉冲时长(输入捕获)、生成输出波形(输出比较与 PWM)等场景;
- 借助定时器预分频器与 RCC 时钟控制器预分频器,可将脉冲时长与波形周期调节至微秒级至毫秒级范围。STM32 各通用定时器相互独立,无共享硬件资源。
3. 计数器模式
通用定时器支持向上计数、向下计数、向上/向下双向计数三种模式:
① 向上计数模式:计数器从 0 0 0 计数至自动装载值(TIMx_ARR),随后重置为 0 0 0 并重新计数,同时触发计数器溢出事件;
② 向下计数模式:计数器从自动装载值(TIMx_ARR)向下计数至 0 0 0,随后恢复至自动装载值并重新计数,同时触发计数器向下溢出事件;
③ 中心对齐模式(向上/向下计数):计数器从 0 0 0 计数至自动装载值 − 1 -1 −1,触发计数器溢出事件;随后向下计数至 1 1 1,再次触发计数器溢出事件;之后重置为 0 0 0 并重复上述计数过程。

4. 定时器工作原理
a. 定时器框图
下图为 STM32 定时器的结构框图,是掌握 STM32 定时器工作机制的基础内容。部分学习者仅通过库函数实现定时器的基础配置与简单应用,却忽略了底层工作原理,这易导致在复杂应用设计中出现基础性错误。因此建议学习者深入理解定时器结构框图,掌握其内在工作逻辑。

该框图可划分为四个核心模块(以红色标注):① 时钟产生模块;② 时基单元模块;③ 输入捕获模块;④ 输出比较模块。
b. 时钟产生器部分
在时钟源选择环节,STM32 定时器提供四种时钟源(以蓝色标注):
① 内部时钟(CK_INT);
② 外部时钟模式 1:外部触发输入(ETR);
③ 内部触发输入(ITRx):可将一个定时器配置为另一个定时器的预分频器,例如将 Timer1 配置为 Timer2 的预分频器;
④ 外部时钟模式 2:外部输入脚(TIx)。

上述四种时钟源的配置逻辑可通过右侧图示说明:
其中,内部触发输入口 ITR1/ITR2/ITR3/ITR4 支持特殊配置:将一个定时器作为另一个定时器的分频器。
外部捕获比较引脚包含两类:
引脚 1:TI1FP1 或 TI1F_ED;
引脚 2:TI2FP2。
c. 时基单元
时基单元为定时器框图的第二模块,包含三个核心寄存器:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动装载寄存器(TIMx_ARR),各寄存器功能说明如下:
- 计数器寄存器(TIMx_CNT):支持向上计数、向下计数、中心对齐计数模式;
- 预分频器寄存器(TIMx_PSC):可将时钟频率按 1 ∼ 65535 1 \sim 65535 1∼65535 范围内的任意值分频,支持运行时修改分频系数;
- 自动装载寄存器(TIMx_ARR):若 TIMx_CR1 寄存器的 ARPE 位配置为 0 0 0,ARR 寄存器值将直接写入影子寄存器;若 ARPE 位配置为 1 1 1,ARR 寄存器值将在每次更新事件(UEV)触发时同步至影子寄存器;若 TIM1_CR1 寄存器的 UDIS 位配置为 0 0 0,计数器溢出时将触发更新事件。
d. 输入捕获通道
- IC1/IC2 与 IC3/IC4 可通过软件配置映射至 TI1/TI2 与 TI3/TI4;
- 4 个 16 位捕捉比较寄存器可以编程用于存放检测到对应的每一次输入捕捉时计数器的值;
- 当产生一次捕捉,相应的 CCxIF 标志位被置 1 1 1;同时如果中断或 DMA 请求使能,则产生中断或 DMA 请求;
- 如果当 CCxIF 标志位已经为 1 1 1,当又产生一个捕捉,则捕捉溢出标志位 CCxOF 将被置 1 1 1。

e. 输出比较通道(PWM)
- PWM 模式输出特性:
定时器 2、3、4 可生成 4 路独立 PWM 信号;
信号频率与占空比可通过以下方式配置:- 自动重载寄存器(TIMx_ARR):用于设置 PWM 周期;
- 捕获比较寄存器(TIMx_CCRx):用于设置 PWM 占空时长。
示例:生成 40 kHz 40\ \text{kHz} 40 kHz 占空比 50 % 50\% 50% 的 PWM 信号(定时器 2 时钟为 72 MHz 72\ \text{MHz} 72 MHz):
预分频寄存器配置为 0 0 0(计数器时钟 = TIM1CLK / ( 0 + 1 ) = \text{TIM1CLK}/(0+1) =TIM1CLK/(0+1)),自动重载寄存器配置为 1799 1799 1799,CCRx 寄存器配置为 899 899 899。
- PWM 模式类型:
支持边沿对齐模式与中心对齐模式两种配置。

二、定时器中断应用
1. 内部时钟选择


若 APB1 总线分频系数不为 1 1 1,则通用定时器时钟频率为 APB1 时钟频率的 2 2 2 倍。
SystemInit 函数默认配置下的时钟参数:
SYSCLK = 72 MHz AHB 时钟 = 72 MHz APB1 时钟 = 36 MHz \text{SYSCLK}=72\ \text{MHz}\\ \text{AHB 时钟}=72\ \text{MHz}\\ \text{APB1 时钟}=36\ \text{MHz} SYSCLK=72 MHzAHB 时钟=72 MHzAPB1 时钟=36 MHz
因此 APB1 分频系数 = AHB 时钟 / APB1 时钟 = 2 \text{APB1 分频系数}=\text{AHB 时钟}/\text{APB1 时钟}=2 APB1 分频系数=AHB 时钟/APB1 时钟=2,通用定时器时钟 CK INT = 2 × 36 MHz = 72 MHz \text{CK}_{\text{INT}} = 2 \times 36\ \text{MHz} = 72\ \text{MHz} CKINT=2×36 MHz=72 MHz。
2. 计数器模式
-
向上计数模式(时钟分频因子 = 1 =1 =1):


-
向下计数模式(时钟分频因子 = 1 =1 =1):


-
中央对齐计数模式(时钟分频因子 = 1 =1 =1, ARR = 6 \text{ARR}=6 ARR=6):


3. 定时器中断实验相关寄存器
-
计数器当前值寄存器(TIMx_CNT):

-
预分频寄存器(TIMx_PSC):

-
自动重装载寄存器(TIMx_ARR):

-
控制寄存器 1(TIMx_CR1):

-
DMA 中断使能寄存器(TIMx_DIER):

4. 常用库函数
定时器参数初始化函数:
cpp
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
结构体成员定义:
cpp
typedef struct
{
uint16_t TIM_Prescaler; // 预分频系数
uint16_t TIM_CounterMode; // 计数模式
uint16_t TIM_Period; // 自动重装载值
uint16_t TIM_ClockDivision; // 时钟分割因子
uint8_t TIM_RepetitionCounter; // 重复计数器值(仅高级定时器有效)
} TIM_TimeBaseInitTypeDef;
典型初始化配置:
cpp
TIM_TimeBaseStructure.TIM_Period = 4999;
TIM_TimeBaseStructure.TIM_Prescaler = 7199;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
定时器使能函数:
cpp
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
定时器中断使能函数:
cpp
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
状态标志位获取和清除函数:
cpp
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
5. 定时器中断实现步骤
① 使能定时器时钟:
RCC_APB1PeriphClockCmd();
② 初始化定时器,配置自动重装载值(ARR)与预分频系数(PSC):
TIM_TimeBaseInit();
③ 开启定时器中断,并配置嵌套向量中断控制器(NVIC):
TIM_ITConfig();
NVIC_Init();
④ 使能定时器:
TIM_Cmd();
⑤ 编写中断服务函数:
TIMx_IRQHandler();
6. 应用实例
以下为定时器中断实现代码,配置为每 500 ms 500\ \text{ms} 500 ms 触发一次中断,在中断服务函数中控制 LED 状态翻转。中断溢出时间计算公式为:
T out = ( ARR + 1 ) × ( PSC + 1 ) T clk T_{\text{out}} = \frac{(\text{ARR}+1) \times (\text{PSC}+1)}{\text{T}_{\text{clk}}} Tout=Tclk(ARR+1)×(PSC+1)
cpp
// timer.c 源文件
#include "timer.h"
#include "led.h"
// 通用定时器 3 中断初始化
// 时钟源为 APB1 时钟的 2 倍(APB1 时钟 = 36 MHz)
// arr:自动重装值
// psc:时钟预分频数
void TIM3_Int_Init(u16 arr, u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能 TIM3 时钟
// 初始化 TIM3 时基参数
TIM_TimeBaseStructure.TIM_Period = arr; // 设置自动重装载寄存器值
TIM_TimeBaseStructure.TIM_Prescaler = psc; // 设置预分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分割因子 = 1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 初始化时基单元
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 使能 TIM3 更新中断
// 配置 NVIC 中断优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; // 选择 TIM3 中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级 0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 响应优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStructure); // 初始化 NVIC 寄存器
TIM_Cmd(TIM3, ENABLE); // 使能 TIM3
}
// 定时器 3 中断服务函数
void TIM3_IRQHandler(void) // TIM3 中断入口
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) // 检查更新中断标志
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 清除更新中断标志
LED1 = !LED1; // LED 状态翻转
}
}
cpp
// timer.h 头文件
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
void TIM3_Int_Init(u16 arr, u16 psc);
#endif
cpp
// main.c 源文件
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"
int main(void)
{
delay_init(); // 初始化延时函数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 配置 NVIC 中断分组 2
uart_init(115200); // 初始化串口(波特率 115200)
LED_Init(); // 初始化 LED 端口
TIM3_Int_Init(4999, 7199); // 配置 10 kHz 计数频率,500 ms 溢出
while(1)
{
LED0 = !LED0;
delay_ms(200);
}
}
三、定时器 PWM 输出实验
1. 通用定时器 PWM 概述
PWM(Pulse Width Modulation,脉冲宽度调制)通过调制一系列脉冲的宽度,等效生成目标波形(包含幅值与形状特征),实现对模拟信号电平的数字编码。其核心逻辑为通过调节占空比(一个周期内高电平持续时间占总周期的百分比,如方波占空比为 50 % 50\% 50%),改变输出信号的能量或幅值。PWM 广泛应用于呼吸灯控制、直流电机/舵机驱动等场景,是单片机的常用功能之一。
在 STM32 单片机中,可通过定时器的输出比较功能生成 PWM 波形:
PWM 模式下,信号频率由 TIMx_ARR 寄存器值决定,占空比由 TIMx_CCRx 寄存器值决定,其工作框图如下:

横坐标为时间轴,纵坐标为 CNT 计数值。CNT 计数值随时间从 0 0 0 递增至 ARR,随后重置为 0 0 0 并重复该过程;CCRx 为比较值,通过比较 CNT 与 CCRx 的大小,并结合输出配置,可生成高低电平逻辑,最终形成 PWM 波形。通过调节 ARR 的值可以调节 PWM 的周期,调节 CCRx 的值大小可以调节 PWM 占空比。
以通道 1 为例,PWM 工作流程如下:

时钟源(内部时钟 CNT 或外部触发时钟 ETRF)输入至输入模式控制器,通过 OCMR1 寄存器的 OC1M[2:0] 位配置 PWM 模式;经选择器后,由 CCER 寄存器的 CC1P 位设置输出极性;最后通过 CCER 寄存器的 CC1E 位使能输出,最终由 OC1 引脚输出 PWM 波形。
关键寄存器说明:
- CCR1( x = 1 , 2 , 3 , 4 x=1,2,3,4 x=1,2,3,4):捕获比较寄存器,用于设置比较值;
- CCMR1:OC1M[2:0] 位用于配置 PWM 模式 1( 0 b 110 0\mathrm{b}110 0b110)或模式 2( 0 b 111 0\mathrm{b}111 0b111);
- CCER:CC1P 位配置输出极性( 0 0 0:高电平有效, 1 1 1:低电平有效);CC1E 位配置输出使能( 0 0 0:关闭, 1 1 1:打开)。
2. PWM 模式
PWM 包含模式 1 与模式 2 两类,其差异可通过 TIMx_CCMR1 寄存器的 OC1M[2:0] 位定义:

简而言之:PWM 模式 1 下,当 CNT < CCRx \text{CNT} < \text{CCRx} CNT<CCRx 时输出有效电平;PWM 模式 2 下,当 CNT > CCRx \text{CNT} > \text{CCRx} CNT>CCRx 时输出有效电平。该特性是 PWM 配置的基础要点。
以下为 PWM 模式 1 结合向上计数模式的工作逻辑:

3. 相关寄存器介绍
-
捕获/比较寄存器 1(TIMx_CCR1) :

以 CCR1 为例,CCR2、CCR3、CCR4 寄存器结构与功能一致。
-
捕获比较模式寄存器 1(TIMx_CCMR1) :


每个捕获比较模式寄存器可控制 2 个通道,因此每个定时器对应 2 个该类型寄存器。其中 OC1M(OC2M)位为核心配置位,用于设置 PWM 模式 1 或模式 2。
-
捕获/比较使能寄存器(TIMx_CCER) :

CC1E 位(位 0)与 CC1P 位(位 1)为核心配置位,分别控制输出使能与输出极性。
-
自动重装载寄存器(TIMx_ARR) :

该寄存器的库函数配置方法将在后续章节说明。
4. 定时器输出通道引脚
与定时器中断不同,PWM 输出需通过单片机引脚输出物理脉冲信号。以下为定时器 3 的通道引脚配置(支持部分映射或完全映射),其他定时器引脚可参考芯片手册:

5. 定时器 PWM 库函数配置
- 输出比较初始化函数 :
与时基单元初始化不同,PWM 配置需额外初始化输出通道:
cpp
void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
结构体成员定义:
cpp
typedef struct
{
uint16_t TIM_OCMode; // PWM 模式 1 或模式 2
uint16_t TIM_OutputState; // 输出使能/失能
uint16_t TIM_OutputNState; // 互补输出使能/失能(仅高级定时器有效)
uint16_t TIM_Pulse; // 比较值(写入 CCRx)
uint16_t TIM_OCPolarity; // 比较输出极性
uint16_t TIM_OCNPolarity; // 互补输出极性(仅高级定时器有效)
uint16_t TIM_OCIdleState; // 空闲状态输出电平(仅高级定时器有效)
uint16_t TIM_OCNIdleState; // 互补输出空闲状态电平(仅高级定时器有效)
} TIM_OCInitTypeDef;
初始化示例:
cpp
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; // 配置 PWM 模式 2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能比较输出
TIM_OCInitStructure.TIM_Pulse = 100; // 设置比较值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性:高电平有效
TIM_OC2Init(TIM3, &TIM_OCInitStructure); // 初始化 TIM3 通道 2
- 设置比较值函数:
cpp
void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Compare); // X 为通道号(1~4)
- 使能输出比较预装载函数:
cpp
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
- 使能自动重装载预装载寄存器函数:
cpp
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
- PWM 输出配置步骤 :
① 使能定时器 3 与目标 IO 口时钟:
使能定时器 3 时钟:RCC_APB1PeriphClockCmd();
使能 GPIOB 时钟:RCC_APB2PeriphClockCmd();
② 初始化 IO 口为复用推挽输出模式:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init();
③ 配置引脚重映射(以 PB5 作为 TIM3_CH2 输出为例):
使能 AFIO 时钟:RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
配置部分重映射:GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
④ 初始化定时器时基单元(配置 ARR、PSC 等):
TIM_TimeBaseInit();
⑤ 初始化输出比较参数:
TIM_OC2Init();
⑥ 使能输出比较预装载寄存器:
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
⑦ 使能定时器:
TIM_Cmd();
⑧ 动态修改比较值以调节占空比:
TIM_SetCompare2();
6. 实例
通过 STM32 定时器 TIM3 的 PWM 功能输出可变占空比的 PWM 波,驱动 LED 实现亮度渐变(从暗到亮再到暗循环),代码如下:
cpp
// timer.c 源文件
#include "timer.h"
#include "led.h"
#include "usart.h"
// TIM3 PWM 初始化
// arr:自动重装值
// psc:时钟预分频数
void TIM3_PWM_Init(u16 arr, u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能 TIM3 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); // 使能 GPIOB 与 AFIO 时钟
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); // TIM3 部分重映射:TIM3_CH2 -> PB5
// 配置 PB5 为复用推挽输出(TIM3_CH2 PWM 输出)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 选择 PB5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化 GPIOB
// 初始化 TIM3 时基单元
TIM_TimeBaseStructure.TIM_Period = arr; // 设置自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler = psc; // 设置预分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分割因子 = 0
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 初始化时基单元
// 初始化 TIM3 通道 2 PWM 模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; // 配置 PWM 模式 2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能输出
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性:高电平有效
TIM_OC2Init(TIM3, &TIM_OCInitStructure); // 初始化通道 2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); // 使能通道 2 预装载寄存器
TIM_Cmd(TIM3, ENABLE); // 使能 TIM3
}
cpp
// timer.h 头文件
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
void TIM3_PWM_Init(u16 arr, u16 psc);
#endif
cpp
// main.c 源文件
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"
int main(void)
{
u16 led0pwmval = 0;
u8 dir = 1;
delay_init(); // 初始化延时函数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 配置中断分组 2
uart_init(115200); // 初始化串口
LED_Init(); // 初始化 LED 端口
TIM3_PWM_Init(899, 0); // 不分频,PWM 频率 = 72 MHz / 900 = 80 kHz
while(1)
{
delay_ms(10);
if(dir) led0pwmval++;
else led0pwmval--;
if(led0pwmval > 300) dir = 0;
if(led0pwmval == 0) dir = 1;
TIM_SetCompare2(TIM3, led0pwmval);
}
}
总结
- STM32 定时器分为高级、通用、基本三类,其中通用定时器(TIM2-TIM5)为常用类型,支持多模式计数、输入捕获、PWM 输出等功能,本章围绕 STM32 定时器展开,涵盖工作原理、寄存器说明、配置方法,以及定时器中断、PWM 输出等常用功能的实现逻辑。
- 定时器时钟频率由 APB1 预分频系数决定,公式为:APB1 分频系数为 1 时 f TIM = f APB1 f_{\text{TIM}}=f_{\text{APB1}} fTIM=fAPB1,否则 f TIM = 2 × f APB1 f_{\text{TIM}}=2 \times f_{\text{APB1}} fTIM=2×fAPB1。
- 通用定时器基础配置依赖时基单元(ARR、PSC、CNT)与输出比较寄存器(CCRx),定时周期计算公式为 T out = ( arr + 1 ) ( psc + 1 ) f Tclk T_{\text{out}} = \frac{(\text{arr}+1)(\text{psc}+1)}{f_{\text{Tclk}}} Tout=fTclk(arr+1)(psc+1),PWM 信号的频率由 ARR 决定、占空比由 CCRx 决定。
- 定时器中断配置步骤为:时钟使能 → 时基初始化 → 中断配置 → 定时器使能 → 编写中断服务函数。
- 定时器中断与 PWM 输出的实现流程存在差异,PWM 输出需额外配置 GPIO 复用功能、输出比较参数及引脚重映射,且可通过动态修改 CCRx 值调节占空比。
via:
- STM32定时器配置(TIM1、TIM2、TIM3、TIM4、TIM5、TIM8)高级定时器+普通定时器,定时计数模式下总结 - 竹风清 - 博客园
https://www.cnblogs.com/pertor/p/9488813.html - STM32定时器详解:原理、配置与应用实战-CSDN博客
https://blog.csdn.net/qq_44016222/article/details/123507270