本帖最后由 meiyaolei 于 2025-3-2 18:06 编辑
APM32M3514 电机通用评估板评测:无刷电机运转
1.硬件概述
APM32M3514 电机通用评估板是一款基于 APM32M3514 微控制器的开发板,专为电机控制应用设计。它支持多种电机类型,包括无刷直流电机(BLDC)和永磁同步电机(PMSM)。
微控制器:APM32M3514,基于 ARM Cortex-M3 内核,主频高达 120MHz。
电机驱动接口:支持三相无刷电机的驱动,集成 PWM 输出和电流检测。
通信接口:支持 UART、I2C、SPI 等通信协议,便于调试和数据传输。
调试接口:支持 SWD/JTAG 调试,方便开发和故障排查。
2. 测试环境
电机类型:三相无刷直流电机(BLDC)。电机输出接口:
电源:24V DC 电源。
开发环境:Keil MDK 或 IAR Embedded Workbench。
调试工具:ST-Link。
3. 硬件连接
将无刷电机的三相线(U、V、W)连接到评估板的电机驱动接口。
电机连接示意图:


连接霍尔传感器到评估板的霍尔信号输入接口。

连接电源24V DC到评估板的电源输入接口。

4.软件配置
PWM 更新:
void PWM_Update(Motor_TypeDef *Motor)
{
if(Motor->User.s8Direction != -1)
{
Motor->PWMx.Timer->CC1 = (32768-Motor->Foc.stc_SvpwmPara.u16q15_DutyU)*PWM_PERIOD >> 15;
Motor->PWMx.Timer->CC2 = (32768-Motor->Foc.stc_SvpwmPara.u16q15_DutyV)*PWM_PERIOD >> 15;
}
else
{
Motor->PWMx.Timer->CC1 = (32768-Motor->Foc.stc_SvpwmPara.u16q15_DutyV)*PWM_PERIOD >> 15;
Motor->PWMx.Timer->CC2 = (32768-Motor->Foc.stc_SvpwmPara.u16q15_DutyU)*PWM_PERIOD >> 15;
}
Motor->PWMx.Timer->CC3 = (32768-Motor->Foc.stc_SvpwmPara.u16q15_DutyW)*PWM_PERIOD >> 15;
}
初始电机控制:
int8_t s8InitError = 0;
Motor->PWMx.Timer = TMR1;
/* init function */
vsp2rpm_init();
id_ramp_init();
iq_transit_ramp_init(&stc_TransitRamp);
spd_ramp_init();
pll_pi_init(&Motor->stc_PiPll);
iq_pi_init(&Motor->stc_IqPi);
id_pi_init(&Motor->stc_IdPi);
spd_pi_init(&Motor->stc_SpdPi);
stall_init(&Motor_type.stc_Stall);
s8InitError = smo_para_init(&Motor_type.stc_SmoPara);
Motor->User.s8Direction = 1;
Motor->User.u16SlowLoopDiv = PWMFREQ / SLOWLOOP_FREQ; // slow loop counters
Motor->User.bSlowLoopFlag = FALSE;
Motor->User.s16CmdRpm = 0;
Motor->User.s16Vsp = 0;
Motor->User.s16SoftwareSpdCmd = 0;
Motor->User.u16PreChargeCnt = 0;
Motor->User.u16PreChargeTime = PRECHARGE_TIME;
Motor->User.u16FaultReleaseTimeCmd = FAULTRELEASE_TIME*SLOWLOOP_FREQ;
Motor->User.u16FreeWheelSpdCmd = FREEWHEEL_SPEED;
Motor->User.u16FreeWheelTimeCmd = FREEWHEEL_TIME*SLOWLOOP_FREQ;
Motor->User.s16q20_SpinSpdInc = 1048576/SPEED_CALIBRATION*SPIN_SPD_INC/SLOWLOOP_FREQ;
Motor->User.s16q20_StartSpdInc = 1048576/SPEED_CALIBRATION*STARTUP_SPD_INC/SLOWLOOP_FREQ;
Motor->User.stc_fault.u16_Fault** = 0;
Motor->User.stc_fault.u16_OcCnt = 0;
Motor->User.stc_fault.u16_OcTime = OC_TIME;
Motor->User.stc_fault.u16_OvCnt = 0;
Motor->User.stc_fault.u16_OvTime = OV_TIME;
Motor->User.stc_fault.u16_UvCnt = 0;
Motor->User.stc_fault.u16_UvTime = UV_TIME;
Motor->User.stc_fault.u16_OsCnt = 0;
Motor->User.stc_fault.u16_OsTime = OS_TIME;
Motor->User.stc_fault.u16_PllErrCnt = 0;
Motor->User.stc_fault.u16_PllErrTime = PLLERR_TIME;
Motor->Foc.s16SpdToTheta = SPEED_TO_THETA;
Motor->Foc.s16CmdTheta = 0;
Motor->Foc.s16SpdCmd = 0;
Motor->Foc.s16SpdFilt = 0;
Motor->Foc.s16SpeedRamp = 0;
Motor->Foc.s16q15SpdObs = 0;
Motor->Foc.stc_IdqCmd.s16q15_D = 0;
Motor->Foc.stc_IdqCmd.s16q15_Q = 0;
if(s8InitError !=0)
{
Motor->User.stc_fault.u16_Fault** = INIT_ERROR;
}
速度控制:
static void M1_RunSpinSlow(void)
{
Motor_type.Foc.u16q15VdqSqrt = isqrt32((uint32_t)(Motor_type.Foc.stc_Vdq.s16q15_D * Motor_type.Foc.stc_Vdq.s16q15_D + Motor_type.Foc.stc_Vdq.s16q15_Q * Motor_type.Foc.stc_Vdq.s16q15_Q));
Motor_type.Foc.s16SpeedRamp = ramp_s16(Motor_type.Foc.s16SpdCmd,&stc_SpdRamp);
/* low pass filter for speed, Fc : 200Hz*/
Motor_type.Foc.s16SpdFilt = (Motor_type.Foc.s16SpdFilt*14521 + Motor_type.stc_SmoPara.s16q15SpdObs*18247) >> 15;
/* pi for speed */
Motor_type.stc_SpdPi.s16_Error = Motor_type.Foc.s16SpeedRamp - Motor_type.Foc.s16SpdFilt;
anti_pi(&(Motor_type.stc_SpdPi));
/* set Id/q command */
Motor_type.Foc.stc_IdqCmd.s16q15_Q = Motor_type.stc_SpdPi.s32_Out;
Motor_type.Foc.stc_IdqCmd.s16q15_D = 0;
if((abs(Motor_type.Foc.s16SpeedRamp)<Motor_type.User.u16FreeWheelSpdCmd) && (abs(Motor_type.Foc.s16SpdCmd)<Motor_type.User.u16FreeWheelSpdCmd))
{
M1_SwitchRunSpinFreewheel();
}
}
电流环:
void current_ctrl(Motor_TypeDef *Motor)
{
clarke(&Motor->Foc.stc_Iuvw, &Motor->Foc.stc_Iab); // Clarke 变换
park(&Motor->Foc.stc_Iab, &Motor->Foc.stc_SinCos, &Motor->Foc.stc_Idq); // Park 变换
/* PI 控制器用于 D 轴电流 */
Motor->stc_IdPi.s16_Error = Motor->Foc.stc_IdqCmd.s16q15_D - Motor->Foc.stc_Idq.s16q15_D;
anti_pi(&Motor->stc_IdPi);
Motor->Foc.stc_Vdq.s16q15_D = Motor->stc_IdPi.s32_Out;
/* 限制 Vq 的最大值 */
uint32_t u32_Temp;
int16_t s16q15Vmax = Motor->Foc.s16Vbus * 18918 >> 15; // Vmax = Vbus / sqrt(3)
u32_Temp = s16q15Vmax * s16q15Vmax
- Motor->Foc.stc_Vdq.s16q15_D * Motor->Foc.stc_Vdq.s16q15_D;
Motor->stc_IqPi.s32_Umax = isqrt32(u32_Temp);
Motor->stc_IqPi.s32_Umin = -Motor->stc_IqPi.s32_Umax;
/* PI 控制器用于 Q 轴电流 */
Motor->stc_IqPi.s16_Error = Motor->Foc.stc_IdqCmd.s16q15_Q - Motor->Foc.stc_Idq.s16q15_Q;
anti_pi(&Motor->stc_IqPi);
Motor->Foc.stc_Vdq.s16q15_Q = Motor->stc_IqPi.s32_Out;
/* 逆 Park 变换 */
inv_park(&Motor->Foc.stc_Vdq, &Motor->Foc.stc_SinCos, &Motor->Foc.stc_Vab);
}
主函数:
//Reads key from demoboard.
NewDIRKey = GPIO_ReadInputBit(GPIOC,GPIO_PIN_13); //PC13 Direction方向按键
if(NewDIRKey == BIT_RESET)
{
/*设定新方向为反转CCW*/
Motor_type.User.s8NewDir = -1;
}
else{
/*设定新方向为正转CW*/
Motor_type.User.s8NewDir = 1;
}
if(Motor_type.User.s8NewDir != Motor_type.User.s8Direction)
{
/*启动转向切换功能*/
Motor_type.User.bDirSwitchEnable = true;
}
if(Motor_type.User.bSlowLoopFlag)
{
WWDTFeedDog();
/* Slow Loop Statemachine */
s_STATE_SLOW[eM1_MainState]();
Motor_type.User.bSlowLoopFlag = 0;
}
5.电机转动效果
|