/** ****************************************************************************** * @file tim.c * @author Jerry * @version V2.1 * @date 19-April-2022 * @brief tim program body. ****************************************************************************** * @attention * * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x.h" #include "global.h" #include "string.h" #include "soe.h" CALI_STRUCT cali; uint8_t bAlarmFlag; uint8_t bAlarmFlagOld; AFE_RAM afeRam; AFE_FLG afeFlg; int16_t siCurBuf[4]; //CADC以250ms周期采样4次 uint8_t ucCadcTimeCnt; //CADC采样计数 uint8_t bDSGING; //放电状态标记 uint8_t bCHGING; //充电状态标记 uint8_t bSTANDBY; //待机状态标记 uint8_t bFC; //=1充满电 uint8_t ucChgEndTimeCnt; //充电截止条件判断计数器 uint8_t ucChgEndRTimeCnt;// uint8_t E2ucChgEndDelay; //充电截止条件判断延时 uint8_t E2uiChgEndVol; //充电截止电压 uint8_t E2siChgEndCur; //充电截止电流 uint8_t bCHGEnd; //充电结束关充电MOS标记 uint8_t bCHGClosedFlg; //关闭充电标记 uint8_t curLimitFlag; uint8_t curLimitCount; uint16_t curLimitReleaseCount; uint16_t curLimitCloseCount; uint8_t DSGcount; //小电流放电计数 uint8_t DSGminiFlag; //小电流放电标志 uint8_t CHGcount; uint8_t CHGminiFlag; uint8_t ErrDSGcount; //放电MOS故障的延时计数 uint8_t ErrCHGcount; //充电MOS故障的延时计数 uint8_t ErrDSGRelaycount;//放电MOS故障恢复的延时计数 uint8_t ErrCHGRelaycount;//充电MOS故障恢复的延时计数 uint8_t nullCurrent_Flag; //此时1s内的电流采样值无效标志 uint8_t sc_OccurFlag; //浪涌短路出现过的标志 uint8_t tsc_OccurFlag; //真短路出现过的标志 uint8_t pchgFail_OccurFlag; //预充超时失败出现过的标志 uint8_t sc_RepeatFlag; //浪涌短路持续出现的标志 uint8_t sc_RepeatDelay; //等待浪涌短路倒计时,最大60s =>对应消失后60s内未再次出现,说明正常 uint8_t sc_RepeatCount; //浪涌短路重复的计数,最大5次 =>对应连续5次出现短路 =>会在第五次短路时,MCU接管将标志位置1,控制MOS持续关闭 uint8_t tsc_RepeatFlag; //真短路持续出现的标志 uint8_t tsc_RepeatDelay; //等待真短路倒计时,最大60s =>对应消失后60s内未再次出现,说明正常 uint8_t tsc_RepeatCount; //真短路重复的计数,最大5次 =>对应连续5次出现短路 =>会在第五次短路时,MCU接管将标志位置1,控制MOS持续关闭 uint8_t pchgFail_RepeatFlag; //预充超时失败持续出现的标志 uint8_t pchgFail_RepeatTime; //等待预充超时失败倒计时,最大60s =>对应消失后60s内未再次出现,说明正常 uint8_t pchgFail_RepeatCount; //预充超时失败重复的计数,最大5次 =>对应连续5次出现预充超时失败 =>会在第五次预充超时失败时,锁定不可恢复标志位,控制MOS持续关闭 uint8_t fcc4_count; //满充条件4的延时计数 uint8_t fcc4r_count; //满充条件4释放的延时计数 uint16_t CTRL_Order; //上位机[临时]控制MOS关闭指令 uint8_t OCC2_Flag; uint16_t OCC2MoniCount; uint8_t sc_Often_Flag; //浪涌短路连续发生,执行锁定的标志 uint16_t tsc_relaycount; //真短路5min自动解除的延时计数 uint8_t dsgCtrl; //放电MOS控制状态 uint8_t dsgCtrl_old; int16_t cellVol[20]; //20串电压 int16_t cellVoltageMax; int16_t cellVoltageMin; uint8_t MOS_Close_Flg; //需要控制MOS全关的标志 uint8_t sc_close_flag; //控制浪涌短路保护关闭的标志 //写AFE的寄存器 uint8_t AFE_Write(uint8_t addr, uint8_t lenth, uint8_t *data) { uint8_t i; uint8_t result; result = 0; for(i=0; i MCU RAM -> AFE #define afeReg_num 14 uint8_t MEMORY_UpdateAFE(void) { uint8_t i; uint8_t WrBuf[14]; uint8_t RdBuf[14]; uint8_t afe_mode; //默认值 WrBuf[0] = 0x00; //SCONF4 [bit0~4:10000-16串] WrBuf[1] = 0x08; //SCONF5 bit3:1-开启CADC电流采集 WrBuf[2] = 0x08; //SCONF6 bit3:1-开启短路保护 WrBuf[3] = 0x00; //SCONF7 bit6:0-负载检测上拉电流(暂时默认60uA) WrBuf[4] = 0x00; //OWV/ALARMH WrBuf[5] = 0x04; //ALARML bit2:1-短路保护Alarm发送低电平脉冲 WrBuf[6] = 0x00; //OVT/OVH WrBuf[7] = 0x00; //OVL WrBuf[8] = 0x00; //UVT/UVH WrBuf[9] = 0x00; //UVL WrBuf[10] = 0x00; //OCD1V/OCD1T WrBuf[11] = 0x00; //OCD2V/OCD2T [bit0~3:放电过流2保护=2*10+10=30mV] WrBuf[12] = 0x00; //SCV/SCT bit4~5:短路保护=2*VOCD2=60mV [bit0~3:延时0us] WrBuf[13] = 0x00; //OCCV/OCCT //电池串数:先看ee_sconf1是否在5~16,是则用SCONF1路径;否则用ee_sconf4 afe_mode = (paraMem.sc_mode >> 8) & 0xFF; { uint8_t cn1 = bmsMem.ee_sconf1 & 0x0F; //SCONF1低4位,5-15串,0表示16串 if((cn1 >= 5 && cn1 <= 15) || cn1 == 0) //5~15串 或 16串(cn=0) { bmsMem.ucCellNum = (cn1 == 0) ? 16 : cn1; //cn=0是16串(4位字段存不下16) WrBuf[0] |= bmsMem.ucCellNum & 0x0F; //309/35XX通用4位cn } else if(afe_mode == 1) //SH36735XX,支持4/17~20串 { bmsMem.ucCellNum = paraMem.ee_sconf4 & 0x1F; //SCONF4低5位,4-20串 if(bmsMem.ucCellNum < 4 || bmsMem.ucCellNum > 20) { bmsMem.ucCellNum = 20; // 越界默认20串 } WrBuf[0] = bmsMem.ucCellNum & 0x1F; // 写入SCONF4 } else //SH367309,不支持4/17~20串 { bmsMem.ucCellNum = 16; // 越界默认16串 WrBuf[0] |= bmsMem.ucCellNum & 0x0F; } } //短路电流=(OCD2V*10+10)*2 WrBuf[11] |= (bmsMem.ee_scv_sct >> 4) & 0x0F; //短路延时 WrBuf[12] |= bmsMem.ee_scv_sct & 0x0F; if(AFE_Write(REG_ADDR_SCONF4, 14, WrBuf) == 0) { if(AFE_Read(REG_ADDR_SCONF4, 14, RdBuf) == 0) { for(i=0;i<14;i++) { if(RdBuf[i] != WrBuf[i]) { return 1; //写入有误 } } return 0; } else { return 2; //读取数据失败 } } else { AFE_Reset(); return 3; //写入数据失败 } } //电压获取 //main->while 1s void AFE_VoltageProcess(void) { uint8_t i; int16_t max,min,maxIndex,minIndex; //计算最高最低 int32_t temp; //计算总压 uint8_t afe_mode; uint8_t rdLen; //先确定串数和读取长度:先看ee_sconf1是否在5~16,是则用SCONF1路径;否则用ee_sconf4 afe_mode = (paraMem.sc_mode >> 8) & 0xFF; { uint8_t cn1 = bmsMem.ee_sconf1 & 0x0F; //SCONF1低4位,5-15串,0表示16串 if((cn1 >= 5 && cn1 <= 15) || cn1 == 0) //5~15串 或 16串(cn=0) { bmsMem.ucCellNum = (cn1 == 0) ? 16 : cn1; //cn=0是16串(4位字段存不下16) rdLen = 32; //16串 × 2字节 } else if(afe_mode == 1) //SH36735XX,支持4/17~20串 { bmsMem.ucCellNum = paraMem.ee_sconf4 & 0x1F; //SCONF4低5位,4-20串 if(bmsMem.ucCellNum < 4 || bmsMem.ucCellNum > 20) { bmsMem.ucCellNum = 20; // 越界默认20串 } rdLen = 40; //20串 × 2字节 } else //SH367309,不支持4/17~20串 { bmsMem.ucCellNum = 16; // 越界默认16串 rdLen = 32; //16串 × 2字节 } } if(AFE_Read(REG_ADDR_CELL1H, rdLen, &afeRam.cell1h) != 0) { return; } //采集电芯电压(显示给上位机) bmsMem.vCell[0] = ((uint16_t)afeRam.cell1h <<8 | afeRam.cell1l ) *5 >> 5; //=cell1*5/32 bmsMem.vCell[1] = ((uint16_t)afeRam.cell2h <<8 | afeRam.cell2l ) *5 >> 5; bmsMem.vCell[2] = ((uint16_t)afeRam.cell3h <<8 | afeRam.cell3l ) *5 >> 5; bmsMem.vCell[3] = ((uint16_t)afeRam.cell4h <<8 | afeRam.cell4l ) *5 >> 5; bmsMem.vCell[4] = ((uint16_t)afeRam.cell5h <<8 | afeRam.cell5l ) *5 >> 5; bmsMem.vCell[5] = ((uint16_t)afeRam.cell6h <<8 | afeRam.cell6l ) *5 >> 5; bmsMem.vCell[6] = ((uint16_t)afeRam.cell7h <<8 | afeRam.cell7l ) *5 >> 5; bmsMem.vCell[7] = ((uint16_t)afeRam.cell8h <<8 | afeRam.cell8l ) *5 >> 5; bmsMem.vCell[8] = ((uint16_t)afeRam.cell9h <<8 | afeRam.cell9l ) *5 >> 5; bmsMem.vCell[9] = ((uint16_t)afeRam.cell10h <<8 | afeRam.cell10l) *5 >> 5; bmsMem.vCell[10] = ((uint16_t)afeRam.cell11h <<8 | afeRam.cell11l) *5 >> 5; bmsMem.vCell[11] = ((uint16_t)afeRam.cell12h <<8 | afeRam.cell12l) *5 >> 5; bmsMem.vCell[12] = ((uint16_t)afeRam.cell13h <<8 | afeRam.cell13l) *5 >> 5; bmsMem.vCell[13] = ((uint16_t)afeRam.cell14h <<8 | afeRam.cell14l) *5 >> 5; bmsMem.vCell[14] = ((uint16_t)afeRam.cell15h <<8 | afeRam.cell15l) *5 >> 5; bmsMem.vCell[15] = ((uint16_t)afeRam.cell16h <<8 | afeRam.cell16l) *5 >> 5; if(afe_mode == 1) { bmsMem.vCell2[0] = ((uint16_t)afeRam.cell17h<<8 | afeRam.cell17l)*5>>5; bmsMem.vCell2[1] = ((uint16_t)afeRam.cell18h<<8 | afeRam.cell18l)*5>>5; bmsMem.vCell2[2] = ((uint16_t)afeRam.cell19h<<8 | afeRam.cell19l)*5>>5; bmsMem.vCell2[3] = ((uint16_t)afeRam.cell20h<<8 | afeRam.cell20l)*5>>5; } //采集电芯电压(实际) cellVol[0] = (int16_t)((uint16_t)afeRam.cell1h <<8 | afeRam.cell1l ) *5 >> 5; //=cell1*5/32 cellVol[1] = (int16_t)((uint16_t)afeRam.cell2h <<8 | afeRam.cell2l ) *5 >> 5; cellVol[2] = (int16_t)((uint16_t)afeRam.cell3h <<8 | afeRam.cell3l ) *5 >> 5; cellVol[3] = (int16_t)((uint16_t)afeRam.cell4h <<8 | afeRam.cell4l ) *5 >> 5; cellVol[4] = (int16_t)((uint16_t)afeRam.cell5h <<8 | afeRam.cell5l ) *5 >> 5; cellVol[5] = (int16_t)((uint16_t)afeRam.cell6h <<8 | afeRam.cell6l ) *5 >> 5; cellVol[6] = (int16_t)((uint16_t)afeRam.cell7h <<8 | afeRam.cell7l ) *5 >> 5; cellVol[7] = (int16_t)((uint16_t)afeRam.cell8h <<8 | afeRam.cell8l ) *5 >> 5; cellVol[8] = (int16_t)((uint16_t)afeRam.cell9h <<8 | afeRam.cell9l ) *5 >> 5; //=cell1*5/32 cellVol[9] = (int16_t)((uint16_t)afeRam.cell10h <<8 | afeRam.cell10l) *5 >> 5; cellVol[10] = (int16_t)((uint16_t)afeRam.cell11h <<8 | afeRam.cell11l) *5 >> 5; cellVol[11] = (int16_t)((uint16_t)afeRam.cell12h <<8 | afeRam.cell12l) *5 >> 5; cellVol[12] = (int16_t)((uint16_t)afeRam.cell13h <<8 | afeRam.cell13l) *5 >> 5; cellVol[13] = (int16_t)((uint16_t)afeRam.cell14h <<8 | afeRam.cell14l) *5 >> 5; cellVol[14] = (int16_t)((uint16_t)afeRam.cell15h <<8 | afeRam.cell15l) *5 >> 5; cellVol[15] = (int16_t)((uint16_t)afeRam.cell16h <<8 | afeRam.cell16l) *5 >> 5; if(afe_mode == 1) { cellVol[16] = (int16_t)((uint16_t)afeRam.cell17h <<8 | afeRam.cell17l) *5 >> 5; cellVol[17] = (int16_t)((uint16_t)afeRam.cell18h <<8 | afeRam.cell18l) *5 >> 5; cellVol[18] = (int16_t)((uint16_t)afeRam.cell19h <<8 | afeRam.cell19l) *5 >> 5; cellVol[19] = (int16_t)((uint16_t)afeRam.cell20h <<8 | afeRam.cell20l) *5 >> 5; } //计算总电压 temp = 0; for(i=0;icellVol[i]) { min = cellVol[i]; minIndex = i; } } cellVoltageMax = max; cellVoltageMin = min; if(maxIndex < 16) { bmsMem.cellVoltageMax = bmsMem.vCell[maxIndex]; } else { bmsMem.cellVoltageMax = bmsMem.vCell2[maxIndex - 16]; } if(minIndex < 16) { bmsMem.cellVoltageMin = bmsMem.vCell[minIndex]; } else { bmsMem.cellVoltageMin = bmsMem.vCell2[minIndex - 16]; } bmsMem.cellVoltageMaxIndex = maxIndex; bmsMem.cellVoltageMinIndex = minIndex; //sum of all packs bmsMem.can_VolMax = bmsMem.cellVoltageMax; bmsMem.can_VolMaxIndex = bmsMem.cellVoltageMaxIndex; bmsMem.can_VolMin = bmsMem.cellVoltageMin; bmsMem.can_VolMinIndex = bmsMem.cellVoltageMinIndex; //过压相关报警和保护 Trigger_OVAlarm(); //报警 Release_OVAlarm(); //报警恢复 Trigger_OVProtect(); //保护 Release_OVProtect(); //保护恢复 //欠压相关 if((bmsMem.balanceStatus & 0x0020) == 0) { Trigger_UVAlarm(); //报警 Release_UVAlarm(); //报警恢复 Trigger_UVProtect(); //保护 Release_UVProtect(); //保护恢复 } else { bmsMem.bStatus1 &= ~0x0202; bmsMem.bStatus3 &= ~0x0A00; } } //电流获取 //read 4 times and average void AFE_CurrentProcess(void) { uint8_t temp[2]; int16_t avecur; avecur = siCurBuf[ucCadcTimeCnt]; //4个CADC的值存放于数组中 if(AFE_Read(REG_ADDR_CADCDH, 2, temp) != 0) { siCurBuf[ucCadcTimeCnt] = avecur; //读失败了将上一组电流重赋值 } else { avecur =(int16_t) (temp[0]<<8 | temp[1]); //读成功赋值 siCurBuf[ucCadcTimeCnt] = avecur; } if(++ucCadcTimeCnt >= 4) //计算1s内电流的平均值 { ucCadcTimeCnt = 0; avecur = ((int32_t)siCurBuf[0]+siCurBuf[1]+siCurBuf[2]+siCurBuf[3]) >> 2; cali.tempCur = avecur - cali.cadcZero; bmsMem.cadcAveVal = avecur; //显示cadc寄存器电流 //对当前电流执行校准,计算校准参数 if(cali.cmdZero != 0) { cali.flagWrZeroToEE = cali.cmdZero; cali.cmdZero = 0; cali.cadcZero = avecur; bmsMem.cadcZero = cali.cadcZero; } else if(cali.cmdGain != 0) { cali.flagWrGainToEE = cali.cmdGain; cali.cmdGain = 0; if(cali.tempCur<0) { cali.cadcGain = -cali.current* 100 / cali.tempCur; } else if(cali.tempCur>0) { cali.cadcGain = cali.current* 100 / cali.tempCur; } bmsMem.cadcGain = cali.cadcGain; } //更新电流值 if(nullCurrent_Flag == 0) { bmsMem.packCurrent = (int32_t)cali.cadcGain * cali.tempCur /100; } else //这一秒的电流值无效,同时因为触发条件是写AFE芯片会关闭MOS,正常来说也是无电流的 { bmsMem.packCurrent = 0; nullCurrent_Flag = 0; } //sum of all packs bmsMem.can_cur = (int16_t) (bmsMem.packCurrent/10); //统一数值单位0.01A //小电流延迟显示 if((bmsMem.packCurrent > (-100)) && (bmsMem.packCurrent < 0)) //小电流放电 { if(DSGminiFlag == 0) { DSGcount++; if(DSGcount >= 3) //延迟3s显示 { DSGminiFlag = 1; DSGcount = 0; } else { bmsMem.packCurrent = 0; } } } else if((bmsMem.packCurrent > 0) && (bmsMem.packCurrent < 100)) //小电流充电 { if(CHGminiFlag == 0) { CHGcount++; if(CHGcount >= 3) //延迟3s显示 { CHGminiFlag = 1; CHGcount = 0; } else { bmsMem.packCurrent = 0; } } } else { DSGcount = 0; CHGcount = 0; DSGminiFlag = 0; CHGminiFlag = 0; } //判断充放电状态 bDSGING = 0; bCHGING = 0; bSTANDBY = 0; if(bmsMem.packCurrent <= (-100)) { bDSGING = 1; } else if(bmsMem.packCurrent >= 100) { bCHGING = 1; } else { //待机状态时,电流值存在(上位机可看) //待机状态时,不参与容量计算,但参与电流校准 bSTANDBY = 1; } if(curLimit_ctrlFlag == 1) //开启限流后,根据电流值立刻改动限流的占空比 { //根据实时电流值调整占空比 CHG_LIMIT_PWM_Adjust(); } } //充放电状态赋值 bmsMem.bStatus3 &= 0xff3f; if(bCHGING == 1) { bmsMem.bStatus3 |= 0x0080; } if(bDSGING == 1) { bmsMem.bStatus3 |= 0x0040; } //存在充电或放电,休眠起始点更新 if((bmsMem.packCurrent <= (-2000)) || (bmsMem.packCurrent >= 2000)) { if(((paraMem.sleep_min_disable & 0x8000) == 0) || ((paraMem.sleep2_min_disable & 0x8000) == 0)) //任意一项休眠都更新 { sleep_flag = 0; SLEEP_Refresh(); SLEEP2_Refresh(); } } } //电流校准后保存 void CALI_CurrentProcess(void) { //收到零点校准指令 if(cali.flagWrZeroToEE != 0) { if(scr_WrZero_Flg == 1) { scr_WrZero_Flg = 2; //表示完成 } else if(cali.flagWrZeroToEE == 1) //上位机执行的校准需要回复,云平台是另外的 { modbusFaaRxFlg = 1; modbus1FaaRxFlg = 1; } cali.flagWrZeroToEE = 0; cali.flagZeroCaliFail = EEPROM_CALI_WrZero(cali.cadcZero); } //收到增益校准指令 if(cali.flagWrGainToEE != 0) { if(scr_WrGain_Flg == 1) { scr_WrGain_Flg = 2; //表示完成 } else if(cali.flagWrGainToEE == 1) //上位机执行的校准需要回复,云平台是另外的 { modbusFbbRxFlg = 1; modbus1FbbRxFlg = 1; } cali.flagWrGainToEE = 0; cali.flagGainCaliFail = EEPROM_CALI_WrGain(cali.cadcGain); } } //获取MOS温度和环境温度 //main->while 1s void AFE_TemperaProcess(void) { //获取afe温度 if(AFE_Read(REG_ADDR_TEMP1H, 6, &afeRam.temp1h) != 0) { return; } afeFlg.temp1 = ((uint16_t)afeRam.temp1h <<8 | afeRam.temp1l); afeFlg.temp2 = ((uint16_t)afeRam.temp2h <<8 | afeRam.temp2l); afeFlg.temp3 = ((uint16_t)afeRam.temp3h <<8 | afeRam.temp3l); bmsMem.afe_T1 = TEMP_Cal_CMFA(afeFlg.temp1 * 1000 /(32768-afeFlg.temp1)); bmsMem.afe_T2 = TEMP_Cal_CMFA(afeFlg.temp2 * 1000 /(32768-afeFlg.temp2)); bmsMem.afe_T3 = TEMP_Cal_CMFA(afeFlg.temp3 * 1000 /(32768-afeFlg.temp3)); //针对bmsMem.afe_T1+T2,进行MOS温度告警和告警释放 Trigger_afeTAlarm(); Release_afeTAlarm(); //针对bmsMem.afe_T1+T2,进行MOS温度保护和保护释放 Trigger_afeTProtect(); Release_afeTProtect(); //针对bmsMem.afe_T3,进行环境温度告警和告警释放 Trigger_amTAlarm(); Release_amTAlarm(); //针对bmsMem.afe_T3,进行环境温度保护和保护释放 Trigger_amTProtect(); Release_amTProtect(); } //充电限流10A的控制标志位 void CHG_LIMIT_Ctrl(void) { //触发 if(curLimitFlag == 0) { //常规大电流限流保护 if(bmsMem.packCurrent >= (bmsMem.CHGLimit_Value * 1000)) { curLimitCount++; if(curLimitCount >= bmsMem.CHGLimit_Count) { curLimitCount = 0; curLimitFlag = 1; } } } //延时释放 else { if(bCHGING == 1) //充电过程中,持续10min后释放 { curLimitReleaseCount++; if(curLimitReleaseCount >= bmsMem.CHGLimit_ReleaseCount) { curLimitReleaseCount = 0; curLimitFlag = 0; } } else { curLimitCloseCount++; if(curLimitCloseCount >= 8) { curLimitCloseCount = 0; curLimitFlag = 0; } } } //若之前有充电报警在,限流不能打开 //包括AFE的充电报警 //但去掉充电过流 if(((bmsMem.bStatus1 & 0x41) != 0) || ((bmsMem.bStatus2 & 0x0183) != 0) || ((bmsMem.bStatus3 & 0x0100) != 0) || ((bmsMem.temperaStatus & 0x05) != 0) || ((bmsMem.balanceStatus & 0x0500) != 0)) { curLimitReleaseCount = 0; curLimitFlag = 0; } //若正在放电,限流板应当关闭 if(bDSGING == 1) { curLimitReleaseCount = 0; curLimitFlag = 0; } //进行充电MOS控制时,限流板也关闭 if(((CTRL_Order & 0x02) != 0) || ((paraMem.ctrl_disable & 0x02) != 0)) { curLimitReleaseCount = 0; curLimitFlag = 0; } //限流标志 if(curLimitFlag == 0) { bmsMem.balanceStatus &= 0xffef; } else { bmsMem.balanceStatus |= 0x0010; } } //放电过流2的判断 void OCC2_TIM_Moni(void) { //放电过流2 if((bmsMem.bStatus1 & BIT10) ==0) { if(bmsMem.packCurrent < -paraMem.mcu_ocd2*1000) { OCC2MoniCount++; if(OCC2MoniCount > paraMem.mcu_ocd2_t) //单位10ms { bmsMem.bStatus1 |= BIT10; OCC2MoniCount = 0; } } else { OCC2MoniCount = 0; } } } //因预充使用了CTTRL引脚,所以放电过流2只是用中断来写RAM关闭放电MOS void OCC2_Ctrl(void) { uint8_t temp[1]; //触发后立刻关闭放电MOS if((bmsMem.bStatus1 & BIT10) != 0) { //只在第一次执行 if(OCC2_Flag == 0) { if(AFE_Read(REG_ADDR_SCONF2,1,temp) == 0) { temp[0] &= ~0x02; AFE_Write(REG_ADDR_SCONF2,1,&temp[0]); OCC2_Flag = 1; } } } else { OCC2_Flag = 0; } } //统一写MOS控制到RAM,并控制限流。限流和充放MOS要有时间间隔 void AFE_Ctrl(void) { //默认正常[充放MOS全由硬件控制] uint8_t temp = 0x83; //开放电MOS前开预充 if(PCHG_Flag == 1) { temp &= ~0x02; //保持关闭放电MOS PCHG_Ctrl(); //走预充流程 } /*控制限流关闭在前*/ if(curLimitFlag == 0) { CHG_LIMIT_Off(); } //休眠模式[关闭放电MOS,不影响充电MOS和限流板状态] if(sleep_flag == 1) { temp &= ~0x02; } //各种充电保护(不带afe的)+满充条件4[关闭充电MOS和限流板,不影响放电MOS状态] if(((bmsMem.bStatus1 & 0x0901) != 0) || ((bmsMem.bStatus2 & 0x0083) != 0) || ((bmsMem.temperaStatus & 0x0515) != 0)) //关闭充电MOS { temp &= ~0x01; if(((bmsMem.bStatus1 & 0x0901) != 0) || ((bmsMem.bStatus2 & 0x0083) != 0) || ((bmsMem.temperaStatus & 0x0505) != 0)) //除了充电过流外,会同步关闭限流 { curLimitReleaseCount = 0; curLimitFlag = 0; } } //各种放电保护(带真短路和预充失败)[关闭放电MOS,不影响充电MOS和限流板状态] if(((bmsMem.bStatus1 & 0x062E) != 0) || ((bmsMem.bStatus2 & 0x007C) != 0) || ((bmsMem.temperaStatus & 0x0A2A) != 0)) //关闭放电MOS { temp &= ~0x02; } //限流启用[关闭充电MOS,后续开启限流,不影响放电MOS状态] if(curLimitFlag == 1) { temp &= ~0x01; } /*因上位机写入指令而控制*/ if(((CTRL_Order & 0x01) != 0) || ((paraMem.ctrl_disable & 0x01) != 0)) //强制关闭放电MOS { temp &= ~0x02; } if(((CTRL_Order & 0x02) != 0) || ((paraMem.ctrl_disable & 0x02) != 0)) //强制关闭充电MOS { temp &= ~0x01; } /*当放电MOS被关闭,将要被打开,执行预充而不打开放电MOS*/ if((temp & 0x02) != 0) //要开启放电MOS { dsgCtrl = 0xAA; } else //要关闭放电MOS { dsgCtrl = 0xBB; } if(dsgCtrl_old == 0) //初始值0不参与判断 { dsgCtrl_old = dsgCtrl; } else { if((dsgCtrl == 0xAA) && (dsgCtrl_old != 0xAA)) //从关闭转变为打开 { if(PCHG_Flag == 0) { temp &= ~0x02; //保持关闭 PCHG_Flag = 1;//启动预充 } else if(PCHG_Flag == 2) { PCHG_Flag = 0;//下次可以继续启动预充 dsgCtrl_old = dsgCtrl; } } else { dsgCtrl_old = dsgCtrl; } } /*开关MOS控制*/ AFE_Write(REG_ADDR_SCONF2,1,&temp); /*控制限流打开在后*/ if(curLimitFlag == 1) { CHG_LIMIT_On(); } } //MOS控制开 //预充流程结束/真短路检测结束/真短路释放 void CTRL_On(void) { //不需要控制,只要后续AFE_Ctrl正常控制 MOS_Close_Flg = 0; } //MOS控制关 void CTRL_Off(void) { uint8_t temp = 0x80; AFE_Write(REG_ADDR_SCONF2,1,&temp); //控制全关时,正常控制MOS处也要同步 MOS_Close_Flg = 1; } //获取AFE状态位 //main->while 1s void AFE_ProtectProcess(void) { uint8_t temp[5]; //read flag1-3,bstatus1-2 if(AFE_Read(REG_ADDR_FLAG1,5,temp) == 0) { //短路保护 if((temp[0] & BIT4) != 0) { bmsMem.bStatus1 |= BIT5; } else { bmsMem.bStatus1 &= ~BIT5; } //充电MOS状态 if((temp[3] & BIT0) != 0) { bmsMem.bStatus3 |= BIT1; } else { bmsMem.bStatus3 &= ~BIT1; } //放电MOS状态 if((temp[3] & BIT1) != 0) { bmsMem.bStatus3 |= BIT0; } else { bmsMem.bStatus3 &= ~BIT0; } } //浪涌短路保护的释放 if(sc_close_flag == 1) { uint8_t temp = 0x00; if(AFE_Write(REG_ADDR_FLAG1,1,&temp) == 0) //清空AFE标志位 { temp = 0x80; if(AFE_Write(REG_ADDR_SCONF2,1,&temp) == 0) //继续允许MCU清零标志位 { bmsMem.bStatus1 &= ~BIT5; //浪涌短路保护标志释放(只有2步都成功后才真正清除和释放) sc_close_flag = 0; } } } //充放电MOS故障监测 if((bmsMem.bStatus3 & 0x01) == 0) //放电MOS是关闭状态 { //当出现MOS故障,会主动关闭对应MOS,若此时还有电流,持续报警MOS故障 if((bmsMem.bStatus2 & 0x40) == 0) //还没出现放电MOS故障 { if(bmsMem.packCurrent < (-2000)) //有放电电流 { ErrDSGcount++; if(ErrDSGcount >= 30) { bmsMem.bStatus2 |= BIT6; //说明放电MOS故障 } } else { ErrDSGcount = 0; } } else //已经出现放电MOS故障 { //当因MOS故障关闭MOS后电流消失,那就消去MOS故障 if(bmsMem.packCurrent > (-100)) //不再是放电电流 { ErrDSGRelaycount++; if(ErrDSGRelaycount >= 3) { bmsMem.bStatus2 &= ~BIT6; //说明放电MOS正常 } } else { ErrDSGRelaycount = 0; } } } else //放电MOS也是开启状态 { ErrDSGcount = 0; ErrDSGRelaycount = 0; bmsMem.bStatus2 &= ~BIT6; //不考虑放电MOS是否故障 } if(((bmsMem.bStatus3 & 0x02) == 0) && (curLimitFlag == 0)) //充电MOS是关闭状态 //11.7同时判断限流板没开启 { if((bmsMem.bStatus2 & 0x80) == 0) //还没出现充电MOS故障 { if(bmsMem.packCurrent > 2000) //有充电电流 { ErrCHGcount++; if(ErrCHGcount >= 30) { bmsMem.bStatus2 |= BIT7; //说明充电MOS故障 } } else { ErrCHGcount = 0; } } else //已经出现放电MOS故障 { if(bmsMem.packCurrent < 100) //不再是充电电流 { ErrCHGRelaycount++; if(ErrCHGRelaycount >= 3) { bmsMem.bStatus2 &= ~BIT7; //说明放电MOS正常 } } else { ErrCHGRelaycount = 0; } } } else { ErrCHGcount = 0; ErrCHGRelaycount = 0; bmsMem.bStatus2 &= ~BIT7; //说明充电MOS正常 } //DO执行条件:出现MOS故障 if((bmsMem.bStatus2 & 0xC0) == 0) { DO_Off(); bmsMem.temperaStatus &= 0xff7f; } else { DO_On(); //开启继电器让外部控制 bmsMem.temperaStatus |= 0x0080; } /*浪涌短路保护连续出现的计算和锁定*/ //浪涌短路保护释放——无法释放,只能等待自恢复时间8s //连续出现5次后,直接MCU接管标志位并控制MOS全关 //浪涌短路过程中检测是否真短路 if((bmsMem.balanceStatus & BIT6) != 0) { bmsMem.bStatus1 |= 0x0020; CTRL_Off(); } else { //浪涌短路出现 if((bmsMem.bStatus1 & BIT5) != 0) { //刚出现时 if(sc_OccurFlag == 0) { sc_OccurFlag = 1; sc_RepeatDelay = 0; //分析是否满足锁定条件 if(sc_RepeatFlag == 0) //此前60s内并未出现 (此时重复次数应=0) { sc_RepeatFlag = 1; //用于在消失后的计时判断 } else { sc_RepeatCount++; //浪涌短路持续60s不出现的话,sc_OccurFlag会置0,所以这时候存在值1,说明是在60s内出现的,计数次数+1 if(sc_RepeatCount+1 >= paraMem.scWaitNum) //当计数达到4时(即连续发生了五次浪涌短路),直接锁定,"浪涌短路"持续显示,持续关闭MOS { sc_RepeatCount = 0; bmsMem.balanceStatus |= BIT6; //浪涌短路锁定启用,只有重启可清零 } } } } //浪涌短路消失后 else { sc_OccurFlag = 0; if(TSC_detectFlag != 0xAA) { TSC_detectFlag = 0; } //浪涌短路出现后又消失,若在60s内监测到浪涌短路不开启则计数恢复0,否则计数+1 if(sc_RepeatFlag == 1) { sc_RepeatDelay++; if(sc_RepeatDelay > paraMem.scWait_T) //持续60s { sc_RepeatFlag = 0; //标志置0 sc_RepeatDelay = 0; //倒计时清零 sc_RepeatCount = 0; //连续出现计数清零 } } else { sc_RepeatDelay = 0; } } } /*真短路保护连续出现的计算和锁定,和未锁定时的自动释放*/ //真短路保护释放——5min自动解除 //连续出现5次后,直接MCU接管标志位并控制MOS if((bmsMem.balanceStatus & BIT7) != 0) { bmsMem.bStatus2 |= 0x0010; CTRL_Off(); } else { //5min自动解除 if((bmsMem.bStatus2 & BIT4) != 0) { tsc_relaycount++; if(tsc_relaycount > 300) { tsc_relaycount = 0; TSC_Flag = 0; TSC_detectFlag = 0; bmsMem.bStatus2 &= ~BIT4; CTRL_On(); //释放充放MOS } } //真短路出现 if((bmsMem.bStatus2 & BIT4) != 0) { //刚出现时 if(tsc_OccurFlag == 0) { tsc_OccurFlag = 1; tsc_RepeatDelay = 0; //分析是否满足锁定条件 if(tsc_RepeatFlag == 0) //此前60s内并未出现 (此时重复次数应=0) { tsc_RepeatFlag = 1; //用于在消失后的计时判断 } else { tsc_RepeatCount++; //真短路持续60s不出现的话,tsc_OccurFlag会置0,所以这时候存在值1,说明是在60s内出现的,计数次数+1 if(tsc_RepeatCount+1 >= paraMem.scWaitNum) //当计数达到4时(即连续发生了五次真短路),直接锁定,"真短路"持续显示,持续关闭MOS { tsc_RepeatCount = 0; bmsMem.balanceStatus |= BIT7; //真短路锁定用[预充超时失败锁定]标志位启用,只有重启可清零 } } } } //真短路消失 else { tsc_OccurFlag = 0; //真短路出现后又消失,若在60s内监测到真短路不开启则计数恢复0,否则计数+1 if(tsc_RepeatFlag == 1) { tsc_RepeatDelay++; if(tsc_RepeatDelay > paraMem.scWait_T) //持续60s { tsc_RepeatFlag = 0; //标志置0 tsc_RepeatDelay = 0; //倒计时清零 tsc_RepeatCount = 0; //连续出现计数清零 } } else { tsc_RepeatDelay = 0; } } } //满充条件4满足后,停止充电 if((paraMem.soc100_methods & 0x08) != 0) { if((bmsMem.bStatus1 & 0x0800) == 0) //还没出现满充停充 { if((bmsMem.packVoltage >= paraMem.soc100_vol*100) && (bmsMem.packCurrent <= paraMem.soc100_cur*100) && (bCHGING == 1)) { fcc4_count++; if(fcc4_count >= 3) { bmsMem.bStatus1 |= 0x0800; //置标志位,控制MOS关闭 } } else { fcc4_count = 0; } } else //出现后如果任一对应条件消失,标志释放 { if((bmsMem.packVoltage < paraMem.soc100_vol*100) || (bmsMem.soc < 96) || (bmsMem.packCurrent < -3000)) //特殊解除项:①SOC<96% ②放电电流>3A { fcc4r_count++; if(fcc4r_count >= 3) { bmsMem.bStatus1 &= 0xf7ff; //标志位恢复 } } else { fcc4r_count = 0; } } } else { bmsMem.bStatus1 &= 0xf7ff; } //sum of all packs bmsMem.can_status_byte1 = bmsMem.bStatus1; bmsMem.can_status_byte2 = bmsMem.bStatus2; bmsMem.can_status_byte3 = bmsMem.bStatus3; bmsMem.can_status_byte4 = bmsMem.temperaStatus; //温度报警判断已在此之前执行 #if Key_PressLong if((ON_confirm_flg != 0) && (RST_confirm_flg != 1) && (OFF_confirm_flg != 1)) #endif { //(过压单独讨论,其他的都在这) //报警灯亮与报警跳转 //浪涌短路加回来 if(((bmsMem.bStatus1 & 0x067e) != 0) || ((bmsMem.bStatus2 & 0x001f) !=0) || ((bmsMem.bStatus3 & 0x0008) !=0) || ((bmsMem.temperaStatus & 0x0f3f) !=0)) { if(sleep_flag == 0) LED_ALARM_On(); else LED_ALARM_Off(); } //只亮报警灯 else if(((bmsMem.bStatus2 & 0x00e0) !=0) || ((bmsMem.temperaStatus & 0x0040) !=0) || ((bmsMem.balanceStatus & BIT6) != 0)) //BIT6.7-放电MOS故障、充电MOS故障、预充失败、急停 (不在屏幕上) //浪涌短路锁定亮灯 { if(sleep_flag == 0) LED_ALARM_On(); else LED_ALARM_Off(); } //报警灯灭 else { //若出现总体过压|单体过压,则不恢复原状,等待之后的判断 if((bmsMem.bStatus1 & 0x0101) == 0) { LED_ALARM_Off(); } } //主机屏幕报警页跳转判断(所有保护) if(((bmsMem.bStatus1 & 0x077f) != 0) || ((bmsMem.bStatus2 & 0x001f) !=0) || ((bmsMem.bStatus3 & 0x0008) !=0) || ((bmsMem.temperaStatus & 0x0f3f) !=0)) { bAlarmFlag = 1; } else { bAlarmFlag = 0; bAlarmFlagOld = 0; } } //soe记录判断 soe.bsNew[0] = bmsMem.bStatus1 & 0xff; soe.bsNew[1] = bmsMem.bStatus2 & 0xff; soe.bsNew[2] = bmsMem.bStatus3 & 0xff; soe.bsNew[3] = bmsMem.temperaStatus & 0xff; soe.bsNew[4] = bmsMem.balanceStatus & 0xff; soe.bsNew[5] = ((bmsMem.bStatus1>>4) & 0xf0) | ((bmsMem.temperaStatus>>8) & 0x0f); //占用原packStatus位置,保存新增保护 //电压报警备份 //原来是正常状态 VS 已经出现报警 //单体过压 if((soe.bsOld[0] & 0x01) == 0) { if((soe.bsNew[0] & 0x01) != 0) //报警触发 { soe.bsOld[0] = soe.bsNew[0]; //如果已经执行记录,就不会再执行 soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[0] & 0x01) == 0) //没有报警,上次清除 { soe.bsOld[0] &= 0XFE; //~0X01 } } //单体欠压 if((soe.bsOld[0] & 0x02) == 0) { if((soe.bsNew[0] & 0x02) != 0) //报警触发 { soe.bsOld[0] = soe.bsNew[0]; //如果已经执行记录,就不会再执行 soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[0] & 0x02) == 0) //没有报警,上次清除 { soe.bsOld[0] &= 0XFD; //~0X02 } } //总体过压 if((soe.bsOld[5] & 0x10) == 0) { if((soe.bsNew[5] & 0x10) != 0) //报警触发 { soe.bsOld[5] = soe.bsNew[5]; //如果已经执行记录,就不会再执行 soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[5] & 0x10) == 0) //没有报警,上次清除 { soe.bsOld[5] &= 0XEF; //~0X10 } } //总体欠压 if((soe.bsOld[5] & 0x20) == 0) { if((soe.bsNew[5] & 0x20) != 0) //报警触发 { soe.bsOld[5] = soe.bsNew[5]; //如果已经执行记录,就不会再执行 soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[5] & 0x20) == 0) //没有报警,上次清除 { soe.bsOld[5] &= 0XDF; //~0X20 } } //异常高压 if((soe.bsOld[0] & 0x40) == 0) { if((soe.bsNew[0] & 0x40) != 0) //报警触发 { soe.bsOld[0] = soe.bsNew[0]; //如果已经执行记录,就不会再执行 soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[0] & 0x40) == 0) //没有报警,上次清除 { soe.bsOld[0] &= 0XBF; //~0X40 } } //低电压禁止充电 if((soe.bsOld[2] & 0x08) == 0) { if((soe.bsNew[2] & 0x08) != 0) //报警触发 { soe.bsOld[2] = soe.bsNew[2]; //如果已经执行记录,就不会再执行 soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[2] & 0x08) == 0) //没有报警,上次清除 { soe.bsOld[2] &= 0XF7; //~0X08 } } //电流报警备份 //充电过流 if(((soe.bsOld[0] & 0x10) == 0) && ((soe.bsOld[3] & 0x10) == 0)) { if(((soe.bsNew[0] & 0x10) != 0) || ((soe.bsNew[3] & 0x10) != 0)) //报警触发 { soe.bsOld[0] = soe.bsNew[0]; //如果已经执行记录,就不会再执行 soe.bsOld[3] = soe.bsNew[3]; soe.bkType = BKTYPE_ALARM; } } else { if(((soe.bsNew[0] & 0x10) == 0) && ((soe.bsNew[3] & 0x10) == 0)) //没有报警,上次清除 { soe.bsOld[0] &= 0XEF; //~0X10 soe.bsOld[3] &= 0XEF; //~0X10 } } //放电过流1 if(((soe.bsOld[0] & 0x04) == 0) && ((soe.bsOld[3] & 0x20) == 0)) { if(((soe.bsNew[0] & 0x04) != 0) || ((soe.bsNew[3] & 0x20) != 0)) //报警触发 { soe.bsOld[0] = soe.bsNew[0]; //如果已经执行记录,就不会再执行 soe.bsOld[3] = soe.bsNew[3]; soe.bkType = BKTYPE_ALARM; } } else { if(((soe.bsNew[0] & 0x04) == 0) && ((soe.bsNew[3] & 0x20) == 0)) //没有报警,上次清除 { soe.bsOld[0] &= 0XFB; //~0x04 soe.bsOld[3] &= 0XDF; //~0x20 } } //放电过流2 if(((soe.bsOld[0] & 0x08) == 0) && ((soe.bsOld[5] & 0x40) == 0)) { if(((soe.bsNew[0] & 0x08) != 0) || ((soe.bsNew[5] & 0x40) != 0)) //报警触发 { soe.bsOld[0] = soe.bsNew[0]; //如果已经执行记录,就不会再执行 soe.bsOld[5] = soe.bsNew[5]; soe.bkType = BKTYPE_ALARM; } } else { if(((soe.bsNew[0] & 0x08) == 0) && ((soe.bsNew[5] & 0x40) == 0)) //没有报警,上次清除 { soe.bsOld[0] &= 0XF7; //~0x08 soe.bsOld[5] &= 0XBF; //~0x40 } } //浪涌短路 if((soe.bsOld[0] & 0x20) == 0) { if((soe.bsNew[0] & 0x20) != 0) //报警触发 { soe.bsOld[0] = soe.bsNew[0]; //如果已经执行记录,就不会再执行 soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[0] & 0x20) == 0) //没有报警,上次清除 { soe.bsOld[0] &= 0XDF; //~0X20 } } //真短路 if(((soe.bsOld[1] & 0x10) ==0)) { if((soe.bsNew[1] & 0x10) != 0) { soe.bsOld[1] = soe.bsNew[1]; soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[1] & 0x10) == 0) { soe.bsOld[1] &= 0XEF; //~0X10 } } //温度报警备份 //充电高温 if(((soe.bsOld[1] & 0x02) == 0) && ((soe.bsOld[3] & 0x01) == 0) && ((soe.bsOld[5] & 0x01) == 0)) { if(((soe.bsNew[1] & 0x02) !=0) || ((soe.bsNew[3] & 0x01) !=0) || ((soe.bsNew[5] & 0x01) !=0)) { soe.bsOld[1] = soe.bsNew[1]; //如果已经执行记录,就不会再执行 soe.bsOld[3] = soe.bsNew[3]; soe.bsOld[5] = soe.bsNew[5]; soe.bkType = BKTYPE_ALARM; } } else { if(((soe.bsNew[1] & 0x02) ==0) && ((soe.bsNew[3] & 0x01) ==0) && ((soe.bsNew[5] & 0x01) ==0)) { soe.bsOld[1] &= 0XFD; //~0x02 soe.bsOld[3] &= 0XFE; //~0x01 soe.bsOld[5] &= 0XFE; //~0x01 } } //放电高温 if(((soe.bsOld[1] & 0x08) == 0) && ((soe.bsOld[3] & 0x02) == 0) && ((soe.bsOld[5] & 0x02) == 0)) { if(((soe.bsNew[1] & 0x08) !=0) || ((soe.bsNew[3] & 0x02) !=0) || ((soe.bsNew[5] & 0x02) !=0)) { soe.bsOld[1] = soe.bsNew[1]; //如果已经执行记录,就不会再执行 soe.bsOld[3] = soe.bsNew[3]; soe.bsOld[5] = soe.bsNew[5]; soe.bkType = BKTYPE_ALARM; } } else { if(((soe.bsNew[1] & 0x08) ==0) && ((soe.bsNew[3] & 0x02) ==0) && ((soe.bsNew[5] & 0x02) ==0)) { soe.bsOld[1] &= 0XF7; //~0x08 soe.bsOld[3] &= 0XFD; //~0x02 soe.bsOld[5] &= 0XFD; //~0x02 } } //充电低温 if(((soe.bsOld[1] & 0x01) == 0) && ((soe.bsOld[3] & 0x04) == 0) && ((soe.bsOld[5] & 0x04) == 0)) { if(((soe.bsNew[1] & 0x01) !=0) || ((soe.bsNew[3] & 0x04) !=0) || ((soe.bsNew[5] & 0x04) !=0)) { soe.bsOld[1] = soe.bsNew[1]; //如果已经执行记录,就不会再执行 soe.bsOld[3] = soe.bsNew[3]; soe.bsOld[5] = soe.bsNew[5]; soe.bkType = BKTYPE_ALARM; } } else { if(((soe.bsNew[1] & 0x01) ==0) && ((soe.bsNew[3] & 0x04) ==0) && ((soe.bsNew[5] & 0x04) ==0)) { soe.bsOld[1] &= 0XFE; //~0x01 soe.bsOld[3] &= 0XFB; //~0x04 soe.bsOld[5] &= 0XFB; //~0x04 } } //放电低温 if(((soe.bsOld[1] & 0x04) == 0) && ((soe.bsOld[3] & 0x08) == 0) && ((soe.bsOld[5] & 0x08) == 0)) { if(((soe.bsNew[1] & 0x04) !=0) || ((soe.bsNew[3] & 0x08) !=0) || ((soe.bsNew[5] & 0x08) !=0)) { soe.bsOld[1] = soe.bsNew[1]; //如果已经执行记录,就不会再执行 soe.bsOld[3] = soe.bsNew[3]; soe.bsOld[5] = soe.bsNew[5]; soe.bkType = BKTYPE_ALARM; } } else { if( ((soe.bsNew[1] & 0x04) ==0) && ((soe.bsNew[3] & 0x08) ==0) && ((soe.bsNew[5] & 0x08) ==0)) { soe.bsOld[1] &= 0XFB; //~0x04 soe.bsOld[3] &= 0XF7; //~0x08 soe.bsOld[5] &= 0XF7; //~0x08 } } //DI-急停 if( ((soe.bsOld[3] & 0x40) ==0) ) { if((soe.bsNew[3] & 0x40) != 0) { soe.bsOld[3] = soe.bsNew[3]; soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[3] & 0x40) == 0) { soe.bsOld[3] &= 0XBF; //~0X40 } } //故障 //放电MOS故障 if( ((soe.bsOld[1] & 0x40) ==0) ) { if((soe.bsNew[1] & 0x40) != 0) { soe.bsOld[1] = soe.bsNew[1]; soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[1] & 0x40) == 0) { soe.bsOld[1] &= 0XBF; //~0X40 } } //充电MOS故障 if( ((soe.bsOld[1] & 0x80) ==0) ) { if((soe.bsNew[1] & 0x80) != 0) { soe.bsOld[1] = soe.bsNew[1]; soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[1] & 0x80) == 0) { soe.bsOld[1] &= 0X7F; //~0X80 } } //预充失败 if( ((soe.bsOld[1] & 0x20) ==0) ) { if((soe.bsNew[1] & 0x20) != 0) { soe.bsOld[1] = soe.bsNew[1]; soe.bkType = BKTYPE_ALARM; } } else { if((soe.bsNew[1] & 0x20) == 0) { soe.bsOld[1] &= 0XDF; //~0X20 } } if(soe.bkType !=0) //当出现情况,进行记录 { SOE_BkData(soe.bkType); //函数内部清除BKTYPE标记 } }