南京凌鸥 FOC 方案培训 Lv3 笔记

第1讲培训资料说明_哔哩哔哩_bilibili

LKS08系列-南京凌鸥创芯电子有限公司-LINKO SEMICONDUCTOR CO.,LTD

这是南京凌欧 Lv3 无感foc 框架培训的一些笔记,视频和资料连接在上方。

其中原理图和 PCB 下载位置如下: 

一、凌欧课程思维导图

二、FOC理论框架讲解

2.1 FOC 无感控制框图

其中位置和角度速度均由观测器给出,观测器需要输入当前的 Iq、Id、Uq 和 Ud,其中 Uq 和 Ud可以使用如下图 park 逆变换后的,也可以通过分压电阻直接采集三项得到。

 对于FOC控制,我们通常是将 d 轴电流为 0,而将 q 轴电流设为目标电流。

  • 磁场分量(d轴)​:调控磁通,影响电机效率和速度范围。
  • 转矩分量(q轴)​:直接驱动转矩,决定电机动态响应。

2.2 FOC 转矩控制框图

在这种控制模式下,只控制电机的力矩,而不对速度做出限制。

2.3 FOC 速度控制

在转矩控制前叠加了一个目标速度,这样形成了速度闭环。

2.4 FOC 位置控制

在目标速度后前置了一个位置环,这样能使得 FOC 能按照目标的位置区间控制。

2.5 电流采样

采样方式优势劣势
三电阻采样方便、算法简单、适合入门学习增加成本、增加运放
双电阻减少运放,减少检流电阻需要增加补偿算法
单电阻只需要一个检流电阻和运放算法复杂度增加、处理困难

二、基本参数设置

2.1 电流采样参数设置

2.1.1 ADC_SUPPLY_VOLTAGE、AMPLIFICATION_GAIN 配置

是凌欧 MCU 内置的运放配置得到的值,根据内部运放寄存器设计配置即可。

MC_Parameter.h 22 行:

#define ADC_SUPPLY_VOLTAGE             (3.6)               /* 单位: V  ADC基准电压,3.6或者

2.1.2 RSHUNT 配置

采样电阻值,根据原理图配置即可。

MC_Parameter.h 26 行:

#define RSHUNT                         (0.005)             /* 单位: Ω  采样电阻阻值 */

2.1.3 VOLTAGE_SHUNT_RATIO 配置

在扩展板上的分压采样如下:

在核心板的分压采样电阻如下:

根据分压公式:Vout = Vin × (R2 / (R1 + R2))

所以填入的值就是:1.0 / (20.0 * 2 + 1.0)

MC_Parameter.h 27 行:

#define VOLTAGE_SHUNT_RATIO            (1.0/(20.0 * 2 + 1.0)) /* 母线电压分压比 */

2.1.4 BEMF_SHUNT_RATIO 配置

这个参数配置反向电动势采样的分压,在扩展板上如下:

 其 UX、VX、WX 端连接到高侧 MOSFET 的漏极,也就是连接三项的地方。

在核心板中电阻如下:

MC_Parameter.h 28 行:

#define BEMF_SHUNT_RATIO               (1.0/(20.0 * 2 + 1.0)) /* 反电势电压分压比 */

2.1.5 CURRENT_SAMPLE_TYPE 配置

MC_Parameter.h 32 行:

#define ROTOR_SENSOR_TYPE              ROTOR_SENSORLESS       /* 电机位置传感器类型选择 */

其中可以配置以下的参数:

MC_Type.h 57 行:

#define ROTOR_HALL_SENSOR              1                  /* 电机转子传感器类型为HALL */
#define ROTOR_SENSORLESS               2                  /* 电机转子传感器类型为无HALL */
#define ROTOR_HALL2SENSORLESS          3                  /* 电机转子传感器类型为HALL + 观测器Sensorless */

 全部代码:

MC_Parameter.h 22 行:

/* -----------------------------Hardware Parameter---------------------------- */
#define ADC_SUPPLY_VOLTAGE             (3.6)               /* 单位: V  ADC基准电压,3.6或者2.4,大部分应用选择3.6 */
/*采样匹配电阻 1K欧, 200:10=(200/(10.4+2)=16.129 */
/*采样匹配电阻 40K欧, 200:10=(200/(10.4+40)=3.96825 */
#define AMPLIFICATION_GAIN             (16.129)            /* 运放放大倍数 */  
#define RSHUNT                         (0.005)             /* 单位: Ω  采样电阻阻值 */
#define VOLTAGE_SHUNT_RATIO            (1.0/(20.0 * 2 + 1.0)) /* 母线电压分压比 */
#define BEMF_SHUNT_RATIO               (1.0/(20.0 * 2 + 1.0)) /* 反电势电压分压比 */

#define CURRENT_SAMPLE_TYPE            CURRENT_SAMPLE_2SHUNT /* 电流采样方式选择 */

#define ROTOR_SENSOR_TYPE              ROTOR_SENSORLESS       /* 电机位置传感器类型选择 */

三、电机相关参数

3.1 额定电流、额定电压、额定转速配置

MC_Parameter.h 36 行:

#define U_RATED_VOLTAGE                (24)               /* 单位:V, 电机额定工作电压,设置为正常工作电压 */
#define U_RATED_CURRENT                (6.0)              /* 单位:A, 电机额定工作电流,相电流最大值 */
#define U_MAX_FREQ                     (600.0)            /* 单位:Hz,  电机最高运行转速 */

其中额定转速配置一般是电机电频率的二倍。 

四、硬件配置

 

4.1 MCPWM 设置

hardware_config.h 50 行

#define MCU_MCLK                       (96000000LL)       /* PWM模块运行主频 */
#define PWM_MCLK                       ((u32)MCU_MCLK)    /* PWM模块运行主频 */
#define PWM_PRSC                       ((u8)0)            /* PWM模块运行预分频器 */
#define PWM_FREQ                       ((u16)16000)       /* PWM斩波频率 */

以上参数其中最重要的就是 PWM 斩波频率,他决定了 PWM 驱动电机的频率。 

4.1.1 频率

PWM_PERIOD 是外设中 PWM 信号的周期设置:

hardware_init.h 551 行

MCPWM_InitStructure.MCPWM_PERIOD = PWM_PERIOD;            /* 计数周期设置 */
#define PWM_PERIOD                     ((u16) (PWM_MCLK / (u32)(2 * PWM_FREQ *(PWM_PRSC+1))))

  这个宏定义 PWM_PERIOD 用于计算 PWM 信号的重装载值。

PERIOD=\frac{MCLK}{2*FREQ*(PRSC+1)}

其中的除 2 是 PWM 工作在中央对齐模式(计数器先递增后递减),此时实际频率需除以 2。

假设:MCLK = 72Mhz、FREQ = 16kHz、PRSC = 0

则周期值为 2250

4.1.2 死区

hardware_config.h 61 行

#define DEADTIME_NS                    ((u16)1200)       /* 死区时间 */
#define DEADTIME                       (u16)(((unsigned long long)PWM_MCLK * (unsigned long long)DEADTIME_NS)/1000000000uL)
  
#define DEADTIMECOMPVOLTAGE            (u16)(DEADTIME_NS/(1000000000.0/PWM_FREQ)*MAX_MODULE_VALUE)  

4.1.3 通路设置

hardware_config.h 42 

#if ((CHIP_PART_NUMBER == LKS32MC084D)||(CHIP_PART_NUMBER == LKS32MC086D)||(CHIP_PART_NUMBER == LKS32MC087D)) 
#define  MCPWM_SWAP_FUNCTION           1                  /* 芯片内置预驱标志位*/
#define  PRE_DRIVER_POLARITY           P_HIGH__N_HIGH     /* 预驱预动极性设置 上管高电平有效,下管高电平有效 */
#else
#define  PRE_DRIVER_POLARITY           P_HIGH__N_LOW      /* 预驱预动极性设置 上管高电平有效,下管低电平有效 */
#endif

 上管高电平有效,下低高电平有效的意思是,驱动芯片在接收到高电平的时候,上管输出高电平;驱动芯片在接收到低电平的时候,下管输出高电平。

下图是驱动芯片的真值表,我们应该使用上管高电平有效、下低高电平有效驱动。

 

4.2 采样次数

待补充

4.2.1 采样次数

待补充

4.2.2 采样通道

待补充

4.3 OPA

待补充

4.3.1 放大倍数设置

待补充

4.4 电流采样相关设置

待补充

五、调试时相关保护设置

5.1 错误检测开启

5.1.1 硬件过流检测

其中硬件过流检测是通过 CMP 外设比较器实现的,比较检测母线测流电阻,如果超过预定值即进入中断。

在下面即是 CMP 中断,经过计数后为 stru_Faults.B.HardCurretError = 1; 置位

interrupt.h 319 行

void CMP_IRQHandler(void)
{
    CMP_IF = BIT0 | BIT1;

    if(CMP_IF & (BIT1))
    {
        volatile u8 t_bi, t_bcnt;

        t_bcnt = 0;
        for(t_bi = 0; t_bi < 5; t_bi++)
        {
            if(SYS_AFE_CMP & BIT15) /* BIT14 CMP0 OUT Flag| BIT15 CMP1 OUT Flag */
            {   
                t_bcnt ++;
            }
        }

        if(t_bcnt > 3)
        {
            PWMOutputs(DISABLE);
            MCPWM_EIF = BIT4|BIT5;
            stru_Faults.B.HardCurretError = 1;// 硬件过流标志位置1
        }
    }
}

这颗 MCU 的MCPWM 也有过流检测的功能,在 MCPWM_IRQHandler 中断触发可以这样配置:

interrupt.h 167 行 MCPWM_IRQHandler 函数内

if((MCPWM_EIF & BIT4) || (MCPWM_EIF & BIT5))//MCPWM_FALL事件 硬件过流判断
{		   
    MCPWM_EIF = BIT4|BIT5;
    stru_Faults.B.HardCurretError = 1;// 硬件过流标志位置1
}

5.1.2 软件过流检测

在 adc 中断中,调用 FaultCurrentCheck 检测软件过流保护。原理是判断相电流的绝对值,如果大于目标就置位。

fault_detection.c 43 行

/*****************************************************************************
 * 函数名   : void FaultCurrentCheck(s16 Ia, s16 Ib, s16 Ic)
 * 说明     : 软件过流检测
 * 设计思路 :1. 如果三相电流绝对值超过设定的软件过流值,则判定为软件过流。
 * 参数     :Ia、Ib、Ic
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void FaultCurrentCheck(stru_CurrPhaseUVW *pstruCurrent)
{
    if((ABS(pstruCurrent->nPhaseU) > stru_FaultValue.nOverCurrent) || (ABS(pstruCurrent->nPhaseV) > stru_FaultValue.nOverCurrent) || (ABS(pstruCurrent->nPhaseW) > stru_FaultValue.nOverCurrent))
    {
        PWMOutputs(DISABLE);
        stru_Faults.B.SoftCurretError = 1;
    }
}

在这里规定了相线限流值

MC_Parameter.h 200 行

#define I_PH_OVERCURRENT_FAULT         (10.0)              /* 单位:A 软件过流检测设定值 */

上面的这个宏定义经过标幺化传给 stru_FaultValue.nOverCurrent 使用

fault_detection.c 359 行

void FaultInit(void)
{
    /********过流故障检测变量初始化*****/
    stru_FaultValue.nOverCurrent = App2CoreCurTrans(User2AppCurTrans(I_PH_OVERCURRENT_FAULT));
    ...
}

5.1.3 过欠压检测

在这里保存了欠压恢复相关的变量。

MC_Parameter.c 203 行

/*------------------------------------FaultDetection---------------------------*/
/* 过流检测参数 */
#define I_PH_OVERCURRENT_FAULT         (10.0)              /* 单位:A 软件过流检测设定值 */

/* 过欠压检测参数 */
#define U_DCB_OVERVOLTAGE_FAULT        (60.0)               /* 单位:V 过压检测设定值 */
#define U_DCB_OVERVOLTAGE_RECOVER      (59.5)               /* 单位:V 过压恢复设定值 */
#define U_DCB_UNDERVOLTAGE_FAULT       (20.0)               /* 单位:V 欠压检测设定值 */
#define U_DCB_UNDERVOLTAGE_RECOVER     (20.5)               /* 单位:V 欠压恢复设定值 */

/* 离水空转参数 */
#define I_PH_EMPTY_FAULT               (0.3)              /* 单位:A 空转检测电流设定值 */
#define SPEED_EMPTY_FAULT              (50.0)             /* 单位:Hz 空转检测转速设定值  */

/* 温度检测参数 */
#define TEMP_FAULT                     (150)              /* 过温检测设定值 */
#define TEMP_RECOVER                   (170)              /* 过温恢复设定值 */
#define TEMP_BREAK                     (4000)             /* NTC开路设定值 */
                                                                  
/* 堵转检测参数 */
#define SPEED_STALL_MAX_FAULT          (300.0)            /* 单位:Hz 堵转检测转速最大值 */
#define SPEED_STALL_MIN_FAULT          (10.0)             /* 单位:Hz 堵转检测转速最小值 */

#define I_PH_STALL_FAULT               (1.5)              /* 单位:A 堵转检测电流设定值 */

#define SPEED_STALL_FAULT              (20.0)             /* 单位:Hz 堵转检测转速设定值 */
#define IQ_STALL_FAULT                 (0.2)              /* 单位:A 堵转检测电流设定值 */

/* 二次启动检测参数 */
#define START_TIME_FAULT               (200)              /* 单位:5ms 开环之后1s内还不进入闭环就重启,1s这个时间根据实际应用调整 */

/* 缺相检测参数 */
#define I_PHASE_LOSS_FAULT             (3000)             /* 数字量,根据实际测试中struCurrentAmplitude.nPhA/struCurrentAmplitude.nPhB/struCurrentAmplitude.nPhC */
                                                          /* 的计算值来设定,在缺相和正常运行的中间取值。 */
/* 故障恢复时间 */
#define VOLT_FAULT_RECOVER_TIME        (2000)             /* 单位:ms  过欠压恢复时间 */
#define CURRENT_FAULT_RECOVER_TIME     (2000)             /* 单位:ms  过流恢复时间 */
#define STALL_FAULT_RECOVER_TIME       (2000)             /* 单位:ms  堵转恢复时间 */
#define PHASELOSS_FAULT_RECOVER_TIME   (2000)             /* 单位:ms  缺相恢复时间 */
#define TEMP_FAULT_RECOVER_TIME        (2000)             /* 单位:ms  过温恢复时间 */
#define START_FAULT_RECOVER_TIME       (1000)             /* 单位:ms  二次启动恢复时间 */
#define EMPTY_FAULT_RECOVER_TIME       (2000)             /* 单位:ms  离水空转恢复时间 */

 过欠压没有在中断里实现,而是在任务调度中调用 FaultCheck() 触发保护逻辑。

Task_Schedulter.c 53 行

/*******************************************************************************
 函数名称:    void Task_Scheduler(void)
 功能描述:    按时间片任务调度函数
 输入参数:    无
 输出参数:    无
 返 回 值:    无
 其它说明:
 修改日期      版本号          修改人            修改内容
 -----------------------------------------------------------------------------
 2020/8/5      V1.0           Howlet Li          创建
 *******************************************************************************/
void Task_Scheduler(void)
{
    volatile u32 t_data;

    if (struTaskScheduler.bTimeCnt1ms >= TASK_SCHEDU_1MS)
    {   /* 1毫秒事件,任务调度 */

        struTaskScheduler.bTimeCnt1ms = 0;

        SetTime_CountDown();  /* 倒计数函数计时处理 */

        FaultCheck();        //错误检测
        
        ...
    }
}

 其中,FaultCheck 是故障检测函数,在这里每隔 5ms 调用了电压检测函数

fault_detection.c 420 行

/***********************************************************************************
 * 函数名   : FaultCheck(void)
 * 说明     : 故障检测处理
 * 设计思路 :1.每个故障检测的处理周期为5ms
 * 参数     :无
 * 返回值   :无
 * 修改时间 :2020.08.17
 ***********************************************************************************/
void FaultCheck(void)
{
    static s16 t_nFlagCheck = 0;

    if(t_nFlagCheck < 5)
    {
        t_nFlagCheck ++;
    }
    else
    {
        t_nFlagCheck = 1;
    }


    switch(t_nFlagCheck)
    {
        case 1:
        { 
            FaultVoltageCheck(struFOC_CurrLoop.nBusVoltage, &struFaultVoltTime);                                        //过欠压检测
            break;
        }

 在这里是过欠压检测的函数实现

FaultVoltageCheck.c 62 行

/*****************************************************************************
 * 函数名   : void FaultVoltageCheck(s32 Udcb, stru_stru_FaultTime_t *FaultTime)
 * 说明     : 过欠压检测 
 * 设计思路 :1.当母线电压大于过压设定值则判定为过压故障;当母线电压小于欠压设定值 \
 *              则判定为欠压故障。滤波时间为1s,这个可根据实际需求修改。
 * 参数     :Udcb,stru_stru_FaultTime_t
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void FaultVoltageCheck(s32 Udcb, stru_FaultTime_t *pFaultTime)
{
    if(Udcb >= stru_FaultValue.nOverVoltage)    //母线电压大于过压设定值则时间累加
    {
        pFaultTime->nCheckCnt1 ++;
    }
    else if(Udcb < stru_FaultValue.nUnderVoltage) // 母线电压小于欠压设定值则时间累加
    {
        pFaultTime->nCheckCnt2 ++;
    }
    else
    {
        pFaultTime->nCheckCnt1 = 0;
        pFaultTime->nCheckCnt2 = 0;
    }

    if(pFaultTime->nCheckCnt1 >= 200)//时间超过1s则判定为过压
    {
        PWMOutputs(DISABLE);
        pFaultTime->nCheckCnt1 = 0;
        stru_Faults.B.VoltOverError = 1;//过压错误标志位置1
    }

    if(pFaultTime->nCheckCnt2 >= 200)//时间超过1s则判定为欠压
    {
        PWMOutputs(DISABLE);
        pFaultTime->nCheckCnt2 = 0;
        stru_Faults.B.VoltUnderError = 1;//欠压错误标志位置1
    }
}

5.1.3 其他保护检测关闭

Task_Scheduler.c 42 行 Task_Scheduler 函数

如果 发现错误置位后,就把 struFOC_CtrProc.eSysState = FAULT,也就是当前电机状态机设置为错误状态。

if(stru_Faults.R != 0)   //出现故障则进入FAULT状态
{
    struFOC_CtrProc.eSysState = FAULT;
            
    ...
}

5.2 错误恢复关闭

如果电机进入故障状态后,即等待 stru_Faults.R == 0 后恢复成空闲模式。

 state_machine.c 42 行 Sys_State_Machine 函数 系统状态机 电机状态各状态切换调度

...    
case FAULT:
    {
        /* 故障状态 */
        StateFault();                         //故障处理函数

        if (stru_Faults.R == 0)
        {
            struFOC_CtrProc.eSysState = IDLE;
        }

        break;
    }
...

 state_machine 是故障状态进行功能重启的逻辑函数,PWMOutputs(DISABLE) 直接禁用掉 pwm 输出。

state_machine.c 1057 行

/*****************************************************************************
 * 函数名   : void StateFault(void)
 * 说明     : 故障状态,主要是进行故障状态的重启处理
 * 设计思路 :1.在故障状态,如果检测到故障消失,则清零stru_Faults对应故障位。\
 * 参数     :无
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void StateFault(void)
{
    struFOC_CtrProc.bMC_RunFlg = 0;

    PWMOutputs(DISABLE);

    FaultRecover();    //故障恢复处理函数
}

 在这个函数中处理所有的故障恢复逻辑,其中包括了所有的错误恢复逻辑。

fault_detection.c 515 行

/***********************************************************************************
 * 函数名   : FaultRecover(void)
 * 说明     : 故障恢复程序处理
 * 设计思路 :1.过欠压恢复:       母线电压在正常工作范围内,持续2s则清除过欠压故障标志位; \
 *            2.软件&硬件过流恢复:2s后清除过流故障标志位;                                 \
 *            3.堵转恢复:         2s后清除堵转故障标志位;                                 \
 *            4.缺相恢复:         2s后清除过流故障标志位;                                 \
 *            5.过温恢复:         NTC在正常工作范围内,持续2s则清除过温故障标志位; \
 *            6.启动恢复:         1s后重启
 * 参数     :无
 * 返回值   :无
 * 修改时间 :2020.08.17
 ***********************************************************************************/
void FaultRecover(void)
{       
    /****************过欠压恢复****************/
    if((stru_Faults.B.VoltOverError == 1) || (stru_Faults.B.VoltUnderError == 1))
    {   //母线电压在欠压恢复值和过压恢复值之间则判定为正常状态
        if((struFOC_CurrLoop.nBusVoltage >= stru_FaultValue.nUnderVoltageRecover) 
          && (struFOC_CurrLoop.nBusVoltage <= stru_FaultValue.nOverVoltageRecover))
        {
            if(struFaultVoltTime.nRecoverCntr < VOLT_FAULT_RECOVER_TIME)     //滤波时间2s,然后清零过欠压故障标志位
            {
                struFaultVoltTime.nRecoverCntr ++;
            }
            else
            {
                stru_Faults.B.VoltOverError = 0;
                stru_Faults.B.VoltUnderError = 0;
                struFaultVoltTime.nRecoverCntr = 0;
            }
        }
        else
        {
            struFaultVoltTime.nRecoverCntr = 0;
        }
    }

    /****************过流恢复****************/
    if((stru_Faults.B.HardCurretError == 1) || (stru_Faults.B.SoftCurretError == 1))
    {
        if(struFaultCurrentTime.nRecoverCntr < CURRENT_FAULT_RECOVER_TIME)//2s后清零过流故障标志位
        {
            struFaultCurrentTime.nRecoverCntr ++;
        }
        else
        {
            if(stru_Faults.B.HardCurretError == 1)
            {
                stru_Faults.B.HardCurretError = 0;
            }

            if(stru_Faults.B.SoftCurretError == 1)
            {
                stru_Faults.B.SoftCurretError = 0;
            }

            struFaultCurrentTime.nRecoverTime ++;
            struFaultCurrentTime.nRecoverCntr = 0;
        }
    }

    /****************堵转恢复****************/
    if(stru_Faults.B.StallError == 1)
    {
        if(struFaultStallTime.nRecoverCntr < STALL_FAULT_RECOVER_TIME)   //2s后清零堵转故障标志位
        {
            struFaultStallTime.nRecoverCntr ++;
        }
        else
        {
            stru_Faults.B.StallError = 0;
            struFaultStallTime.nRecoverCntr = 0;
            stru_FaultValue.nStallFlag = 0;
        }
    }

    /****************离水空转恢复****************/
    if(stru_Faults.B.EmptyError == 1)
    {
        if(struFaultEmptyTime.nRecoverCntr < EMPTY_FAULT_RECOVER_TIME)//2s后清零离水空转故障标志位
        {
            struFaultEmptyTime.nRecoverCntr ++;
        }
        else
        {
            stru_Faults.B.EmptyError = 0;
            struFaultEmptyTime.nRecoverCntr = 0;
        }
    }

    /****************缺相恢复****************/
    if(stru_Faults.B.PhaseLossError == 1)
    {
        if(struFaultPhaseTime.nRecoverCntr < PHASELOSS_FAULT_RECOVER_TIME) //2s后清零缺相故障标志位
        {
            struFaultPhaseTime.nRecoverCntr ++;
        }
        else
        {
            stru_Faults.B.PhaseLossError = 0;
            struFaultPhaseTime.nRecoverCntr = 0;
        }
    }

    /****************过温恢复****************/
    if(stru_Faults.B.TempOverError == 1)
    {
        if((struAppCommData.nTempADC > TEMP_RECOVER) && (struAppCommData.nTempADC < TEMP_BREAK))//NTC阻值在设定阻值之间则判定为正常状态 
        {
            if(struFaultTempTime.nRecoverCntr < TEMP_FAULT_RECOVER_TIME)//滤波时间2s,然后清零过温故障标志位
            {
                struFaultTempTime.nRecoverCntr ++;
            }
            else
            {
                stru_Faults.B.TempOverError = 0;
                struFaultTempTime.nRecoverCntr = 0;
            }
        }
        else
        {
            struFaultTempTime.nRecoverCntr = 0;
        }
    }

    /****************启动失败恢复****************/
    if(stru_Faults.B.StartError == 1)
    {
        if(struFaultStartTime.nRecoverCntr < START_FAULT_RECOVER_TIME) //1s后清零缺相故障标志位
        {
            struFaultStartTime.nRecoverCntr ++;
        }
        else
        {
            stru_Faults.B.StartError = 0;
            struFaultStartTime.nRecoverCntr = 0;
            stru_FaultValue.nStartFlag = 0;
        }
    }
}

 故障恢复时间宏定义

 MC_Parameter.h  233 行

/* 故障恢复时间 */
#define VOLT_FAULT_RECOVER_TIME        (2000)             /* 单位:ms  过欠压恢复时间 */
#define CURRENT_FAULT_RECOVER_TIME     (2000)             /* 单位:ms  过流恢复时间 */
#define STALL_FAULT_RECOVER_TIME       (2000)             /* 单位:ms  堵转恢复时间 */
#define PHASELOSS_FAULT_RECOVER_TIME   (2000)             /* 单位:ms  缺相恢复时间 */
#define TEMP_FAULT_RECOVER_TIME        (2000)             /* 单位:ms  过温恢复时间 */
#define START_FAULT_RECOVER_TIME       (1000)             /* 单位:ms  二次启动恢复时间 */
#define EMPTY_FAULT_RECOVER_TIME       (2000)             /* 单位:ms  离水空转恢复时间 */

六、软件调试

6.1 预定位调试

电机的预定位(Pre-positioning)是指在电机启动前,通过特定控制策略将转子强制拉到已知的初始位置,以确保无传感器控制或位置传感器校准的准确性。

下面是预定义参数的一些宏定义,其中包括了预定位设置和强拖设置的电流和时间配置。

MC_Parameter.h 108 行

#define ALIGN_ANGLE                    (0)                /* 单位:度 预定位角度 */
#define U_START_CUR_SET_F              (1.5)              /* 单位: A 第一段定位电流 */
#define U_START_CUR_SET_S              (3.0)              /* 单位: A 第二段定位电流 */
#define DC_HOLDTIME_TIME_LENTH         (50)               /* 单位: ms 第一段定位时间 */
#define DC_HOLDTIME_TIME_LENTH_STAGE1  (100)               /* 单位: ms 第二段定位时间 */
#define DC_ALIGN_TOTAL_LENTH            \
       (DC_HOLDTIME_TIME_LENTH + DC_HOLDTIME_TIME_LENTH_STAGE1)/* 定位总时长 */

#define ALIGN_CURRENT_ACC              (0.5)              /* 单位: (1/8)A/ms  定位电流加速调整值  初始位置检测使能后给到最大值,不能超过30,否则数据会溢出。 */
#define ALIGN_CURRENT_DEC              (0.5)              /* 单位: (1/8)A/ms  定位电流减速调整值  初始位置检测使能后给到最大值,不能超过30,否则数据会溢出。 */

 其中 C28 是自举电容是自举电路,为 VB 端提供超过 VCC_PROWER 的电压,提高驱动 MOS 的能力,因为 NMOS 管的导通基本条件就是 VGS 大于一定的阈值电压 VGS(th)。

自举电路就是升压电路,简单来说在该电路中, 自举电路的作用是使得 LKS560 高端驱动,即 IR2110S 的第 8 引脚 HO 输出信号 可以满足大于 VGS(th) 。

在第一次启动时,如果我们先开的是上管,就需要提前打开下管,使得 C28 一侧与地导通,这样C28 正极的电压就是 15V 减去 D1 二极管的压降,这样才可以给自举电容充电,这样才能满足上管的 VGS(th) 的导通电压。

在下面可以设置自举电容预充电时间。

MC_Parameter.h 78 行

/* ----------------------------预驱自举电容预充电参数--------------------------- */
#define CHARGE_TIME                    (100)              /* 每相预充电时间,根据实际硬件参数修改 */

下面的代码是预充电函数,大致意思是根据占空比开下管充电,使得 C28 一侧与地导通。

/*****************************************************************************
 * 函数名   : void StateCharge(void)
 * 说明     : 预充电函数,对自举电容进行预充电,对于不同的硬件要注意调整预充电时间
 * 设计思路 :依次打开A相、B相、C相下桥,对自举电容充电。
 * 参数     :无
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void StateCharge(void)
{
    if (struAppCommData.bChargeFlag == 0)
    {
        struAppCommData.bChargeFlag = 1;

        struFOC_CurrLoop.mVoltUVW_PWM.nPhaseU = (u16)(PWM_PERIOD * 0.3); //预充电占空比
        struFOC_CurrLoop.mVoltUVW_PWM.nPhaseV = (u16)(PWM_PERIOD * 0.3); //预充电占空比
        struFOC_CurrLoop.mVoltUVW_PWM.nPhaseW = (u16)(PWM_PERIOD * 0.3); //预充电占空比

        struFOC_CurrLoop.mVoltUVW_NegPWM.nPhaseU = -struFOC_CurrLoop.mVoltUVW_PWM.nPhaseU;
        struFOC_CurrLoop.mVoltUVW_NegPWM.nPhaseV = -struFOC_CurrLoop.mVoltUVW_PWM.nPhaseV;
        struFOC_CurrLoop.mVoltUVW_NegPWM.nPhaseW = -struFOC_CurrLoop.mVoltUVW_PWM.nPhaseW;

        struFOC_CurrLoop.MCPWMx_RegUpdate();          /* 加载MCPWM模块占空比值,加载MCPWM模块ADC触发点寄存器值 */

        struTime.nChargeTime  = 0;
    }
    else
    {
        if (struTime.nChargeTime == 0)  //打开A相下桥PWM
        {
            MCPWM_PRT = 0x0000DEAD;

            MCPWM_IO01 = 0x0C08 | mIPD_CtrProc.hDriverPolarity;
            MCPWM_IO23 = 0x000C | mIPD_CtrProc.hDriverPolarity;

            MCPWM_PRT = 0x0000;

            PWMOutputs(ENABLE);    //使能输出
            __nop();
        }
        else if (struTime.nChargeTime == CHARGE_TIME)  //打开B相下桥PWM
        {
            MCPWM_PRT = 0x0000DEAD;
            MCPWM_IO01 = 0x080C | mIPD_CtrProc.hDriverPolarity;
            MCPWM_PRT = 0x0000;
            __nop();
        }
        else if (struTime.nChargeTime == CHARGE_TIME * 2) //打开C相下桥PWM
        {
            MCPWM_PRT = 0x0000DEAD;
            MCPWM_IO23 = 0x08 | mIPD_CtrProc.hDriverPolarity;
            MCPWM_PRT = 0x0000;
            __nop();
        }

        if (struTime.nChargeTime < (CHARGE_TIME * 3))  //CHARGE_TIME为每段预充电时间,可根据硬件实际设置
        {
            struTime.nChargeTime ++ ;
        }
        else
        {
            PWMOutputs(DISABLE);
            __disable_irq();

            struFOC_CurrLoop.mVoltUVW_PWM.nPhaseU = 0;
            struFOC_CurrLoop.mVoltUVW_PWM.nPhaseV = 0;    /* 清零MCPWM比较值寄存器 */
            struFOC_CurrLoop.mVoltUVW_PWM.nPhaseW = 0;

            struFOC_CurrLoop.mVoltUVW_NegPWM.nPhaseU = -struFOC_CurrLoop.mVoltUVW_PWM.nPhaseU;
            struFOC_CurrLoop.mVoltUVW_NegPWM.nPhaseV = -struFOC_CurrLoop.mVoltUVW_PWM.nPhaseV;
            struFOC_CurrLoop.mVoltUVW_NegPWM.nPhaseW = -struFOC_CurrLoop.mVoltUVW_PWM.nPhaseW;

            struFOC_CurrLoop.MCPWMx_RegUpdate();          /* 加载MCPWM模块占空比值,加载MCPWM模块ADC触发点寄存器值 */
            MCPWM_UPDATE = 0xFF;

            MCPWM_init();
            ADC_STATE_RESET();
            __enable_irq();
            struAppCommData.bChargeEndFlag = 1;
        }
    }

    if (struAppCommData.bChargeEndFlag == 1) //预充电完成
    {
        struAppCommData.bChargeFlag = 0;
        struTime.nChargeTime = 0;
        struAppCommData.bChargeEndFlag = 0;

        StateInit();

#if (DIR_BEMF_CHECK_STATUS == TRUE)
#if DIR_BEMF_CHECK_MODE
        //软件估算顺逆风需要开启PWM
        PWMOutputs(ENABLE);
        struFOC_CtrProc.eSysState = DIR_CHECK;
#else
        //反电动势检测电路需要管关闭PWM
        PWMOutputs(DISABLE);
        struFOC_CtrProc.eSysState = BEMF_CHECK;
#endif
#else
#if (SEEK_POSITION_STATUS == TRUE)  //如果初始位置检测状态使能,则进入初始位置检测状态
        {
            struFOC_CtrProc.eSysState = POS_SEEK;
            PWMOutputs(DISABLE);
        }
#elif (SEEK_POSITION_STATUS == FALSE) //如果初始位置检测状态不使能,则进入预定位状态,给定预定位角度
        {
            struFOC_CtrProc.eSysState = INIT;
            struFluxOB_Param.wElectAngleOpen = ((u32)(User2AppAngleTrans(ALIGN_ANGLE) * (u32)struApp2Core.angle >> (struApp2Core.angleShftNum))) << 16;
        }
#endif
#endif

    }
}

6.2 开环强拖

MC_Parameter.h 119 行

/*---------------------------------开环参数------------------------------------*/
#define OPEN_ANGLE_TAG_FREQ            (20.0)             /* 单位:Hz 开环拖动最终频率 */
#define FREQ_ACC                       (5.0)              /* 单位:(1/128)Hz/ms 开环拖动频率加速调整值 */
#define FREQ_DEC                       (5.0)              /* 单位:(1/128)Hz/ms 开环拖动频率减速调整值 */

#define OPEN_RUN_STATUS                (FALSE)             /* 开环状态 TRUE = 开环运行, FALSE = 闭环运行 */
  
#define MATCH_TIME                     (5)                /* 估算和给定电流匹配次数 */

电机频率 (f) 是指电机每秒钟所完成的旋转周期数,通常以赫兹 (Hz) 作为单位进行表示。电机频率是电机运行时最基本的参数之一,直接影响着电机的性能和运行状态,公式为:

n_{s}=\frac{60f}{p}

  • ns​ 为同步转速 (rpm)
  • f 为电源频率 (Hz)
  • p 为电机极对数

下面的代码使用 SpeedReferenceGen(&mOpenForceRun) 输出一个电机频率,然后满足预定位的误差五次计数即开启强拖运行。

state_machine.c 809 行

/*****************************************************************************
 * 函数名   : void StateOpen(void)
 * 说明     : 电机强拖程序
 * 设计思路 :1.给定电机强拖频率、强拖电流、强拖加速度,使电机从静止开始拖动到设定的强拖频率。           \
              2.当电机达到设定频率,且估算角度和强拖角度误差在(10.98°~ 98.87°)之内则判断为估算         \
                已经跟随到强拖角度,连续5次则从开环切换到闭环。                                          \
              3.由于强拖给定的是Id,所以在程序留了从Id-->Iq电流的切换时间,切换时间的长短依照实际电机负载\
                来调整。(总的原则,负载轻则切换时间短;负载重则切换时间长,对于灯扇类应用则可以适当延长,\
                等扇叶完全展开后再切入速度闭环。                                                         \
              4.开环状态用来测试电机极对数,计算公式:极对数N = 60f/Speed ,其中f为电机电频率,Speed为电机\
                机械转速。
 * 参数     :无
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void StateOpen(void)
{
    if (struAppCommData.bOpenRunFlag == 0)
    {
        if (struFOC_CtrProc.bMotorDirtionCtrl == CW)  //根据运行方向,调整强拖频率的方向
        {
            mOpenForceRun.wOpen2CloseFreq = struAppCommData.wSvcMinFreq;  //顺时针则频率给正
        }
        else
        {
            mOpenForceRun.wOpen2CloseFreq = -struAppCommData.wSvcMinFreq; //逆时针则频率给负
        }

        mOpenForceRun.nFreqAccStep = User2AppFreqTrans(FREQ_ACC);         //强拖频率加速调整值
        mOpenForceRun.nFreqDecStep = User2AppFreqTrans(FREQ_DEC);         //强拖频率减速调整值

        SpeedReferenceGen(&mOpenForceRun);  //强拖频率爬坡程序
        struMotorSpeed.wSpeedSet = mOpenForceRun.wRampFreqRef >> 7;
        struMotorSpeed.wSpeedRef = App2CoreFreqTrans(struMotorSpeed.wSpeedSet);

        if (struMotorSpeed.wSpeedSet == mOpenForceRun.wOpen2CloseFreq)    //电机达到设定的拖动频率
        {
            struAppCommData.wThetaErr = struFluxOB_Param.wElectAngleEst - struFluxOB_Param.wElectAngleOpen; //计算估算角度和强拖给定角度的误差
            struAppCommData.wThetaErr = ABS(struAppCommData.wThetaErr) >> 16;

            if ((struAppCommData.wThetaErr > 2000) && (struAppCommData.wThetaErr < 18000)) //估算角度和强拖给定角度误差在(10.98°~ 98.87°)之间则判断为估算正确。
            {
                struAppCommData.nMatchCnt ++;
            }
            else
            {
                struAppCommData.nMatchCnt = 0;
            }

            if (struAppCommData.nMatchCnt > MATCH_TIME)   //角度误差连续5次在设定范围内则进入估算闭环
            {
#if (OPEN_RUN_STATUS == TRUE)
                {
                }
#elif (OPEN_RUN_STATUS == FALSE)
                {
                    struFOC_CtrProc.eSysState = RUN;

                    struAppCommData.bOpenRunFlag = 1;

                    if (struFOC_CtrProc.bMotorDirtionCtrl == CW)
                    {
                        struFOC_CurrLoop.nQCurrentSet = App2CoreCurTrans(User2AppCurTrans(U_START_CUR_SET_S));
                    }
                    else if (struFOC_CtrProc.bMotorDirtionCtrl == CCW)
                    {
                        struFOC_CurrLoop.nQCurrentSet = -App2CoreCurTrans(User2AppCurTrans(U_START_CUR_SET_S));
                    }

                    struFOC_CurrLoop.nDCurrentSet = App2CoreCurTrans(User2AppCurTrans(U_START_CUR_SET_F));//d轴电流给定,由于开环拖动给定的是Id,闭环估算时Id逐渐将为0,Iq逐渐从0加到给定值
                    //所以切换到闭环后预留了电流切换时间。如果电流切换的速度过快,则会造成转矩波动。

                    struAppCommData.nCurrentACC = App2CoreCurTrans(User2AppCurTrans(OPEN2CLOSE_RUN_CURRENT_RAMP));//电流加速调整值
                    struAppCommData.nCurrentDEC = App2CoreCurTrans(User2AppCurTrans(OPEN2CLOSE_RUN_CURRENT_RAMP));//电流减速调整值

                    CurrentLoopAxisD_Set();
                    CurrentLoopAxisQ_Set();

                }
#endif
            }
        }
    }
}

6.3 开环切闭环

MC_Parameter.h 129 行

#define OPEN2CLOSE_RUN_COV_TIME        (30)               /* 开环闭环切换过渡时间:单位:mS */
#define OPEN2CLOSE_RUN_CURRENT_RAMP    (0.1)             /* 开环闭环切换过渡内,D,Q轴电流变化斜率。单位:A/ms */

state_machine.c 129 行

case RUN:
{
    /* 运行状态  */

    StateRun();                               //闭环处理函数
    break;
}

当电机频率指定正确后切换状态机 struFOC_CtrProc.eSysState = RUN 到 StateRun(void) 真正开始强拖。 

StateRun.c 880 行

/*****************************************************************************
 * 函数名   : void StateOpen(void)
 * 说明     : 电机run状态处理程序,一般为速度环、功率环的处理
 * 设计思路 :1.根据实际负载计算速度/功率/电流的爬坡、速度环/功率环的PI       \
 * 参数     :无
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
float Iq_Set = 0.8;
void StateRun(void)
{
    if (struAppCommData.bOpenRunFlag == 1) //DQ轴电流切换程序
    {
        if (struTime.nOpenRunCntr < OPEN2CLOSE_RUN_COV_TIME)
        {
            // 这段时间内,使Iq逐渐上升到开环拖动电流,Id逐渐降低为第一段定位电流。时间长短跟负载匹配。
            struTime.nOpenRunCntr++;
            /* D/Q轴电流变化斜率设置 */
            struAppCommData.nCurrentACC = App2CoreCurTrans(User2AppCurTrans(OPEN2CLOSE_RUN_CURRENT_RAMP));
            struAppCommData.nCurrentDEC = App2CoreCurTrans(User2AppCurTrans(OPEN2CLOSE_RUN_CURRENT_RAMP));
        }
        else
        {
            //Id设置为0,根据实际设置,计算速度环或者功率环
            struTime.nOpenRunCntr = 0;
            struAppCommData.bOpenRunFlag = 2;

            struAppCommData.nCurrentACC = App2CoreCurTrans(User2AppCurTrans(TORQUE_MODE_CURRENT_CHANGE_ACC));
            struAppCommData.nCurrentDEC = App2CoreCurTrans(User2AppCurTrans(TORQUE_MODE_CURRENT_CHANGE_DEC));

            if (struFOC_CtrProc.bMotorDirtionCtrl == CW)
            {
                struFOC_CurrLoop.nQCurrentSet = App2CoreCurTrans(User2AppCurTrans(IQ_SET));      //Q轴电流给定
            }
            else if (struFOC_CtrProc.bMotorDirtionCtrl == CCW)
            {
                struFOC_CurrLoop.nQCurrentSet = -App2CoreCurTrans(User2AppCurTrans(IQ_SET));    //Q轴电流给定
            }
        }
    }
    else if (struAppCommData.bOpenRunFlag == 2)
    {

        /*******************速度环处理*******************************/
#if (CLOSE_LOOP == SPEED_LOOP)
        {
            if (struTime.nLoopDelyTime < STATE04_WAITE_TIME)//速度环参数初始化时间,大部分应用设置为100ms
            {
                struTime.nLoopDelyTime ++;

                struMotorSpeed.mSpeedPI.wIntegral = (s64)struFOC_CurrLoop.nQCur_Reference << 22;
                struMotorSpeed.wSpeedRef = struMotorSpeed.wSpeedfbk;
            }
            else
            {
                if (++struAppCommData.nLoopCntr >= SPEED_LOOP_CNTR)   //速度环环路计算周期。
                {
                    struAppCommData.nLoopCntr = 0;

                    if (struTime.nLoopDelyTime == STATE04_WAITE_TIME)  //首次进入速度环,速度环的初始值设置为Iq。
                    {
                        struTime.nLoopDelyTime ++;
                        struMotorSpeed.mSpeedPI.wIntegral = (s64)struFOC_CurrLoop.nQCurrentSet << 22;
                        struMotorSpeed.wSpeedRef = struMotorSpeed.wSpeedfbk;
                    }

#if (POWER_LIMIT_STATUS == TRUE)          //限功率使能,速度环限制最大输出功率
                    {
                        PowerLimitCalc(&struMotorSpeed, struPower.wPowerValue);
                        struMotorSpeed.wSpeedSet = struMotorSpeed.wPowerLimitSpeedRef - struMotorSpeed.wPowerLimitSpeedSet;
                    }
#elif (POWER_LIMIT_STATUS == FALSE)
                    {
                        //调速指令,速度参考给定SPEED_SET 单位Hz
                        //struMotorSpeed.wSpeedSet = App2CoreFreqTrans(User2AppFreqTrans(SPEED_SET)); //速度参考给定
                        struMotorSpeed.wSpeedSet = struAppCommData.wSpeedValue;

                    }
#endif

                    if (struFOC_CtrProc.bMotorDirtionCtrl == CW)
                    {
                        if (struMotorSpeed.wSpeedSet < 0)
                        {
                            struMotorSpeed.wSpeedSet = -struMotorSpeed.wSpeedSet;
                        }
                    }
                    else if (struFOC_CtrProc.bMotorDirtionCtrl == CCW)
                    {
                        if (struMotorSpeed.wSpeedSet > 0)
                        {
                            struMotorSpeed.wSpeedSet = - struMotorSpeed.wSpeedSet;
                        }
                    }

                    SpeedLoop_Set(&struMotorSpeed); //速度爬坡

                    SpeedLoopReg(&struMotorSpeed);// 速度环PI计算

                }
            }
        }

        /*******************电流环处理*******************************/
#elif (CLOSE_LOOP == CURRENT_LOOP)
        {

            if (struFOC_CtrProc.bMotorDirtionCtrl == CW)
            {
                struFOC_CurrLoop.nQCurrentSet = App2CoreCurTrans(User2AppCurTrans(Iq_Set));
            }
            else if (struFOC_CtrProc.bMotorDirtionCtrl == CCW)
            {
                struFOC_CurrLoop.nQCurrentSet = -App2CoreCurTrans(User2AppCurTrans(Iq_Set));
            }
				    struMotorSpeed.wSpeedRef =  struMotorSpeed.wSpeedfbk;
        }

        /*******************功率环处理*******************************/
#elif (CLOSE_LOOP == POWER_LOOP)
        {
            if (++struAppCommData.nLoopCntr >= POWER_LOOP_CNTR) //功率环环路计算周期。
            {
                struAppCommData.nLoopCntr = 0;

#if(SPPED_LIMIT_STATUS == TRUE)     //限速功能使能 ,功率环限制最大转速。
                {
                    SpeedLimitCalc(struMotorSpeed.wSpeedfbk, &struPower);  //限速度计算
                    
                    struPower.wPowerSet = struPower.wSpeedLimitPowerRef - struPower.wSpeedLimitPowerSet;      // 根据限速度函数的输出设置给定功率
                }
#elif (SPPED_LIMIT_STATUS == FALSE)
                {
                    struPower.wPowerSet = POWER_CALC(POWER_SET);//功率参考给定
                }
#endif

                if (struFOC_CtrProc.bMotorDirtionCtrl == CW)
                {
                    struPower.wPowerSet = struPower.wPowerSet;
                    struPower.wPowerValue = struPower.wPowerValue;
                }
                else if (struFOC_CtrProc.bMotorDirtionCtrl == CCW)
                {
                    struPower.wPowerSet = -struPower.wPowerSet;
                    struPower.wPowerValue = -struPower.wPowerValue;
                }

                if (struAppCommData.nPowerFistFlag == 0) //首次进入速度环,功率环的初始值设置为Iq
                {
                    struAppCommData.nPowerFistFlag = 1;
                    struPower.struPowerRamp.wRef = struPower.wPowerValue;
                    struPower.struPowerPI.wIntegral = ((s32)struFOC_CurrLoop.nQCur_Reference << 16);
                }

                struPower.struPowerRamp.wSet = struPower.wPowerSet;
                struPower.wPowerRef = RampControl(&struPower.struPowerRamp);    //功率环爬坡函数

                PowerLoopReg(&struPower);                 //功率环PI计算
            }
        }
#endif
    }

    struFOC_CurrLoop.nDCurrentSet = 0;       //Id设置为0
    CurrentLoopAxisD_Set();
    CurrentLoopAxisQ_Set();

}

6.4 电流闭环

6.4.1 期望 Iq 电流设置

待补充

MC_Parameter.c 143 行

/*----------------------------------电流环参数---------------------------------*/
#define IQ_SET                         (0.3)              /* 单位:A IqRef,Iq给定值 */
 
#define VQMAX                          (6000)             /* Q轴最大输出限制,Q15格式,取值范围0~6000 */
#define VQMIN                          (-6000)            /* Q轴最小输出限制,Q15格式,取值范围0~-6000 */

#define VDMAX                          (6000)             /* D轴最大输出限制,Q15格式,取值范围0~6000 */
#define VDMIN                          (-6000)            /* D轴最小输出限制,Q15格式,取值范围0~6000 */

#define P_CURRENT_KP                   (4000)             /* 电流环Kp,实际运用的Kp会根据这个值和电机参数计算出最终的Kp */
#define P_CURRENT_KI                   (2000)             /* 电流环Ki,实际运用的Kp会根据这个值和电机参数计算出最终的Ki */

#define AUTO_FW_LIM                    ((s16)0)            /* 自动弱磁D轴电流限制,Q12格式,最大值 4096 */

#define TORQUE_MODE_CURRENT_CHANGE_ACC (0.1)              /* 单位:A/ms 电流加速调整值 */
#define TORQUE_MODE_CURRENT_CHANGE_DEC (0.1)              /* 单位:A/ms 电流减速调整值 */

state_machine.c 982 行

        /*******************电流环处理*******************************/
#elif (CLOSE_LOOP == CURRENT_LOOP)
        {

            if (struFOC_CtrProc.bMotorDirtionCtrl == CW)
            {
                struFOC_CurrLoop.nQCurrentSet = App2CoreCurTrans(User2AppCurTrans(Iq_Set));
            }
            else if (struFOC_CtrProc.bMotorDirtionCtrl == CCW)
            {
                struFOC_CurrLoop.nQCurrentSet = -App2CoreCurTrans(User2AppCurTrans(Iq_Set));
            }
				    struMotorSpeed.wSpeedRef =  struMotorSpeed.wSpeedfbk;
        }

state_machine.c 983 行

/*******************************************************************************
 函数名称:    void ADC0_IRQHandler(void)
 功能描述:    ADC0中断处理函数
 输入参数:    无
 输出参数:    无
 返 回 值:    无
 其它说明:
 修改日期      版本号          修改人            修改内容
 -----------------------------------------------------------------------------
 2020/8/5      V1.0           Howlet Li          创建
 *******************************************************************************/
void ADC0_IRQHandler(void)
{
    ...
    FOC_Model(&struFOC_CtrProc);              /* FOC电流内环 */
    ...
}

state_machine.c 983 行

/*******************************************************************************
 函数名称:    CurrentLoopReg(stru_FOC_CurrLoopDef *this)
 功能描述:    D、Q轴电流计算,输出Vd、Vq
 输入参数:    stru_FOC_CurrLoopDef *this  结构体指针
 输出参数:    无
 返 回 值:    无
 其它说明:
 修改日期      版本号          修改人            修改内容
 -----------------------------------------------------------------------------
 2020/8/5      V1.0           Howlet Li          创建
 *******************************************************************************/
void CurrentLoopReg(stru_FOC_CurrLoopDef *this)
{
    this->mPI_Torque.wInError = this->nQCur_Reference - this->mStatCurrDQ.nAxisQ; /* Q轴输入误差 */
    this->mPI_Flux.wInError   = this->nDCur_Reference - this->mStatCurrDQ.nAxisD + this->npmsmSvcImFw; /* D轴输入误差 */

    /* 误差限幅,可根据实际负载调整,影响PI响应的快慢 */
    this->mPI_Torque.wInError = sat(this->mPI_Torque.wInError, -0x800, 0x800);
    this->mPI_Flux.wInError   = sat(this->mPI_Flux.wInError, -0x800, 0x800);

#if SVPWM_MODE
    this->mStatVoltDQ.nAxisQ = 0;        /* Q轴电流PI计算,输出Vq 4096 对应额定电压*/
    this->mStatVoltDQ.nAxisD = 600;     /* D轴电流PI计算, 输出Vd 4096 对应额定电压*/
#else
    this->mStatVoltDQ.nAxisQ = CurrentPIRegulator(&this->mPI_Torque);   /* Q轴电流PI计算,输出Vq */
    this->mStatVoltDQ.nAxisD = CurrentPIRegulator(&this->mPI_Flux);     /* D轴电流PI计算,输出Vd */
#endif
	
    ModuCircle_Limitation();  /* 电压极限圆限制 */
}

6.4.2 电流斜坡设置

待补充

state_machine.c 1162 行

/*******************************************************************************
 函数名称:    void CurrentLoopAxisD_Set(void)
 功能描述:    电流环D轴电流参考斜坡给定
 输入参数:    无
 输出参数:    无
 返 回 值:    无
 其它说明:
 修改日期      版本号          修改人            修改内容
 -----------------------------------------------------------------------------
 2020/8/5      V1.0           Howlet Li          创建
 *******************************************************************************/
void CurrentLoopAxisD_Set(void)
{
    if (struFOC_CurrLoop.nDCur_Reference > struFOC_CurrLoop.nDCurrentSet)
    {
        if ((struFOC_CurrLoop.nDCur_Reference - struFOC_CurrLoop.nDCurrentSet) > struAppCommData.nCurrentDEC)
        {
            struFOC_CurrLoop.nDCur_Reference -= struAppCommData.nCurrentDEC;
        }
        else
        {
            struFOC_CurrLoop.nDCur_Reference --;
        }
    }

    if (struFOC_CurrLoop.nDCur_Reference <= struFOC_CurrLoop.nDCurrentSet)
    {
        if ((struFOC_CurrLoop.nDCurrentSet - struFOC_CurrLoop.nDCur_Reference) > struAppCommData.nCurrentACC)
        {
            struFOC_CurrLoop.nDCur_Reference += struAppCommData.nCurrentACC;
        }
        else
        {
            struFOC_CurrLoop.nDCur_Reference ++;
        }

    }

}

6.4.3 电流环 KP & KI 细调

待补充

6.5 速度环

6.5.1 期望速度设定

interrupt.c  84 行

struAppCommData.nVspADC = (s16)ADC0_DAT5; /*电位器信号采样结果*/

StateRun.c 888 行

/***********************VSP检测设定****************************/ 
#define VSP_OFF               (1000.0) //电位器关机电压     计算公式:  0.2/3.6*32767 ,0.2为关机电压
#define VSP_MIN               (1500.0) //电位器电压最小值   计算公式:  0.3/3.6*32767 ,0.3为最小电压
#define VSP_MAX               (27380.0)//电位器电压最大值  计算公式:   2.2/3.6*32767 ,2.2为最大电压

#define VSP_SPEED_MIN         (30.0)    //单位:Hz
#define VSP_SPEED_MAX         (220.0)   //单位:Hz

#define VSP_SPEED_SCALE       (float)(VSP_SPEED_MAX - VSP_SPEED_MIN)/(VSP_MAX - VSP_MIN)  //PWM 调速斜率

StateRun.c 888 行

/*****************************************************************************
 * 函数名   : VspSpeedScan(void)
 * 说明     : 
 * 设计思路 :1.根据检测到电压计算对应转速
 * 参数     :无
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void VspSpeedScan(void)
{
    if(struAppCommData.nVspADC < VSP_OFF)
    {
        struFOC_CtrProc.bMC_RunFlg = 0;
    }
    else if(struAppCommData.nVspADC < VSP_MIN)
    {
         struAppCommData.wVSPSpeedSet = VSP_SPEED_MIN;
        
        if((struFOC_CtrProc.bMC_RunFlg == 0) && (stru_Faults.R == 0))
        {
            struFOC_CtrProc.bMC_RunFlg = 1;
        }
    }
    else if(struAppCommData.nVspADC  < VSP_MAX)
    {
        struAppCommData.wVSPSpeedSet = (VSP_SPEED_SCALE * (struAppCommData.nVspADC - VSP_MIN)) + VSP_SPEED_MIN;
        
        if((struFOC_CtrProc.bMC_RunFlg == 0) && (stru_Faults.R == 0))
        {
            struFOC_CtrProc.bMC_RunFlg = 1;
        }
        
    }
    else
    {
        struAppCommData.wVSPSpeedSet = VSP_SPEED_MAX;

        if((struFOC_CtrProc.bMC_RunFlg == 0) && (stru_Faults.R == 0))
        {
            struFOC_CtrProc.bMC_RunFlg = 1;
        }
    }
    struAppCommData.wSpeedValue = App2CoreFreqTrans(User2AppFreqTrans(struAppCommData.wVSPSpeedSet));
 		
}

6.5.2 速度环输出 IQMAX & IQMIN 设置

待补充

6.5.3 速度环 KP & KI

待补充

6.5.4 速度斜坡设置

SpeedScan.c 923 行

        /*******************速度环处理*******************************/
#if (CLOSE_LOOP == SPEED_LOOP)
        {
            if (struTime.nLoopDelyTime < STATE04_WAITE_TIME)//速度环参数初始化时间,大部分应用设置为100ms
            {
                struTime.nLoopDelyTime ++;

                struMotorSpeed.mSpeedPI.wIntegral = (s64)struFOC_CurrLoop.nQCur_Reference << 22;
                struMotorSpeed.wSpeedRef = struMotorSpeed.wSpeedfbk;
            }
            else
            {
                if (++struAppCommData.nLoopCntr >= SPEED_LOOP_CNTR)   //速度环环路计算周期。
                {
                    struAppCommData.nLoopCntr = 0;

                    if (struTime.nLoopDelyTime == STATE04_WAITE_TIME)  //首次进入速度环,速度环的初始值设置为Iq。
                    {
                        struTime.nLoopDelyTime ++;
                        struMotorSpeed.mSpeedPI.wIntegral = (s64)struFOC_CurrLoop.nQCurrentSet << 22;
                        struMotorSpeed.wSpeedRef = struMotorSpeed.wSpeedfbk;
                    }

#if (POWER_LIMIT_STATUS == TRUE)          //限功率使能,速度环限制最大输出功率
                    {
                        PowerLimitCalc(&struMotorSpeed, struPower.wPowerValue);
                        struMotorSpeed.wSpeedSet = struMotorSpeed.wPowerLimitSpeedRef - struMotorSpeed.wPowerLimitSpeedSet;
                    }
#elif (POWER_LIMIT_STATUS == FALSE)
                    {
                        //调速指令,速度参考给定SPEED_SET 单位Hz
                        //struMotorSpeed.wSpeedSet = App2CoreFreqTrans(User2AppFreqTrans(SPEED_SET)); //速度参考给定
                        struMotorSpeed.wSpeedSet = struAppCommData.wSpeedValue;

                    }
#endif

                    if (struFOC_CtrProc.bMotorDirtionCtrl == CW)
                    {
                        if (struMotorSpeed.wSpeedSet < 0)
                        {
                            struMotorSpeed.wSpeedSet = -struMotorSpeed.wSpeedSet;
                        }
                    }
                    else if (struFOC_CtrProc.bMotorDirtionCtrl == CCW)
                    {
                        if (struMotorSpeed.wSpeedSet > 0)
                        {
                            struMotorSpeed.wSpeedSet = - struMotorSpeed.wSpeedSet;
                        }
                    }

                    SpeedLoop_Set(&struMotorSpeed); //速度爬坡

                    SpeedLoopReg(&struMotorSpeed);// 速度环PI计算

                }
            }
        }

state_machine.c 1231 行 

/*******************************************************************************
 函数名称:    void SpeedLoop_Set(MechanicalQuantity *this)
 功能描述:    速度参考斜坡函数
 输入参数:    无
 输出参数:    无
 返 回 值:    无
 其它说明:
 修改日期      版本号          修改人            修改内容
 -----------------------------------------------------------------------------
 2020/10/8      V1.0           Andrew Kong          创建
 *******************************************************************************/
void SpeedLoop_Set(MechanicalQuantity *this)
{
    if (this->wSpeedRef < this->wSpeedSet)
    {
        this->wSpeedRef += this->wSpeedRampACCStep;

        if (this->wSpeedRef >= this->wSpeedSet)
        {
            this->wSpeedRef = this->wSpeedSet;
        }
    }

    if (this->wSpeedRef > this->wSpeedSet)
    {
        this->wSpeedRef -= this->wSpeedRampDECStep;

        if (this->wSpeedRef <= this->wSpeedSet)
        {
            this->wSpeedRef = this->wSpeedSet;
        }
    }
}

6.5.5 速度环限功率

待补充

6.8 初始位置检查

state_machine.c 1231 行

/*****************************************************************************
 * 函数名   : void StatePosSeek(void)
 * 说明     : 初始位置检测程序,电机静止状态检测电机电角度
 * 设计思路 :采用脉冲注入方式,检测电机静止状态的电角度
 * 参数     :无
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void StatePosSeek(void)
{
    mIPD_CtrProc.bIPD_State = 1;                             /* 调置为IPD检测状态 */
    mIPD_CtrProc.bIPD_StepFlg = 0;
    mIPD_CtrProc.bCurrentSampleType = CURRENT_SAMPLE_TYPE;

    mIPD_CtrProc.wIPD_PlusWidthSet = IPD_PLUS_TIME_WIDTH;    /* 脉冲注入宽度 */
    mIPD_CtrProc.wIPD_IdleWaitSet = IPD_PLUS_WAIT_TIME;      /* 脉冲注入后,电流衰减到零等待时间设置 */
    mIPD_CtrProc.nPWM_PERIOD = PWM_PERIOD;

    ADC_SOFTWARE_TRIG_ONLY();
    ADC_STATE_RESET();

    __disable_irq();                  /* 关闭中断 中断总开关 */
    IPD_RotorPosEst();                /* 6脉冲注入,初始位置检测 */
    __enable_irq();                   /* 开启总中断 */

    ADC0_init();                      /* ADC初始化 */
    MCPWM_init();                     /* PWM初始化 */

    if (struFOC_CtrProc.bMotorDirtionCtrl == CW)
    {
        struFluxOB_Param.wElectAngleOpen  = (struAppCommData.nStartAngleComp + mIPD_CtrProc.IPD_Angle) << 16; //初始角度给定
    }
    else if (struFOC_CtrProc.bMotorDirtionCtrl == CCW)
    {
        struFluxOB_Param.wElectAngleOpen  = (mIPD_CtrProc.IPD_Angle - struAppCommData.nStartAngleComp) << 16; //初始角度给定
    }
}

 6.9 顺逆风检测

StateRun.c 888 行

/* -------------------------------- 顺逆风检测模式选择------------------------------ */
#define DIR_BEMF_CHECK_STATUS          (FALSE)            /* 顺逆风检查状态 TRUE = 开启顺逆风检测, FALSE = 关闭顺逆风检测 */
#define BEMF_CHECK_MDE                  (0)               /* 反电动势做顺逆风,需反电动势电路,一般单电阻采样使用(双电阻可以使用)*/
#define DIR_CHECK_MDE                   (1)               /* 观测器做顺逆风,无需反电动势电路,一般双电阻采样使用(部分电机使用单电阻采样也可以使用改顺逆风检测,具体需要根据实际调试确认是否可以)*/
#define DIR_BEMF_CHECK_MODE         (BEMF_CHECK_MDE)      /* 顺逆风检测模式选择*/

七、正反转

MC_Parameter.h 69 行

/* ----------------------------direction check Parameter----------------------- */
#define CW                             (0)                /* 电机转向:顺时针 */ 
#define CCW                            (1)                /* 电机转向:逆时针 */

StateRun.c 888 行

    struFOC_CtrProc.bMotorDirtionCtrl = CW;   /* 电机转向 */
#if (ROTOR_SENSOR_TYPE == ROTOR_SENSORLESS) 
    struFOC_CtrProc.bMotorDirtionCtrlPhase = CCW;   /* 软件改变相线的方式,改变电机转向 */

StateRun.c 888 行

if(struFOC_CtrProc.bMotorDirtionCtrlPhase == CW)
{
		this->bHallCommTab[0] = 3; //--1(30°)
		this->bHallCommTab[1] = 2; //--5(90°)
		this->bHallCommTab[2] = 6; //--4(150°)
		this->bHallCommTab[3] = 4; //--6(210°)
		this->bHallCommTab[4] = 5; //--2(270°)
		this->bHallCommTab[5] = 1; //--3(330°)
}else{	
		this->bHallCommTab[0] = 3; //--1(30°)
		this->bHallCommTab[1] = 1; //--5(90°)
		this->bHallCommTab[2] = 5; //--4(150°)
		this->bHallCommTab[3] = 4; //--6(210°)
		this->bHallCommTab[4] = 6; //--2(270°)
		this->bHallCommTab[5] = 2; //--3(330°)
}

FOC_Drive.c 63 行

    /* clark变换 */
#if (CURRENT_SAMPLE_TYPE != CURRENT_SAMPLE_1SHUNT)	
	  if(struFOC_CtrProc.bMotorDirtionCtrlPhase == CW)
		{
       this->mStatCurrAlfaBeta.nBeta = _IQ15mpy(18919, (this->mStatCurrUVW.nPhaseV - this->mStatCurrUVW.nPhaseW));
    }else{
			 this->mStatCurrAlfaBeta.nBeta = _IQ15mpy(18919, (this->mStatCurrUVW.nPhaseW - this->mStatCurrUVW.nPhaseV));
		}
#else
		   this->mStatCurrAlfaBeta.nBeta = _IQ15mpy(18919, (this->mStatCurrUVW.nPhaseV - this->mStatCurrUVW.nPhaseW));
#endif
		this->mStatCurrAlfaBeta.nAlph = this->mStatCurrUVW.nPhaseU;

八、错误检查调试

下面包括了所有的故障检测函数

fault_deltecion.c 420 行

/***********************************************************************************
 * 函数名   : FaultCheck(void)
 * 说明     : 故障检测处理
 * 设计思路 :1.每个故障检测的处理周期为5ms
 * 参数     :无
 * 返回值   :无
 * 修改时间 :2020.08.17
 ***********************************************************************************/
void FaultCheck(void)
{
    static s16 t_nFlagCheck = 0;

    if(t_nFlagCheck < 5)
    {
        t_nFlagCheck ++;
    }
    else
    {
        t_nFlagCheck = 1;
    }


    switch(t_nFlagCheck)
    {
        case 1:
        { 
            FaultVoltageCheck(struFOC_CurrLoop.nBusVoltage, &struFaultVoltTime);                                        //过欠压检测
            break;
        }
        case 2:
        {
            if(struFOC_CtrProc.eSysState == RUN)          
            {
//                FaultStallCheck(struMotorSpeed.wSpeedfbk, struFOC_CurrLoop.mStatCurrDQ.nAxisQ, &struImaxCurrent, &struFaultStallTime);  //堵转检测
            }
            break;
        }
        case 3:
        {
//            if(struFOC_CtrProc.eSysState == RUN)
//            {
//                FaultEmptyCheck(struFOC_CurrLoop.mStatCurrDQ.nAxisQ, struMotorSpeed.wSpeedfbk, &struFaultEmptyTime);  //离水空转检测
//            }
//            
//            FaultTempCheck(struAppCommData.nTempADC, &struFaultTempTime);                                             //过温检测
            break;
        }
        case 4:
        {
            if(struFOC_CtrProc.eSysState == RUN)
            {
//                FaultPhaseCheck(&struImaxCurrent,&struCurrentAmplitude, &struFaultPhaseTime);                                    //缺相检测
            }
            break;
        }
        case 5:
        {
 
            if((struFOC_CtrProc.eSysState == OPEN_RUN)||(struFOC_CtrProc.eSysState == RUN))
            {
//                FaultStartCheck(struMotorSpeed.wSpeedfbk, struFOC_CurrLoop.mStatCurrDQ.nAxisQ, &struImaxCurrent, &struFaultStartTime);//二次启动检测
            }
            break;
        }
        default:
            break;
    }
}

这里声明了故障恢复的一些限制

 MC_Parameter.h 200 行

/*------------------------------------FaultDetection---------------------------*/
/* 过流检测参数 */
#define I_PH_OVERCURRENT_FAULT         (10.0)              /* 单位:A 软件过流检测设定值 */

/* 过欠压检测参数 */
#define U_DCB_OVERVOLTAGE_FAULT        (60.0)               /* 单位:V 过压检测设定值 */
#define U_DCB_OVERVOLTAGE_RECOVER      (59.5)               /* 单位:V 过压恢复设定值 */
#define U_DCB_UNDERVOLTAGE_FAULT       (20.0)               /* 单位:V 欠压检测设定值 */
#define U_DCB_UNDERVOLTAGE_RECOVER     (20.5)               /* 单位:V 欠压恢复设定值 */

/* 离水空转参数 */
#define I_PH_EMPTY_FAULT               (0.3)              /* 单位:A 空转检测电流设定值 */
#define SPEED_EMPTY_FAULT              (50.0)             /* 单位:Hz 空转检测转速设定值  */

/* 温度检测参数 */
#define TEMP_FAULT                     (150)              /* 过温检测设定值 */
#define TEMP_RECOVER                   (170)              /* 过温恢复设定值 */
#define TEMP_BREAK                     (4000)             /* NTC开路设定值 */
                                                                  
/* 堵转检测参数 */
#define SPEED_STALL_MAX_FAULT          (300.0)            /* 单位:Hz 堵转检测转速最大值 */
#define SPEED_STALL_MIN_FAULT          (10.0)             /* 单位:Hz 堵转检测转速最小值 */

#define I_PH_STALL_FAULT               (1.5)              /* 单位:A 堵转检测电流设定值 */

#define SPEED_STALL_FAULT              (20.0)             /* 单位:Hz 堵转检测转速设定值 */
#define IQ_STALL_FAULT                 (0.2)              /* 单位:A 堵转检测电流设定值 */

/* 二次启动检测参数 */
#define START_TIME_FAULT               (200)              /* 单位:5ms 开环之后1s内还不进入闭环就重启,1s这个时间根据实际应用调整 */

/* 缺相检测参数 */
#define I_PHASE_LOSS_FAULT             (3000)             /* 数字量,根据实际测试中struCurrentAmplitude.nPhA/struCurrentAmplitude.nPhB/struCurrentAmplitude.nPhC */
                                                          /* 的计算值来设定,在缺相和正常运行的中间取值。 */

  fault_detection.c 35 行

/*****************************************************************************
 * 函数名   : void FaultCurrentCheck(s16 Ia, s16 Ib, s16 Ic)
 * 说明     : 软件过流检测
 * 设计思路 :1. 如果三相电流绝对值超过设定的软件过流值,则判定为软件过流。
 * 参数     :Ia、Ib、Ic
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void FaultCurrentCheck(stru_CurrPhaseUVW *pstruCurrent)
{
    if((ABS(pstruCurrent->nPhaseU) > stru_FaultValue.nOverCurrent) || (ABS(pstruCurrent->nPhaseV) > stru_FaultValue.nOverCurrent) || (ABS(pstruCurrent->nPhaseW) > stru_FaultValue.nOverCurrent))
    {
        PWMOutputs(DISABLE);
        stru_Faults.B.SoftCurretError = 1;
    }

}

fault_detection.c 53 行

/*****************************************************************************
 * 函数名   : void FaultVoltageCheck(s32 Udcb, stru_stru_FaultTime_t *FaultTime)
 * 说明     : 过欠压检测 
 * 设计思路 :1.当母线电压大于过压设定值则判定为过压故障;当母线电压小于欠压设定值 \
 *              则判定为欠压故障。滤波时间为1s,这个可根据实际需求修改。
 * 参数     :Udcb,stru_stru_FaultTime_t
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void FaultVoltageCheck(s32 Udcb, stru_FaultTime_t *pFaultTime)
{
    if(Udcb >= stru_FaultValue.nOverVoltage)    //母线电压大于过压设定值则时间累加
    {
        pFaultTime->nCheckCnt1 ++;
    }
    else if(Udcb < stru_FaultValue.nUnderVoltage) // 母线电压小于欠压设定值则时间累加
    {
        pFaultTime->nCheckCnt2 ++;
    }
    else
    {
        pFaultTime->nCheckCnt1 = 0;
        pFaultTime->nCheckCnt2 = 0;
    }

    if(pFaultTime->nCheckCnt1 >= 200)//时间超过1s则判定为过压
    {
        PWMOutputs(DISABLE);
        pFaultTime->nCheckCnt1 = 0;
        stru_Faults.B.VoltOverError = 1;//过压错误标志位置1
    }

    if(pFaultTime->nCheckCnt2 >= 200)//时间超过1s则判定为欠压
    {
        PWMOutputs(DISABLE);
        pFaultTime->nCheckCnt2 = 0;
        stru_Faults.B.VoltUnderError = 1;//欠压错误标志位置1
    }
}

fault_detection.c 53 行

/*****************************************************************************
 * 函数名   : FaultEmptyCheck(s16 Iq, s32 wSpeedFbk, stru_stru_FaultTime_t *FaultTime)
 * 说明     : 离水空转检测 
 * 设计思路 :1.如果Iq小于空转电流设定值,并且转速大于空转转速设定值,则判定为离水空转。\
 *              滤波时间为1s,这个可根据实际需求修改。 
 * 参数     :s16 nIq, s32 wSpeedFbk, stru_FaultTime_t *pstruFaultTime
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void FaultEmptyCheck(s16 nIq, s32 wSpeedFbk, stru_FaultTime_t *pstruFaultTime)
{
    if((ABS(nIq) < stru_FaultValue.nEmptyCurrent) && (ABS(wSpeedFbk) > stru_FaultValue.wEmptySpeed)) //如果Iq小于设定值,转速大于设定值则时间累加,否则时间清0
    {
        pstruFaultTime->nCheckCnt1 ++;
    }
    else
    {
        pstruFaultTime->nCheckCnt1 = 0;
    }

    if(pstruFaultTime->nCheckCnt1 >= 200)  //累加时间超过200 * 5ms = 1s则判定为离水空转
    {
        PWMOutputs(DISABLE);
        pstruFaultTime->nCheckCnt1 = 0;
        stru_Faults.B.EmptyError = 1;       //空转错误标志位置1
    }
}

fault_detection.c 103 行

/*****************************************************************************
 * 函数名   : FaultStallCheck(s32 SpeedFbk, s16 Iq, stru_CurrPhaseUVW *pIabcMax, stru_stru_FaultTime_t *FaultTime)
 * 说明     : 堵转检测 
 * 设计思路 :堵转检测目前分为三种办法
 *            1.电机转速大于设定最大值或者小于设定最小值,则判定为堵转 ;                 \
 *            2.Iq大于设定值,转速小于设定值则判断堵转。主要思路为电流和转速正相关;      \
 *            3.三相电流幅值大于堵转电流设定值则判断为堵转。
 * 参数     :s32 nSpeedFbk, s16 bIq, stru_CurrPhaseUVW *pstruIabcMax, stru_FaultTime_t *pstruFaultTime
 * 返回值   :无
 * 修改时间 :2020.08.17
 *****************************************************************************/
void FaultStallCheck(s32 nSpeedFbk, s16 bIq, stru_CurrPhaseUVW *pstruIabcMax, stru_FaultTime_t *pstruFaultTime)
{
    if(pstruFaultTime->nStartDelay < 40) //延时5ms *40 = 200ms,避开开环拖动的影响
    {
        pstruFaultTime->nStartDelay ++;
    }
    else
    {
        if((ABS(nSpeedFbk) > stru_FaultValue.wStallSpeedMax) || (ABS(nSpeedFbk) < stru_FaultValue.wStallSpeedMin))  //电机转速在实际运行范围之外则判定为堵转
        {
            if(pstruFaultTime->nCheckCnt1 < 100)      //滤波时间500ms 100*5ms
            {
                pstruFaultTime->nCheckCnt1 ++;
            }
            else                                 //判定为电机堵转
            {                                   
                PWMOutputs(DISABLE);
                pstruFaultTime->nCheckCnt1 = 0;
                stru_Faults.B.StallError = 1;         //堵转错误标志位置1
                stru_FaultValue.nStallFlag = 1;        //堵转标志位为1,用于区分触发了哪种堵转
            }
        }
        else
        {
            pstruFaultTime->nCheckCnt1 = 0;
        }

        if((ABS(nSpeedFbk) < stru_FaultValue.wStallSpeed) && (ABS(bIq) > stru_FaultValue.nStallCurrentIq)) //Iq和转速不匹配,Iq大、转速低,则判定为堵转。
        {
            if(pstruFaultTime->nCheckCnt2 < 400)      //滤波时间2s,400*5ms = 2000ms
            {
                pstruFaultTime->nCheckCnt2 ++;
            }
            else                                 //判定为电机堵转 
            {
                PWMOutputs(DISABLE);
                pstruFaultTime->nCheckCnt2 = 0;
                stru_Faults.B.StallError = 1;         //堵转错误标志位置1
                stru_FaultValue.nStallFlag = 2;       //堵转标志位为2,用于区分触发了哪种堵转
            }
        }
        else
        {
            pstruFaultTime->nCheckCnt2 = 0;
        }

        if((pstruIabcMax->nPhaseU > stru_FaultValue.nStallCurrent) || (pstruIabcMax->nPhaseV > stru_FaultValue.nStallCurrent) || (pstruIabcMax->nPhaseW > stru_FaultValue.nStallCurrent))//三相电流幅值超过堵转电流设定值则判定为堵转
        {
            PWMOutputs(DISABLE);
            stru_Faults.B.StallError = 1;            //堵转错误标志位置1
            stru_FaultValue.nStallFlag = 3;          //堵转标志位为3,用于区分触发了哪种堵转
        }

    }
}

fault_detection.c 266 行

/***********************************************************************************
 * 函数名   : FaultPhaseCheck(stru_CurrPhaseUVW  *pstruImaxCurrent,stru_CurrentAmplitude_t *pstruCurrentAmplitude, stru_FaultTime_t *pstruFaultTime)
 * 说明     : 缺相检测 
 * 设计思路 :1.三相电流幅值相差3倍,则判定为电机缺相,检测时间是2S,时间可以根据项目实际频率调整
 *            2.三相电流的积分值过小,持续1s,判定为缺相
 * 参数     :stru_CurrPhaseUVW  *pstruImaxCurrent,stru_CurrentAmplitude_t *pstruCurrentAmplitude, stru_FaultTime_t *pstruFaultTime
 * 返回值   :无
 * 修改时间 :2020.08.17

 * 修改时间 : 2020.10.09 
 * 修改内容 :调整函数传参
 ***********************************************************************************/
void FaultPhaseCheck(stru_CurrPhaseUVW  *pstruImaxCurrent,stru_CurrentAmplitude_t *pstruCurrentAmplitude, stru_FaultTime_t *pstruFaultTime)
{
    if(pstruFaultTime->nCheckCnt1 < 400)//400*5ms 
    {
        pstruFaultTime->nCheckCnt1 ++;
    }
    else
    {
        pstruFaultTime->nCheckCnt1 = 0;
        
        if(((pstruImaxCurrent->nPhaseU >> 2) > pstruImaxCurrent->nPhaseV) || (((pstruImaxCurrent->nPhaseV >> 2) > pstruImaxCurrent->nPhaseW)) ||
          (((pstruImaxCurrent->nPhaseW >> 2) > pstruImaxCurrent->nPhaseU)))            //如果三相电流幅值相差3倍则判定为缺相,倍数需要根据实际负载调整
        {
            PWMOutputs(DISABLE);
            stru_Faults.B.PhaseLossError = 1;//缺相错误标志位置1
            stru_FaultValue.nPhaseLossFlag = 1;//第一种缺相保护
        }
        
        pstruImaxCurrent->nPhaseU = 0;
        pstruImaxCurrent->nPhaseV = 0;
        pstruImaxCurrent->nPhaseW = 0;
    }

    if((pstruCurrentAmplitude->nPhA < I_PHASE_LOSS_FAULT)||(pstruCurrentAmplitude->nPhB < I_PHASE_LOSS_FAULT)||(pstruCurrentAmplitude->nPhC < I_PHASE_LOSS_FAULT)) //缺三相
    {
        if(pstruFaultTime->nCheckCnt2 < 50)     //滤波时间为200*0.5s = 1s
        {
            pstruFaultTime->nCheckCnt2 ++;
        }
        else
        {
            pstruFaultTime->nCheckCnt2 = 0;
            PWMOutputs(DISABLE);
            stru_Faults.B.PhaseLossError = 1;//缺相错误标志位置1
            stru_FaultValue.nPhaseLossFlag = 2;//第二种缺相保护
        }
    }
    else
    {
        pstruFaultTime->nCheckCnt2 = 0;
    }
}

fault_detection.c 266 行

/***********************************************************************************
 * 函数名   : FaultTempCheck(s16 nTemperature, stru_FaultTime_t *pFaultTime)
 * 说明     : 温度保护检测,针对NTC设计,对于PTC则需要修改 
 * 设计思路 :1.根据NTC的阻值去判断是否发生过温故障
 * 参数     :s16 nTemperature, stru_FaultTime_t *pFaultTime
 * 返回值   :无
 * 修改时间 :2020.08.17
 ***********************************************************************************/
void FaultTempCheck(s16 nTemperature, stru_FaultTime_t *pstruFaultTime)
{
    if((nTemperature < TEMP_FAULT) || (nTemperature > TEMP_BREAK))    //NTC阻值小于设定值,则判定为过温故障;NTC阻值大于NTC开路值,则判定为NTC开路
    {
        pstruFaultTime->nCheckCnt1 ++;
    }
    else
    {
        pstruFaultTime->nCheckCnt1 = 0;
    }

    if(pstruFaultTime->nCheckCnt1 > 400)//滤波时间2s,400*5ms = 2000ms
    {
        PWMOutputs(DISABLE);
        stru_Faults.B.TempOverError = 1;//温度故障标志位置1
        pstruFaultTime->nCheckCnt1 = 0;
    }
}

九、错误恢复介绍

在这里保存了所有自动回复的时间

MC_Parameter.h 232 行

/* 故障恢复时间 */
#define VOLT_FAULT_RECOVER_TIME        (2000)             /* 单位:ms  过欠压恢复时间 */
#define CURRENT_FAULT_RECOVER_TIME     (2000)             /* 单位:ms  过流恢复时间 */
#define STALL_FAULT_RECOVER_TIME       (2000)             /* 单位:ms  堵转恢复时间 */
#define PHASELOSS_FAULT_RECOVER_TIME   (2000)             /* 单位:ms  缺相恢复时间 */
#define TEMP_FAULT_RECOVER_TIME        (2000)             /* 单位:ms  过温恢复时间 */
#define START_FAULT_RECOVER_TIME       (1000)             /* 单位:ms  二次启动恢复时间 */
#define EMPTY_FAULT_RECOVER_TIME       (2000)             /* 单位:ms  离水空转恢复时间 */

各种恢复等逻辑大致如下,根据宏定义时间计时,到即设置恢复。

恢复函数全部代码: 

fault_detection.h 515 行

/***********************************************************************************
 * 函数名   : FaultRecover(void)
 * 说明     : 故障恢复程序处理
 * 设计思路 :1.过欠压恢复:       母线电压在正常工作范围内,持续2s则清除过欠压故障标志位; \
 *            2.软件&硬件过流恢复:2s后清除过流故障标志位;                                 \
 *            3.堵转恢复:         2s后清除堵转故障标志位;                                 \
 *            4.缺相恢复:         2s后清除过流故障标志位;                                 \
 *            5.过温恢复:         NTC在正常工作范围内,持续2s则清除过温故障标志位; \
 *            6.启动恢复:         1s后重启
 * 参数     :无
 * 返回值   :无
 * 修改时间 :2020.08.17
 ***********************************************************************************/
void FaultRecover(void)
{       
    /****************过欠压恢复****************/
    if((stru_Faults.B.VoltOverError == 1) || (stru_Faults.B.VoltUnderError == 1))
    {   //母线电压在欠压恢复值和过压恢复值之间则判定为正常状态
        if((struFOC_CurrLoop.nBusVoltage >= stru_FaultValue.nUnderVoltageRecover) 
          && (struFOC_CurrLoop.nBusVoltage <= stru_FaultValue.nOverVoltageRecover))
        {
            if(struFaultVoltTime.nRecoverCntr < VOLT_FAULT_RECOVER_TIME)     //滤波时间2s,然后清零过欠压故障标志位
            {
                struFaultVoltTime.nRecoverCntr ++;
            }
            else
            {
                stru_Faults.B.VoltOverError = 0;
                stru_Faults.B.VoltUnderError = 0;
                struFaultVoltTime.nRecoverCntr = 0;
            }
        }
        else
        {
            struFaultVoltTime.nRecoverCntr = 0;
        }
    }

    /****************过流恢复****************/
    if((stru_Faults.B.HardCurretError == 1) || (stru_Faults.B.SoftCurretError == 1))
    {
        if(struFaultCurrentTime.nRecoverCntr < CURRENT_FAULT_RECOVER_TIME)//2s后清零过流故障标志位
        {
            struFaultCurrentTime.nRecoverCntr ++;
        }
        else
        {
            if(stru_Faults.B.HardCurretError == 1)
            {
                stru_Faults.B.HardCurretError = 0;
            }

            if(stru_Faults.B.SoftCurretError == 1)
            {
                stru_Faults.B.SoftCurretError = 0;
            }

            struFaultCurrentTime.nRecoverTime ++;
            struFaultCurrentTime.nRecoverCntr = 0;
        }
    }

    /****************堵转恢复****************/
    if(stru_Faults.B.StallError == 1)
    {
        if(struFaultStallTime.nRecoverCntr < STALL_FAULT_RECOVER_TIME)   //2s后清零堵转故障标志位
        {
            struFaultStallTime.nRecoverCntr ++;
        }
        else
        {
            stru_Faults.B.StallError = 0;
            struFaultStallTime.nRecoverCntr = 0;
            stru_FaultValue.nStallFlag = 0;
        }
    }

    /****************离水空转恢复****************/
    if(stru_Faults.B.EmptyError == 1)
    {
        if(struFaultEmptyTime.nRecoverCntr < EMPTY_FAULT_RECOVER_TIME)//2s后清零离水空转故障标志位
        {
            struFaultEmptyTime.nRecoverCntr ++;
        }
        else
        {
            stru_Faults.B.EmptyError = 0;
            struFaultEmptyTime.nRecoverCntr = 0;
        }
    }

    /****************缺相恢复****************/
    if(stru_Faults.B.PhaseLossError == 1)
    {
        if(struFaultPhaseTime.nRecoverCntr < PHASELOSS_FAULT_RECOVER_TIME) //2s后清零缺相故障标志位
        {
            struFaultPhaseTime.nRecoverCntr ++;
        }
        else
        {
            stru_Faults.B.PhaseLossError = 0;
            struFaultPhaseTime.nRecoverCntr = 0;
        }
    }

    /****************过温恢复****************/
    if(stru_Faults.B.TempOverError == 1)
    {
        if((struAppCommData.nTempADC > TEMP_RECOVER) && (struAppCommData.nTempADC < TEMP_BREAK))//NTC阻值在设定阻值之间则判定为正常状态 
        {
            if(struFaultTempTime.nRecoverCntr < TEMP_FAULT_RECOVER_TIME)//滤波时间2s,然后清零过温故障标志位
            {
                struFaultTempTime.nRecoverCntr ++;
            }
            else
            {
                stru_Faults.B.TempOverError = 0;
                struFaultTempTime.nRecoverCntr = 0;
            }
        }
        else
        {
            struFaultTempTime.nRecoverCntr = 0;
        }
    }

    /****************启动失败恢复****************/
    if(stru_Faults.B.StartError == 1)
    {
        if(struFaultStartTime.nRecoverCntr < START_FAULT_RECOVER_TIME) //1s后清零缺相故障标志位
        {
            struFaultStartTime.nRecoverCntr ++;
        }
        else
        {
            stru_Faults.B.StartError = 0;
            struFaultStartTime.nRecoverCntr = 0;
            stru_FaultValue.nStartFlag = 0;
        }
    }

}

十、弱磁

弱磁即减弱磁通,该方法以降低转矩为代价,使电机转速超过其额定转速。弱磁可用于自动化应用中的电机控制,以及电动汽车和机车的牵引电机控制,以便在可接受较低转矩时实现较高的电机转速。

永磁同步电机 (PMSM) 具有高功率密度、高转速和快速动态响应,因而广泛见于上述应用。然而,当定子端电压达到逆变器输出极限时,PMSM 转速会受限。因此,PMSM 需要通过弱磁提高轴转速,使其超过设计的额定值。实现更高电机转速的一种方法是调节逆变器电力电子开关,以控制定子 d 轴和 q 轴电流,从而抵消转子磁体产生的气隙磁通量。

转矩速度特征曲线显示,电机的反电动势(定子电压)与电机转速成正比上升。此行为发生在 PMSM 的恒定转矩区域,在该区域,我们可以使用磁场定向控制 (FOC) 来调节电机。然而,当转速继续上升时,施加的电压达到最大值,反电动势电压超过施加的电压,从而阻止电机转速增加。为了让电机转速超过其基本转速,我们使用弱磁模式,同时保持恒定输出功率,该输出功率是转矩和电机转速的乘积。在弱磁过程中,电机以降低最大转矩为代价,在最大可用电压下加快转速。

如下图,虚线部分即是电压极限圆,当 id 为负电压极限达到顶点。对于电机来说,电压只和转速有关,电流只和转矩有关。所以提高电压极限即可提速。

10.1 自动弱磁

MC_Paramete.h 154 行

#define AUTO_FW_LIM                    ((s16)0)            /* 自动弱磁D轴电流限制,Q12格式,最大值 4096 */

state_machine.h 354 行

    /* 弱磁参数初始化 */
    AFWR.KI = 10;
    AFWR.KP = 50;
    AFWR.INTEG = 0;
    AFWR.LIM_H = 0;
    AFWR.LIM_L = -struFOC_CurrLoop.nWeakFieldLim;
    struFOC_CurrLoop.npmsmSvcImFw = 0;

FOC_Drive.c 157 行

struFOC_CurrLoop.npmsmSvcImFw = AutoFieldWeakReg();/*自动弱磁*/
			  				
CurrentLoopReg(this);   /* D Q轴电流环PI调节*/

FOC_Drive.c 221 行

/*******************************************************************************
 函数名称:    CurrentLoopReg(stru_FOC_CurrLoopDef *this)
 功能描述:    D、Q轴电流计算,输出Vd、Vq
 输入参数:    stru_FOC_CurrLoopDef *this  结构体指针
 输出参数:    无
 返 回 值:    无
 其它说明:
 修改日期      版本号          修改人            修改内容
 -----------------------------------------------------------------------------
 2020/8/5      V1.0           Howlet Li          创建
 *******************************************************************************/
void CurrentLoopReg(stru_FOC_CurrLoopDef *this)
{
    this->mPI_Torque.wInError = this->nQCur_Reference - this->mStatCurrDQ.nAxisQ; /* Q轴输入误差 */
    this->mPI_Flux.wInError   = this->nDCur_Reference - this->mStatCurrDQ.nAxisD + this->npmsmSvcImFw; /* D轴输入误差 */

    /* 误差限幅,可根据实际负载调整,影响PI响应的快慢 */
    this->mPI_Torque.wInError = sat(this->mPI_Torque.wInError, -0x800, 0x800);
    this->mPI_Flux.wInError   = sat(this->mPI_Flux.wInError, -0x800, 0x800);

#if SVPWM_MODE
    this->mStatVoltDQ.nAxisQ = 0;        /* Q轴电流PI计算,输出Vq 4096 对应额定电压*/
    this->mStatVoltDQ.nAxisD = 600;     /* D轴电流PI计算, 输出Vd 4096 对应额定电压*/
#else
    this->mStatVoltDQ.nAxisQ = CurrentPIRegulator(&this->mPI_Torque);   /* Q轴电流PI计算,输出Vq */
    this->mStatVoltDQ.nAxisD = CurrentPIRegulator(&this->mPI_Flux);     /* D轴电流PI计算,输出Vd */
#endif
	
    ModuCircle_Limitation();  /* 电压极限圆限制 */
}

10.2 手动弱磁

待补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值