1494 lines
34 KiB
C
1494 lines
34 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 "stdio.h"
|
||
|
||
ONLINE_MEMORY onlineMem;
|
||
|
||
VERSION_MEMORY VersionMem;
|
||
PARA_MEMORY paraMem;
|
||
BMS_MEMORY bmsMem;
|
||
BMS_MEMORY bmsMem_slave;
|
||
|
||
PROTOCOL_SRNE_MEMORY SRNEMem;
|
||
PROTOCOL_VOLTRONIC_MEMORY VoltronicMem;
|
||
PROTOCOL_SMK_MEMORY SMKMem;
|
||
PROTOCOL_Growatt_MEMORY GrowattMem;
|
||
|
||
UNION_VOLTAGE_STATUS staVol;
|
||
UNION_CURRENT_STATUS staCur;
|
||
UNION_TEMPERA_STATUS1 staTemp1;
|
||
UNION_TEMPERA_STATUS2 staTemp2;
|
||
UNION_MOSFET_STATUS staMos;
|
||
UNION_PACK_STATUS staPack;
|
||
|
||
uint16_t alarm_occ_old;
|
||
uint16_t alarm_ocd1_old;
|
||
uint16_t alarm_puv_old;
|
||
uint8_t chgCurLimit_changeFlg;
|
||
uint8_t dsgCurLimit_changeFlg;
|
||
uint8_t dsgVolLimit_changeFlg;
|
||
|
||
const uint8_t CRC8Table[]=
|
||
{ //120424-1 CRC Table
|
||
0x00,0x07,0x0E,0x09,0x1C,0x1B,0x12,0x15,0x38,0x3F,0x36,0x31,0x24,0x23,0x2A,0x2D,
|
||
0x70,0x77,0x7E,0x79,0x6C,0x6B,0x62,0x65,0x48,0x4F,0x46,0x41,0x54,0x53,0x5A,0x5D,
|
||
0xE0,0xE7,0xEE,0xE9,0xFC,0xFB,0xF2,0xF5,0xD8,0xDF,0xD6,0xD1,0xC4,0xC3,0xCA,0xCD,
|
||
0x90,0x97,0x9E,0x99,0x8C,0x8B,0x82,0x85,0xA8,0xAF,0xA6,0xA1,0xB4,0xB3,0xBA,0xBD,
|
||
0xC7,0xC0,0xC9,0xCE,0xDB,0xDC,0xD5,0xD2,0xFF,0xF8,0xF1,0xF6,0xE3,0xE4,0xED,0xEA,
|
||
0xB7,0xB0,0xB9,0xBE,0xAB,0xAC,0xA5,0xA2,0x8F,0x88,0x81,0x86,0x93,0x94,0x9D,0x9A,
|
||
0x27,0x20,0x29,0x2E,0x3B,0x3C,0x35,0x32,0x1F,0x18,0x11,0x16,0x03,0x04,0x0D,0x0A,
|
||
0x57,0x50,0x59,0x5E,0x4B,0x4C,0x45,0x42,0x6F,0x68,0x61,0x66,0x73,0x74,0x7D,0x7A,
|
||
0x89,0x8E,0x87,0x80,0x95,0x92,0x9B,0x9C,0xB1,0xB6,0xBF,0xB8,0xAD,0xAA,0xA3,0xA4,
|
||
0xF9,0xFE,0xF7,0xF0,0xE5,0xE2,0xEB,0xEC,0xC1,0xC6,0xCF,0xC8,0xDD,0xDA,0xD3,0xD4,
|
||
0x69,0x6E,0x67,0x60,0x75,0x72,0x7B,0x7C,0x51,0x56,0x5F,0x58,0x4D,0x4A,0x43,0x44,
|
||
0x19,0x1E,0x17,0x10,0x05,0x02,0x0B,0x0C,0x21,0x26,0x2F,0x28,0x3D,0x3A,0x33,0x34,
|
||
0x4E,0x49,0x40,0x47,0x52,0x55,0x5C,0x5B,0x76,0x71,0x78,0x7F,0x6A,0x6D,0x64,0x63,
|
||
0x3E,0x39,0x30,0x37,0x22,0x25,0x2C,0x2B,0x06,0x01,0x08,0x0F,0x1A,0x1D,0x14,0x13,
|
||
0xAE,0xA9,0xA0,0xA7,0xB2,0xB5,0xBC,0xBB,0x96,0x91,0x98,0x9F,0x8A,0x8D,0x84,0x83,
|
||
0xDE,0xD9,0xD0,0xD7,0xC2,0xC5,0xCC,0xCB,0xE6,0xE1,0xE8,0xEF,0xFA,0xFD,0xF4,0xF3
|
||
};
|
||
|
||
//look-up table calculte CRC
|
||
uint8_t CRC8_Cal(uint8_t *pdata, uint8_t len)
|
||
{
|
||
uint8_t crc8 = 0;
|
||
|
||
for(; len > 0; len--)
|
||
{
|
||
crc8 = CRC8Table[crc8^*pdata];
|
||
pdata++;
|
||
}
|
||
return(crc8);
|
||
}
|
||
|
||
//和Flash_CRC校验同理的值
|
||
uint16_t CRC16_FirmtoEE(uint8_t *data, uint16_t len)
|
||
{
|
||
uint16_t i,j;
|
||
uint16_t mCrc = 0;
|
||
|
||
for(i=0; i<len; i++)
|
||
{
|
||
mCrc ^= ((uint16_t)data[i] << 8);
|
||
for(j=8; j!=0; j--)
|
||
{
|
||
if(mCrc & 0x8000)
|
||
mCrc = mCrc << 1 ^ 0x1021;
|
||
else
|
||
mCrc = mCrc << 1;
|
||
}
|
||
}
|
||
return mCrc;
|
||
}
|
||
|
||
//转换为ASCII字符传输
|
||
uint8_t toASCII(uint8_t data)
|
||
{
|
||
uint8_t result;
|
||
|
||
if(data<10) //0~9 -> 0x30~0x39
|
||
{
|
||
result = 0x30 + data;
|
||
}
|
||
else //A~F -> 0x41~0x46
|
||
{
|
||
result = 0x37 + data;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
//根据当前时间取伪随机数,范围AddrMax+1~65534
|
||
#define MODULUS 2147483647
|
||
#define MULTIPLIER 1103515245
|
||
#define ADDEND 12345
|
||
uint16_t get_random(void)
|
||
{
|
||
uint32_t time;
|
||
uint32_t rand;
|
||
uint16_t index;
|
||
|
||
time=RTC_GetCounter();
|
||
rand=(time * MULTIPLIER + ADDEND) % MODULUS; //取值范围是0到MODULUS-1
|
||
|
||
index=rand%(65535-(AddrMax+1)-1+1)+(AddrMax+1); //取值范围是AddrMax+1~65534
|
||
|
||
return index;
|
||
}
|
||
|
||
//功能函数:获取字符串里的参数值
|
||
uint8_t GetStr(const char* dataKey, char End1, char End2, char* InStr, char* OutStr)
|
||
{
|
||
uint8_t datalen = 0; //字符串长度
|
||
|
||
char* dataStart = strstr(InStr, dataKey); //找dataKey
|
||
if(dataStart == NULL)
|
||
{
|
||
return 0; //找不到dataKey,返回0
|
||
}
|
||
dataStart += strlen(dataKey); //跳过dataKey
|
||
|
||
char* dataEnd = strchr(dataStart, End1); //先找End1
|
||
if(dataEnd == NULL)
|
||
{
|
||
dataEnd = strchr(dataStart, End2); //再找End2
|
||
}
|
||
if(dataEnd == NULL)
|
||
{
|
||
return 0; //找不到End1和End2,返回0
|
||
}
|
||
|
||
datalen = dataEnd - dataStart;
|
||
strncpy(OutStr, dataStart, datalen);
|
||
OutStr[datalen] = '\0';
|
||
|
||
return datalen; //返回内容长度
|
||
}
|
||
|
||
//功能函数:获取request_id
|
||
uint8_t GetID(char* InStr, char* OutStr)
|
||
{
|
||
//{"request_id":"123124sdf",…}
|
||
const char* dataKey = "\"request_id\":\"";
|
||
char End = '\"';
|
||
|
||
uint8_t datalen = 0; //字符串长度
|
||
|
||
char* dataStart = strstr(InStr, dataKey); //找dataKey
|
||
if(dataStart == NULL)
|
||
{
|
||
return 0; //找不到dataKey,返回0
|
||
}
|
||
dataStart += strlen(dataKey);
|
||
|
||
char* dataEnd = strchr(dataStart, End); //找End
|
||
if(dataEnd == NULL)
|
||
{
|
||
return 0; //找不到End,返回0
|
||
}
|
||
|
||
datalen = dataEnd - dataStart;
|
||
strncpy(OutStr, dataStart, datalen);
|
||
OutStr[datalen] = '\0';
|
||
|
||
return datalen; //返回内容长度
|
||
}
|
||
|
||
//功能函数:获取字符串里的参数值
|
||
//增加:只输入名称,会寻找之后的第一个':'
|
||
//注意:只适合"Name":Value这种格式,结束符固定','或'}'
|
||
uint8_t GetStrFromJson(const char* dataKey, char* InStr, char* OutStr)
|
||
{
|
||
uint8_t datalen = 0; //字符串长度
|
||
|
||
char* dataStart = strstr(InStr, dataKey); //找dataKey
|
||
if(dataStart == NULL)
|
||
{
|
||
return 0; //找不到dataKey,返回0
|
||
}
|
||
dataStart += strlen(dataKey); //跳过dataKey
|
||
|
||
dataStart = strchr(dataStart, ':');//找dataKey之后的第一个':'
|
||
if(dataStart == NULL)
|
||
{
|
||
return 0; //找不到':',返回0
|
||
}
|
||
dataStart += 1; //跳过冒号
|
||
|
||
while (*dataStart == ' ') dataStart++; //跳过空白
|
||
|
||
char* dataEnd = strchr(dataStart, ','); //先找End1
|
||
if(dataEnd == NULL)
|
||
{
|
||
dataEnd = strchr(dataStart, '}'); //再找End2
|
||
}
|
||
if(dataEnd == NULL)
|
||
{
|
||
return 0; //找不到End1和End2,返回0
|
||
}
|
||
|
||
datalen = dataEnd - dataStart;
|
||
strncpy(OutStr, dataStart, datalen);
|
||
OutStr[datalen] = '\0';
|
||
|
||
return datalen; //返回内容长度
|
||
}
|
||
|
||
//计算无符号数在十进制转字符串后,要多少字节
|
||
//输入最大5位数,保险起见再加1位
|
||
uint8_t uint_str_len(uint32_t value)
|
||
{
|
||
if(value < 10) return 1;
|
||
else if((value < 100)) return 2;
|
||
else if((value < 1000)) return 3;
|
||
else if((value < 10000)) return 4;
|
||
else if((value < 100000)) return 5;
|
||
else if((value < 1000000)) return 6;
|
||
else if((value < 10000000)) return 7;
|
||
else if((value < 100000000)) return 8;
|
||
else if((value < 1000000000)) return 9;
|
||
return 10;
|
||
}
|
||
|
||
//计算有符号数在十进制转字符串后,要多少字节
|
||
uint8_t int_str_len(int32_t value)
|
||
{
|
||
uint32_t abs_vlaue;
|
||
uint8_t abs_len;
|
||
|
||
if(value == INT32_MIN) return 11; //"-2147483648"
|
||
|
||
abs_vlaue = (value<0) ? (uint32_t)(-value):(uint32_t)value;
|
||
abs_len = uint_str_len(abs_vlaue);
|
||
|
||
return (value<0) ? abs_len+1:abs_len;
|
||
}
|
||
|
||
//实时更新并机总数据和数据判断,1s执行1次
|
||
uint8_t OnlineNum; //BMS正常工作数量
|
||
uint8_t OnlineFirstAddr; //第一个是正常工作的并机地址
|
||
uint8_t chg_curLimitNum; //充电限流置0的个数,SOC大于100%的时候启用
|
||
uint8_t dsg_curLimitNum; //放电限流置0的个数,SOC小于10%的时候启用
|
||
uint8_t chg_cur0Num; //因报警触发充电限流40A时,出现保护限流0A的个数
|
||
void canMem_refresh(void)
|
||
{
|
||
uint8_t i;
|
||
int32_t oldcur = canMem[0].cur; //保留上一次的总电流值,在计算值异常时放入
|
||
|
||
|
||
/*并机汇总信息的计算*/
|
||
//1.485采集数据初始化
|
||
canMem[0].status_byte1 = 0;
|
||
canMem[0].status_byte2 = 0;
|
||
canMem[0].status_byte3 = 0;
|
||
canMem[0].status_byte4 = 0;
|
||
canMem[0].soc = 0;
|
||
canMem[0].soh = 0;
|
||
canMem[0].cur = 0;
|
||
canMem[0].temp = 0;
|
||
canMem[0].VolMax = 0;
|
||
canMem[0].VolMin = 0;
|
||
canMem[0].VolMaxIndex = 0;
|
||
canMem[0].VolMinIndex = 0;
|
||
canMem[0].TempMax = 0;
|
||
canMem[0].TempMin = 0;
|
||
canMem[0].TempMaxIndex = 0;
|
||
canMem[0].TempMinIndex = 0;
|
||
|
||
//Wh版屏幕
|
||
canMem[0].cumuliCap = 0;
|
||
canMem[0].cycleCnt = 0;
|
||
|
||
//负值矫正
|
||
canMem[0].cellVoltageMax = 0;
|
||
canMem[0].cellVoltageMin = 0;
|
||
|
||
|
||
canMem[1].status_byte1 = bmsMem.can_status_byte1;
|
||
canMem[1].status_byte2 = bmsMem.can_status_byte2;
|
||
canMem[1].status_byte3 = bmsMem.can_status_byte3;
|
||
canMem[1].status_byte4 = bmsMem.can_status_byte4;
|
||
canMem[1].soc = bmsMem.can_soc;
|
||
canMem[1].soh = bmsMem.can_soh;
|
||
canMem[1].cur = (int16_t)bmsMem.can_cur;
|
||
canMem[1].temp = (int16_t)bmsMem.can_temp;
|
||
canMem[1].VolMax = bmsMem.can_VolMax;
|
||
canMem[1].VolMin = bmsMem.can_VolMin;
|
||
canMem[1].VolMaxIndex = bmsMem.can_VolMaxIndex;
|
||
canMem[1].VolMinIndex = bmsMem.can_VolMinIndex;
|
||
canMem[1].TempMax = bmsMem.can_TempMax;
|
||
canMem[1].TempMin = bmsMem.can_TempMin;
|
||
canMem[1].TempMaxIndex = bmsMem.can_TempMaxIndex;
|
||
canMem[1].TempMinIndex = bmsMem.can_TempMinIndex;
|
||
|
||
//Wh版屏幕
|
||
canMem[1].cumuliCap = bmsMem.can_cumuliCap;
|
||
canMem[1].cycleCnt = bmsMem.can_cycleCnt;
|
||
|
||
//负值矫正
|
||
canMem[1].cellVoltageMax = (int16_t)(canMem[1].VolMax*32/5)*5/32;
|
||
canMem[1].cellVoltageMin = (int16_t)(canMem[1].VolMin*32/5)*5/32;
|
||
|
||
#if Addr_SetAuto
|
||
if((paraMem.addr_FREE_Flg == 0) && (assignAddr_random != 0))
|
||
{
|
||
canMem[1].com = assignAddr_random; //赋值主机自身生成的队列标志位
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
canMem[1].com = 1; //就算此时没有生成好的队列标志位,也要置1不能是0(按逻辑其实这里一定有队列标志位)
|
||
}
|
||
|
||
//2.统计当前通讯正常从机数量
|
||
bmsMem.E2_485Snum = 1;
|
||
for(i=2;i<=paraMem.PACK_NUM;i++)
|
||
{
|
||
if(canMem[i].com != 0) //引入队列标志位后的改动
|
||
{
|
||
bmsMem.E2_485Snum++;
|
||
}
|
||
}
|
||
|
||
//3.计算并机总值
|
||
//报警记录的并机值
|
||
for(i=1;i<=paraMem.PACK_NUM;i++)
|
||
{
|
||
if(canMem[i].com != 0)
|
||
{
|
||
canMem[0].status_byte1 |= canMem[i].status_byte1;
|
||
canMem[0].status_byte2 |= canMem[i].status_byte2;
|
||
canMem[0].status_byte3 |= canMem[i].status_byte3;
|
||
canMem[0].status_byte4 |= canMem[i].status_byte4;
|
||
}
|
||
}
|
||
//参数的并机值
|
||
//当处于并机模式,只纳入在线正常工作的BMS的数据
|
||
if(bmsMem.E2_485Snum >= 2)
|
||
{
|
||
/*统计工作正常的数量,addr=1也要检测*/
|
||
OnlineNum = 0;
|
||
OnlineFirstAddr = 0;
|
||
for(i=1;i<=paraMem.PACK_NUM;i++)
|
||
{
|
||
if(canMem[i].com != 0) //引入队列标志位后的改动
|
||
{
|
||
//没有任何报警的BMS才认为是在线的(不考虑总体/单体过压)
|
||
if( ((canMem[i].status_byte1 & 0x067e) == 0) && ((canMem[i].status_byte2 & 0x00ff) == 0) && ((canMem[i].status_byte3 & 0x0008) == 0) && ((canMem[i].status_byte4 & 0x0f7f) == 0) )
|
||
{
|
||
canMem[0].soc += canMem[i].soc;
|
||
canMem[0].soh += canMem[i].soh;
|
||
canMem[0].cur += canMem[i].cur;
|
||
canMem[0].temp += canMem[i].temp;
|
||
|
||
//Wh版屏幕
|
||
canMem[0].cumuliCap += canMem[i].cumuliCap;
|
||
canMem[0].cycleCnt += canMem[i].cycleCnt;
|
||
|
||
if(OnlineFirstAddr == 0) OnlineFirstAddr = i;
|
||
OnlineNum++;
|
||
}
|
||
}
|
||
}
|
||
|
||
if(OnlineNum != 0) //存在才能进行除计算
|
||
{
|
||
//计算平均值
|
||
canMem[0].soc = canMem[0].soc / OnlineNum;
|
||
canMem[0].soh = canMem[0].soh / OnlineNum;
|
||
canMem[0].temp = canMem[0].temp / OnlineNum;
|
||
|
||
//计算最大最小值
|
||
canMem[0].VolMax = canMem[OnlineFirstAddr].VolMax;
|
||
canMem[0].VolMin = canMem[OnlineFirstAddr].VolMin;
|
||
canMem[0].cellVoltageMax = canMem[OnlineFirstAddr].cellVoltageMax; //负值矫正
|
||
canMem[0].cellVoltageMin = canMem[OnlineFirstAddr].cellVoltageMin; //负值矫正
|
||
canMem[0].VolMaxIndex = canMem[OnlineFirstAddr].VolMaxIndex;
|
||
canMem[0].VolMinIndex = canMem[OnlineFirstAddr].VolMinIndex;
|
||
canMem[0].TempMax = canMem[OnlineFirstAddr].TempMax;
|
||
canMem[0].TempMin = canMem[OnlineFirstAddr].TempMin;
|
||
canMem[0].TempMaxIndex = canMem[OnlineFirstAddr].TempMaxIndex;
|
||
canMem[0].TempMinIndex = canMem[OnlineFirstAddr].TempMinIndex;
|
||
for(i=OnlineFirstAddr+1;i<=paraMem.PACK_NUM;i++)
|
||
{
|
||
if(canMem[i].com != 0) //只比较在线的
|
||
{
|
||
//没有执行任何保护的BMS才认为是在线的(不考虑总体/单体过压)
|
||
if( ((canMem[i].status_byte1 & 0x067e) == 0) && ((canMem[i].status_byte2 & 0x00ff) == 0) && ((canMem[i].status_byte3 & 0x0008) == 0) && ((canMem[i].status_byte4 & 0x0f7f) == 0) )
|
||
{
|
||
//if(canMem[i].VolMax > canMem[0].VolMax)
|
||
if(canMem[i].cellVoltageMax > canMem[0].cellVoltageMax)
|
||
{
|
||
canMem[0].cellVoltageMax = canMem[i].cellVoltageMax; //负值矫正
|
||
|
||
canMem[0].VolMax = canMem[i].VolMax;
|
||
canMem[0].VolMaxIndex = canMem[i].VolMaxIndex+bmsMem.ucCellNum*(i-1);
|
||
}
|
||
//if(canMem[i].VolMin < canMem[0].VolMin)
|
||
if(canMem[i].cellVoltageMin < canMem[0].cellVoltageMin)
|
||
{
|
||
canMem[0].cellVoltageMin = canMem[i].cellVoltageMin; //负值矫正
|
||
|
||
canMem[0].VolMin = canMem[i].VolMin;
|
||
canMem[0].VolMinIndex = canMem[i].VolMinIndex+bmsMem.ucCellNum*(i-1);
|
||
}
|
||
|
||
if(canMem[i].TempMax > canMem[0].TempMax)
|
||
{
|
||
canMem[0].TempMax = canMem[i].TempMax;
|
||
canMem[0].TempMaxIndex = canMem[i].TempMaxIndex+4*(i-1);
|
||
}
|
||
if(canMem[i].TempMin < canMem[0].TempMin)
|
||
{
|
||
canMem[0].TempMin = canMem[i].TempMin;
|
||
canMem[0].TempMinIndex = canMem[i].TempMinIndex+4*(i-1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//只连一台,只显示主机自身
|
||
else
|
||
{
|
||
//赋值1,不影响协议显示
|
||
OnlineNum = 1;
|
||
|
||
//单板直接等于主机值
|
||
canMem[0].soc = canMem[1].soc;
|
||
canMem[0].soh = canMem[1].soh;
|
||
canMem[0].cur = canMem[1].cur;
|
||
canMem[0].temp = canMem[1].temp;
|
||
|
||
canMem[0].VolMax = canMem[1].VolMax;
|
||
canMem[0].VolMin = canMem[1].VolMin;
|
||
canMem[0].VolMaxIndex = canMem[1].VolMaxIndex;
|
||
canMem[0].VolMinIndex = canMem[1].VolMinIndex;
|
||
canMem[0].TempMax = canMem[1].TempMax;
|
||
canMem[0].TempMin = canMem[1].TempMin;
|
||
canMem[0].TempMaxIndex = canMem[1].TempMaxIndex;
|
||
canMem[0].TempMinIndex = canMem[1].TempMinIndex;
|
||
|
||
//Wh版屏幕
|
||
canMem[0].cumuliCap = canMem[1].cumuliCap;
|
||
canMem[0].cycleCnt = canMem[1].cycleCnt;
|
||
|
||
//负值矫正
|
||
canMem[0].cellVoltageMax = (int16_t)(canMem[0].VolMax*32/5)*5/32;
|
||
canMem[0].cellVoltageMin = (int16_t)(canMem[0].VolMin*32/5)*5/32;
|
||
}
|
||
|
||
//额外补丁:超过600A的异常电流值不显示
|
||
if( (canMem[0].cur >= 60000) || (canMem[0].cur <= (-60000)) ) //600A = 60000*0.01A
|
||
{
|
||
canMem[0].cur = oldcur;
|
||
}
|
||
|
||
|
||
//4.数据分析判断
|
||
//逆变器通信:充到100%,启用禁充标志,低于99%释放
|
||
if((paraMem.requestFlg_enable & 0x0080) != 0)
|
||
{
|
||
if(canMem[0].soc >= paraMem.chg_forbid_Soc)
|
||
{
|
||
chg_forbidFlg = 1;
|
||
}
|
||
else if(canMem[0].soc <= paraMem.chg_forbid_rSoc)
|
||
{
|
||
chg_forbidFlg = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
chg_forbidFlg = 0;
|
||
}
|
||
//逆变器通信:小于10%,启用禁放标志;超过20%后释放
|
||
if((paraMem.requestFlg_enable & 0x0040) != 0)
|
||
{
|
||
if(canMem[0].soc <= paraMem.dsg_forbid_Soc)
|
||
{
|
||
dsg_forbidFlg = 1;
|
||
}
|
||
else if(canMem[0].soc >= paraMem.dsg_forbid_rSoc)
|
||
{
|
||
dsg_forbidFlg = 0;
|
||
}
|
||
|
||
//当PACK电压=放电请求电压时,BMS发送禁放指令
|
||
if(bmsMem.packVoltage <= bmsMem.inverter_dsgVolLimit*100)
|
||
{
|
||
dsg_forbidFlg = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
dsg_forbidFlg = 0;
|
||
}
|
||
//逆变器通信:小于10%,启用强充标志;超过20%后释放
|
||
if((paraMem.requestFlg_enable & 0x0020) != 0)
|
||
{
|
||
if(canMem[0].soc <= paraMem.chg_force_Soc)
|
||
{
|
||
chg_forceFlg = 1;
|
||
}
|
||
else if(canMem[0].soc >= paraMem.chg_force_rSoc)
|
||
{
|
||
chg_forceFlg = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
chg_forceFlg = 0;
|
||
}
|
||
//逆变器通信:出现充电单体/总体过压告警后,逆变器充电限流固定40A
|
||
if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
{
|
||
chg_curlimitFlg = 1;
|
||
}
|
||
else
|
||
{
|
||
chg_curlimitFlg = 0;
|
||
}
|
||
|
||
|
||
//对于正常在线的PACK,若满足条件则计数,以在未完全禁充禁放时,更改限压限流值
|
||
chg_curLimitNum = 0;
|
||
dsg_curLimitNum = 0;
|
||
chg_cur0Num = 0;
|
||
for(i=1;i<=paraMem.PACK_NUM;i++)
|
||
{
|
||
if(canMem[i].com != 0) //引入队列标志位后的改动
|
||
{
|
||
//没有任何报警的BMS才认为是在线的(不考虑总体/单体过压)
|
||
if( ((canMem[i].status_byte1 & 0x067e) == 0) && ((canMem[i].status_byte2 & 0x00ff) == 0) && ((canMem[i].status_byte3 & 0x0008) == 0) && ((canMem[i].status_byte4 & 0x0f7f) == 0) )
|
||
{
|
||
if((canMem[i].soc >= paraMem.chg_forbid_Soc) && ((paraMem.requestFlg_enable & 0x0080) != 0)) //禁充个数
|
||
{
|
||
chg_curLimitNum++;
|
||
}
|
||
if((canMem[i].soc < paraMem.dsg_forbid_Soc) && ((paraMem.requestFlg_enable & 0x0040) != 0)) //禁放个数
|
||
{
|
||
dsg_curLimitNum++;
|
||
}
|
||
if((canMem[i].status_byte1 & 0x0101) != 0) //出现过压保护的个数
|
||
{
|
||
chg_cur0Num++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//更新回复上位机对并机信息的请求所需的数据,1s执行1次
|
||
void onlineMem_refresh(void)
|
||
{
|
||
uint8_t i;
|
||
|
||
/**上位机读信息的处理**/
|
||
//上位机询问并机情况的回复
|
||
onlineMem.Online[0] = 0; //3.11 表示工作正常的并机个数
|
||
for(i=1; i<=paraMem.PACK_NUM; i++)
|
||
{
|
||
if(canMem[i].com != 0)
|
||
{
|
||
if( ((canMem[i].status_byte1 & 0x067e) ==0) && ((canMem[i].status_byte2 & 0x00ff) ==0) && ((canMem[i].status_byte3 & 0x0008) ==0) && ((canMem[i].status_byte4 & 0x0f7f) ==0) )
|
||
{
|
||
onlineMem.Online[0]++; //该从机的(不管总体/单体过压报警的其他)报警都没有,就认为在线数量+1
|
||
|
||
if((canMem[i].status_byte1 & 0x01) ==0) //若不存在过压报警,确认正常
|
||
{
|
||
onlineMem.Online[i] = 0xAA; //正常
|
||
}
|
||
else
|
||
{
|
||
onlineMem.Online[i] = 0xBB; //存在报警
|
||
}
|
||
}
|
||
else
|
||
{
|
||
onlineMem.Online[i] = 0xBB; //存在报警
|
||
}
|
||
}
|
||
else
|
||
{
|
||
onlineMem.Online[i] = 0x00;
|
||
}
|
||
}
|
||
//若实际不在并机,则固定1个
|
||
if(bmsMem.E2_485Snum == 1)
|
||
{
|
||
onlineMem.Online[0] = 1;
|
||
}
|
||
}
|
||
|
||
//参数改动函数,1s执行1次
|
||
uint8_t Addr_SetCount;//改虚地址后等待10s
|
||
void ParaChange(void)
|
||
{
|
||
uint8_t tempWr[2];
|
||
|
||
|
||
#if Addr_SetAuto
|
||
uint8_t tmpRd;
|
||
|
||
//分配地址-从机:虚地址10s自恢复
|
||
if((bmsMem.E2_485Addr == 0) || (bmsMem.E2_485Addr > AddrMax)) //若地址长时间保持为虚地址,自动恢复原地址
|
||
{
|
||
Addr_SetCount++;
|
||
if(Addr_SetCount > 10) //10s
|
||
{
|
||
Addr_SetCount=0;
|
||
|
||
EEPROM_RdMulByte(EE_ADDR,&tmpRd);
|
||
if((tmpRd>=1) && (tmpRd<=AddrMax))
|
||
{
|
||
bmsMem.E2_485Addr = tmpRd;
|
||
}
|
||
else
|
||
{
|
||
bmsMem.E2_485Addr = 2;
|
||
}
|
||
scr_RdData_Index = bmsMem.E2_485Addr;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Addr_SetCount=0;
|
||
}
|
||
#endif
|
||
|
||
|
||
#if LTE_Conn
|
||
if((sleep_flag == 0) && (LTE_sleep_flag == 2))
|
||
{
|
||
LTE_sleep_flag = 0xAA; //4G执行退出休眠
|
||
}
|
||
#endif
|
||
|
||
|
||
/**上位机写参数的处理**/
|
||
//上位机修改容量
|
||
if(bmsMem.write_Capacity !=0)
|
||
{
|
||
if((bmsMem.write_Capacity>0) && (bmsMem.write_Capacity<=1000)) //范围1~1000Ah
|
||
{
|
||
tempWr[0] = (bmsMem.write_Capacity >> 8) & 0xff;
|
||
tempWr[1] = (bmsMem.write_Capacity >> 0) & 0xff;
|
||
EEPROM_WrMulByte(EE_NCC,tempWr);
|
||
delay_ms(5);
|
||
|
||
//赋值额定容量
|
||
bmsMem.ncc = 3600 * 1000 * bmsMem.write_Capacity;
|
||
ncc_Ah = bmsMem.write_Capacity;
|
||
|
||
//赋值满充容量=额定容量
|
||
fcc = bmsMem.ncc;
|
||
fcc_Ah = ncc_Ah;
|
||
tmpWrFCC[0] = (fcc>>24) & 0xff;
|
||
tmpWrFCC[1] = (fcc>>16) & 0xff;
|
||
tmpWrFCC[2] = (fcc>> 8) & 0xff;
|
||
tmpWrFCC[3] = (fcc>> 0) & 0xff;
|
||
tmpWrFCC[4] = tmpWrFCC[0] ^ 0xff;
|
||
tmpWrFCC[5] = tmpWrFCC[1] ^ 0xff;
|
||
tmpWrFCC[6] = tmpWrFCC[2] ^ 0xff;
|
||
tmpWrFCC[7] = tmpWrFCC[3] ^ 0xff;
|
||
EEPROM_WrMulByte(EE_FCC,tmpWrFCC);
|
||
delay_ms(20);
|
||
|
||
//赋值剩余容量=新的满充容量*SOC
|
||
bmsMem.rcc = fcc/100 * bmsMem.soc;
|
||
rcc_Ah = fcc_Ah * bmsMem.soc / 100;
|
||
oldrcc_Ah = rcc_Ah;
|
||
|
||
//改额定容量不影响此前的满放满充过程
|
||
|
||
bmsMem.write_Capacity = 0;
|
||
}
|
||
else
|
||
{
|
||
bmsMem.write_Capacity = 0;
|
||
}
|
||
}
|
||
//上位机修改SOC
|
||
if(bmsMem.write_Soc !=0)
|
||
{
|
||
if(bmsMem.write_Soc <= 100) //范围判断
|
||
{
|
||
EEPROM_WrMulByte(EE_SOC,&bmsMem.write_Soc);
|
||
delay_ms(5);
|
||
|
||
//赋值SOC
|
||
bmsMem.soc = bmsMem.write_Soc;
|
||
|
||
//赋值剩余容量=满充容量*新的SOC
|
||
bmsMem.rcc = fcc/100 * bmsMem.soc;
|
||
rcc_Ah = fcc_Ah * bmsMem.soc / 100;
|
||
oldrcc_Ah = rcc_Ah;
|
||
|
||
//在满放满充过程中,修改SOC会影响效果,不再执行
|
||
if(fcc_CaliStartFlag == 1)
|
||
{
|
||
fcc_CaliStartFlag = 0;
|
||
if(LSEErrFlag == 0)
|
||
{
|
||
EEPROM_WrMulByte(EE_FCC_TIME,ClearEE);
|
||
delay_ms(5);
|
||
}
|
||
}
|
||
|
||
bmsMem.write_Soc = 0;
|
||
}
|
||
else if(bmsMem.write_Soc == 0xAA)
|
||
{
|
||
bmsMem.write_Soc = 0;
|
||
EEPROM_WrMulByte(EE_SOC,&bmsMem.write_Soc);
|
||
delay_ms(5);
|
||
|
||
//赋值SOC
|
||
bmsMem.soc = bmsMem.write_Soc;
|
||
|
||
//赋值剩余容量=满充容量*新的SOC
|
||
bmsMem.rcc = fcc/100 * bmsMem.soc;
|
||
rcc_Ah = fcc_Ah * bmsMem.soc /100;
|
||
oldrcc_Ah = rcc_Ah;
|
||
|
||
//在满放满充过程中,修改SOC会影响效果,不再执行
|
||
if(fcc_CaliStartFlag == 1)
|
||
{
|
||
fcc_CaliStartFlag = 0;
|
||
if(LSEErrFlag == 0)
|
||
{
|
||
EEPROM_WrMulByte(EE_FCC_TIME,ClearEE);
|
||
delay_ms(5);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
bmsMem.write_Soc = 0;
|
||
}
|
||
}
|
||
|
||
//上位机修改休眠是否启用的标志位
|
||
if((paraMem.sleep_min_disable & 0x8000) == 0) //现在启用休眠1
|
||
{
|
||
if((sleep_enableflag & 0x01) == 0) //之前不执行休眠1
|
||
{
|
||
//在第一次发现不同后更新sleep
|
||
sleep_enableflag |= 0x01;
|
||
SLEEP_Refresh();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//保持清零
|
||
sleep_enableflag &= 0xfe;
|
||
sleeptimecount=0;
|
||
//若休眠模式都已关闭,退出休眠
|
||
if(sleep_enableflag == 0) sleep_flag = 0;
|
||
}
|
||
if((paraMem.sleep2_min_disable & 0x8000) == 0) //现在启用休眠2
|
||
{
|
||
if((sleep_enableflag & 0x02) == 0) //之前不执行休眠2
|
||
{
|
||
//在第一次发现不同后更新sleep
|
||
sleep_enableflag |= 0x02;
|
||
SLEEP2_Refresh();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//保持清零
|
||
sleep_enableflag &= 0xfd;
|
||
sleep2timecount=0;
|
||
//若休眠模式都已关闭,退出休眠
|
||
if(sleep_enableflag == 0) sleep_flag = 0;
|
||
}
|
||
|
||
//上位机解锁电流保护次数超限锁定
|
||
if((CTRL_Order & 0x10) != 0)
|
||
{
|
||
CTRL_Order &= 0xef; //用完恢复
|
||
bmsMem.balanceStatus &= 0xf8ff; //~0x0700 可解除3种锁定,短路保护不可解除
|
||
}
|
||
|
||
|
||
//更新了充电过流告警电流
|
||
if(alarm_occ_old != paraMem.alarm_occ)
|
||
{
|
||
alarm_occ_old = paraMem.alarm_occ;
|
||
chgCurLimit_changeFlg = 1;
|
||
}
|
||
//更新了放电过流1告警电流
|
||
if(alarm_ocd1_old != paraMem.alarm_ocd1)
|
||
{
|
||
alarm_ocd1_old = paraMem.alarm_ocd1;
|
||
dsgCurLimit_changeFlg = 1;
|
||
}
|
||
//更新了总体欠压告警电压
|
||
if(alarm_puv_old != paraMem.alarm_puv)
|
||
{
|
||
alarm_puv_old = paraMem.alarm_puv;
|
||
dsgVolLimit_changeFlg = 1;
|
||
}
|
||
//充放电过流告警,影响逆变器充放电限流
|
||
if((chgCurLimit_changeFlg == 1) || (dsgCurLimit_changeFlg == 1) || (dsgVolLimit_changeFlg == 1))
|
||
{
|
||
//修改充电过流告警电流后,逆变器充电限流值=该值-10A
|
||
if(chgCurLimit_changeFlg == 1)
|
||
{
|
||
chgCurLimit_changeFlg = 0;
|
||
bmsMem.inverter_chgCurLimit = paraMem.alarm_occ * 10 - 100;
|
||
}
|
||
//修改放电过流1告警电流后,逆变器放电限流值=该值-10A
|
||
if(dsgCurLimit_changeFlg == 1)
|
||
{
|
||
dsgCurLimit_changeFlg = 0;
|
||
bmsMem.inverter_dsgCurLimit = paraMem.alarm_ocd1 * 10 - 100;
|
||
}
|
||
//修改总体欠压告警电压后,逆变器放电限压值=该值
|
||
if(dsgVolLimit_changeFlg == 1)
|
||
{
|
||
dsgVolLimit_changeFlg = 0;
|
||
bmsMem.inverter_dsgVolLimit = paraMem.alarm_puv;
|
||
}
|
||
|
||
//bmsMem中数据更新到FLASH A区和B区和AFE EEPORM
|
||
if((MEMORY_UpdateFlash(FLASH_DATA_A_BASE) == 0) && (MEMORY_UpdateFlash(FLASH_DATA_B_BASE) == 0))
|
||
{
|
||
staPack.bits.flashUpdate = 0;
|
||
}
|
||
else
|
||
{
|
||
staPack.bits.flashUpdate = 1;
|
||
}
|
||
bmsMem.packStatus = staPack.byte;
|
||
}
|
||
}
|
||
|
||
//分配地址过程中,地址变动很快,故单独拎出直接放while循环里
|
||
void Addr_Set(void)
|
||
{
|
||
if(bmsMem.write_Addr !=0)
|
||
{
|
||
if(bmsMem.write_Addr <= AddrMax) //范围判断
|
||
{
|
||
EEPROM_WrMulByte(EE_ADDR,&bmsMem.write_Addr);
|
||
delay_ms(5);
|
||
|
||
bmsMem.E2_485Addr = bmsMem.write_Addr;
|
||
bmsMem.write_Addr = 0;
|
||
|
||
#if Addr_SetAuto
|
||
if(paraMem.addr_FREE_Flg == 0)
|
||
{
|
||
uint8_t tmp[2]={0,0};
|
||
|
||
//分配地址的状态(此时可接收队列标志位)
|
||
assignAddr_State = 2;
|
||
bmsMem.can_ArrayIndex = 0;
|
||
EEPROM_WrMulByte(EE_ASSIGN,tmp);
|
||
delay_ms(5);
|
||
}
|
||
#endif
|
||
|
||
//改地址后,屏幕显示也对应修改
|
||
scr_RdData_Index = bmsMem.E2_485Addr;
|
||
}
|
||
else
|
||
{
|
||
bmsMem.write_Addr = 0;
|
||
}
|
||
}
|
||
|
||
//因IO3变动而清空队列标志
|
||
if(ClearArray_Flag == 1)
|
||
{
|
||
uint8_t tmp[2]={0,0};
|
||
|
||
ClearArray_Flag = 0;
|
||
|
||
EEPROM_WrMulByte(EE_ASSIGN,tmp);
|
||
delay_ms(5);
|
||
}
|
||
|
||
#if Addr_SetAuto
|
||
if(paraMem.addr_FREE_Flg == 0)
|
||
{
|
||
//从机根据自身地址,决定IO2输出给下一从机的电平
|
||
if((bmsMem.E2_485Addr >= 2) && (bmsMem.E2_485Addr <= AddrMax))
|
||
{
|
||
IO2_OUTReset(); //正常地址的OUT引脚置低
|
||
}
|
||
else if(bmsMem.E2_485Addr > AddrMax)
|
||
{
|
||
IO2_OUTSet(); //OUT引脚置高,让下一个从机进入等待
|
||
}
|
||
}
|
||
else
|
||
{
|
||
IO2_OUTReset(); //所有地址保持置低
|
||
}
|
||
#endif
|
||
}
|
||
|
||
//休眠1的计时起点更新
|
||
void SLEEP_Refresh(void)
|
||
{
|
||
if(LSEErrFlag!=1)
|
||
sleeptimecount=RTC_GetCounter();
|
||
else
|
||
sleep_Moni_Count=SLEEP_MON_CNT;
|
||
}
|
||
|
||
//休眠2的计时起点更新
|
||
void SLEEP2_Refresh(void)
|
||
{
|
||
//满足休眠电压,无均衡,无电流
|
||
if((cellVoltageMin <= sleep2Vol) && ((bmsMem.balanceStatus & 0x0001) == 0) && (bmsMem.packCurrent > (-200)) && (bmsMem.packCurrent < 200))
|
||
{
|
||
//无除过压以外的保护
|
||
if(((bmsMem.bStatus1 & 0x067e) == 0) && ((bmsMem.bStatus2 & 0x00ff) == 0) && ((bmsMem.bStatus3 & 0x0008) == 0) && ((bmsMem.temperaStatus & 0x0f7f) == 0))
|
||
{
|
||
if(LSEErrFlag!=1)
|
||
sleep2timecount=RTC_GetCounter();
|
||
else
|
||
sleep2_Moni_Count=SLEEP2_MON_CNT;
|
||
}
|
||
}
|
||
}
|
||
|
||
//启动休眠1的定时
|
||
#define SLEEP_MON_CNT 6000*(paraMem.sleep_min_disable&0x7FFF) //60*100个10ms=1min
|
||
uint32_t sleep_Moni_Count;
|
||
void SLEEP_TIM_Moni(void)
|
||
{
|
||
//当没触发休眠
|
||
if(sleep_flag == 0)
|
||
{
|
||
if((paraMem.sleep_min_disable & 0x8000) == 0) //0代表启用休眠
|
||
{
|
||
sleep_Moni_Count--;
|
||
if(sleep_Moni_Count == 0)
|
||
{
|
||
sleep_Moni_Count = SLEEP_MON_CNT;
|
||
sleep_flag = 1;
|
||
|
||
#if LTE_Conn
|
||
pre_sleep_flag = 2;
|
||
pre_sleep_waitCnt = 0;
|
||
sleepOn_time=timecount;
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//启动休眠2的定时
|
||
#define SLEEP2_MON_CNT 6000*(paraMem.sleep2_min_disable&0x7FFF) //60*100个10ms=1min
|
||
uint32_t sleep2_Moni_Count;
|
||
void SLEEP2_TIM_Moni(void)
|
||
{
|
||
//当没触发休眠
|
||
if(sleep_flag == 0)
|
||
{
|
||
if((paraMem.sleep2_min_disable & 0x8000) == 0) //0代表启用休眠
|
||
{
|
||
//满足休眠电压,无均衡,无电流
|
||
if((cellVoltageMin <= sleep2Vol) && ((bmsMem.balanceStatus & 0x0001) == 0) && (bmsMem.packCurrent > (-200)) && (bmsMem.packCurrent < 200))
|
||
{
|
||
//无除过压以外的保护
|
||
if(((bmsMem.bStatus1 & 0x067e) == 0) && ((bmsMem.bStatus2 & 0x00ff) == 0) && ((bmsMem.bStatus3 & 0x0008) == 0) && ((bmsMem.temperaStatus & 0x0f7f) == 0))
|
||
{
|
||
sleep2_Moni_Count--;
|
||
if(sleep2_Moni_Count == 0)
|
||
{
|
||
sleep2_Moni_Count = SLEEP2_MON_CNT;
|
||
sleep_flag = 1;
|
||
|
||
#if LTE_Conn
|
||
pre_sleep_flag = 2;
|
||
pre_sleep_waitCnt = 0;
|
||
sleepOn_time=timecount;
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//欠压强制复位的定时
|
||
#define UVOff_MON_CNT 30000 //5*60*100个10ms=5分钟
|
||
uint16_t uvoff_Moni_Count;
|
||
void UVOff_TIM_Moni(void)
|
||
{
|
||
//屏幕手动关欠压启动了
|
||
if((bmsMem.balanceStatus & 0x20) != 0)
|
||
{
|
||
uvoff_Moni_Count--;
|
||
if(uvoff_Moni_Count == 0)
|
||
{
|
||
uvoff_Moni_Count = UVOff_MON_CNT;
|
||
bmsMem.balanceStatus &= 0xffdf;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
uvoff_Moni_Count = UVOff_MON_CNT;
|
||
}
|
||
}
|
||
|
||
//校准满充容量的倒计时(中间开关机,会关闭。但这是重要功能,需在晶振故障时仍有计时)
|
||
#define FCCCALI_MON_CNT 6000*(paraMem.cali_min_disable&0x7FFF) //60*100个10ms=1min
|
||
uint32_t fcc_Cali_Moni_Count;
|
||
void FCCCali_TIM_Moni(void)
|
||
{
|
||
//倒计时12h
|
||
if(fcc_CaliStartFlag == 1)
|
||
{
|
||
fcc_Cali_Moni_Count--;
|
||
if(fcc_Cali_Moni_Count == 0)
|
||
{
|
||
fcc_Cali_Moni_Count = FCCCALI_MON_CNT;
|
||
fcc_CaliStartFlag = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
fcc_Cali_Moni_Count = FCCCALI_MON_CNT;
|
||
}
|
||
}
|
||
|
||
//更新软件版本
|
||
void Refresh_FirmwareVersion(void)
|
||
{
|
||
if(VersionMem.Software[2] < 0xA0)
|
||
{
|
||
sprintf(FirmwareVersion, "%u.%u.%u.%u", VersionMem.Software[0], VersionMem.Software[1], VersionMem.Software[2], VersionMem.Software[3]);
|
||
}
|
||
else
|
||
{
|
||
sprintf(FirmwareVersion, "%u.%u.%02X.%u",VersionMem.Software[0], VersionMem.Software[1],VersionMem.Software[2], VersionMem.Software[3]);
|
||
}
|
||
}
|
||
|
||
//更新硬件版本
|
||
void Refresh_HardwareVersion(void)
|
||
{
|
||
if(VersionMem.Hardware[2] < 'A')
|
||
{
|
||
sprintf(HardwareVersion, "%u.%u.%u", VersionMem.Hardware[0], VersionMem.Hardware[1], VersionMem.Hardware[2]); //最后1位是数字
|
||
}
|
||
else
|
||
{
|
||
sprintf(HardwareVersion, "%u.%u.%c", VersionMem.Hardware[0], VersionMem.Hardware[1], VersionMem.Hardware[2]); //最后1位是字符
|
||
}
|
||
}
|
||
|
||
//更新屏幕版本
|
||
void Refresh_ScreenVersion(void)
|
||
{
|
||
if(VersionMem.Screen == 0)
|
||
{
|
||
memset(ScreenVersion, 0, 6); //清空
|
||
}
|
||
else
|
||
{
|
||
uint8_t data = VersionMem.Screen;
|
||
uint8_t list1=0,list2=0;
|
||
|
||
//最高两位_00对应028,01对应035,10对应042,11对应070
|
||
if((data>>6 == 0x00) && (data >= 0x04))
|
||
{
|
||
list1 = 28;
|
||
list2 = (data & 0x3f) +1-4;
|
||
}
|
||
else if(data>>6 == 0x01)
|
||
{
|
||
list1 = 35;
|
||
list2 = (data & 0x3f) +1;
|
||
}
|
||
else if(data>>6 == 0x02)
|
||
{
|
||
list1 = 43;
|
||
list2 = (data & 0x3f) +1;
|
||
}
|
||
else if(data>>6 == 0x03)
|
||
{
|
||
list1 = 70;
|
||
list2 = (data & 0x3f) +1;
|
||
}
|
||
|
||
if(list2 < 10)
|
||
{
|
||
sprintf(ScreenVersion, "0%u0%u", list1, list2);
|
||
}
|
||
else
|
||
{
|
||
sprintf(ScreenVersion, "0%u%u", list1, list2);
|
||
}
|
||
}
|
||
}
|
||
|
||
//更新BMS_SN
|
||
void Refresh_BMS_SN(void)
|
||
{
|
||
uint8_t i;
|
||
|
||
//固定9位数字
|
||
for(i=0;i<9;i++)
|
||
{
|
||
sprintf(&BMS_SN[i], "%c", VersionMem.BMS_SN[i]);
|
||
}
|
||
}
|
||
|
||
//更新PACK_SN
|
||
void Refresh_PACK_SN(void)
|
||
{
|
||
uint8_t i;
|
||
|
||
//最大共15字节,不足填充0xff
|
||
for(i=0;i<15;i++)
|
||
{
|
||
if(VersionMem.PACK_SN[i] == 0xff) break;
|
||
sprintf(&PACK_SN[i], "%c", VersionMem.PACK_SN[i]);
|
||
}
|
||
}
|
||
|
||
#if LTE_Conn
|
||
//默认值
|
||
#define DOMAIN domain_TianChu
|
||
#define PORT 1883
|
||
#define USERNAME username
|
||
#define PASSWORD password
|
||
|
||
char domain_TianChu[] = "tcp://mqtt.ricnsmart.com"; //天储平台
|
||
char username[] = "device";
|
||
char password[] = "E6Mk2Rj6uhFU4Zgy3kWCbghvaDYka8Dz";
|
||
//char clientId[] = "jdg0bcu4RMG!rmt0ubv"; //任意长度,所以改为和SN号一致
|
||
|
||
//4G通信凭证跟随SN号变动,更新到Flash
|
||
void LTE_4G_Domain_ChangeSN(void)
|
||
{
|
||
uint8_t i;
|
||
|
||
//清空原值
|
||
memset(&VersionMem.ClientID[0], 0, 23);
|
||
|
||
//改动ClientID=SN号
|
||
for(i=0;i<9;i++)
|
||
{
|
||
VersionMem.ClientID[i] = VersionMem.BMS_SN[i];
|
||
}
|
||
|
||
//计算CRC校验值
|
||
static uint8_t temp[HOSTMEM_LEN];
|
||
memcpy(temp, &VersionMem.host[0], HOSTMEM_LEN);
|
||
|
||
VersionMem.hostAll_crc = CRC8_Cal(&temp[0], 153);
|
||
|
||
//更新Flash
|
||
if((MEMORY_UpdateFlash(FLASH_DATA_A_BASE) == 0) && (MEMORY_UpdateFlash(FLASH_DATA_B_BASE) == 0))
|
||
{
|
||
staPack.bits.flashUpdate = 0;
|
||
}
|
||
else
|
||
{
|
||
staPack.bits.flashUpdate = 1;
|
||
}
|
||
bmsMem.packStatus = staPack.byte;
|
||
}
|
||
|
||
//4G通信凭证开机初始化
|
||
uint8_t Host_Def_Flag; //用默认值填充Host的标志
|
||
uint8_t Port_Def_Flag; //用默认值填充Port的标志
|
||
uint8_t UserName_Def_Flag; //用默认值填充UserName的标志
|
||
uint8_t Password_Def_Flag; //用默认值填充Password的标志
|
||
uint8_t ClientID_Def_Flag; //用SN号填充ClientID的标志
|
||
void LTE_4G_Domain_Init(void)
|
||
{
|
||
uint8_t i;
|
||
|
||
//若发现Host的内容为空,将默认值填充
|
||
Host_Def_Flag = 1;
|
||
for(i=0;i<40;i++)
|
||
{
|
||
if(VersionMem.host[i] != 0x00)
|
||
{
|
||
Host_Def_Flag = 0;
|
||
break;
|
||
}
|
||
}
|
||
if(Host_Def_Flag == 1)
|
||
{
|
||
uint8_t *data = (uint8_t *)DOMAIN;
|
||
|
||
i = 0;
|
||
while(data[i] != (uint8_t)'\0')
|
||
{
|
||
VersionMem.host[i] = data[i];
|
||
i++;
|
||
}
|
||
}
|
||
|
||
//若发现Port的内容为空,将默认值填充
|
||
if(VersionMem.port == 0x0000)
|
||
{
|
||
Port_Def_Flag = 1;
|
||
VersionMem.port = PORT;
|
||
}
|
||
|
||
//若发现UserName的内容为空,将默认值填充
|
||
UserName_Def_Flag = 1;
|
||
for(i=0;i<40;i++)
|
||
{
|
||
if(VersionMem.UserName[i] != 0x00)
|
||
{
|
||
UserName_Def_Flag = 0;
|
||
break;
|
||
}
|
||
}
|
||
if(UserName_Def_Flag == 1)
|
||
{
|
||
uint8_t *data = (uint8_t *)USERNAME;
|
||
|
||
i = 0;
|
||
while(data[i] != (uint8_t)'\0')
|
||
{
|
||
VersionMem.UserName[i] = data[i];
|
||
i++;
|
||
}
|
||
}
|
||
|
||
//若发现Password的内容为空,将默认值填充
|
||
Password_Def_Flag = 1;
|
||
for(i=0;i<40;i++)
|
||
{
|
||
if(VersionMem.PassWord[i] != 0x00)
|
||
{
|
||
Password_Def_Flag = 0;
|
||
break;
|
||
}
|
||
}
|
||
if(Password_Def_Flag == 1)
|
||
{
|
||
uint8_t *data = (uint8_t *)PASSWORD;
|
||
|
||
i = 0;
|
||
while(data[i] != (uint8_t)'\0')
|
||
{
|
||
VersionMem.PassWord[i] = data[i];
|
||
i++;
|
||
}
|
||
}
|
||
|
||
//若发现ClientID的内容为空,直接填充SN号
|
||
ClientID_Def_Flag = 1;
|
||
for(i=0;i<23;i++)
|
||
{
|
||
if(VersionMem.ClientID[i] != 0x00)
|
||
{
|
||
ClientID_Def_Flag = 0;
|
||
break;
|
||
}
|
||
}
|
||
if(ClientID_Def_Flag == 1)
|
||
{
|
||
for(i=0;i<9;i++)
|
||
{
|
||
VersionMem.ClientID[i] = VersionMem.BMS_SN[i];
|
||
}
|
||
}
|
||
|
||
//任意一个改动,写入Flash
|
||
if((Host_Def_Flag == 1) || (Port_Def_Flag == 1) || (UserName_Def_Flag == 1) || (Password_Def_Flag == 1) || (ClientID_Def_Flag == 1))
|
||
{
|
||
//计算CRC校验值
|
||
static uint8_t temp[HOSTMEM_LEN];
|
||
memcpy(temp, &VersionMem.host[0], HOSTMEM_LEN);
|
||
|
||
VersionMem.hostAll_crc = CRC8_Cal(&temp[0], 153);
|
||
|
||
//更新Flash
|
||
if((MEMORY_UpdateFlash(FLASH_DATA_A_BASE) == 0) && (MEMORY_UpdateFlash(FLASH_DATA_B_BASE) == 0))
|
||
{
|
||
staPack.bits.flashUpdate = 0;
|
||
}
|
||
else
|
||
{
|
||
staPack.bits.flashUpdate = 1;
|
||
}
|
||
bmsMem.packStatus = staPack.byte;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//各种初始默认值
|
||
void uf_GLOBAL_Init(void)
|
||
{
|
||
uint8_t i;
|
||
uint8_t tmpRd[16]; //用于读SN号
|
||
|
||
//初始值,之后会刷新
|
||
bmsMem.ucCellNum = 16;
|
||
bmsMem.cycleCount = 0;
|
||
bmsMem.soh = 99;
|
||
|
||
|
||
//根据配置读取
|
||
fcc = 10000;
|
||
bmsMem.ncc = 10000;
|
||
bmsMem.rcc = 5000;
|
||
bmsMem.soc = 50;
|
||
//bmsMem.E2uiDsgEndVol = 2500;//4.21修改
|
||
//for(i=0;i<10;i++)
|
||
//{
|
||
// bmsMem.E2uiVOC[i] = bmsMem.E2uiDsgEndVol+100*(i+1);
|
||
//}
|
||
|
||
bmsMem.temperaStatus = 0;
|
||
bmsMem.balanceStatus = 0;
|
||
bmsMem.packStatus = 0;
|
||
bmsMem.bStatus1 = 0;
|
||
bmsMem.bStatus2 = 0;
|
||
bmsMem.bStatus3 = 0;
|
||
|
||
|
||
//校准数据初始化
|
||
cali.current = 100000; //用于计算增益参数
|
||
|
||
cali.cmdZero = 0;
|
||
cali.cmdGain = 0;
|
||
cali.flagWrZeroToEE = 0;
|
||
cali.flagWrGainToEE = 0;
|
||
|
||
cali.cadcZero = 0;
|
||
cali.cadcGain = 0;
|
||
cali.cadcZero = EEPROM_CALI_RdZero();
|
||
delay_ms(20);
|
||
cali.cadcGain = EEPROM_CALI_RdGain();
|
||
delay_ms(20);
|
||
|
||
bmsMem.cadcZero = cali.cadcZero;
|
||
bmsMem.cadcGain = cali.cadcGain;
|
||
|
||
|
||
//[宁化]参数更新同步
|
||
alarm_occ_old = paraMem.alarm_occ;
|
||
alarm_ocd1_old = paraMem.alarm_ocd1;
|
||
alarm_puv_old = paraMem.alarm_puv;
|
||
|
||
|
||
#if Addr_SetAuto
|
||
//延时2s进行485通信
|
||
assignAddr_relay = 2;
|
||
#endif
|
||
|
||
|
||
//上位机求取数据的地址,只对主机有效默认是自身1
|
||
ConfigData_Index = 1;
|
||
//屏幕显示数据地址,每块BMS的屏幕都显示
|
||
scr_RdData_Index = bmsMem.E2_485Addr;
|
||
|
||
//开机初始化,屏幕记录要读数据并显示出来
|
||
scr_RdRecord_Flg = 1;
|
||
|
||
|
||
//该程序的软件版本号
|
||
VersionMem.Software[0] = 4; //大版本,有硬件不兼容项才变
|
||
VersionMem.Software[1] = 0; //客户对应出货单号
|
||
VersionMem.Software[2] = 0; //程序更新次数 A表示4G B表示蓝牙 C表示WIFI
|
||
VersionMem.Software[3] = 0; //程序后续小修改
|
||
//软件版本以当前程序的为准
|
||
EEPROM_RdMulByte(EE_Software,tmpRd);
|
||
if((tmpRd[0] != VersionMem.Software[0]) || (tmpRd[1] != VersionMem.Software[1]) || (tmpRd[2] != VersionMem.Software[2]) || (tmpRd[3] != VersionMem.Software[3])) //软件不是当前值,就进行写入
|
||
{
|
||
EEPROM_WrMulByte(EE_Software,VersionMem.Software);
|
||
delay_ms(5);
|
||
}
|
||
//填充FirmwareVersion
|
||
Refresh_FirmwareVersion();
|
||
|
||
//该程序的硬件版本号
|
||
VersionMem.Hardware[0] = 1;
|
||
VersionMem.Hardware[1] = 0;
|
||
VersionMem.Hardware[2] = 0;
|
||
//硬件版本号以EEPROM里面的为准,上面这个只做参考
|
||
EEPROM_RdMulByte(EE_Hardware,tmpRd);
|
||
if(tmpRd[0] == 0xff) //硬件的第1位不存在
|
||
{
|
||
EEPROM_WrMulByte(EE_Hardware,VersionMem.Hardware);
|
||
delay_ms(5);
|
||
}
|
||
else
|
||
{
|
||
VersionMem.Hardware[0] = tmpRd[0];
|
||
VersionMem.Hardware[1] = tmpRd[1];
|
||
VersionMem.Hardware[2] = tmpRd[2];
|
||
}
|
||
//填充HardwareVersion
|
||
Refresh_HardwareVersion();
|
||
|
||
|
||
//显示屏幕版本号
|
||
//最高两位表示型号,01对应035,10对应043,11对应070
|
||
//剩下6位表示序号Index,范围0~63,显示为1~64
|
||
EEPROM_RdMulByte(EE_Screen,tmpRd);
|
||
if(tmpRd[0] != 0xff)
|
||
{
|
||
VersionMem.Screen = tmpRd[0];
|
||
}
|
||
else
|
||
{
|
||
VersionMem.Screen = 0x00+37; //对应02834,也即2.8寸陶晶驰版
|
||
}
|
||
//填充ScreenVersion
|
||
Refresh_ScreenVersion();
|
||
|
||
//显示BMS_SN号
|
||
EEPROM_RdMulByte(EE_BMS_SN,tmpRd);
|
||
VersionMem.BMS_crc8 = CRC8_Cal(&tmpRd[0],9);
|
||
if(tmpRd[9] == VersionMem.BMS_crc8) //crc校验正确
|
||
{
|
||
for(i=0;i<9;i++)
|
||
{
|
||
VersionMem.BMS_SN[i] = tmpRd[i];
|
||
}
|
||
//填充BMS_SN
|
||
Refresh_BMS_SN();
|
||
}
|
||
else
|
||
{
|
||
//清零
|
||
memset(VersionMem.BMS_SN, 0, 9);
|
||
VersionMem.BMS_crc8 = 0;
|
||
|
||
memset(BMS_SN, 0, 9);
|
||
}
|
||
|
||
//显示PACK_SN号
|
||
EEPROM_RdMulByte(EE_PACK_SN,tmpRd);
|
||
VersionMem.PACK_crc8 = CRC8_Cal(&tmpRd[0],15);
|
||
if(tmpRd[15] == VersionMem.PACK_crc8) //crc校验正确
|
||
{
|
||
//最大共15字节,不足填充0xff
|
||
for(i=0;i<15;i++)
|
||
{
|
||
VersionMem.PACK_SN[i] = tmpRd[i];
|
||
}
|
||
//填充PACK_SN
|
||
Refresh_PACK_SN();
|
||
}
|
||
else
|
||
{
|
||
//清零
|
||
memset(VersionMem.PACK_SN, 0, 15);
|
||
VersionMem.PACK_crc8 = 0;
|
||
|
||
memset(PACK_SN, 0, 15);
|
||
}
|
||
|
||
#if LTE_Conn
|
||
//显示4G凭证
|
||
LTE_4G_Domain_Init();
|
||
#endif
|
||
}
|
||
|