一、通用定时器
1.通用定时器描述

一、计数模式:16 位向上 / 向下 / 中央对齐
原理:
- 向上计数 :计数器从
0
递增到ARR
(自动重装值),溢出时触发更新事件(中断 / DMA)。- 向下计数 :计数器从
ARR
递减到0
,下溢时触发更新事件。- 中央对齐(向上 / 向下) :计数器先向上到
ARR
,再向下到0
,循环往复(对称计数,适合对称 PWM)。例子:
向上计数 → 定时中断 :
配置
TIM3
为向上计数,ARR=999
,PSC=71
(假设系统时钟 72MHz,分频后计数器频率为72MHz/(71+1)=1MHz
,计数周期 1μs)。每
(999+1)×1μs=1ms
触发一次更新中断,用于 1ms 定时任务(如 PID 控制周期、传感器采样)。中央对齐 → 对称 PWM :
三相电机驱动需对称 PWM (减少谐波),配置
TIM1
(高级定时器,但通用定时器也支持中央对齐)为中央对齐,ARR=999
,CCR=500
(占空比 50%)。计数器先从 0→999(向上),到 500 时翻转电平;再从 999→0(向下),到 500 时再次翻转,形成对称方波,降低电机电磁噪声。
二、16 位可编程预分频器(PSC)
原理:
预分频器
PSC
决定分频系数 (1~65536
,公式:计数器频率 = TIMx_CLK / (PSC + 1)
),用于调整计数速度。例子:
- 低速定时需求 :
若需计数器每 10ms 递增 1 次(频率 100Hz),系统时钟 72MHz,则:
PSC + 1 = 72MHz / 100Hz = 720000
→ 但PSC
是 16 位(最大 65535),无法直接实现。
→ 拆分方案 :先用PSC=719
(分频 100 倍,72MHz→720KHz),再设ARR=999
(周期(999+1)×(1/720KHz)≈1.388ms
),通过多次计数累加实现 10ms 定时(如累计 7 次更新事件)。三、4 个独立通道:输入捕获 / 输出比较 / PWM / 单脉冲
1. 输入捕获 → 测量脉冲 / 频率
原理:捕获外部信号的边沿(上升 / 下降沿),记录计数器值,计算时间差。
例子:测量红外信号频率(如遥控器波形):
- 配置
TIM4_CH1
为输入捕获,上升沿触发。- 第一次捕获:记录计数器值
CCR1
(信号上升沿时刻)。- 第二次捕获:记录
CCR2
(下一个上升沿时刻)。- 频率 =
1 / [(CCR2 - CCR1) × 计数周期]
。
若计数周期 1μs,CCR2-CCR1=1000
→ 频率 1KHz。2. 输出比较 → 精准电平翻转
原理:计数器与
CCR
(比较值)匹配时,触发电平翻转 / 中断。例子:LED 精准闪烁(500ms 周期):
- 配置
TIM2_CH2
为输出比较,ARR=49999
(计数频率 1KHz,周期 1ms),CCR=25000
。- 当计数器到 25000 时,电平翻转(250ms 时翻转),实现 500ms 周期闪烁(250ms 亮,250ms 灭)。
3. PWM 生成 → 电机调速 / LED 调光
原理:通过
ARR
定周期,CCR
定占空比,生成方波。例子:直流电机调速(边沿对齐 PWM):
- 配置
TIM5_CH3
为 PWM 输出,ARR=999
(周期 1ms),CCR=300
(占空比 30%)。- 电机功率与占空比成正比,30% 占空比对应低速运行;若调至 80%,电机加速。
4. 单脉冲模式 → 触发单次动作
原理:外部触发(如 GPIO 上升沿)后,输出一个固定宽度的脉冲 (由
CCR
决定)。例子:触发 ADC 单次采样:
- 配置
TIM1_CH4
为单脉冲模式,CCR=100
(脉冲宽度 100× 计数周期)。- 当外部触发信号到来,输出 10μs 脉冲,启动 ADC 转换(确保采样窗口精准)。
四、同步电路:多定时器协同
原理:通过 TRGO(触发输出)→ TRGI(触发输入) 连接,实现多定时器同步启动 / 停止。
例子:双轴运动控制同步触发:
TIM3
为主定时器,TRGO 输出连接TIM2
的 TRGI 输入。- 当
TIM3
启动时,TIM2
同步启动,保证两个轴的运动时间对齐(如机械臂两关节同时动作)。五、中断 / DMA 触发:事件驱动
定时器可在以下事件触发中断或 DMA:
- 更新事件:计数器溢出 / 下溢(如定时采集传感器)。
- 触发事件:定时器启动 / 停止(如记录电机启动时间戳)。
- 输入捕获:捕获到外部脉冲(如测量高频信号)。
- 输出比较:比较匹配(如定时关闭加热管)。
例子:10ms 周期采集温度传感器:
- 配置
TIM2
更新中断,每 10ms 触发一次。- 在中断服务函数中,读取温度传感器数据,保证采样周期稳定。
六、编码器 / 霍尔传感器支持
1. 编码器接口 → 电机测速 / 方向检测
原理:解码正交编码器的 AB 相脉冲,计数器自动根据边沿增减(上升沿 + 下降沿都计数,精度翻倍)。
例子:电机转速测量:
- 编码器每转输出 1000 个脉冲,配置
TIM2
为编码器模式。- 每秒读取计数器值
CNT
,转速 =CNT / 1000
转 / 秒(如 1 秒内 CNT=10000→10 转 / 秒)。2. 霍尔传感器 → 电机换相
原理:解码电机的 霍尔信号(3 路),获取转子位置,触发换相逻辑。
例子:无刷电机换相:
- 霍尔信号(如 011、101 等状态)输入定时器,当检测到状态变化时,切换功率管导通相,实现无刷电机换向。
七、硬件约束:16 位 ARR 和 PSC(Cortex-M3 内核)
ARR
(自动重装值)和PSC
(预分频器)都是16 位寄存器 ,最大取值65535
。- 若需 超长周期(如 10 秒),需结合软件计数(如累计 1000 次 10ms 更新事件),或使用 32 位定时器(如 TIM2、TIM5 在 STM32F1 中是 32 位计数器,突破 ARR 的 16 位限制,但 PSC 仍为 16 位)。
2. 通用定时器框图分析


一、模块作用拆解
1. CNT 计数器
- 是定时器的 "心跳",实时递增 / 递减计数 (由定时器时钟驱动,受
PSC
分频控制)。- 比如配置为向上计数,
CNT
会从0
一直数到ARR
(自动重装值),再回到0
循环。2. 捕获 / 比较寄存器(以通道 1 为例)
- 存一个目标数值 (比如
75-1=74
),用来和CNT
的实时值做比较。- 它是 "判定条件" 的核心:
CNT
实时值是否满足条件,全看和这个寄存器的数值关系。3. OC1REF(输出参考信号)
- 比较的中间结果 :当
CNT
满足条件(如CNT < 捕获/比较寄存器值
),OC1REF
输出高电平;不满足则输出低电平。- 注意:这是内部逻辑信号,还没到实际引脚!
4. 输出控制(Output Control)
- 决定最终引脚输出(
TIMx_CH1
)的实际电平 ,会结合CCER
寄存器的极性配置(高 / 低电平有效)。- 比如:若配置 "高电平有效",则
OC1REF
高电平时,引脚输出高电平;若配置 "低电平有效",则OC1REF
高电平时,引脚输出低电平(翻转一次)。二、结合 PWM 例子详细推导
假设需求:生成 占空比 7.5% 的 PWM 信号,参数:
ARR = 1000 - 1 = 999
(计数器范围0~999
,共 1000 个计数点 )捕获/比较寄存器 = 75
(目标比较值 )步骤 1:计数器循环计数
CNT
从0
开始,以定时器时钟频率 向上计数,直到999
,然后回到0
重新开始。
- 假设定时器时钟是
1MHz
(周期1μs
),则CNT
每1μs
加 1,数到999
需要1000μs
(1ms),即 PWM 周期是1ms
。步骤 2:比较逻辑 → 生成 OC1REF
CNT
实时值与捕获/比较寄存器值(75)
比较:
- 当
CNT < 75
时(共 75 个计数点:0~74
):OC1REF = 高电平
- 当
CNT >= 75
时(共 925 个计数点:75~999
):OC1REF = 低电平
步骤 3:输出控制 → 引脚实际电平
假设配置 高电平有效 (
CCER
寄存器的CC1P=0
):
OC1REF
高电平时,引脚TIMx_CH1
输出高电平OC1REF
低电平时,引脚TIMx_CH1
输出低电平最终引脚波形:
- 高电平持续
75μs
(0~74
共 75 个计数点,每个点1μs
)- 低电平持续
925μs
(75~999
共 925 个计数点 )步骤 4:占空比计算
占空比 =
高电平时间 / PWM 周期
=75μs / 1000μs = 7.5%

一、信号流程:外部信号如何进入定时器?
外部信号(比如传感器脉冲、编码器信号)从
TIMx_CH1
引脚输入,经过以下模块处理:
外部信号 → 异或门 → 输入滤波器和边沿检测器 → 预分频器 → 定时器内部
二、核心模块作用拆解
1. 异或门(XOR)
- 作用:信号极性控制,决定是否翻转输入信号的电平。
- 应用:比如外部信号是低电平有效,但你想转成高电平触发,就可以通过异或门翻转(配合 TRC 信号实现)。
2. 输入滤波器和边沿检测器
- 滤波器:滤除高频噪声 ,避免毛刺触发误判。
- 原理:通过配置采样频率和采样次数,只有持续稳定的电平变化才会被识别。
- 例子:外部按键抖动(几十 ms 高频抖动),滤波器可以只识别稳定的电平跳变。
- 边沿检测器:检测上升沿 / 下降沿 ,决定触发事件的条件。
- 可配置为:仅上升沿触发、仅下降沿触发、上升沿 + 下降沿触发。
3. 预分频器(Prescaler)
- 作用:分频控制,决定 "几个外部脉冲才触发一次定时器事件"。
- 例子:
- 预分频器设为
3
,则每 4 个外部脉冲(0~3 计数)才会让定时器内部计数 1 次。- 常用于 "降低信号频率,或只记录特定间隔的脉冲"。
4. TI1、TI1FP1、TI1FP2
TI1
:原始输入信号(未滤波)。TI1FP1
:滤波后信号(经过滤波器和边沿检测的干净信号)。TI1FP2
:反向滤波后信号(TI1FP1 的电平翻转版,用于正交解码)。5. TRC(Trigger Reference Clock)
- 作用:触发参考信号,可用于异或门的极性控制,或作为同步触发源。
- 应用:比如让定时器在外部信号上升沿时同步启动计数。
**3.**通用定时器基本功能
操作流程和基础定时器 TIM6 和 TIM7 一致
cpp
#include "tim3.h"
// TIM3初始化函数
// psc: 预分频器值
// arr: 自动重装载值
void TIM3_Init(u16 psc, u16 arr)
{
// 1. 使能TIM3时钟
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // 置位TIM3时钟使能位
// 2. 关闭定时器,避免配置冲突
TIM3->CR1 &= ~(0x01); // 清除CEN位,关闭计数器
// 3. 配置预分频器和自动重装载寄存器
TIM3->PSC = psc - 1; // 预分频器配置(值 = 实际分频系数 - 1)
TIM3->ARR = arr - 1; // 自动重装载值配置(值 = 实际周期数 - 1)
// 4. 配置计数模式(向上计数)
TIM3->CR1 &= ~(0x1 << 4); // 清除DIR位,设置为向上计数
// 5. 使能更新中断
TIM3->DIER |= 0x01; // 置位UIE位,使能更新中断
// 6. 开启定时器
TIM3->CR1 |= 0x01; // 置位CEN位,使能计数器
// 7. 配置NVIC中断
NVIC_EnableIRQ(TIM3_IRQn); // 使能TIM3中断
NVIC_SetPriority(TIM3_IRQn, 5); // 设置中断优先级为5
}
// 中断计数器
u16 TIM3_IT_Count = 0;
// TIM3中断服务函数
void TIM3_IRQHandler(void)
{
// 检查是否是更新中断
if (TIM3->SR & 0x01)
{
// 清除中断标志位
TIM3->SR &= ~0x01;
// 这里可以添加中断处理逻辑
TIM3_IT_Count++; // 计数器加1
// 示例:每1000次中断做一次处理(需根据实际定时周期计算)
if (TIM3_IT_Count >= 1000)
{
TIM3_IT_Count = 0;
// 执行定时任务...
}
}
}
1. TIM3_Init 初始化函数核心配置
时钟使能 :通过
RCC_APB1ENR_TIM3EN
位使能 TIM3 定时器时钟,TIM3 属于 APB1 总线外设定时器关闭:配置前先关闭计数器(清除 CEN 位),确保寄存器配置可靠
分频与周期配置:
PSC
:预分频器,值为实际分频系数减 1(因为计数器从 0 开始)ARR
:自动重装载值,值为实际周期计数减 1- 定时周期计算公式:
周期 = (PSC + 1) * (ARR + 1) / 定时器时钟频率
计数模式:配置为向上计数模式(默认也是向上计数,这里显式配置使代码更清晰)
中断配置:
- 使能更新中断(UIE 位),当计数器达到 ARR 值时产生中断
- 通过 NVIC 配置中断使能和优先级
2. 中断服务函数
- 中断标志检查 :通过
SR
寄存器的 UIF 位判断是否发生更新中断- 标志清除:必须手动清除中断标志位,否则会持续触发中断
- 中断处理 :通过
TIM3_IT_Count
计数器记录中断次数,可根据需要添加定时任务逻辑
4. PWM实现呼吸灯
3.4.1 PWM 概述
- PWM 核心参数
- 频率:1 秒钟,PWM 输出波形的次数。需依据实际设备应用场景分析确定,不同场景对频率需求不同,如电机控制、LED 调光等场景,合适频率可保障功能稳定与效果。
- 占空比:一个 PWM 周期内,高电平持续时间与整个 PWM 周期时间的比值,决定了有效电平在周期内的占比,影响输出能量、亮度等。
- 实现依赖
需要利用 TIM2 ~ 5 通用定时器完成 PWM 输出,这些定时器具备输出比较、PWM 模式配置等功能,可通过设置预分频器(PSC)、自动重装值(ARR)、比较值(CCR)等寄存器,生成符合参数要求的 PWM 波形 。

3.4.2 AFIO****控制定时器对应输出通道重映射
主要针对不同的 TIM 定时对外输出通道引脚映射关系。
3.4.3 TIM3CH2****寄存器分析
TIM3 CCMR 输入输出模式控制寄存器
3.4.5****核心代码实现
tim3.h:
cpp
#include "stm32f10x.h"
// TIM3_CH2(PB5)初始化函数,支持PWM输出
// psc: 预分频器值
// arr: 自动重装载值
void TIM3_CH2_PB5_PWM(u16 psc, u16 arr)
{
/* 1. 时钟使能 */
RCC->APB2ENR |= (RCC_APB2ENR_AFIOEN | RCC_APB2ENR_IOPBEN); // 使能AFIO和GPIOB时钟
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // 使能TIM3时钟
/* 2. 关闭定时器,确保配置可靠 */
TIM3->CR1 = 0;
/* 3. 配置PB5为复用推挽输出 */
GPIOB->CRL &= ~(0x0F << 20); // 清除PB5原有配置
GPIOB->CRL |= (0x0B << 20); // 1011:复用推挽输出,50MHz
/* 4. TIM3_CH2部分重映射到PB5 */
AFIO->MAPR &= ~(0x03 << 10); // 清除原有映射配置
AFIO->MAPR |= (0x02 << 10); // 部分重映射:TIM3_CH2->PB5
/* 5. 定时器基础配置 */
TIM3->CR1 |= (0x01 << 7); // ARR开启缓冲
TIM3->CR1 &= ~(0x03 << 5); // 边缘对齐模式
TIM3->CR1 &= ~(0x01 << 4); // 向上计数模式
TIM3->PSC = psc - 1; // 预分频配置
TIM3->ARR = arr - 1; // 自动重装载值配置
TIM3->CNT = 0; // 计数器清零
/* 6. 配置PWM模式 */
TIM3->CCMR1 &= ~(0x03 << 8); // 配置为输出模式(CC2S=00)
TIM3->CCMR1 |= (0x01 << 10); // 快速使能(OC2FE=1)
TIM3->CCMR1 |= (0x01 << 11); // CCR2预装载使能(OC2PE=1)
TIM3->CCMR1 |= (0x06 << 12); // PWM模式1(OC2M=110):CNT<CCR时输出有效电平
/* 7. 配置输出极性(可根据硬件需求切换高低电平有效) */
TIM3->CCER &= ~(0x03 << 4); // 清除CC2相关配置
TIM3->CCER |= (0x01 << 4); // 使能CH2输出(CC2E=1)
// TIM3->CCER |= (0x01 << 5); // 如需低电平有效,取消此注释
/* 8. 开启定时器 */
TIM3->CR1 |= 0x01;
}
// 设置CCR2值,控制占空比
void TIM3_CH2_PB5_SetCCR(u16 ccr)
{
TIM3->CCR2 = ccr;
}
main.c:
cpp
#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "tim3.h"
int main(void)
{
// 初始化外设
Led_Init();
Key_Init();
Delay_Init();
/*
* 初始化TIM3_CH2:72分频,ARR=1000
* 定时器时钟频率 = 72MHz / 72 = 1MHz
* PWM周期 = (1000) * 1us = 1ms(频率1kHz)
*/
TIM3_CH2_PB5_PWM(72, 1000);
u16 duty_value = 0; // 占空比数值(0~1000)
u8 flag = 0; // 呼吸灯方向标志
while (1)
{
// 设置占空比,控制LED亮度
TIM3_CH2_PB5_SetCCR(duty_value);
// 呼吸灯逻辑:逐渐变亮→逐渐变暗循环
if (flag)
{
duty_value -= 10;
if (duty_value <= 0)
flag = 0; // 达到最暗,准备变亮
}
else
{
duty_value += 10;
if (duty_value >= 1000)
flag = 1; // 达到最亮,准备变暗
}
Delay_Ms(10); // 延时控制呼吸速度
}
}
重点:GPIO 引脚兼具普通 IO 与复用功能,普通 IO 模式下由代码操作 ODR 等寄存器直接控制引脚输出高低电平(信号从 MCU 到外部设备),而复用模式(如复用推挽、复用开漏)则将引脚控制权移交 MCU 内部集成的外设(如 TIM3 定时器、USART 串口等),此时引脚电平由外设(如定时器生成的 PWM 波形、串口的通信信号)决定,信号流向始终为 MCU 内部外设→引脚→外部设备(如 LED、电机、传感器等),且同一时刻引脚仅能服务于普通 IO 或复用外设中的一种功能,但可通过重新配置 GPIO 模式实现功能切换;定时器等复用外设本质是 MCU 内部硬件模块,需配合引脚作为 "内外桥梁",才能将内部生成的定时、PWM 等信号传递到外部,实现对外部设备的精准控制(如定时中断、PWM 调光调速)
0voice · GitHub