1. 项目概述
最近在开发一款基于国产SWM190 M0核MCU的风机控制系统,实现了完整的FOC(磁场定向控制)算法方案。这个项目最大的特点是在低成本M0核上实现了高性能的无传感器电机控制,包含了龙伯格观测器、SVPWM调制、顺逆风启动等核心功能,代码完全开源可移植。
这套方案已经在多个风机产品上实现量产,实测性能稳定可靠。相比传统方波控制方案,FOC控制的风机运行更安静、效率更高,特别是在低速工况下优势明显。下面我就详细分享这个项目的技术实现细节和开发经验。
2. 硬件平台选型
2.1 MCU选择:SWM190特性分析
SWM190是一款国产32位M0核MCU,主频48MHz,具有以下关键特性非常适合电机控制:
- 6路独立PWM输出(支持互补和死区控制)
- 3个独立的12位ADC模块(采样速率1Msps)
- 硬件除法器和三角函数加速器
- 64KB Flash + 8KB SRAM
- 工作电压2.5-5.5V
选择这款MCU主要基于几个考虑:
- 成本优势:相比进口M0核芯片价格低30%以上
- 外设匹配:PWM和ADC资源完全满足FOC控制需求
- 国产化要求:项目有明确的国产芯片使用要求
2.2 功率驱动电路设计
风机驱动采用典型的三相逆变电路:
code复制母线电压:12V DC
功率管:IPD90N04S4(40V/90A MOS)
电流采样:3电阻采样(50mΩ/1%精度)
栅极驱动:EG2131(集成死区控制)
关键设计要点:
- 栅极驱动电阻选用10Ω,减小开关噪声
- 每个MOS管并联100nF电容吸收尖峰电压
- 电流采样运放采用LMV358,带宽2MHz
- 母线电容使用2个100uF电解+1个1uF陶瓷电容
3. 软件架构设计
3.1 系统整体架构
采用分层模块化设计,主要分为四层:
-
硬件抽象层(HAL)
- PWM驱动
- ADC采样
- GPIO控制
- 定时器管理
-
电机控制层(MCL)
- FOC核心算法
- 龙伯格观测器
- SVPWM调制
- PID控制器
-
应用层(APP)
- 状态机管理
- 故障处理
- 用户接口
-
驱动层(DRV)
- 蜂鸣器驱动
- 红外接收
- 线控器接口
3.2 关键数据结构
定义了几个核心数据结构来管理电机状态:
c复制typedef struct {
int16_t Id; // d轴电流
int16_t Iq; // q轴电流
int16_t Vd; // d轴电压
int16_t Vq; // q轴电压
int16_t Angle; // 转子角度(0-3599)
int16_t Speed; // 转速(RPM)
} FOC_State_t;
typedef struct {
uint8_t RunStatus; // 运行状态
uint8_t FaultCode; // 故障代码
uint16_t RefSpeed; // 目标转速
uint8_t Direction; // 旋转方向
} Motor_Status_t;
4. FOC核心算法实现
4.1 坐标变换实现
4.1.1 Clarke变换
将三相电流(Ia,Ib,Ic)转换为两相静止坐标系(α,β):
c复制void Clarke_Transform(int16_t Ia, int16_t Ib, int16_t Ic, int16_t *Ialpha, int16_t *Ibeta)
{
*Ialpha = Ia;
*Ibeta = (Ia + 2*Ib) * 0.57735; // 1/sqrt(3)
}
注意:实际代码中使用定点数运算,这里为便于理解展示浮点形式。
4.1.2 Park变换
将静止坐标系(α,β)转换到旋转坐标系(d,q):
c复制void Park_Transform(int16_t Ialpha, int16_t Ibeta, int16_t Angle, int16_t *Id, int16_t *Iq)
{
float rad = Angle * 0.001745; // 角度转弧度
*Id = Ialpha * cos(rad) + Ibeta * sin(rad);
*Iq = -Ialpha * sin(rad) + Ibeta * cos(rad);
}
4.2 电流环设计
采用PI控制器实现电流环调节:
c复制typedef struct {
int16_t Kp; // 比例系数
int16_t Ki; // 积分系数
int32_t SumError; // 误差积分
int16_t OutMax; // 输出限幅
} PI_Controller_t;
int16_t PI_Update(PI_Controller_t *pi, int16_t Error)
{
pi->SumError += Error;
// 抗积分饱和处理
if(pi->SumError > (pi->OutMax*1000/pi->Ki))
pi->SumError = pi->OutMax*1000/pi->Ki;
else if(pi->SumError < -(pi->OutMax*1000/pi->Ki))
pi->SumError = -(pi->OutMax*1000/pi->Ki);
int32_t output = (pi->Kp * Error + pi->Ki * pi->SumError/1000);
// 输出限幅
if(output > pi->OutMax) output = pi->OutMax;
if(output < -pi->OutMax) output = -pi->OutMax;
return (int16_t)output;
}
4.3 SVPWM实现
采用7段式SVPWM调制,关键实现步骤:
- 扇区判断
- 基本矢量作用时间计算
- PWM占空比生成
c复制void SVPWM_Generate(int16_t Valpha, int16_t Vbeta, uint16_t *T1, uint16_t *T2, uint8_t *Sector)
{
// 扇区判断
uint8_t sector = 0;
if(Vbeta >= 0) {
if(Valpha >= 0) {
if(Valpha * 1732 < Vbeta * 1000) sector = 1; // 1732=sqrt(3)*1000
else sector = 0;
} else {
if(-Valpha * 1732 < Vbeta * 1000) sector = 2;
else sector = 3;
}
} else {
// 类似处理其他扇区...
}
// 计算作用时间
uint32_t T0, T1, T2;
switch(sector) {
case 0: {
T1 = (int32_t)(Valpha * PWM_PERIOD) / VDC;
T2 = (int32_t)(Vbeta * 1155 * PWM_PERIOD) / VDC; // 1155=1000/sqrt(3)
break;
}
// 其他扇区计算...
}
// 7段式PWM占空比生成
uint16_t Ta, Tb, Tc;
switch(sector) {
case 0: {
Ta = (PWM_PERIOD - T1 - T2)/2;
Tb = Ta + T1;
Tc = Tb + T2;
break;
}
// 其他扇区...
}
*T1 = Ta; *T2 = Tb; *Sector = sector;
}
5. 龙伯格观测器实现
5.1 观测器数学模型
龙伯格观测器基于电机状态方程:
code复制dIsα/dt = (Vsα - Rs*Isα + ω*Lq*Isβ - Eα)/Ld
dIsβ/dt = (Vsβ - Rs*Isβ - ω*Ld*Isα - Eβ)/Lq
dEα/dt = -ω*Eβ + K1*(Isα_est - Isα)
dEβ/dt = ω*Eα + K1*(Isβ_est - Isβ)
其中:
- Isα,Isβ:定子电流
- Vsα,Vsβ:定子电压
- Eα,Eβ:反电动势
- ω:电角速度
5.2 代码实现
c复制typedef struct {
int16_t Is_alpha; // α轴电流
int16_t Is_beta; // β轴电流
int16_t Es_alpha; // α轴反电动势
int16_t Es_beta; // β轴反电动势
int16_t Speed; // 估算转速
int16_t Angle; // 估算角度
int16_t K1; // 观测器增益1
int16_t K2; // 观测器增益2
} Luenberger_Observer_t;
void Observer_Update(Luenberger_Observer_t *obs,
int16_t Vs_alpha, int16_t Vs_beta,
int16_t Is_alpha_meas, int16_t Is_beta_meas)
{
// 电流估算
int32_t dIs_alpha = (Vs_alpha - RS*obs->Is_alpha + obs->Speed*LQ*obs->Is_beta/1000 - obs->Es_alpha)/LD;
int32_t dIs_beta = (Vs_beta - RS*obs->Is_beta - obs->Speed*LD*obs->Is_alpha/1000 - obs->Es_beta)/LQ;
obs->Is_alpha += dIs_alpha * TS / 1000;
obs->Is_beta += dIs_beta * TS / 1000;
// 反电动势估算
int32_t dEs_alpha = -obs->Speed*obs->Es_beta/1000 + obs->K1*(obs->Is_alpha - Is_alpha_meas);
int32_t dEs_beta = obs->Speed*obs->Es_alpha/1000 + obs->K1*(obs->Is_beta - Is_beta_meas);
obs->Es_alpha += dEs_alpha * TS / 1000;
obs->Es_beta += dEs_beta * TS / 1000;
// 角度和速度估算
obs->Angle = atan2(obs->Es_beta, obs->Es_alpha) * 57296 / 1000; // 弧度转角度*100
obs->Speed = (obs->Es_alpha*obs->Es_alpha + obs->Es_beta*obs->Es_beta) * obs->K2 / 1000;
}
5.3 参数整定经验
观测器增益K1和K2的整定非常关键,经过多次实验总结出以下经验:
-
K1选择:
- 太小:观测器响应慢,动态性能差
- 太大:系统不稳定,容易振荡
- 推荐初值:K1 = 2π×BW (BW为期望带宽)
-
K2选择:
- 与转速估算精度直接相关
- 推荐初值:K2 = 1/(Ke×P) (Ke为反电动势常数,P为极对数)
实测在风机应用中,K1=200,K2=50时效果最佳。
6. 启动策略实现
6.1 顺风启动流程
-
预定位阶段:
- 给q轴施加固定电流(约20%额定)
- 保持d轴电流为0
- 持续时间:200ms
-
开环加速阶段:
- 线性增加转子角度
- 同时增加q轴电流
- 持续时间:500ms
-
闭环切换阶段:
- 当转速达到50RPM时
- 切换到龙伯格观测器
- 启用闭环控制
6.2 逆风启动处理
检测到逆风启动时(反电动势相位与预期相反):
- 先进行短时反向驱动(100ms)
- 然后执行正常顺风启动流程
- 增加q轴电流至30%额定
关键代码:
c复制void Motor_StartUp(void)
{
// 检测初始位置
FOC_SetCurrent(0, START_CURRENT);
delay_ms(200);
// 检查是否逆风
if(Observer_GetSpeed() < -20) { // 检测到反向转速
FOC_SetCurrent(0, -START_CURRENT); // 反向驱动
delay_ms(100);
}
// 开环加速
for(int i=0; i<500; i++) {
FOC_SetAngle(i * 720 / 500); // 0-720度(2圈)
FOC_SetCurrent(0, START_CURRENT + i*(RATED_CURRENT-START_CURRENT)/500);
delay_ms(1);
}
// 切换到闭环
FOC_SetControlMode(FOC_CLOSED_LOOP);
}
7. 调试经验与问题排查
7.1 常见问题及解决方案
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 电机抖动不转 | 1. 相序错误 2. 电流采样极性反 3. 观测器增益过大 |
1. 检查UVW相序 2. 检查采样电阻接线 3. 减小K1/K2 |
| 高速时失步 | 1. 母线电压不足 2. 电流环响应慢 3. 观测器精度不足 |
1. 提高母线电压 2. 增加电流环带宽 3. 优化观测器参数 |
| 启动反转 | 1. 逆风启动 2. 观测器初始角度错误 |
1. 启用逆风检测 2. 增加预定位时间 |
| 噪声大 | 1. PWM频率低 2. 死区时间不当 3. 电流采样噪声 |
1. 提高PWM频率 2. 优化死区时间 3. 增加采样滤波 |
7.2 关键调试步骤
-
开环测试:
- 固定角度增量,观察电机是否平稳旋转
- 检查三相电流波形是否平衡
-
电流环调试:
- 先调q轴,再调d轴
- 从较小Kp开始,逐步增加
- 观察电流阶跃响应
-
观测器调试:
- 先静态测试(手动旋转电机)
- 比较观测角度与实际角度
- 动态测试时关注低速性能
-
闭环整定:
- 先低速运行(<30%额定)
- 逐步提高速度参考
- 监测电流波形和转速响应
8. 性能优化技巧
8.1 计算优化
M0核资源有限,需要特别注意算法优化:
-
定点数运算:
- 全部使用Q格式定点数
- 三角函数使用查表法(512点)
-
除法优化:
- 用移位代替除法
- 必须除法时使用硬件除法器
-
内存优化:
- 频繁访问的变量定义在SRAM中
- 大数组使用const定义到Flash
8.2 实时性保证
关键时序要求:
- PWM中断:16kHz(62.5us周期)
- 电流环:必须在20us内完成
- 速度环:1kHz执行
实现方法:
- ADC采样使用DMA
- 关键代码用汇编优化
- 非关键任务放在主循环
9. 量产测试方案
9.1 自动化测试流程
-
参数扫描测试:
- 电压范围:8-14V
- 转速范围:100-300RPM
- 记录电流、效率、温升
-
耐久测试:
- 连续运行72小时
- 每1小时记录关键参数
- 检查性能衰减
-
环境测试:
- 高温(60℃)和低温(-10℃)测试
- 振动测试(5-500Hz)
9.2 生产烧录配置
-
Bootloader设计:
- 通过UART接口升级
- 支持CRC校验
- 超时自动跳转
-
参数校准:
- 电流零点自动校准
- 电压采样校准
- 保存到Flash最后页
-
生产测试模式:
- 短接测试点进入
- 自动运行诊断程序
- 输出测试报告
10. 移植到其他平台
这套代码架构设计时就考虑了可移植性,主要需要修改的部分:
-
硬件抽象层:
- PWM配置
- ADC采样
- GPIO控制
-
编译器相关:
- 中断向量表
- 内联汇编
- 特殊功能寄存器
-
性能调优:
- 根据新平台CPU性能
- 调整控制频率
- 优化算法实现
移植到STM32F030的实测数据显示,只需修改约10%的代码即可运行。
