1603 lines
37 KiB
C
1603 lines
37 KiB
C
/**
|
||
******************************************************************************
|
||
* @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<lenth; i++)
|
||
{
|
||
result = AFE_WriteOneByte(addr, data);
|
||
if(result != 0)
|
||
{
|
||
delay_ms(1);
|
||
result = AFE_WriteOneByte(addr, data);
|
||
if(result != 0)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
addr++;
|
||
data++;
|
||
delay_ms(1);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
//读AFE的寄存器
|
||
uint8_t AFE_Read(uint8_t addr, uint8_t lenth, uint8_t *data)
|
||
{
|
||
uint8_t result = 0;
|
||
|
||
result = AFE_ReadMulByte(addr, lenth, data);
|
||
if(result != 0)
|
||
{
|
||
//读失败,重新初始化SPI
|
||
SPI2_Error();
|
||
delay_ms(10);
|
||
|
||
result = AFE_ReadMulByte(addr, lenth, data);
|
||
if(result != 0)
|
||
{
|
||
//读失败,重新初始化SPI
|
||
SPI2_Error();
|
||
delay_ms(10);
|
||
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
//从Flash数据更新到AFE
|
||
//FLASH -> 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;i<bmsMem.ucCellNum;i++)
|
||
{
|
||
temp += (int32_t)cellVol[i];
|
||
}
|
||
bmsMem.packVoltage = (uint32_t)temp;
|
||
|
||
//计算电芯电压最大最小值
|
||
max = cellVol[0];
|
||
min = cellVol[0];
|
||
maxIndex = 0;
|
||
minIndex = 0;
|
||
for(i=0;i<bmsMem.ucCellNum;i++)
|
||
{
|
||
if(max<cellVol[i])
|
||
{
|
||
max = cellVol[i];
|
||
maxIndex = i;
|
||
}
|
||
|
||
if(min>cellVol[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标记
|
||
}
|
||
}
|
||
|
||
|