3. 定时器与PWM输出:高级定时器TIMER0配置、互补PWM输出、死区时间插入、刹车功能、PWM频率与分辨率计算

做FOC控制,说白了就是跟电流波形较劲。而生成波形的前线部队,就是定时器跟PWM。GD32的TIMER0是个高级定时器,专门干这活的。我刚开始接触GD32时,总觉得定时器配置就是填几个寄存器,后来发现坑不少——死区设小了炸管子,刹车没配好电机飞车。嗯,这一章咱们就把这些硬骨头啃下来。

3.1 高级定时器TIMER0:FOC的“心脏起搏器”

GD32的TIMER0,本质上是一个16位自动重装载计数器。它比普通定时器多了几个关键能力:互补输出、死区插入、刹车输入、编码器接口。在FOC里,我们主要用它来产生6路互补PWM,驱动三相逆变器的6个开关管。

我个人习惯把TIMER0看作一个“波形工厂”:

  • 时基单元:决定PWM的周期(频率)
  • 比较通道:决定PWM的占空比(电压矢量)
  • 互补输出:生成上下桥臂的互补信号
  • 死区模块:防止上下管直通
  • 刹车功能:紧急情况下强制关断

核心配置流程:时钟使能 → 时基配置 → 通道配置(PWM模式) → 互补输出配置 → 死区配置 → 刹车配置 → 使能输出

3.2 互补PWM输出:上下桥臂的“双胞胎”信号

FOC控制三相逆变器,每一相需要两个开关管:上管和下管。这两个管的驱动信号必须互补——上管开的时候下管关,反之亦然。但硬件上不可能做到瞬间切换,所以需要插入死区时间。

GD32的TIMER0支持通道x(CHx)和通道xN(CHxN)互补输出。配置时只需要设置主通道的占空比,互补通道会自动取反并插入死区。

// 配置TIMER0通道0为PWM1模式,输出互补PWM
timer_channel_output_config(TIMER0, TIMER_CH_0, &oc_config);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, duty_cycle);
timer_channel_complementary_output_config(TIMER0, TIMER_CH_0, TIMER_OCxN_ENABLE);

我在项目中遇到过一个问题:互补输出使能后,发现下管波形一直为低。查了半天,原来是忘了配置TIMER_OCxN_ENABLE。嗯,这个坑踩过一次就不会忘了。

3.3 死区时间插入:保护功率管的“安全气囊”

死区时间,就是上下管都关断的那段短暂时间。目的是防止上管还没完全关断,下管就开了——这叫“直通”,轻则发热,重则炸管。

GD32的死区配置通过TIMERx_CAR寄存器实现。死区时间由DTG[7:0]位决定,支持多种分频模式:

DTG[7:0]范围 死区时间计算公式 典型应用场景
0x00 ~ 0x7F DT × tDTS 低速MOS管(死区需求大)
0x80 ~ 0xBF (64 + DTG[5:0]) × 2 × tDTS 中速IGBT
0xC0 ~ 0xDF (32 + DTG[4:0]) × 8 × tDTS 高速MOS管
0xE0 ~ 0xFF (32 + DTG[4:0]) × 16 × tDTS 超高速GaN/SiC器件

举个例子:tDTS = 10ns(TIMER0时钟=100MHz),DTG=0x50,死区时间 = 0x50 × 10ns = 800ns。这个值对于大多数MOS管来说够用了。

我的经验:死区时间不是越大越好。太大会导致波形失真,电流谐波增加,电机噪音变大。我一般从1μs开始试,用示波器看上下管波形,确保死区时间内没有直通,然后逐步减小到安全下限。

3.4 刹车功能:电机的“紧急制动阀”

FOC系统里,刹车功能不是用来停车的,而是用来保命的。当检测到过流、过压、过热等故障时,刹车信号会立即强制PWM输出为安全状态(通常是所有管子关断)。

GD32的TIMER0支持两种刹车源:

  • 外部刹车输入(BRK):通过GPIO引脚输入,响应快
  • 软件刹车:通过寄存器位触发,适合程序自检

配置刹车功能时,需要指定刹车极性(高电平有效还是低电平有效)和刹车后的输出状态:

timer_break_config break_config;
break_config.break_state = TIMER_BREAK_ENABLE;
break_config.break_polarity = TIMER_BREAK_POLARITY_HIGH;  // 高电平触发刹车
break_config.break_output_state = TIMER_BREAK_OUTPUT_DISABLE;  // 刹车后输出关断
timer_break_config(TIMER0, &break_config);

曾经踩过的坑:我曾经把刹车极性配反了,结果刹车引脚一直处于触发状态,PWM死活出不来。查了两天才发现是极性问题。建议大家在调试阶段先用软件刹车验证逻辑,再切到外部刹车。

3.5 PWM频率与分辨率计算:鱼和熊掌的权衡

PWM频率和分辨率是一对矛盾体。频率越高,电流纹波越小,但分辨率会降低;频率越低,分辨率越高,但电流纹波变大,电机噪音也大。

GD32的TIMER0是16位计数器,最大计数值为65535。PWM频率计算公式:

f_PWM = f_TIM / (ARR + 1)

其中:
f_TIM = TIMER0时钟频率(通常为系统时钟)
ARR = 自动重装载寄存器值

分辨率计算公式:

分辨率 = 1 / (ARR + 1) × 100%

例如:ARR = 999,分辨率为0.1%

咱们算个实际例子:系统时钟=100MHz,目标PWM频率=20kHz:

ARR = 100MHz / 20kHz - 1 = 5000 - 1 = 4999
分辨率 = 1 / 5000 = 0.02%

这个分辨率对于FOC控制来说足够了。但如果你想要更高的PWM频率(比如100kHz),ARR就变成999,分辨率降到0.1%。这时候做高精度电流控制就会吃力。

PWM频率 ARR值 分辨率 适用场景
10 kHz 9999 0.01% 大功率电机、低开关损耗
20 kHz 4999 0.02% 通用FOC、人耳听不到噪音
50 kHz 1999 0.05% 高速电机、低纹波需求
100 kHz 999 0.10% 超高速电机、GaN/SiC器件

我的建议:对于大多数FOC应用,20kHz是黄金频率。人耳听不到,分辨率够用,开关损耗也适中。如果你做的是高速主轴电机,可以上50kHz甚至100kHz,但要注意分辨率下降带来的电流纹波问题。

3.6 知识体系总览:TIMER0配置全景图

下面这张图把TIMER0在FOC中的配置逻辑串起来了。你想想看,从时钟进来,到6路PWM出去,中间经历了哪些环节:

GD32 TIMER0 FOC PWM配置流程图 TIMER0 FOC PWM配置全景图 1. 时钟使能 2. 时基配置(ARR/CKDIV) 3. 通道配置(PWM模式) 4. 互补输出使能 5. 死区时间配置 6. 刹车功能配置 7. 使能PWM输出 💡 刹车信号可来自外部引脚 或软件触发,优先级最高 ⚠️ 死区时间需根据功率管 开关特性精确设置

这张图把整个配置流程串起来了。你从时钟开始,一步步走到PWM输出。每个环节都有对应的寄存器配置,缺一不可。

3.7 实战配置清单:照着做就行

最后,我整理了一份配置清单。你写代码时对着这个清单检查,基本不会漏东西:

  1. 时钟:使能TIMER0时钟,配置预分频器
  2. 时基:设置ARR(决定PWM频率),选择计数模式(向上计数)
  3. 通道:配置为PWM1模式,设置占空比初始值
  4. 互补:使能CHxN输出,配置输出极性
  5. 死区:根据功率管参数计算DTG值,写入CAR寄存器
  6. 刹车:配置刹车源、极性、输出状态
  7. 使能:使能TIMER0,使能主输出(TIMER_CEN和TIMER_BREAK)

调试小技巧:先用逻辑分析仪看PWM波形,确认频率、占空比、死区时间都对,再接到功率板上。我曾经跳过这一步,直接上电,结果死区时间设小了,管子瞬间冒烟。嗯,从那以后我再也不敢偷懒了。