This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

求一份EPWM驱动无感BLDC电机的源程序

应用三步启动法,反电动势检测过零换向

  • 网上找找艾研科技的例程,PWM驱动电机的,不知道和你这个是否一样的。
  • 看看TI提供的参考方案有没有,下载个controlSUIT
  • 好的,我看一下
  • 下载了,不太一样,看不懂。。。
  • 您可以先看一下

     无刷直流 (BLDC) 电机的无传感器梯形控制

  • 很高兴能帮到您!
  • #include "hardware.h"
    #include "bldc.h"

    u16 Temp = 0;

    volatile State_TypeDef State = Idle;

    Task_TypeDef Task;

    Flag_TypeDef Flag;

    vu16 ADC_VALUE[ADC_NUMBER*ADC_BUFFER]={0};
    u16 SysTime = 0; /* 系统时间 */
    u8 Phase = 0; /* 通电绕组 */
    u16 PwmDuty = 0; /* PWM占空比 */
    u8 AlignRotorCount = 0; /* 电机启动时锁定转子的次数 */
    u8 BlankingCount = 0; /* 消隐时长 */
    //u8 ZeroBeforeCount = 0; /* 过零点之前的检测次数 */
    u8 ZeroCrossCount = 0; /* 到达过零点的检测次数 */
    u8 ZeroAcquireCount = 0; /* 进入到同步运行状态前的过零点次数 */
    u16 CommutateTime = 0; /* 过零检测到到换向的时间 */
    u16 AccelerateCommutateTime = 0; /* 电机加速的换向的时间 */
    u16 AdcPotentiometer = 0; /* 电位器ADC转换结果 */
    u16 AdcBEMF = 0; /* BEMF电压ADC转换结果 */
    u16 AdcCurrent = 0; /* 电流放大器ADC转换结果 */
    u16 AdcVbus = 0; /* 电源电压ADC转换结果 */
    u16 ZeroVref = 0; /* 过零检测基准电压,等于电源电压的一半 */
    u8 SpeedErrorCount = 0; /* 电机速度异常次数 */
    u16 ZeroPeriod = 1000; /* 过零周期即60度换向时间 */
    u16 MotorRpm = 0; /* 电机转速,单位RPM */
    u16 AccelerateTime = 0; /* 电机加速运转的时间 */
    //u16 PhaseAdvance = 0; /* 超前相位 */
    u16 Current = 0; /* 电流值 */
    u16 Iref = 0; /* 电流放大器输出偏置 */

    #define MaxIX 999 //最大记录条数
    vu16 BEMF_REC[MaxIX+1]={0}; // 反电动势记录
    u16 ix = 0; // 记录下标
    /********************************************************************************************
    * Function Name : void Scan_Key(void)
    * Description : 按键扫描程序,用于启动或者停止电机运转
    * Input : 无
    * Return : 无
    *********************************************************************************************/
    void Scan_Key(void)
    {
    if(Key_Status() == PRESS)
    {
    if(State == Idle)
    {
    while(Key_Status() != RELEASE);
    State = Start;
    }
    else
    {
    while(Key_Status() != RELEASE);
    State = Stop;
    }
    }
    }


    void Start_Motor(void)
    {
    Close_LED7();
    Close_LED8();
    Close_LED9();

    Flag.AcquireZero = 0;
    Flag.ZeroCross = 0;
    SpeedErrorCount = 0;
    AccelerateTime = 0;
    AlignRotorCount = 3; /* 初始化电机转子定位次数 */

    Update_PwmDuty((u32)ALIGN_ROTOR_PWM*FULL_DUTY/100);
    Phase = 0;
    Commutate();
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
    State = AlignRotor;
    SysTime = 0;
    Task.AlignRotor = 0;
    printf("Start AlignRotor !!!\n\r");
    }

    /********************************************************************************************
    * Function Name : void AlignMotorRotor(void)
    * Description : 转子定位程序
    * Input : 无
    * Return : 无
    *********************************************************************************************/
    void Align_MotorRotor(void)
    {
    if(AlignRotorCount > 0)
    {
    Phase = 0;
    Commutate();
    Update_PwmDuty((u32)ALIGN_ROTOR_PWM*FULL_DUTY/100);
    AlignRotorCount --;
    if (AlignRotorCount == 0)
    {
    Update_PwmDuty((u32)PWM_ACCELERATE_START*FULL_DUTY/100); //更新初始加速占空比
    AccelerateCommutateTime = TIM2_FREQ*20/START_RPM/MOTOR_POLES; //设计初始加速时间参数

    /* 启动TIM2,进入到加速状态 */
    TIM2_Counter = 0;
    Clear_TIM2_Update_IF();
    Enable_TIM2_Update_IT();

    Clear_TIM1_CC4_IF();
    Enable_TIM1_CC4_IT();

    State = Accelerate;
    //State = Stop;
    }
    }
    }

    void Commutate(void)
    {
    Disable_AH();
    Disable_AL();
    Disable_BH();
    Disable_BL();
    Disable_CH();
    Disable_CL();

    switch(Phase)
    {
    case 0: /* AB相 */
    {
    //Disable_CH();
    Enable_AH();
    Enable_BL();
    #if (DIRECTION == COUNTER_CLOCKWISE)
    Flag.BemfEdge = FALLING;
    Phase = 1;
    #else
    Flag.BemfEdge = RISING;
    Phase = 5;
    #endif
    }
    break;

    case 1: /* AC相 */
    {
    Enable_AH();
    //Disable_BL();
    Enable_CL();
    #if (DIRECTION == COUNTER_CLOCKWISE)
    Flag.BemfEdge = RISING;
    Phase = 2;
    #else
    Flag.BemfEdge = FALLING;
    Phase = 0;
    #endif
    }
    break;

    case 2: /* BC相 */
    {
    //Disable_AH();
    Enable_BH();
    Enable_CL();
    #if (DIRECTION == COUNTER_CLOCKWISE)
    Flag.BemfEdge = FALLING;
    Phase = 3;
    #else
    Flag.BemfEdge = RISING;
    Phase = 1;
    #endif
    }
    break;

    case 3: /* BA相 */
    {
    Enable_BH();
    //Disable_CL();
    Enable_AL();
    #if (DIRECTION == COUNTER_CLOCKWISE)
    Flag.BemfEdge = RISING;
    Phase = 4;
    #else
    Flag.BemfEdge = FALLING;
    Phase = 2;
    #endif
    }
    break;

    case 4: /* CA相 */
    {
    //Disable_BH();
    Enable_CH();
    Enable_AL();
    #if (DIRECTION == COUNTER_CLOCKWISE)
    Flag.BemfEdge = FALLING;
    Phase = 5;
    #else
    Flag.BemfEdge = RISING;
    Phase = 3;
    #endif
    }
    break;

    case 5: /* CB相 */
    {
    Enable_CH();
    //Disable_AL();
    Enable_BL();
    #if (DIRECTION == COUNTER_CLOCKWISE)
    Flag.BemfEdge = RISING;
    Phase = 0;
    #else
    Flag.BemfEdge = FALLING;
    Phase = 4;
    #endif
    }
    break;

    default:
    break;
    }

    Flag.ZeroCross = 0;
    BlankingCount = BLANKING_COUNT;
    ZeroCrossCount = 0;
    }

    void Stop_Running(void)
    {
    Disable_PwmOutput();
    Clear_TIM1_CC4_IF();
    Disable_TIM1_CC4_IT();
    Clear_TIM2_Update_IF();
    Disable_TIM2_Update_IT();
    State = Idle;

    if(Flag.FailedStart) /* 输出错误标志 */
    {
    Flag.FailedStart = 0;
    printf("Error: Failed to start!!!\n\r");
    }

    if(Flag.CurrentHigh)
    {
    Flag.CurrentHigh = 0;
    printf("Error: Current is too large!!!\n\r");
    }

    if(Flag.SpeedHigh)
    {
    Flag.SpeedHigh = 0;
    printf("Error: Motor speed is too high !!!\n\r");
    }

    if(Flag.SpeedLow)
    {
    Flag.SpeedLow = 0;
    printf("Error: Motor speed is too low !!!\n\r");
    }

    if(Flag.LostZero)
    {
    Flag.LostZero = 0;
    printf("Error: Sensor error !!!\n\r");
    }

    printf("Motor stop !!!\n\r");
    }
    // ROUNDUP( INDIRECT("E7") * 20 / ( INDIRECT("D13")* B7*B7 / INDIRECT("F13") / INDIRECT("F13") + INDIRECT("F7") ) / INDIRECT("G7") ,0 )
    void Accelerate_Motor(void) // 加速
    {
    u16 speed = 0; // 新的目标速度
    u32 ct = 0; // 新的换向时间

    speed = ((u32)AccelerateTime*AccelerateTime)/ACCELERATE_TIME; /* 计算新的目标速度 */
    speed = ((u32)(END_RPM - START_RPM)*speed)/ACCELERATE_TIME;
    speed += START_RPM;

    ct = (u32)TIM2_FREQ*20/speed/MOTOR_POLES; /* 将速度转换为相应的换向时长 */

    //ct = AccelerateCommutateTime*14/15-1;
    if(ct > 65535) AccelerateCommutateTime = 65535;
    else AccelerateCommutateTime = ct;



    PwmDuty = ((u32)PWM_ACCELERATE_DELTA*AccelerateTime/ACCELERATE_TIME); /* 计算PWM增量 */
    PwmDuty += (u16)((u32)PWM_ACCELERATE_START*FULL_DUTY/100); /* 更新PWM */
    Update_PwmDuty(PwmDuty);

    if((AccelerateCommutateTime <= TIM2_FREQ*20/ZERO_ACQUIRE_RPM/MOTOR_POLES)&& /* 开始捕获过零点 */
    (Flag.AcquireZero == 0))
    {
    Flag.AcquireZero = 1;
    ZeroAcquireCount = 0;
    // Open_LED7();
    }

    if(AccelerateCommutateTime <= TIM2_FREQ*20/END_RPM/MOTOR_POLES) /* 加速到启动终止速度时,启动失败 */
    {
    State = Stop;
    Flag.FailedStart = 1;
    Open_LED6();
    }
    }

    void Check_ZeroCrossing(void)
    {
    u16 t = 0;

    if(BlankingCount > 0) /* 等待消隐 */
    {
    BlankingCount --;
    return;
    }

    if((Flag.BemfEdge == FALLING)&&(AdcBEMF < ZeroVref)) /* 判断BEMF电压是否过零 */
    ZeroCrossCount ++;

    if((Flag.BemfEdge == RISING)&&(AdcBEMF > ZeroVref))
    ZeroCrossCount ++;

    //Open_LED7();
    if (ZeroCrossCount > ZERO_SAMPLES-1) /* 达到预期的过零次数 */
    {
    BEMF_REC[ix] = AdcBEMF;
    ix++;
    if(ix>MaxIX) ix = 0;
    //Open_LED8();
    ZeroPeriod = TIM3_Counter; /* 从TIM3计数器读取2次过零点的周期 */
    TIM3_Counter = 0;

    t = ZeroPeriod >> 1; /* 计算30度换向时长 */
    CommutateTime = ((u32)t * (30 - ADVANCE_ANGLE))/30; /* 超前相位补偿 */

    if(CommutateTime > ZERO_CHECK_DELAY) /* ADC过零检测延迟补偿 */
    CommutateTime -= ZERO_CHECK_DELAY;
    else
    CommutateTime = 1;

    if (State == Running)
    {
    Flag.ZeroCross = 1;

    Disable_TIM2_Update_IT();
    TIM2->ARR = CommutateTime;
    TIM2_Counter = 0;
    Clear_TIM2_Update_IF();
    Enable_TIM2_Update_IT();
    Open_LED9(); // 标志着已经切换到闭环控制状态
    }
    else /* 电机加速到同步运转状态的判断 */
    {
    ZeroAcquireCount ++;

    if(ZeroAcquireCount > ZERO_ACQUIRE_COUNT-1) /* 进入过零点同步状态 */
    {
    Flag.ZeroCross = 1;
    Disable_TIM2_Update_IT();
    Flag.AcquireZero = 0;
    State = Running;

    TIM2->ARR = CommutateTime; /* 更新TIM2定时换向 */
    TIM2_Counter = 0;
    Clear_TIM2_Update_IF();
    Enable_TIM2_Update_IT();
    // Open_LED9(); // 标志着已经从开环加速正在切换到闭环控制状态
    }
    }
    }
    }

    /********************************************************************************************
    * Function Name : void Get_MotorSpeed(void)
    * Description : 计算电机速度程序
    RPM = 60/((60°换向周期(秒)*6)*(极数/2)) = 20/(T*P)
    * Input : 无
    * Return : 无
    *********************************************************************************************/
    void Get_MotorSpeed(void)
    {
    static u16 t = 0;

    t += ZeroPeriod; /* 计算2次60度换向周期的平均值 */
    t = t >> 1;
    MotorRpm = (u32)TIM2_FREQ*20/t/MOTOR_POLES; /* RPM = 60/((60°换向周期(秒)*6)*(极数/2)) = 20/(T*P) */
    }

    void Control_Speed(void)
    {
    u16 duty = 0;

    duty = ((u32)AdcPotentiometer*FULL_DUTY)/4095; /* 将ADC转换结果线性转换为PWM的占空比 */
    if(duty > PwmDuty) /* 逐渐调整PWM占空比,避免占空比调整步长太大导致电机失速 */
    {
    PwmDuty += 4;
    if(PwmDuty > FULL_DUTY) PwmDuty = FULL_DUTY;
    }
    else if(duty < PwmDuty)
    {
    if(PwmDuty < 4) PwmDuty = 0;
    else PwmDuty -= 4;
    }
    else return;
    Update_PwmDuty(PwmDuty); /* 更新PWM占空比 */
    }

    /********************************************************************************************
    * Function Name : void Monitor_Speed(void)
    * Description : 电机失速监控程序
    * Input : 无
    * Return : 无
    *********************************************************************************************/
    void Monitor_Speed(void)
    {
    if(MotorRpm < MIN_SPEED) /* 检查电机速度是否过低 */
  • 赞一个,支持下。
  • 刚开始接触伺服驱动这块,看了你分享的代码,懂了大概的原理,能否分享下完整的看看,目前有些东西不知怎么修改去编译通过。

    如果方便的发到qq邮箱,773914998@qq.com,谢谢了。