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 信号的重装载值。
其中的除 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) 作为单位进行表示。电机频率是电机运行时最基本的参数之一,直接影响着电机的性能和运行状态,公式为:
- 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 手动弱磁
待补充