2. FOC开环电压控制
任务目标
本案例使用SVPWM(空间矢量脉宽调制)生成开环电压矢量,驱动三相无刷电机以设定的电角度速度旋转。通过逐步改变电角度并施加对应的电压矢量,验证电机能够跟随指令产生基本运动。该案例不涉及电流采样或闭环反馈,仅验证FOC驱动链路中最基础的电压输出环节。
所需硬件与依赖
- STM32F405/F407开发板(或其他支持高级定时器的MCU)
- 三相逆变桥(如DRV8301、L6234等)及对应驱动电路
- 无刷直流电机(带霍尔或增量编码器,本案例仅需电机能转动即可)
- 直流母线电源(12V~24V)
- HAL库或标准外设库(本代码使用HAL库)
核心实现
以下代码实现SVPWM开环控制:主循环中按固定步长递增电角度,计算三相占空比并更新定时器比较寄存器。SVPWM采用七段式注入零矢量,调制比固定为0.6以保证线性调制区。
// svpwm_openloop.c
#include "main.h"
#include "svpwm_openloop.h"
// 电角度步长(弧度/控制周期)
#define ANGLE_STEP 0.05f
// 调制比(0~1.15)
#define MODULATION_INDEX 0.6f
// 母线电压(V)
#define VBUS 12.0f
static float angle = 0.0f;
// SVPWM扇区判断与占空比计算
void SVPWM_Calc(float alpha, float Ualpha, float Ubeta, uint32_t *dutyA, uint32_t *dutyB, uint32_t *dutyC) {
float U1 = Ubeta;
float U2 = -0.5f * Ubeta + 0.866f * Ualpha;
float U3 = -0.5f * Ubeta - 0.866f * Ualpha;
uint8_t sector = 0;
if (U1 > 0) sector |= 1;
if (U2 > 0) sector |= 2;
if (U3 > 0) sector |= 4;
float Ta, Tb, Tc;
float Ts = 1.0f / 20000.0f; // 20kHz PWM频率
// 根据扇区计算各相导通时间
switch (sector) {
case 1: Ta = U1; Tb = U2; Tc = U3; break;
case 2: Ta = U2; Tb = U1; Tc = U3; break;
case 3: Ta = U2; Tb = U3; Tc = U1; break;
case 4: Ta = U3; Tb = U2; Tc = U1; break;
case 5: Ta = U3; Tb = U1; Tc = U2; break;
case 6: Ta = U1; Tb = U3; Tc = U2; break;
default: Ta = 0; Tb = 0; Tc = 0; break;
}
// 七段式零矢量注入
float Tmin = 0.0f;
float Tmax = Ts;
float Tavg = (Ta + Tb + Tc) / 3.0f;
Ta -= Tavg;
Tb -= Tavg;
Tc -= Tavg;
// 转换为定时器计数值(ARR=1000)
uint32_t arr = 1000;
*dutyA = (uint32_t)((Ta / Ts) * arr);
*dutyB = (uint32_t)((Tb / Ts) * arr);
*dutyC = (uint32_t)((Tc / Ts) * arr);
}
// 开环控制主函数(在定时器中断或主循环中周期调用)
void OpenLoop_Step(void) {
// 递增电角度
angle += ANGLE_STEP;
if (angle > 6.2832f) angle -= 6.2832f;
// 由电角度生成alpha-beta轴电压
float Ualpha = MODULATION_INDEX * VBUS * 0.5f * cosf(angle);
float Ubeta = MODULATION_INDEX * VBUS * 0.5f * sinf(angle);
// 计算三相占空比
uint32_t dutyA, dutyB, dutyC;
SVPWM_Calc(angle, Ualpha, Ubeta, &dutyA, &dutyB, &dutyC);
// 更新定时器比较寄存器(以TIM1为例)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, dutyA);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, dutyB);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, dutyC);
}
// 初始化PWM输出
void OpenLoop_Init(TIM_HandleTypeDef *htim) {
HAL_TIM_PWM_Start(htim, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(htim, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(htim, TIM_CHANNEL_3);
}
运行与验证
- 将上述代码加入工程,确保TIM1的PWM频率配置为20kHz(ARR=1000,预分频根据时钟计算)。
- 在main函数中调用
OpenLoop_Init(&htim1),然后在主循环或定时器中断中周期调用OpenLoop_Step()。 - 给电机供电,观察电机是否持续旋转。
通过条件:电机以恒定方向连续旋转,无卡顿或剧烈振动。若电机不转,检查母线电压是否足够、PWM频率是否在10kHz~30kHz范围内、调制比是否过大导致过调制。若电机反转,交换任意两相电机线即可。
预期输出:电角度以0.05rad/步递增,对应机械转速取决于电机极对数。例如4极对电机,控制周期1ms时,电转速为0.05rad/ms=50rad/s,机械转速约为12.5rad/s(约119rpm)。该数值由代码逻辑直接推出,实际转速会因负载和母线电压略有偏差。