| 类型 | 实例 | 总线 | 分辨率 | 主要特性 |
|---|---|---|---|---|
| 高级 | TIM1 | APB2 (72MHz) | 16位 | 互补PWM、刹车、死区、编码器接口、重复计数器 |
| 通用 | TIM2 / TIM3 / TIM4 | APB1 (36MHz) | 16位 | PWM输入/输出、编码器、中断/DMA触发 |
| 基本 | TIM6 / TIM7 | APB1 (36MHz) | 16位 | 仅定时中断(无外部引脚) |
注意:TIM2 在 F103xC/D/E 及 F107 是 32 位计数器。C8T6 为 16 位。
graph LR
subgraph TIMER_CLOCK
CLK_SRC["时钟源"] --> PSC["PSC<br/>预分频器<br/>16位"]
end
subgraph TIMER_CORE
PSC --> CNT["CNT<br/>计数器<br/>16位"]
CNT --> ARR["ARR<br/>自动重装<br/>寄存器<br/>16位"]
CNT --> RCR["RCR<br/>重复计数器<br/>(仅高级TIM)"]
end
ARR --> UPDATE["更新事件/中断<br/>UEV"]
RCR --> UPDATE
UPDATE --> UPDATE_EVENT["更新事件"]
UPDATE_EVENT --> SR["SR 寄存器<br/>UIF 标志位"]
| 寄存器 | 位宽 | 作用 |
|---|---|---|
| PSC (Prescaler) | 16bit | 对时钟分频,timer_clk = CLK / (PSC+1) |
| CNT (Counter) | 16bit | 计数当前值,可向上/向下/中央对齐 |
| ARR (Auto-Reload) | 16bit | 自动重装值,CNT 达到 ARR 后溢出发送更新事件 |
| RCR (Repetition) | 16bit | 高级定时器专用,每 (RCR+1) 个溢出才产生更新事件 |
定时频率: f_timer = TIM_CLK / (PSC + 1) / (ARR + 1)
定时时间: T = (PSC + 1) × (ARR + 1) / TIM_CLK
示例 (TIM2, 36MHz):
PSC = 36 - 1 = 35 → f_cnt = 36MHz / 36 = 1MHz → 1μs
ARR = 1000 - 1 → T = 1000 × 1μs = 1ms
graph TD
subgraph CLOCK_SOURCES
INT_CLK["内部时钟<br/>(CK_INT)"] --> TIM_CLK["TIM_CLK"]
ETR_MODE2["外部模式2<br/>(ETR 引脚)"] --> TIM_CLK
subgraph EXTERNAL_MODE1
TI1F_ED["TI1F_ED<br/>(双边沿)"] --> TRGI
TI1FP1["TI1FP1"] --> TRGI
TI2FP2["TI2FP2"] --> TRGI
ETRF["ETRF<br/>(外部触发)"] --> TRGI
end
TRGI["TRGI"] --> TIM_CLK
end
TIM_CLK --> PSC_INPUT["→ PSC"]
void TIM_InternalClockConfig(TIM_TypeDef* TIMx); // 默认已使能,可不用调用
使用 RCC 提供的时钟:TIM1→PCLK2(72MHz),TIM2/3/4→PCLK1(36MHz)。
通过外部引脚(如 TIM2_ETR = PA0)提供时钟源。
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx,
uint16_t TIM_ExtTRGPrescaler,
uint16_t TIM_ExtTRGPolarity,
uint16_t ExtTRGFilter);
通过 CH1/CH2 引脚输入时钟,可用于编码器模式。
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
| TIM_TimeBaseInitTypeDef 成员 | 取值 | 说明 |
|---|---|---|
TIM_Prescaler |
0~65535 | 预分频值 |
TIM_CounterMode |
TIM_CounterMode_Up / Down / CenterAligned1/2/3 |
计数模式 |
TIM_Period |
0~65535 | ARR 自动重装值 |
TIM_ClockDivision |
TIM_CKD_DIV1 / DIV2 / DIV4 |
时钟分频(滤波采样) |
TIM_RepetitionCounter |
0~255 | 重复计数值(仅 TIM1/TIM8) |
| 函数 | 原型 | 说明 |
|---|---|---|
TIM_Cmd |
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState) |
开启/关闭定时器 |
TIM_ITConfig |
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState) |
中断使能 |
TIM_SetCounter |
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter) |
设置 CNT 值 |
TIM_GetCounter |
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx) |
读取 CNT 值 |
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare);
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx,
uint16_t TIM_EncoderMode,
uint16_t TIM_IC1Polarity,
uint16_t TIM_IC2Polarity);
#include "stm32f10x.h"
#include "Delay.h"
#include "OLED.h"
void Timer_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 1. 开启 TIM2 时钟 (APB1)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 2. 时基配置: PCLK1=36MHz, PSC=36-1=36分频→1MHz, ARR=1000-1→1kHz(1ms)
TIM_TimeBaseStructure.TIM_Prescaler = 36 - 1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 3. 清除更新标志位 (防止初始化后立刻进中断)
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
// 4. 使能更新中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
// 5. NVIC 配置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 6. 启动定时器
TIM_Cmd(TIM2, ENABLE);
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
// 翻转 PC13 板载 LED
GPIO_WriteBit(GPIOC, GPIO_Pin_13,
(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13)));
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC, GPIO_Pin_13); // 初始灭
Timer_Init();
while (1)
{
// 主循环空闲 (LED 在中断中翻转)
}
}
对射式红外传感器接 PA0,每次遮挡计数器 +1。
#include "stm32f10x.h"
#include "OLED.h"
void Timer_ETR_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 1. GPIO 配置 (PA0 作为 TIM2_ETR)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 外部信号输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 2. 定时器时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 3. 时基: 不分频, ARR=65535 (最大)
TIM_TimeBaseStructure.TIM_Prescaler = 0; // 不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 65535; // 最大范围
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 4. 外部时钟模式2: ETR 引脚输入
TIM_ETRClockMode2Config(TIM2,
TIM_ExtTRGPSC_OFF, // 无预分频
TIM_ExtTRGPolarity_NonInverted, // 不反相
0x0F); // 滤波 15 个采样
// 5. 启动
TIM_Cmd(TIM2, ENABLE);
}
uint16_t Timer_GetCounter(void)
{
return TIM_GetCounter(TIM2);
}
int main(void)
{
OLED_Init();
Timer_ETR_Init();
uint16_t lastCount = 0;
OLED_ShowString(1, 1, "ETR Count:");
while (1)
{
uint16_t now = Timer_GetCounter();
if (now != lastCount)
{
lastCount = now;
OLED_ShowNum(2, 1, now, 5);
}
}
}
#include "stm32f10x.h"
#include "Delay.h"
void PWM_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// 1. GPIO: PA6 = TIM3_CH1 复用推挽
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 2. TIM3 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// 3. 时基: 36MHz / 36 = 1MHz, ARR=1000 → PWM 频率=1kHz
TIM_TimeBaseStructure.TIM_Prescaler = 36 - 1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// 4. OC1 配置: PWM1 模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比 0
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_Cmd(TIM3, ENABLE);
}
void PWM_SetCompare1(uint16_t compare)
{
TIM_SetCompare1(TIM3, compare);
}
int main(void)
{
PWM_Init();
while (1)
{
// 渐亮
for (uint16_t i = 0; i < 1000; i++)
{
PWM_SetCompare1(i);
Delay_ms(1);
}
// 渐灭
for (uint16_t i = 1000; i > 0; i--)
{
PWM_SetCompare1(i);
Delay_ms(1);
}
}
}
#include "stm32f10x.h"
#include "OLED.h"
void IC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = 36 - 1; // 1μs
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
// IC1: 上升沿捕获, 不分频, 无滤波
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM4, &TIM_ICInitStructure);
TIM_Cmd(TIM4, ENABLE);
}
int main(void)
{
OLED_Init();
IC_Init();
OLED_ShowString(1, 1, "Freq (Hz):");
while (1)
{
// 基础频率测量:等待捕获完成,读 CCR1
// 实际应用中应使用更新中断 + 捕获中断计算频率
uint16_t cap1 = TIM_GetCapture1(TIM4);
OLED_ShowNum(2, 1, cap1, 5);
Delay_ms(100);
}
}
#include "stm32f10x.h"
#include "OLED.h"
void Encoder_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = 0; // 不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 65535; // 最大
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// 编码器模式: TI1+TI2, 双边缘
TIM_EncoderInterfaceConfig(TIM3,
TIM_EncoderMode_TI12,
TIM_ICPolarity_Rising,
TIM_ICPolarity_Rising);
TIM_Cmd(TIM3, ENABLE);
}
int16_t Encoder_Get(void)
{
return (int16_t)TIM_GetCounter(TIM3);
}
int main(void)
{
OLED_Init();
Encoder_Init();
OLED_ShowString(1, 1, "Encoder:");
while (1)
{
int16_t val = Encoder_Get();
OLED_ShowSignedNum(2, 1, val, 6);
Delay_ms(50);
}
}
1. RCC_APB1PeriphClockCmd(TIMx, ENABLE)
2. GPIO_Init() — 根据功能配复用推挽(AF_PP)或浮空输入(IN_FLOATING)
3. TIM_TimeBaseInit() — PSC, ARR, CounterMode
4. 可选: TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE) — 中断使能
5. 可选: NVIC_Init() — 中断优先级
6. 可选: TIM_OCxInit() — 输出比较
7. 可选: TIM_ICInit() — 输入捕获
8. 可选: TIM_EncoderInterfaceConfig() — 编码器
9. TIM_Cmd(TIMx, ENABLE) — 启动定时器
| 定时器 | 中断通道 | IRQn |
|---|---|---|
| TIM1 | TIM1_BRK_IRQn / TIM1_UP_IRQn / TIM1_TRG_COM_IRQn / TIM1_CC_IRQn | 24/25/26/27 |
| TIM2 | TIM2_IRQn | 28 |
| TIM3 | TIM3_IRQn | 29 |
| TIM4 | TIM4_IRQn | 30 |
| TIM5 | TIM5_IRQn | 50 |
| TIM6 | TIM6_IRQn | 54 |
| TIM7 | TIM7_IRQn | 55 |
TIM_Prescaler 写后立即对时钟分频生效,但 PSC 缓冲到 UE 才更新;ARR 预加载可通过 TIM_ARRPreloadConfig 控制SystemInit 默认 APB1/2,所以 TIM2/3/4 时钟 = 36MHz × 2 = 72MHz?不 — 标准库 SystemInit 中 APB1 预分频=2(除2),则 PCLK1 = 36MHz。定时器时钟 = PCLK1 × 2 = 72MHz(当 APB1 预分频≠1 时)TIM_ClearITPendingBitTIM_OC1Init 会重设 PSC/ARR — 如果在 OC Init 之前已经设置了 PSC/ARR,OC Init 内部会重新调用 TimeBaseInit,需在 OC Init 之后重新配置 PSC/ARR 或先设好。正确做法是 TimeBaseInit → OCInit 顺序TIM_OCPolarity_High:CCR ≥ CNT 时输出高;TIM_OCPolarity_Low 反之TIM_ICSelection_DirectTI 选择对应通道的输入引脚,TIM_ICSelection_IndirectTI 选择交叉输入(CH1 用 CH2 的引脚)GPIO_Mode_AF_PP,否则 PWM 信号不会从引脚输出