打印
[电机控制专用MCU]

APM32M3514 电机通用评估板评测:无刷电机运转

[复制链接]
443|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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.电机转动效果





使用特权

评论回复
沙发
Ketose| | 2025-3-16 16:00 | 只看该作者
能否上传一下官方的FOC例程?

使用特权

评论回复
板凳
gouguoccc| | 2025-3-17 07:50 | 只看该作者
120MHz的主频不错,能满足大多数电机控制应用场景了。

使用特权

评论回复
地板
雾里闲逛| | 2025-3-29 22:00 | 只看该作者
这个效果看上去好棒啊!
咱们极海的这款MCU可以实现那种两个电机只有一个小槽的交割的实现啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:工程师
简介:超越自我,为设计激发灵感和想象。

218

主题

751

帖子

5

粉丝