用定时器生成 SPWM 的核心逻辑是:以高频三角波为载波,按正弦规律动态更新 PWM 占空比,最终通过低通滤波还原正弦波。以下是面向 STM32 的标准实现方案与代码。
一、核心原理与参数设计
- 载波:高频三角波(推荐 10--20 kHz,远高于基波),由定时器 ARR/PSC 决定。
- 调制:低频正弦波(如 50 Hz),通过查表或实时计算映射为 PWM 的 CCR 值。
- 更新 :在每个载波周期起点更新 CCR,用定时器更新中断 或DMA实现。
- 公式 :
- PWM 频率:fPWM=ftimer_clk/((PSC+1)×(ARR+1))
- 占空比映射:CCR=(1+sin(θ)×ARR)/2(归一化到 0--ARR)
二、硬件与参数选型(以 STM32F103 72 MHz 为例)
| 参数 | 取值 | 说明 |
|---|---|---|
| 定时器 | TIM1(高级定时器) | 支持互补输出与死区,适合电机驱动 |
| 载波频率 | 10 kHz | fPWM=10 kHz |
| PSC | 71 | 72 MHz / (71+1) = 1 MHz 计数时钟 |
| ARR | 99 | 1 MHz / (99+1) = 10 kHz |
| 基波频率 | 50 Hz | 目标输出频率 |
| 采样点数 | 200 | 中断频率 = 50 Hz × 200 = 10 kHz |
三、标准实现步骤(HAL 库)
1. 生成正弦表(离线 / 初始化)
预先计算一周期正弦值并映射到 0--ARR,提升运行效率。
#define SINE_SIZE 200
uint16_t SineTable[SINE_SIZE];
const uint16_t ARR_VAL = 99; // 对应10 kHz载波
void GenerateSineTable(void) {
for(int i=0; i<SINE_SIZE; i++) {
float theta = 2 * 3.14159f * i / SINE_SIZE;
// 归一化到0~ARR_VAL
SineTable[i] = (1 + sinf(theta)) * ARR_VAL / 2;
}
}
2. 定时器 PWM 初始化
配置时基、通道与预装载,确保更新时 CCR 原子生效。
TIM_HandleTypeDef htim1;
void MX_TIM1_Init(void) {
htim1.Instance = TIM1;
htim1.Init.Prescaler = 71;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = ARR_VAL;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&htim1);
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
// 使能预装载
__HAL_TIM_ENABLE_OCxPRELOAD(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}
3. 中断更新 CCR(推荐)
用 TIM_UP 中断按步长遍历正弦表,实现基波输出。
uint16_t index = 0;
// 每100 us进入一次(对应10 kHz中断)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if(htim->Instance == TIM2) { // TIM2用于定时
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, SineTable[index]);
index = (index + 1) % SINE_SIZE;
}
}
4. 更高性能:DMA 传输(无 CPU 开销)
将正弦表直接绑定到 CCR,适合高频场景。
// 初始化后启动DMA
HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t*)SineTable, SINE_SIZE);
四、关键优化与注意事项
-
死区保护:驱动 MOS 管时,高级定时器需配置死区(如 1 µs),防止上下桥直通。
// 配置死区1 µs(计数时钟1 MHz,死区值=1)
__HAL_TIM_SET_DEADTIME(&htim1, 1); -
互补输出:三相逆变时,用 CHx 与 CHxN 输出互补信号。
-
抗混叠:输出端加 LC 低通滤波器,滤除高频载波,还原平滑正弦波。
-
调制度:通过缩放正弦表幅值调整调制度(0--1),避免过调制失真。
五、完整工程流程(CubeMX+HAL)
- CubeMX 配置:TIM1 为 PWM 生成模式,TIM2 为 10 kHz 更新中断;使能 GPIO 复用输出。
- 生成代码,在
main.c中调用GenerateSineTable()。 - 启动 TIM2 中断与 TIM1 PWM,在回调中更新 CCR 或直接启动 DMA。
- 编译下载,用示波器验证 CH1 输出为 SPWM,经 LC 滤波后为正弦波。
六、常见问题与排查
- 波形失真:检查载波频率是否足够高、正弦表点数是否充足、CCR 更新是否及时。
- 无输出 :确认 GPIO 复用映射正确、PWM 通道使能、主输出使能(高级定时器需
TIM_BDTR寄存器)。 - 噪声大:增加滤波电容 / LC 参数,优化 PCB 布线,PWM 走线尽量短且远离干扰源。
七、扩展:三相 SPWM 与 EtherCAT 同步
- 三相:生成三相互差 120° 的正弦表,在 TIM_UP 中断中同时更新 CH1/CH2/CH3。
- EtherCAT 同步:用 SYNC0 信号初始化 PWM 计数器,确保控制周期与通信同步,提升运动控制精度。