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出去,中间经历了哪些环节:
这张图把整个配置流程串起来了。你从时钟开始,一步步走到PWM输出。每个环节都有对应的寄存器配置,缺一不可。
3.7 实战配置清单:照着做就行
最后,我整理了一份配置清单。你写代码时对着这个清单检查,基本不会漏东西:
- 时钟:使能TIMER0时钟,配置预分频器
- 时基:设置ARR(决定PWM频率),选择计数模式(向上计数)
- 通道:配置为PWM1模式,设置占空比初始值
- 互补:使能CHxN输出,配置输出极性
- 死区:根据功率管参数计算DTG值,写入CAR寄存器
- 刹车:配置刹车源、极性、输出状态
- 使能:使能TIMER0,使能主输出(TIMER_CEN和TIMER_BREAK)
调试小技巧:先用逻辑分析仪看PWM波形,确认频率、占空比、死区时间都对,再接到功率板上。我曾经跳过这一步,直接上电,结果死区时间设小了,管子瞬间冒烟。嗯,从那以后我再也不敢偷懒了。