TIM - 高级定时器
更新于 2026年8月13日
本篇总结
使用 TIM1,输出带死区与刹车保护的互补 PWM。
本示例演示 W55MH32L 高级控制定时器 TIM1 的三项核心能力:互补 PWM 输出、死区时间插入、刹车输入保护。TIM1 在 CH1(PA8)与 CH1N(PB13)上输出极性相反、带死区延时的 PWM 波形,PB12 配置为刹车输入,触发后硬件立即关断所有输出——这是电机驱动、开关电源等场景中防止上下桥臂直通的标准做法。
全程由硬件完成输出与保护,CPU 只需初始化后空转。
TIM 简介
W55MH32 的高级控制定时器 TIM1/TIM8 在通用定时器基础上增加了三项专为电机/电源控制设计的能力:可编程死区互补输出(OCx + OCxN 双路带延时反相输出)、重复计数器 RCR(每 N 次溢出才产生一次更新事件)、刹车输入 BKIN(硬件立刻关断所有输出)。时基核心公式:PWM 周期 = (ARR+1) × (PSC+1) / TIMxCLK,死区时间由 BDTR 寄存器的 DTG 位决定。
| 定时器 | 类型 | 互补输出 | 死区发生器 | 刹车输入 BKIN | 重复计数器 |
|---|---|---|---|---|---|
| TIM1、TIM8 | 高级控制 | 有(CHx/CHxN) | 有(10 位) | 有 | 有(8 位) |
| TIM2、3、4、5 | 通用 | 无 | 无 | 无 | 无 |
| TIM6、TIM7 | 基本 | 无 | 无 | 无 | 无 |
本例程使用 TIM1 通道 1:主输出 PA8 (CH1) 与互补输出 PB13 (CH1N) 组成一对带死区的互补 PWM,刹车输入 PB12 (BKIN) 触发后硬件封锁输出。
前置工具准备
开始本例程前,请确认以下工具已安装:
- WIZ UartTool V1.0:串口日志观察工具:点击下载
- 示波器或逻辑分析仪:观察 PA8/PB13 互补 PWM 波形与死区延时(必需,串口看不到波形)
硬件连接
本例程使用 TIM1 的 CH1 / CH1N / BKIN 三个引脚输出互补 PWM 并监测刹车输入。USART1(PA9/PA10)用于打印状态日志。示波器探头分别接 PA8 与 PB13 即可观察带死区的互补波形;将 PB12 短接到 3V3 可触发刹车。
| 引脚 | 功能 | 方向 | 模式 |
|---|---|---|---|
| PA8 | TIM1_CH1(主输出) | MCU → 示波器 | 复用推挽输出 (AF_PP) |
| PB13 | TIM1_CH1N(互补输出) | MCU → 示波器 | 复用推挽输出 (AF_PP) |
| PB12 | TIM1_BKIN(刹车输入) | 外部 → MCU | 上拉输入 (IPU) |
| PA9 | USART1_TX | 开发板 → PC | 复用推挽输出 (AF_PP) |
| PA10 | USART1_RX | PC → 开发板 | 浮空输入 (IN_FLOATING) |
工程结构
工程位于 SDK 内 1.SDK\ModuleDemo\TIM\TIM_Advanced\,核心文件如下:
TIM_Advanced/
├── USER/
│ ├── main.c ← GPIO/TIM1/BDTR 初始化 + 主循环 + printf 重定向
│ ├── w55mh32_conf.h ← 外设头文件集中包含
│ ├── w55mh32_it.c/h ← 中断服务函数
│ ├── system_w55mh32.c/h← 系统初始化(时钟配置)
│ └── startup_w55mh32.s ← 启动文件
└── SYSTEM/
└── delay/
└── delay.c/h ← SysTick 延时函数
步骤1:GPIO 初始化
文件:USER/main.c | 函数:TIM_Adv_GPIO_Configuration() — 配置 PA8(CH1)、PB13(CH1N) 为复用推挽输出,PB12(BKIN) 为上拉输入。
void TIM_Adv_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 开启 GPIOA / GPIOB 时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
/* PA8: TIM1_CH1 → 复用推挽输出 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* PB13: TIM1_CH1N → 复用推挽输出 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* PB12: TIM1_BKIN → 上拉输入(拉高触发刹车) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}互补输出两路引脚都必须配置为复用推挽输出(AF_PP),否则 CH1N 不会有波形。BKIN 配置为上拉输入,外部拉高即触发刹车。
如果你想自定义
- 换用其他通道对 → CH2/CH2N 对应 PA9/PB14,CH3/CH3N 对应 PA10/PB15。注意 PA9/PA10 与 USART1 冲突,本例选 CH1 避开串口
- 改刹车极性 → 将 BKIN 改为下拉输入(
GPIO_Mode_IPD),并在 BDTR 配置中改TIM_BreakPolarity_Low
步骤2:TIM1 时基与互补 PWM 配置
函数:TIM_Adv_Configuration() — 配置 TIM1 时基(1kHz PWM)与 CH1 互补输出比较(PWM1 模式,占空比 25%)。
void TIM_Adv_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* 开启 TIM1 时钟(TIM1 挂在 APB2 上) */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* 时基:PSC=71 → CK_CNT=1MHz;ARR=999 → PWM 周期 1ms (1kHz) */
TIM_TimeBaseStructure.TIM_Period = 999; // ARR
TIM_TimeBaseStructure.TIM_Prescaler = 71; // PSC,72MHz/72=1MHz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 每次溢出都产生更新事件
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* CH1 互补输出比较:PWM1 模式,占空比 25%(CCR=250) */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // CNT<CCR 时输出有效电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 主输出 OCx 使能
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 互补输出 OCxN 使能
TIM_OCInitStructure.TIM_Pulse = 250; // CCR,占空比 = 250/1000 = 25%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 主输出高电平有效
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; // 互补输出高电平有效
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; // 空闲时主输出低
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; // 空闲时互补输出低
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
/* 使能 CCR1 预装载,运行期改 CCR 会在下个更新事件生效 */
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM1, ENABLE);
}
PWM 频率 = 72MHz / (71+1) / (999+1) = 1kHz,占空比 = 250 / 1000 = 25%。TIM_OutputNState_Enable 是互补输出关键,漏写则 CH1N 引脚无波形。TIM_RepetitionCounter 是高级定时器独有,本例设 0 表示每次溢出都更新。
如果你想自定义
- 改 PWM 频率 → 修改
TIM_Prescaler(PSC)和TIM_Period(ARR)。如 20kHz:PSC=0、ARR=3599 - 改占空比 → 修改
TIM_Pulse(CCR)。运行期可调用TIM_SetCompare1(TIM1, x)实时改占空比 - 改为中央对齐 PWM →
TIM_CounterMode_CenterAligned1,频率减半,适合电机控制
步骤3:BDTR 死区与刹车配置
函数:TIM_Adv_BDTR_Configuration() — 配置死区时间、刹车极性、自动恢复,并使能主输出 MOE 启动定时器。这是高级定时器独有步骤。
void TIM_Adv_BDTR_Configuration(void)
{
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
/* 死区时间 DTG=0xFF:在 tDTS=72MHz 下约 1.75us(最大档位) */
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; // 运行模式下空闲时输出由 OCx 决定
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; // 空闲模式下输出由 OISx 决定
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; // 不锁定,可随时改配置
TIM_BDTRInitStructure.TIM_DeadTime = 0xFF; // 死区发生器,最大死区
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable; // 使能刹车输入
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; // BKIN 高电平有效(拉高触发刹车)
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; // 刹车解除后自动恢复输出
TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
/* 使能主输出 MOE(高级定时器必须)+ 启动计数器 */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_Cmd(TIM1, ENABLE);
}
死区时间 DTG 是 10 位编码值,0xFF 对应 约 1.75μs(tDTS = 1/72MHz),示波器可清晰观察到 CH1 下降沿与 CH1N 上升沿之间的"死区"无脉冲区间。TIM_CtrlPWMOutputs(TIM1, ENABLE) 是高级定时器最容易漏掉的一步——它置位 BDTR.MOE,否则无论 OC 怎么配,引脚都没有输出。
如果你想自定义
- 改死区时间 → DTG 取值与死区关系:
0x00无死区;0x80约 1.0μs;0xFF约 1.75μs(72MHz 下) - 刹车后手动恢复而非自动 →
TIM_AutomaticOutput_Disable,故障解除后需软件调用TIM_CtrlPWMOutputs(TIM1, ENABLE)重新使能
步骤4:主函数逻辑
函数:main() — 初始化延时与 UART → 依次调用 GPIO / 时基+OC / BDTR 配置 → 进入循环周期性打印刹车状态。
int main(void)
{
delay_init();
UART_Configuration(115200);
printf("\nTIM1 Advanced Complementary PWM Test.\n");
printf("CH1=PA8, CH1N=PB13, BKIN=PB12\n");
/* 依次初始化:GPIO → 时基+OC → BDTR+启动 */
TIM_Adv_GPIO_Configuration();
TIM_Adv_Configuration();
TIM_Adv_BDTR_Configuration();
while (1)
{
/* 读取 BDTR.MOE 主输出使能位:1=正常输出,0=刹车触发 */
if (TIM1->BDTR & TIM_BDTR_MOE)
printf("PWM Running (MOE=1)\n");
else
printf("Break Active (MOE=0) -- PB12 pulled high!\n");
delay_ms(500);
}
}主循环每 500ms 读取一次 BDTR.MOE 位:正常输出时为 1,PB12 被拉高触发刹车后硬件自动清 0,解除后(自动恢复模式下)又置回 1。PWM 波形由硬件持续输出,CPU 不参与。
步骤5:printf 重定向
重写 fputc() 将 printf 输出重定向到 USART1,并自动在 \n 前补 \r 确保串口工具正确换行。
int SER_PutChar(int ch)
{
while (!USART_GetFlagStatus(USART_TEST, USART_FLAG_TC));
USART_SendData(USART_TEST, (uint8_t)ch);
return ch;
}
int fputc(int c, FILE *f)
{
if (c == '\n')
SER_PutChar('\r'); // 补回车,确保串口工具正确换行
return (SER_PutChar(c));
}编译与下载
Keil MDK 中打开 TIM_Advanced.uvprojx,F7 编译,确认 0 Error(s)。连接 DEBUG USB 口到 PC,F8 下载。下载成功后按 RESET 键启动新固件。
运行验证
打开 WIZ UartTool V1.0 ,选择开发板对应 COM 口,波特率 115200 / 8N1,打开串口。同时用示波器双通道探头分别接 PA8 与 PB13 。按 RESET 启动后,预期串口持续打印 "PWM Running (MOE=1)",示波器上看到 1kHz、25% 占空比的互补 PWM,两路上升/下降沿之间有约 1.75μs 死区。
TIM1 Advanced Complementary PWM Test.
CH1=PA8, CH1N=PB13, BKIN=PB12
PWM Running (MOE=1)
PWM Running (MOE=1)
Break Active (MOE=0) -- PB12 pulled high! ← 此时将 PB12 接 3V3
Break Active (MOE=0) -- PB12 pulled high!
PWM Running (MOE=1) ← 断开 PB12 后自动恢复
PWM Running (MOE=1)
将 PB12 短接到 3V3 (高电平有效)→ 串口立即打印 "Break Active",示波器上 PA8/PB13 同时变低无输出;断开 PB12 让其回到上拉默认电平后的下个更新事件,PWM 自动恢复。
常见问题
Q: PA8 完全没有 PWM 波形输出
最常见原因是漏掉 TIM_CtrlPWMOutputs(TIM1, ENABLE)。高级定时器必须置位 BDTR.MOE 主输出使能位才会输出,这是与通用定时器最大的区别。另外确认 TIM_Cmd(TIM1, ENABLE) 也已调用。
Q: PA8 有波形但 PB13(CH1N)一直是低电平
三个排查点:① TIM_OutputNState 是否设为 TIM_OutputNState_Enable;② PB13 的 GPIO 是否配置为复用推挽输出(AF_PP);③ GPIOB 时钟是否开启(RCC_APB2Periph_GPIOB)。
Q: 示波器上观察不到死区延时
死区时间通常只有几百纳秒到几微秒,需用示波器时基调到 1μs/div 以下并展开边沿。本例 DTG=0xFF 在 72MHz 下约 1.75μs,若设为 0x00 则无死区,CH1 与 CH1N 同时翻转。死区计算公式较复杂,详见参考手册 BDTR 寄存器 DTG 字段说明。
Q: PB12 触发刹车后 PWM 再也恢复不了
检查 TIM_AutomaticOutput 是否设为 TIM_AutomaticOutput_Enable。若设为 Disable,则刹车解除后 MOE 不会自动置位,需软件调用 TIM_CtrlPWMOutputs(TIM1, ENABLE) 手动恢复。另外 BKIN 极性若配反(实际电平与 TIM_BreakPolarity 不符),会一直处于刹车状态。
Q: 换用 TIM8 后无 PWM 输出
TIM8 与 TIM1 寄存器结构相同但引脚映射不同:TIM8_CH1 在 PC6、CH1N 在 PA7、BKIN 在 PA6。需同步修改 GPIO 初始化中的引脚和端口,并将 RCC_APB2Periph_TIM1 改为 RCC_APB2Periph_TIM8,所有 TIM1 替换为 TIM8。
总结
本文基于 W55MH32L 的 TIM1 实现了高级定时器的互补 PWM + 死区 + 刹车三件套:
- GPIO:PA8(CH1)、PB13(CH1N) 复用推挽,PB12(BKIN) 上拉输入
- 时基 + 输出比较:PSC=71、ARR=999 → 1kHz PWM;CH1 PWM1 模式 25% 占空比,
TIM_OutputNState_Enable使能互补输出 - BDTR:DTG=0xFF 死区约 1.75μs,BKIN 高电平有效,
TIM_AutomaticOutput_Enable故障解除自动恢复 - 关键调用:
TIM_CtrlPWMOutputs(TIM1, ENABLE)置位 MOE,是高级定时器输出必经一步