定时器类型
| 类型 |
编号 |
总线 |
功能 |
| 高级定时器 |
TIM1、TIM8 |
APB2 |
拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能 |
| 通用定时器 |
TIM2、TIM3、TIM4、TIM5 |
APB1 |
拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能 |
| 基本定时器 |
TIM6、TIM7 |
APB1 |
拥有定时中断、主模式触发DAC的功能 |
graph LR
%% 定义样式类
classDef gpio fill:#e1f5fe,stroke:#4fc3f7,stroke-width:2px,color:#0277bd,rx:8,ry:8;
classDef rcc fill:#ffebee,stroke:#ef9a9a,stroke-width:2px,color:#c62828,rx:8,ry:8;
classDef source fill:#e8f5e9,stroke:#a5d6a7,stroke-width:2px,color:#2e7d32,rx:8,ry:8;
classDef mux fill:#fff9c4,stroke:#fff59d,stroke-width:2px,color:#f57f17,rx:8,ry:8;
classDef core fill:#ffe0b2,stroke:#ffb74d,stroke-width:2px,color:#e65100,rx:8,ry:8;
classDef nvic fill:#e0f2f1,stroke:#80cbc4,stroke-width:2px,color:#00695c,rx:8,ry:8;
classDef ext fill:#fff3e0,stroke:#ffcc80,stroke-width:2px,color:#ef6c00,rx:8,ry:8;
subgraph ClockSources [时钟源]
direction TB
RCC[RCC
内部时钟]:::rcc
ETR[ETR
外部时钟]:::source
ITRx[ITRx
其他定时器]:::ext
TIx[TIx
捕获通道]:::ext
end
GPIO_ETR[GPIO]:::gpio --> ETR
GPIO_TIx[GPIO]:::gpio --> TIx
MUX_Sub[多路复用]:::mux
ITRx --> MUX_Sub
TIx --> MUX_Sub
MUX[内部时钟模式
外部时钟模式2
外部时钟模式1
编码器模式]:::mux
RCC --> MUX
ETR --> MUX
MUX_Sub --> MUX
subgraph TimeBase [时基单元]
direction LR
PSC[PSC
预分频器]:::core
CNT[CNT
计数器]:::core
ARR[ARR
自动重装器]:::core
PSC --> CNT
ARR <--> CNT
end
MUX --> PSC
RunCtrl[运行控制]:::core --> TimeBase
IRQCtrl[中断
输出控制]:::nvic
NVIC[NVIC]:::nvic
CNT --> IRQCtrl
IRQCtrl --> NVIC
%% 整体样式设置
style ClockSources fill:#f8fbff,stroke:#d6e4f0,stroke-width:2px,stroke-dasharray: 5 5
style TimeBase fill:#fce4ec,stroke:#f48fb1,stroke-width:2px
掌握函数
| 函数 |
说明 |
| TIM_InternalClockConfig |
配置时钟源 |
| TIM_TimeBaseInitTypeDef |
定义结构体变量 |
| TIM_TimeBaseInit |
配置TIM2的时基单元 |
| TIM_ClearFlag |
中断输出配置 |
| TIM_ITConfig |
开启的更新中断 |
| NVIC_PriorityGroupConfig |
NVIC中断分组 |
| TIM_Cmd |
TIM使能 |
| TIM_GetITStatus |
判断是否是触发中断 |
配置步骤
- 开启时钟
- 配置时钟源
- 时基单元初始化
- 中断输出配置
- NVIC中断分组
- NVIC配置
- TIM使能
代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| void Timer_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_InternalClockConfig(TIM2); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1; TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); TIM_ClearFlag(TIM2, TIM_FLAG_Update); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM2, ENABLE); }
|
1 2 3 4 5 6 7 8 9 10 11
| void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) { Num ++; TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } }
|
TIM 输出比较
| 模式 |
描述 |
| 冻结 |
CNT=CCR时,REF保持为原状态 |
| 匹配时置有效电平 |
CNT=CCR时,REF置有效电平 |
| 匹配时置无效电平 |
CNT=CCR时,REF置无效电平 |
| 匹配时电平翻转 |
CNT=CCR时,REF电平翻转 |
| 强制为无效电平 |
CNT与CCR无效,REF强制为无效电平 |
| 强制为有效电平 |
CNT与CCR无效,REF强制为有效电平 |
| PWM模式1 |
向上计数:CNT<CCR时,REF置有效电平,CNT≥CCR时,REF置无效电平 向下计数:CNT>CCR时,REF置无效电平,CNT≤CCR时,REF置有效电平 |
| PWM模式2 |
向上计数:CNT<CCR时,REF置无效电平,CNT≥CCR时,REF置有效电平 向下计数:CNT>CCR时,REF置有效电平,CNT≤CCR时,REF置无效电平 |
graph LR
%% 定义样式类 (去除了不受支持的 rx 和 ry 属性)
classDef timeCore fill:#ffe0b2,stroke:#ffb74d,stroke-width:2px,color:#e65100;
classDef runCtrl fill:#fff3e0,stroke:#ffcc80,stroke-width:2px,color:#ef6c00;
classDef compUnit fill:#f3e5f5,stroke:#ce93d8,stroke-width:2px,color:#6a1b9a;
classDef gpio fill:#e1f5fe,stroke:#4fc3f7,stroke-width:2px,color:#0277bd;
%% 左侧输入信号 (给个占位字符避免空括号报错)
Input((" ")):::timeCore
Input --> PSC
%% 运行控制
RunCtrl[运行控制]:::runCtrl
%% 时基单元
subgraph TimeBase [时基单元]
direction LR
PSC[PSC
预分频器]:::timeCore
CNT[CNT
计数器]:::timeCore
ARR[ARR
自动重装器]:::timeCore
PSC --> CNT
ARR <--> CNT
end
RunCtrl --> PSC
%% 输出比较单元
subgraph OutputCompare ["输出比较单元 x4"]
direction LR
CCR[CCR
捕获/比较器]:::compUnit
%% 关键修复:使用 HTML 实体编码代替 < 和 ≥
Logic["CNT < CCR时,REF置有效电平
CNT ≥ CCR时,REF置无效电平"]:::compUnit
Polarity[极性选择
输出使能]:::compUnit
CCR --> Logic
Logic -->|REF| Polarity
end
CNT --> CCR
GPIO[GPIO]:::gpio
Polarity --> GPIO
%% 整体样式
style TimeBase fill:#f8fbff,stroke:#d6e4f0,stroke-width:2px,stroke-dasharray: 5 5
style OutputCompare fill:#f8fbff,stroke:#d6e4f0,stroke-width:2px,stroke-dasharray: 5 5
style Input display:none
- PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
- PWM占空比: Duty = CCR / (ARR + 1)
- PWM分辨率: Reso = 1 / (ARR + 1)
PWM配置步骤
- 开启时钟
- GPIO重映射
- GPIO初始化
- 配置时钟源
- 输出比较初始化
- TIM使能
掌握函数
| 函数 |
说明 |
| GPIO_PinRemapConfig |
GPIO重映射 注:必须先开启AFIO的时钟 |
| TIM_OCInitTypeDef |
定义结构体变量 |
| TIM_OCStructInit |
结构体初始化 |
| TIM_OC1Init |
配置输出比较通道 |
| TIM_SetCompare1/2/3/4 |
设置CCR1/2/3/4的值 |
代码演示
1 2 3 4
| void PWM_SetCompare1(uint16_t Compare) { TIM_SetCompare1(TIM2, Compare); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ... TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; TIM_OC1Init(TIM2, &TIM_OCInitStructure); ...
|
graph LR
%% 定义样式类 (淡蓝、浅紫、浅黄、浅橙,去除了绿色)
classDef gpio fill:#e1f5fe,stroke:#4fc3f7,stroke-width:2px,color:#0277bd,rx:8,ry:8;
classDef purple fill:#f3e5f5,stroke:#ce93d8,stroke-width:2px,color:#6a1b9a,rx:8,ry:8;
classDef yellow fill:#fff9c4,stroke:#fff59d,stroke-width:2px,color:#f57f17,rx:8,ry:8;
classDef orange fill:#ffe0b2,stroke:#ffb74d,stroke-width:2px,color:#e65100,rx:8,ry:8;
%% 左侧 GPIO
GPIO[GPIO]:::gpio
%% 输入捕获单元 (淡蓝色背景)
subgraph InputCapture [输入捕获单元1]
direction LR
F[滤波器]:::purple
Edge[边沿检测
极性选择]:::purple
Mux[/多路复用器/]:::yellow
Div[分频器]:::purple
CCR1[CCR1
捕获/比较器]:::purple
end
%% 中间上方控制 (淡黄、浅橙)
TrigSrc[/触发源选择/]:::yellow
Reset[从模式
Reset]:::orange
%% 时基单元 (淡蓝色背景)
subgraph TimeBase [时基单元]
direction LR
PSC[PSC
预分频器]:::orange
CNT[CNT
计数器]:::orange
ARR[ARR
自动重装器]:::orange
end
%% 连接关系
GPIO --> F
F --> Edge
%% 信号分流
Edge -- "TI1FP1" --> Mux
Edge --> TrigSrc
TrigSrc --> Reset
Reset ==> PSC
PSC --> CNT
ARR <--> CNT
Mux --> Div
Div --> CCR1
%% 计数器向下连接到捕获/比较器 (加粗箭头)
CNT ==> CCR1
%% 整体样式设置 (淡蓝色虚线背景框)
style InputCapture fill:#f8fbff,stroke:#d6e4f0,stroke-width:2px,stroke-dasharray: 5 5
style TimeBase fill:#f8fbff,stroke:#d6e4f0,stroke-width:2px,stroke-dasharray: 5 5
掌握函数
| 函数 |
说明 |
| TIM_PrescalerConfig |
设置PSC的值 |
| TIM_ICInitTypeDef |
定义结构体变量 |
| TIM_PWMIConfig |
配置的输入捕获通道 |
| TIM_SelectInputTrigger |
触发源选择 |
| TIM_SelectSlaveMode |
从模式选择复位 |
| TIM_GetCapture1/2/3/4 |
读取CCR1/2/3/4中的值 |
| TIM_EncoderInterfaceConfig |
编码器接口配置 |
代码演示
1 2 3 4 5 6 7 8 9 10
| ... TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); ...
|
1 2 3 4 5 6 7 8 9 10 11
| ... void PWM_SetCompare1(uint16_t Compare) { TIM_SetCompare1(TIM2, Compare); }
void PWM_SetPrescaler(uint16_t Prescaler) { TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate); } ...
|
1 2 3 4
| uint32_t IC_GetFreq(void) { return 1000000 / (TIM_GetCapture1(TIM3) + 1); }
|