基于开源项目HAL STM32F4 +DSP库跑SVPWM开环速度测试
基于开源项目HAL STM32F4 +DSP库跑SVPWM开环速度测试
HAL STM32F4 +ARM DSP库跑SVPWM开环速度测试
本篇硬件电路和代码来源于开源项目:
https://github.com/MengYang-x/STM3F401-FOC/tree/main
硬件电路和项目介绍可以在立创开源广场查看:
https://oshwhub.com/shadow27/tai-yang-neng-wu-ren-chuan
测试效果
移植到STM32F446上,采用自制电机驱动板,采用EG3112,上下桥臂采用高电平驱动控制。
通过输出的三路马鞍波波形:
原作者介绍过的内容,这里就不多做介绍了,详情可以前往立创开源主页了解详情。程序这一块,主要针对stm32F4系列。
测试条件
- STM32F4或者M4内核的相关型号的mcu即可。工程时基于HAL库STM32CubeMX生产的配置工程,移植非常简单。
- 对于 Cortex-M0 或者 M3 处理器类型,由于没有 FPU 因此无法直接进行浮点运算,只能将浮点数进行Q 规格化(q7、q15 或 Q31)处理,如开平方运算:M0/M3 只能通过迭代法(标准数学函数库)计算,而 M4F直接调用 VSQRT 指令完成。
- 如果手上只有stm32f1系列的,可以参考《SimpleFOC移植STM32(二)—— 开环控制》实现控制。
- 或者参考另外一篇文章《HAL STM32F1 通过查表方式实现SVPWM驱动无刷电机测试》
硬件支持条件
- MCU需要支持浮点运算(FPU)功能。
- 一块无刷电机驱动板。(可以参考原作者的硬件。)
- 由于原作者使用的是EG2133驱动芯片,驱动电路中上下桥是连一块的,3路PWM输出即可实现无刷电机转动,如果自己使用的是上下桥独立驱动(6路输出控制),那么需要将定时器的PWM输出通道配置为互补输出通道,(即3路互补输出),同时需要注意输出极性。
必要驱动文件
SVPWM开环速度测试,没有使用到,可以屏蔽掉:
DSP库文件,可以自己从安装的Keil软件ARM文件夹内找到相关驱动库文件:例如:
D:\Keil_v5\ARM\CMSIS\DSP_Lib\Source\FastMathFunctions
或者在
STM32CubeMX
,安装的对应pack包解压文件夹内,:
C:\Users\Administrator\STM32Cube\Repository\STM32Cube_FW_F4_V1.28.0\Drivers\CMSIS\DSP\Source
或者标准库
STM32F4xx_DSP_StdPeriph_Lib_V1.9.0\Libraries\CMSIS\DSP_Lib
中找到对应的所需驱动文件。Keil ARM路径下位置:
也可以到ARM官方的GitHub账号(
https://github.com/ARM-software/CMSIS
)下载所有ARM Cortex-M内核的DSP外设库。STM32CubeMX,pack解压安装文件位置:
同样在标准外设库中也可以找到:(后缀带
f32
需要FPU硬件支持才能高效运行,后缀为
q15
专为无FPU的MCU(如STM32F103)设计,纯整数运算)
数字信号库包含在路径:
STM32F4xx_DSP_StdPeriph_Lib_V1.9.0\Libraries\CMSIS\DSP_Lib
和
STM32F4xx_DSP_StdPeriph_Lib_V1.9.0\Libraries\CMSIS\Lib
下,或者Keil安装目录下
D:\Keil_v5\ARM\CMSIS\Lib\ARM
将它们拷贝到目标工程文件夹下。其中Lib文件夹中包含的是经过不同编译器编译后能够运行在Cortex-M4内核上的底层数学库,DSP_Lib文件夹中包含的是调用底层函数封装而成的API函数源码:
Lib文件夹中包含的底层库包括:
arm_cortexM4lf_math.lib //---->stm32f4 DSP库跑SVPWM开环速度测试需要使用到的
arm_cortexM4bf_math.lib
arm_cortexM4l_math.lib
arm_cortexM4b_math.lib
arm_cortexM3l_math.lib
arm_cortexM3b_math.lib
arm_cortexM0l_math.lib
arm_cortexM0b_math.lib
对应工程中所用到的:
arm_cortexM4lf_math.lib
库文件来源。
STM32F4 DSP和标准外设库(STSW-STM32065) ST官网下载地址:
https://www.st.com.cn/zh/embedded-software/stsw-stm32065.html
当前stm32F4 最新版本:
STSW-STM32065 STM32F4 DSP and standard peripherals library 1.9.0
链接:https://pan.baidu.com/s/1J8VD2re8SRWOGnZXZKcyvQ?pwd=o5an
提取码:o5an
工程中配置的重要一步:需要添加相对于的宏,来开启DSP库进行浮点运算和math计算 “
__CC_ARM,__TARGET_FPU_VFP, __FPU_PRESENT=1U, ARM_MATH_CM4
”
SVPWM实现,DC转AC逆变代码核心函数
// FOC核心函数:输入Uq、Ud和电角度,输出三路PWM
// Uq 范围:0—6.928; MAX: U0*sqrt3/3 (sqrt平方根),
//需要注意:Uq值设置越大,力矩越大,电流越大,电机发热越大。
void setPhaseVoltage(float Uq, float Ud, float angle_el)
{
static float Ts = 1.0f;
float Ta, Tb, Tc;
float t1, t2, t3, t4, t5, t6, t7;
float sum, k_svpwm;
angle_el = _normalizeAngle(angle_el);
// Park逆变换
float U_alpha = -Uq * arm_sin_f32(angle_el) + Ud * arm_cos_f32(angle_el);
float U_beta = Uq * arm_cos_f32(angle_el) + Ud * arm_sin_f32(angle_el);
// 扇区判断
float K = sqrt3 * Ts / Udc; // SVPWM调制比
float u1 = U_beta * K;
float u2 = (0.8660254f * U_alpha - 0.5f * U_beta) * K; // sqrt(3)/2 = 0.8660254
float u3 = (-0.8660254f * U_alpha - 0.5f * U_beta) * K;
uint8_t sector = (u1 > 0.0f) + ((u2 > 0.0f) << 1) + ((u3 > 0.0f) << 2); // sector = A + 2B + 4C
// 非零矢量和零矢量作用时间的计算
switch(sector) {
case 3: // 扇区1
t4 = u2;
t6 = u1;
sum = t4 + t6;
if(sum > Ts) { // 过调制处理
k_svpwm = Ts / sum;
t4 *= k_svpwm;
t6 *= k_svpwm;
}
t7 = (Ts - t4 - t6) / 2.0f;
Ta = t4 + t6 + t7;
Tb = t6 + t7;
Tc = t7;
break;
case 1: // 扇区2
t2 = -u2;
t6 = -u3;
sum = t2 + t6;
if(sum > Ts) {
k_svpwm = Ts / sum;
t2 *= k_svpwm;
t6 *= k_svpwm;
}
t7 = (Ts - t2 - t6) / 2.0f;
Ta = t6 + t7;
Tb = t2 + t6 + t7;
Tc = t7;
break;
case 5: // 扇区3
t2 = u1;
t3 = u3;
sum = t2 + t3;
if(sum > Ts) {
k_svpwm = Ts / sum;
t2 *= k_svpwm;
t3 *= k_svpwm;
}
t7 = (Ts - t2 - t3) / 2.0f;
Ta = t7;
Tb = t2 + t3 + t7;
Tc = t3 + t7;
break;
case 4: // 扇区4
t1 = -u1;
t3 = -u2;
sum = t1 + t3;
if(sum > Ts) {
k_svpwm = Ts / sum;
t1 *= k_svpwm;
t3 *= k_svpwm;
}
t7 = (Ts - t1 - t3) / 2.0f;
Ta = t7;
Tb = t3 + t7;
Tc = t1 + t3 + t7;
break;
case 6: // 扇区5
t1 = u3;
t5 = u2;
sum = t1 + t5;
if(sum > Ts) {
k_svpwm = Ts / sum;
t1 *= k_svpwm;
t5 *= k_svpwm;
}
t7 = (Ts - t1 - t5) / 2.0f;
Ta = t5 + t7;
Tb = t7;
Tc = t1 + t5 + t7;
break;
case 2: // 扇区6
t4 = -u3;
t5 = -u1;
sum = t4 + t5;
if(sum > Ts) {
k_svpwm = Ts / sum;
t4 *= k_svpwm;
t5 *= k_svpwm;
}
t7 = (Ts - t4 - t5) / 2.0f;
Ta = t4 + t5 + t7;
Tb = t7;
Tc = t5 + t7;
break;
default:
break;
}
// printf("[Ta,Tb,Tc]:%f,%f,%f\r\n", Ta, Tb, Tc);
Set_PWM(Ta, Tb, Tc); // 配置输出三路PWM,驱动无刷电机转动
}
STM32CubeMX配置
选择一个高级定时器:(注意这里是按照原作者的EG2133驱动芯片配置的,上下桥驱动控制端连一块,进行配置的)
采用自制驱动板EG3112,上下桥独立驱动,定时器配置互补通道输出:
需要注意一点的是:采用互补通道输出控制方式,这里的死区时间参数,保持默认配置值
0
,如果配置了死区时间,反而对无刷电机的控制造成影响。
为了查看输出波形,还需要配置一个串口,方便观察波形。
SVPWM开环速度测试工程说明
待测试电机参数配置:
motor.c
中修改测试电机的极对数。
极对数测量
如果知道电机型号,可以找到对应资料查阅多更好。如果无刷电机外转子不是全部密封,看的到外转子内壁上永磁体的,可以直接自己数出来。上门贴了有多少块强磁铁,即可得到此数据。对应外转子密封看不到内壁磁体的测量方法:
- 如果有示波器的情况下,用示波器的探头夹住电机的一根线,另一根接探头,然后旋转电机一圈,截取波形,数下峰的个数(上下峰都算),为偶数值除以2,就是电机的极对数。
- 有低压直流可调电源情况下,限制一定的电流,加载一个小电压到三相中的任意两相,用手转动电机一圈,有稳定位置的个数就是极对。
SVPWM开环速度参数设定:
OpenVelocity(6.0f); //数值越大,电机旋转的速度越快
对于采用3路PWM互补输出方式驱动控制:
// 使能TIMx的通道
void PWM_Init(void)
{
HAL_TIM_Base_Start(&htim1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_2);
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3);
}
串口数据观测
设置:添加波形图控件到主窗口
设置串口端口号以及数据类型:
打开串口,并添加数据到波形图控件中:
最终测试效果:
需要注意一点,所测得的马鞍波形,并不代表实际电机真实的驱动转动效果,电机的运转效果与驱动电路和电机参数有关,这个波形是理论推导得来的理想模型。
在SVPWM开环速度测试运行下,无刷电机的U-V-W相波形:
MCU 定时器对应输出通道的PWM驱动波形:
这里的PWM频率,通过示波器测得是15.2K,对应的是程序中定时器输出通道:
PWM频率 = MAIN_CLK/(ARR*2)(没有进行分频,中心对齐方式)
H桥NMOS管栅极驱动波形:
移植工程测试源码
基于STM32F446 MIAN FOSC=180MHz,
链接:https://pan.baidu.com/s/1IidjgkeSnOLZg-Dq4Snm9Q?pwd=842c
提取码:842c