2. 开环电压控制
任务目标
本案例实现无刷直流电机(BLDC)的开环电压控制,包含两种驱动方式:六步换相(方波驱动)与正弦波驱动(SPWM)。通过STM32定时器输出PWM,驱动三相逆变桥,使电机旋转,并观察相电流波形差异。
硬件与依赖
- STM32F103(72MHz主频)或兼容芯片
- DRV8301或类似三相栅极驱动器 + 6个MOSFET逆变桥
- 无刷电机(带霍尔传感器或不带均可,本案例不使用传感器反馈)
- 电流采样:低侧采样电阻 + 运放放大至ADC引脚(可选,用于观察波形)
- 开发环境:STM32CubeIDE 或 Keil MDK
核心原理
六步换相:每60°电角度切换一次导通组合,每次只有两相导通(一相高边+一相低边),第三相关断。导通顺序为AB→AC→BC→BA→CA→CB(或反向)。
正弦波驱动:三相分别施加相位差120°的正弦PWM占空比,实现连续旋转磁场。本案例使用查表法生成正弦波,载波频率20kHz。
关键完整代码
// main.c 核心实现(省略时钟、GPIO初始化)
#include "stm32f1xx_hal.h"
// 定时器句柄(TIM1用于PWM输出,TIM2用于定时中断)
extern TIM_HandleTypeDef htim1;
extern TIM_HandleTypeDef htim2;
// 六步换相导通表(低边有效,高边互补PWM)
// 顺序:AB, AC, BC, BA, CA, CB(对应电机正转)
const uint8_t step_table[6] = {0b000001, 0b000100, 0b000110, 0b001000, 0b001001, 0b000010};
// 位定义:bit0=AH, bit1=AL, bit2=BH, bit3=BL, bit4=CH, bit5=CL
// 正弦波查找表(256点,幅值0~1000,对应PWM占空比0~100%)
const uint16_t sin_table[256] = { /* 预生成数据,见下方生成代码 */ };
volatile uint8_t step_index = 0;
volatile uint16_t pwm_duty = 500; // 初始占空比50%
volatile uint8_t mode = 0; // 0=六步,1=正弦
// 生成正弦表(仅用于初始化,实际运行时查表)
void generate_sin_table(void) {
for (int i = 0; i < 256; i++) {
sin_table[i] = (uint16_t)(500 + 500 * sin(2 * 3.14159 * i / 256));
}
}
// 设置三相PWM占空比(正弦模式)
void set_sin_pwm(uint16_t duty_a, uint16_t duty_b, uint16_t duty_c) {
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty_a); // AH
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, duty_b); // BH
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, duty_c); // CH
// 低边互补输出由TIM1高级定时器自动生成(需配置刹车和死区)
}
// 设置六步换相(方波模式)
void set_six_step(uint8_t step) {
uint8_t pattern = step_table[step];
// 高边PWM输出,低边按需导通
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, (pattern & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET); // AH
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, (pattern & 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET); // AL
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, (pattern & 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET); // BH
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, (pattern & 0x08) ? GPIO_PIN_SET : GPIO_PIN_RESET); // BL
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, (pattern & 0x10) ? GPIO_PIN_SET : GPIO_PIN_RESET); // CH
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, (pattern & 0x20) ? GPIO_PIN_SET : GPIO_PIN_RESET); // CL
}
// 定时器2中断:每1ms调用一次,控制换相频率
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim == &htim2) {
if (mode == 0) {
// 六步换相:每1ms换一步,转速约1000rpm(6极对)
step_index = (step_index + 1) % 6;
set_six_step(step_index);
} else {
// 正弦模式:每1ms步进正弦表
static uint16_t phase = 0;
phase += 2; // 步进速度可调
uint16_t idx = phase % 256;
uint16_t duty_a = sin_table[idx];
uint16_t duty_b = sin_table[(idx + 85) % 256]; // 120°相位差
uint16_t duty_c = sin_table[(idx + 171) % 256]; // 240°相位差
set_sin_pwm(duty_a, duty_b, duty_c);
}
}
}
// 主函数
int main(void) {
HAL_Init();
// ... 系统时钟、GPIO、TIM初始化(略) ...
// 启动PWM输出(20kHz)
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
// 启动定时器中断(1ms)
HAL_TIM_Base_Start_IT(&htim2);
// 初始状态:六步模式,第一步
set_six_step(0);
while (1) {
// 主循环可处理按键切换模式、调速等
// 例如:按键切换 mode 值
}
}
运行与验证
- 编译烧录:使用STM32CubeIDE编译工程,通过ST-Link烧录至开发板。
- 连接电机:将电机三相线(U/V/W)连接至逆变桥输出A/B/C。
- 供电:先给控制板上电(3.3V),再给功率级上电(12V~24V,根据电机额定电压)。
- 观察运行:电机应平稳旋转。六步模式下会有轻微转矩脉动;正弦模式下运行更平滑。
- 电流波形验证:使用示波器探头连接低侧采样电阻两端(或电流探头),观察相电流波形:
- 六步模式:相电流为梯形波,换相点有明显跳变;
- 正弦模式:相电流接近正弦波,无明显跳变。
- 调速验证:修改定时器中断中的步进速度(六步的换相间隔或正弦的phase增量),电机转速应相应变化。
通过判定标准
- 电机在两种模式下均能持续旋转,无卡顿或停转;
- 六步模式下相电流呈现六步换相特征(梯形波),正弦模式下呈现正弦特征;
- 改变步进速度参数后,电机转速随之变化,方向可通过调整换相顺序反转。
常见问题
- 电机不转:检查PWM频率是否在20kHz附近(过高导致MOSFET开关损耗大,过低产生噪音);确认死区时间设置(建议1~2μs);检查MOSFET栅极驱动供电。
- 电流过大:初始占空比从30%开始逐步增加,避免启动电流过大;确认电机相电阻是否过小。
- 正弦模式抖动:正弦表精度不足或载波比过低,建议使用256点表并确保PWM频率≥10kHz。