4811 lines
103 KiB
C
4811 lines
103 KiB
C
/**
|
||
******************************************************************************
|
||
* @file InverterSwitch_Page1.c
|
||
* @author -
|
||
* @version -
|
||
* @date 2026.3.26
|
||
* @brief -
|
||
******************************************************************************
|
||
* @attention
|
||
*
|
||
*
|
||
******************************************************************************
|
||
*/
|
||
|
||
/* Includes ------------------------------------------------------------------*/
|
||
#include "stm32f10x.h"
|
||
#include "global.h"
|
||
|
||
|
||
//这里放的是基本款的第1页函数,不根据发货要求变动
|
||
//CAN:
|
||
//1.Sol-Ark 2.GoodWe 3.Megarevo 4.Pylon
|
||
//5.Deye 6.MUST 7.solis 8.Growatt
|
||
//9.Aiswei 10.Afore 11.Victron 12.Sorotec
|
||
//Modbus:
|
||
//8.Growatt 12.Sorotec
|
||
//YDN:
|
||
//4.Pylon
|
||
|
||
|
||
//CAN:
|
||
//Sol-Ark
|
||
void CAN_Protocol_SolArk(void)
|
||
{
|
||
uint8_t data[8];
|
||
uint16_t totalCapacity;
|
||
|
||
uint16_t tempVol;
|
||
int16_t tempCur;
|
||
|
||
uint16_t chgVolLimit;
|
||
uint16_t dsgVolLimit;
|
||
int16_t chgCurLimit;
|
||
int16_t dsgCurLimit;
|
||
|
||
uint8_t protectByte1 = 0;
|
||
uint8_t protectByte2 = 0;
|
||
|
||
int16_t T_Average; // 平均温度
|
||
|
||
uint8_t alarmByte1 = 0;
|
||
uint8_t alarmByte2 = 0;
|
||
|
||
//保护
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温保护
|
||
//under temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x0005) != 0) || ((canMem[0].status_byte4 & 0x0C0C) != 0))
|
||
{
|
||
protectByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xef;
|
||
}
|
||
|
||
//过温保护
|
||
//over temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x000A) != 0) || ((canMem[0].status_byte4 & 0x0303) != 0))
|
||
{
|
||
protectByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfe;
|
||
}
|
||
|
||
//告警
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温告警
|
||
if(((canMem[0].status_byte2 & 0xCC00) != 0) || ((canMem[0].status_byte4 & 0xC000) != 0))
|
||
{
|
||
alarmByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xef;
|
||
}
|
||
|
||
//过温告警
|
||
if(((canMem[0].status_byte2 & 0x3300) != 0) || ((canMem[0].status_byte4 & 0x3000) != 0))
|
||
{
|
||
alarmByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压告警
|
||
if((canMem[0].status_byte3 & 0x0A00) != 0)
|
||
{
|
||
alarmByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压告警
|
||
// if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfe;
|
||
}
|
||
|
||
if(CAN_SendCount ==0) //ID=0x359
|
||
{
|
||
data[0] = protectByte1;
|
||
data[1] = protectByte2;
|
||
data[2] = alarmByte1;
|
||
data[3] = alarmByte2;
|
||
data[4] = OnlineNum;
|
||
data[5] = 0x50;
|
||
data[6] = 0x4E;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x359, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID = 0x351
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //Sol-Ark禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //Sol-Ark禁放
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[1] = (chgVolLimit >> 8) & 0xFF;
|
||
data[2] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[3] = (chgCurLimit >> 8) & 0xFF;
|
||
data[4] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[5] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[6] = dsgVolLimit & 0xFF; //放电电压限制低位
|
||
data[7] = (dsgVolLimit >> 8) & 0xFF;
|
||
CAN1_SendData(0x351, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2)
|
||
{
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = 0;
|
||
data[2] = canMem[0].soh & 0xFF; //SOH
|
||
data[3] = 0;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x355, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3)
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/10); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;// 平均温度
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = (T_Average -2731) & 0xFF;;
|
||
data[5] = ((T_Average -2731) >>8) & 0xFF; //温度-暂时取平均温度,具体哪一路需要客户确认
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x356, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4)
|
||
{
|
||
RequestFlag = 0xC0; //充电允许0x80,放电允许0x40,不强充~0x20
|
||
if(chg_forbidFlg == 1)//Sol-Ark
|
||
{
|
||
RequestFlag &= 0x7F; //禁充
|
||
}
|
||
if(dsg_forbidFlg == 1)//Sol-Ark
|
||
{
|
||
RequestFlag &= 0xBF; //禁放
|
||
}
|
||
if(chg_forceFlg == 1)//Sol-Ark
|
||
{
|
||
RequestFlag |= 0x20; //强充
|
||
}
|
||
|
||
data[0] = RequestFlag;
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35C, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==5) //0x379
|
||
{
|
||
totalCapacity = ncc_Ah * OnlineNum; //单位1Ah
|
||
|
||
data[0] = totalCapacity & 0xFF; //充电电压限制低位
|
||
data[1] = (totalCapacity >> 8) & 0xFF;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x379, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==6)
|
||
{
|
||
data[0] = 'B';
|
||
data[1] = 'T';
|
||
data[2] = 'Y';
|
||
data[3] = 'G';
|
||
data[4] = '-';
|
||
data[5] = 'B';
|
||
data[6] = 'M';
|
||
data[7] = 'S';
|
||
CAN1_SendData(0x35e, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=7)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//GoodWe 固德威
|
||
void CAN_Protocol_GoodWe(void)
|
||
{
|
||
uint8_t data[8];
|
||
// uint16_t totalCapacity;
|
||
|
||
int16_t tempVol;
|
||
int16_t tempCur;
|
||
|
||
uint16_t chgVolLimit;
|
||
// uint16_t dsgVolLimit;
|
||
int16_t chgCurLimit;
|
||
int16_t dsgCurLimit;
|
||
|
||
uint8_t protectByte1 = 0;
|
||
uint8_t protectByte2 = 0;
|
||
uint8_t alarmByte1 = 0; //固德威在Cell Balance功能上protect和alarm显示不同
|
||
uint8_t alarmByte2 = 0;
|
||
|
||
int16_t T_Average; // 平均温度
|
||
int16_t T_Max; // 最高温度
|
||
int16_t T_Min; // 最低温度
|
||
uint16_t T_MaxIndex;// 最高温度序号,范围0-6
|
||
uint16_t T_MinIndex;// 最低温度序号,范围0-6
|
||
|
||
uint16_t cellVolMax=0; // 电芯单体最高电压-固德威
|
||
int16_t cellVolMin=0; // 电芯单体最低电压-固德威
|
||
uint16_t cellVolMaxIndex; // 电芯单体最高电压序号,范围0-15-固德威
|
||
int16_t cellVolMinIndex; // 电芯单体最低电压序号,范围0-15-固德威
|
||
|
||
|
||
//保护
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温保护
|
||
//under temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x0005) != 0) || ((canMem[0].status_byte4 & 0x0C0C) != 0))
|
||
{
|
||
protectByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xef;
|
||
}
|
||
|
||
//过温保护
|
||
//over temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x000A) != 0) || ((canMem[0].status_byte4 & 0x0303) != 0))
|
||
{
|
||
protectByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfe;
|
||
}
|
||
|
||
//告警
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温告警
|
||
if(((canMem[0].status_byte2 & 0xCC00) != 0) || ((canMem[0].status_byte4 & 0xC000) != 0))
|
||
{
|
||
alarmByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xef;
|
||
}
|
||
|
||
//过温告警
|
||
if(((canMem[0].status_byte2 & 0x3300) != 0) || ((canMem[0].status_byte4 & 0x3000) != 0))
|
||
{
|
||
alarmByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压告警
|
||
if((canMem[0].status_byte3 & 0x0A00) != 0)
|
||
{
|
||
alarmByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压告警
|
||
// if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfe;
|
||
}
|
||
|
||
// //Data1 BIT4 cell balance
|
||
// if((bmsMem.balanceStatus & 0x01) !=0)
|
||
// {
|
||
// protectByte2 |= 0x10;
|
||
// alarmByte2 &= 0xef;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte2 &= 0xef;
|
||
// alarmByte2 |= 0x10;
|
||
// }
|
||
|
||
if(CAN_SendCount ==0) //ID = 0x359 - 报警/警告信息(前4行数据改为更直接的值,后面置0)
|
||
{
|
||
data[0] = protectByte1;
|
||
data[1] = protectByte2;
|
||
data[2] = alarmByte1;
|
||
data[3] = alarmByte2;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x359, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID = 0x351 - 充电限压/限流,放电限流(已修改,不要求放电限压)
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
//dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //GoodWe禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //GoodWe禁放
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[1] = (chgVolLimit >> 8) & 0xFF;
|
||
data[2] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[3] = (chgCurLimit >> 8) & 0xFF;
|
||
data[4] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[5] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x351, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID = 0x355 - 电量SOC/SOH(应该不修改)
|
||
{
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = 0;
|
||
data[2] = canMem[0].soh & 0xFF; //SOH
|
||
data[3] = 0;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x355, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID = 0x356 - 电池电压/电流/温度(应该不修改)
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/10); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;// 平均温度
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = (T_Average -2731) & 0xFF;
|
||
data[5] = ((T_Average -2731) >>8) & 0xFF; //温度-暂时取平均温度,具体哪一路需要客户确认 //signed有符号数
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x356, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID = 0x35C - 充电/放电开关(已修改,由Data[0]的bit6、7控制)
|
||
{
|
||
RequestFlag = 0xC0; //充电允许0x80,放电允许0x40,不强充~0x20
|
||
if(chg_forbidFlg == 1)//GoodWe
|
||
{
|
||
RequestFlag &= 0x7F; //禁充
|
||
}
|
||
if(dsg_forbidFlg == 1)//GoodWe
|
||
{
|
||
RequestFlag &= 0xBF; //禁放
|
||
}
|
||
if(chg_forceFlg == 1)//GoodWe
|
||
{
|
||
RequestFlag |= 0x20; //强充
|
||
}
|
||
|
||
data[0] = 0XC0; //充电允许,放电允许
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35C, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==5) //ID = 0x370 - 最大/最小单体温度,最大/最小单体电压(新加入)
|
||
{
|
||
T_Max = canMem[0].TempMax; // 最高温度
|
||
T_Min = canMem[0].TempMin; // 最低温度
|
||
cellVolMax = canMem[0].VolMax;
|
||
cellVolMin = canMem[0].VolMin;
|
||
|
||
data[0] = (T_Max -2731) & 0xFF; //最大单体温度
|
||
data[1] = ((T_Max -2731) >> 8) & 0xFF;
|
||
data[2] = (T_Min -2731) & 0xFF; //最小单体温度
|
||
data[3] = ((T_Min -2731) >> 8) & 0xFF;
|
||
data[4] = cellVolMax & 0xFF; //最大单体电压
|
||
data[5] = (cellVolMax >> 8) & 0xFF;
|
||
data[6] = cellVolMin & 0xFF; //最小单体电压
|
||
data[7] = (cellVolMin >> 8) & 0xFF;
|
||
CAN1_SendData(0x370, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==6) //ID = 0x371 - 最大/最小单体温度ID,最大/最小单体电压ID(新加入)
|
||
{
|
||
T_MaxIndex = canMem[0].TempMaxIndex;// 最高温度序号,范围0-6
|
||
T_MinIndex = canMem[0].TempMinIndex;// 最低温度序号,范围0-6
|
||
cellVolMaxIndex = canMem[0].VolMaxIndex;
|
||
cellVolMinIndex = canMem[0].VolMinIndex;
|
||
|
||
data[0] = (T_MaxIndex+1) & 0xFF; //最大单体温度序号,实际显示从1开始
|
||
data[1] = ((T_MaxIndex+1) >> 8) & 0xFF;
|
||
data[2] = (T_MinIndex+1) & 0xFF; //最小单体温度序号
|
||
data[3] = ((T_MinIndex+1) >> 8) & 0xFF;
|
||
data[4] = (cellVolMaxIndex+1) & 0xFF; //最大单体电压序号
|
||
data[5] = ((cellVolMaxIndex+1) >> 8) & 0xFF;
|
||
data[6] = (cellVolMinIndex+1) & 0xFF; //最小单体电压序号
|
||
data[7] = ((cellVolMinIndex+1) >> 8) & 0xFF;
|
||
CAN1_SendData(0x371, &data[0]);
|
||
}
|
||
// if(CAN_SendCount ==7) //ID = 0x380 - 传递信息1-4(无要求)
|
||
// {
|
||
// data[0] = 'B';
|
||
// data[1] = ('B' >> 8) & 0xFF;
|
||
// data[2] = 'T';
|
||
// data[3] = ('T' >> 8) & 0xFF;
|
||
// data[4] = 'Y';
|
||
// data[5] = ('Y' >> 8) & 0xFF;
|
||
// data[6] = 'G';
|
||
// data[7] = ('G' >> 8) & 0xFF;
|
||
// CAN1_SendData(0x380, &data[0]);
|
||
// }
|
||
// if(CAN_SendCount ==8) //ID = 0x381 - 传递信息5-8(无要求)
|
||
// {
|
||
// data[0] = '-';
|
||
// data[1] = ('-' >> 8) & 0xFF;
|
||
// data[2] = 'B';
|
||
// data[3] = ('B' >> 8) & 0xFF;
|
||
// data[4] = 'M';
|
||
// data[5] = ('M' >> 8) & 0xFF;
|
||
// data[6] = 'S';
|
||
// data[7] = ('S' >> 8) & 0xFF;
|
||
// CAN1_SendData(0x381, &data[0]);
|
||
// }
|
||
|
||
if(CAN_SendCount>=7)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//Megarevo 迈格瑞能
|
||
void CAN_Protocol_Megarevo(void)
|
||
{
|
||
uint8_t data[8];
|
||
|
||
uint16_t tempVol;
|
||
int16_t tempCur; //总电流
|
||
|
||
uint16_t chgVolLimit;
|
||
int16_t chgCurLimit;
|
||
int16_t dsgCurLimit;
|
||
|
||
uint8_t protectByte1 = 0;
|
||
uint8_t protectByte2 = 0;
|
||
uint8_t alarmByte1 = 0;
|
||
uint8_t alarmByte2 = 0;
|
||
|
||
|
||
int16_t T_Average; // 平均温度
|
||
|
||
|
||
//保护
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温保护
|
||
//under temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x0005) != 0) || ((canMem[0].status_byte4 & 0x0C0C) != 0))
|
||
{
|
||
protectByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xef;
|
||
}
|
||
|
||
//过温保护
|
||
//over temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x000A) != 0) || ((canMem[0].status_byte4 & 0x0303) != 0))
|
||
{
|
||
protectByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte2 |= 0x02;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfD;
|
||
}
|
||
|
||
|
||
//告警
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温告警
|
||
if(((canMem[0].status_byte2 & 0xCC00) != 0) || ((canMem[0].status_byte4 & 0xC000) != 0))
|
||
{
|
||
alarmByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xef;
|
||
}
|
||
|
||
//过温告警
|
||
if(((canMem[0].status_byte2 & 0x3300) != 0) || ((canMem[0].status_byte4 & 0x3000) != 0))
|
||
{
|
||
alarmByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压告警
|
||
if((canMem[0].status_byte3 & 0x0A00) != 0)
|
||
{
|
||
alarmByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压告警
|
||
// if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfe;
|
||
}
|
||
|
||
|
||
if(CAN_SendCount ==0) //ID=0x359 - 报警/保护
|
||
{
|
||
data[0] = protectByte1;
|
||
data[1] = protectByte2;
|
||
data[2] = alarmByte1;
|
||
data[3] = alarmByte2;
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x359, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID = 0x351 --- 充放电电压/电流限制
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
//dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //Megarevo禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //Megarevo禁放
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[1] = (chgVolLimit >> 8) & 0xFF;
|
||
data[2] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[3] = (chgCurLimit >> 8) & 0xFF;
|
||
data[4] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[5] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x351, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID = 0x355 --- SOC/SOH
|
||
{
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = 0;
|
||
data[2] = canMem[0].soh & 0xFF; //SOH
|
||
data[3] = 0;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x355, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID = 0x356 --- 总电压/电流/温度
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/10); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;//单位0.1
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = (T_Average -2731) & 0xFF;
|
||
data[5] = ((T_Average -2731) >>8) & 0xFF; //温度-平均温度
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x356, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID = 0x35C --- 充放电允许
|
||
{
|
||
RequestFlag = 0xC0; //充电允许0x80,放电允许0x40,不强充~0x20
|
||
if(chg_forbidFlg == 1)//Megarevo
|
||
{
|
||
RequestFlag &= 0x7F; //禁充
|
||
}
|
||
if(dsg_forbidFlg == 1)//Megarevo
|
||
{
|
||
RequestFlag &= 0xBF; //禁放
|
||
}
|
||
if(chg_forceFlg == 1)//Megarevo
|
||
{
|
||
RequestFlag |= 0x20; //强充
|
||
}
|
||
|
||
data[0] = RequestFlag; //充电允许,放电允许
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35C, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=5)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//Pylon 派能
|
||
void CAN_Protocol_Pylon(void)
|
||
{
|
||
uint8_t data[8];
|
||
uint32_t totalCapacity;
|
||
|
||
uint16_t tempVol;
|
||
int16_t tempCur;
|
||
|
||
uint16_t chgVolLimit;
|
||
uint16_t dsgVolLimit;
|
||
int16_t chgCurLimit;
|
||
int16_t dsgCurLimit;
|
||
|
||
uint8_t protectByte1 = 0;
|
||
uint8_t protectByte2 = 0;
|
||
uint8_t protectByte3 = 0;
|
||
uint8_t protectByte4 = 0;
|
||
uint8_t protectByte5 = 0;
|
||
uint8_t protectByte6 = 0;
|
||
|
||
uint8_t alarmByte1 = 0;
|
||
uint8_t alarmByte2 = 0;
|
||
|
||
int16_t T_Average; // 平均温度
|
||
int16_t T_Max; // 最高温度
|
||
int16_t T_Min; // 最低温度
|
||
uint16_t T_MaxIndex;// 最高温度序号,范围0-6
|
||
uint16_t T_MinIndex;// 最低温度序号,范围0-6
|
||
|
||
uint16_t cellVolMax=0; // 电芯单体最高电压-Pylon
|
||
uint16_t cellVolMin=0; // 电芯单体最低电压-Pylon
|
||
uint16_t cellVolMaxIndex_Byte1; // 电芯单体最高电压序号,范围0-15-Pylon
|
||
uint16_t cellVolMaxIndex_Byte2;
|
||
uint16_t cellVolMinIndex_Byte1; // 电芯单体最低电压序号,范围0-15-Pylon
|
||
uint16_t cellVolMinIndex_Byte2;
|
||
|
||
|
||
//保护
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温保护
|
||
//under temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x0005) != 0) || ((canMem[0].status_byte4 & 0x0C0C) != 0))
|
||
{
|
||
protectByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xef;
|
||
}
|
||
|
||
//过温保护
|
||
//over temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x000A) != 0) || ((canMem[0].status_byte4 & 0x0303) != 0))
|
||
{
|
||
protectByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfe;
|
||
}
|
||
|
||
//告警
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温告警
|
||
if(((canMem[0].status_byte2 & 0xCC00) != 0) || ((canMem[0].status_byte4 & 0xC000) != 0))
|
||
{
|
||
alarmByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xef;
|
||
}
|
||
|
||
//过温告警
|
||
if(((canMem[0].status_byte2 & 0x3300) != 0) || ((canMem[0].status_byte4 & 0x3000) != 0))
|
||
{
|
||
alarmByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压告警
|
||
if((canMem[0].status_byte3 & 0x0A00) != 0)
|
||
{
|
||
alarmByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压告警
|
||
// if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfe;
|
||
}
|
||
|
||
//Data0 BIT0.1 General[Cancel] //0000 0010
|
||
protectByte3 |= 0x02;
|
||
|
||
//保护
|
||
//放电高温保护
|
||
//over temp at discharging
|
||
if(((canMem[0].status_byte2 & 0x0008) != 0) || ((canMem[0].status_byte4 & 0x0202) != 0))
|
||
{
|
||
protectByte3 &= 0x7f;
|
||
protectByte3 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
protectByte3 &= 0xbf;
|
||
protectByte3 |= 0x80;
|
||
}
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte3 &= 0xdf;
|
||
protectByte3 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte3 &= 0xef;
|
||
protectByte3 |= 0x20;
|
||
}
|
||
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte3 &= 0xf7; //去掉leave
|
||
// protectByte3 |= 0x04; //赋值arrive
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte3 &= 0xfb;
|
||
// protectByte3 |= 0x08;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte3 &= 0xfb;
|
||
// protectByte3 |= 0x08;
|
||
// }
|
||
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte4 &= 0x7f;
|
||
protectByte4 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
protectByte4 &= 0xbf;
|
||
protectByte4 |= 0x80;
|
||
}
|
||
|
||
//充电低温保护
|
||
//Data1 BIT4.5 under temp at charging //0001 0000
|
||
if( ((canMem[0].status_byte2 & 0x0001) != 0) || ((canMem[0].status_byte4 & 0x0404) != 0) )
|
||
{
|
||
protectByte4 &= 0xdf;
|
||
protectByte4 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte4 &= 0xef;
|
||
protectByte4 |= 0x20;
|
||
}
|
||
|
||
//充电高温保护
|
||
//Data1 BIT2.3 over temp at charging //0000 0100
|
||
if( ((canMem[0].status_byte2 & 0x0002) != 0) || ((canMem[0].status_byte4 & 0x0101) != 0) )
|
||
{
|
||
protectByte4 &= 0xf7;
|
||
protectByte4 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
protectByte4 &= 0xfb;
|
||
protectByte4 |= 0x08;
|
||
}
|
||
|
||
//放电低温保护
|
||
//Data1 BIT0.1 under temp at discharging //0000 0001
|
||
if( ((canMem[0].status_byte2 & 0x0004) != 0) || ((canMem[0].status_byte4 & 0x0808) != 0) )
|
||
{
|
||
protectByte4 &= 0xfd;
|
||
protectByte4 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte4 &= 0xfe;
|
||
protectByte4 |= 0x02;
|
||
}
|
||
|
||
//短路
|
||
//Data2 BIT4.5 short circuit //0001 0000
|
||
if((canMem[0].status_byte1 & 0x20) != 0)
|
||
{
|
||
protectByte5 &= 0xdf;
|
||
protectByte5 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte5 &= 0xef;
|
||
protectByte5 |= 0x20;
|
||
}
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte5 &= 0xfd;
|
||
protectByte5 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte5 &= 0xfe;
|
||
protectByte5 |= 0x02;
|
||
}
|
||
//Data2 BIT2.3 Contactor[Cancel] //0000 1000
|
||
protectByte5 |= 0x08;
|
||
//Data2 BIT6.7 BMS internal[Cancel] //1000 0000
|
||
protectByte5 |= 0x80;
|
||
// //Data3 BIT0.1 cell imbanlance //0000 0001
|
||
// if((bmsMem.balanceStatus & 0x01) !=0) //0x01表示平衡
|
||
// {
|
||
// protectByte6 &= 0xfe;
|
||
// protectByte6 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte6 &= 0xfd;
|
||
// protectByte6 |= 0x01;
|
||
// }
|
||
|
||
|
||
if(CAN_SendCount ==0) //ID=0x359 ---保护/报警
|
||
{
|
||
data[0] = protectByte1;
|
||
data[1] = protectByte2;
|
||
data[2] = alarmByte1;
|
||
data[3] = alarmByte2;
|
||
data[4] = OnlineNum;
|
||
data[5] = 0x50;
|
||
data[6] = 0x4E;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x359, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID = 0x351 --- 充放电电压/电流限制
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //Pylon禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //Pylon禁放
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[1] = (chgVolLimit >> 8) & 0xFF;
|
||
data[2] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[3] = (chgCurLimit >> 8) & 0xFF;
|
||
data[4] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[5] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[6] = dsgVolLimit & 0xFF; //放电电压限制低位
|
||
data[7] = (dsgVolLimit >> 8) & 0xFF;
|
||
CAN1_SendData(0x351, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID = 0x355 --- SOC/SOH
|
||
{
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = 0;
|
||
data[2] = canMem[0].soh & 0xFF; //SOH
|
||
data[3] = 0;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x355, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID = 0x356 --- 电池电压/电流/温度
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/10); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;// 平均温度
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = (T_Average -2731) & 0xFF;
|
||
data[5] = ((T_Average -2731) >>8) & 0xFF; //温度-平均温度
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x356, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID = 0x35C --- 充放电允许
|
||
{
|
||
RequestFlag = 0xC0; //充电允许0x80,放电允许0x40,不强充~0x20
|
||
if(chg_forbidFlg == 1)//Pylon
|
||
{
|
||
RequestFlag &= 0x7F; //禁充
|
||
}
|
||
if(dsg_forbidFlg == 1)//Pylon
|
||
{
|
||
RequestFlag &= 0xBF; //禁放
|
||
}
|
||
if(chg_forceFlg == 1)//Pylon
|
||
{
|
||
RequestFlag |= 0x20; //强充
|
||
}
|
||
|
||
data[0] = RequestFlag;
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35C, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==5) //ID = 0x35E --- 电池厂商
|
||
{
|
||
data[0] = 'P';
|
||
data[1] = 'Y';
|
||
data[2] = 'L';
|
||
data[3] = 'O';
|
||
data[4] = 'N';
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35E, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==6) //ID = 0x373 - 最大/最小单体电压/温度(与固德威配置相同)
|
||
{
|
||
cellVolMax = canMem[0].VolMax;
|
||
cellVolMin = canMem[0].VolMin;
|
||
T_Max = canMem[0].TempMax/10; // 最高温度
|
||
T_Min = canMem[0].TempMin/10; // 最低温度
|
||
|
||
data[0] = cellVolMin & 0xFF; //最小单体电压
|
||
data[1] = (cellVolMin >> 8) & 0xFF;
|
||
data[2] = cellVolMax & 0xFF; //最大单体电压
|
||
data[3] = (cellVolMax >> 8) & 0xFF;
|
||
data[4] = (T_Min ) & 0xFF; //最小单体温度
|
||
data[5] = ((T_Min ) >> 8) & 0xFF;
|
||
data[6] = (T_Max ) & 0xFF; //最大单体温度
|
||
data[7] = ((T_Max ) >> 8) & 0xFF;
|
||
CAN1_SendData(0x373, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==7) //ID = 0x379 --- 容量
|
||
{
|
||
totalCapacity = ncc_Ah * OnlineNum; //单位1Ah
|
||
|
||
data[0] = (totalCapacity >> 0 ) & 0xFF; //电池容量
|
||
data[1] = (totalCapacity >> 8 ) & 0xFF;
|
||
data[2] = (totalCapacity >> 16) & 0xFF;
|
||
data[3] = (totalCapacity >> 24) & 0xFF;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x379, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==8) //ID = 0x35A - Alarms/Warnings
|
||
{
|
||
data[0] = protectByte3;
|
||
data[1] = protectByte4;
|
||
data[2] = protectByte5;
|
||
data[3] = protectByte6;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35A, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount ==9) //ID = 0x374 - 最小电池电压地址
|
||
{
|
||
if((canMem[0].VolMinIndex + 1) >= 10)
|
||
{
|
||
cellVolMinIndex_Byte1 = 1;
|
||
cellVolMinIndex_Byte2 = (canMem[0].VolMinIndex+1)-10;
|
||
}
|
||
else
|
||
{
|
||
cellVolMinIndex_Byte1 = 0;
|
||
cellVolMinIndex_Byte2 = (canMem[0].VolMinIndex+1);
|
||
}
|
||
|
||
data[0] = '0';
|
||
data[1] = '1';
|
||
data[2] = 0x30 + cellVolMinIndex_Byte1;
|
||
data[3] = 0X30 + cellVolMinIndex_Byte2;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x374, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==10) //ID = 0x375 - 最大电池电压地址
|
||
{
|
||
if((canMem[0].VolMaxIndex+1)>= 10)
|
||
{
|
||
cellVolMaxIndex_Byte1 = 1;
|
||
cellVolMaxIndex_Byte2 = (canMem[0].VolMaxIndex+1)-10;
|
||
}
|
||
else
|
||
{
|
||
cellVolMaxIndex_Byte1 = 0;
|
||
cellVolMaxIndex_Byte2 = (canMem[0].VolMaxIndex+1);
|
||
}
|
||
|
||
data[0] = '0';
|
||
data[1] = '1';
|
||
data[2] = 0x30 + cellVolMaxIndex_Byte1;
|
||
data[3] = 0x30 + cellVolMaxIndex_Byte2;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x375, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==11) //ID = 0x376 - 最小电池温度地址
|
||
{
|
||
T_MinIndex = canMem[0].TempMinIndex;// 最低温度序号,范围0-6
|
||
|
||
data[0] = '0';
|
||
data[1] = '1';
|
||
data[2] = '0';
|
||
data[3] = 0x30 + (T_MinIndex+1);
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x376, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==12) //ID = 0x377 - 最大电池温度地址
|
||
{
|
||
T_MaxIndex = canMem[0].TempMaxIndex;// 最高温度序号,范围0-6
|
||
|
||
data[0] = '0';
|
||
data[1] = '1';
|
||
data[2] = '0';
|
||
data[3] = 0x30 + (T_MaxIndex+1);
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x377, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=13)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//Deye 德业
|
||
uint8_t Deye_dsg_forbidFlg; //单独属于德业的标志
|
||
void CAN_Protocol_Deye(void)
|
||
{
|
||
uint8_t data[8];
|
||
// uint16_t totalCapacity;
|
||
|
||
uint16_t tempVol;
|
||
int16_t tempCur;
|
||
|
||
uint16_t chgVolLimit;
|
||
uint16_t dsgVolLimit;
|
||
int16_t chgCurLimit;
|
||
int16_t dsgCurLimit;
|
||
|
||
uint8_t protectByte1 = 0;
|
||
uint8_t protectByte2 = 0;
|
||
|
||
uint8_t alarmByte1 = 0;
|
||
uint8_t alarmByte2 = 0;
|
||
|
||
|
||
int16_t T_Average; // 平均温度
|
||
|
||
|
||
//保护
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温保护
|
||
//under temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x0005) != 0) || ((canMem[0].status_byte4 & 0x0C0C) != 0))
|
||
{
|
||
protectByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xef;
|
||
}
|
||
|
||
//过温保护
|
||
//over temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x000A) != 0) || ((canMem[0].status_byte4 & 0x0303) != 0))
|
||
{
|
||
protectByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfe;
|
||
}
|
||
|
||
//告警
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温告警
|
||
if(((canMem[0].status_byte2 & 0xCC00) != 0) || ((canMem[0].status_byte4 & 0xC000) != 0))
|
||
{
|
||
alarmByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xef;
|
||
}
|
||
|
||
//过温告警
|
||
if(((canMem[0].status_byte2 & 0x3300) != 0) || ((canMem[0].status_byte4 & 0x3000) != 0))
|
||
{
|
||
alarmByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压告警
|
||
if((canMem[0].status_byte3 & 0x0A00) != 0)
|
||
{
|
||
alarmByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压告警
|
||
// if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfe;
|
||
}
|
||
|
||
if(canMem[0].soc<=5) //Deye自己的强充标志变化值
|
||
{
|
||
Deye_dsg_forbidFlg = 1;
|
||
}
|
||
else if(canMem[0].soc>=10)
|
||
{
|
||
Deye_dsg_forbidFlg = 0;
|
||
}
|
||
|
||
|
||
if(CAN_SendCount ==0) //ID = 0x359 --- 报警/保护
|
||
{
|
||
data[0] = protectByte1; //电芯过压
|
||
data[1] = protectByte2;
|
||
data[2] = alarmByte1;
|
||
data[3] = alarmByte2;
|
||
data[4] = 0X00;
|
||
data[5] = 0x50;
|
||
data[6] = 0x4E;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x359, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID = 0x351 --- 充放电限压/限流
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //Deye禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(Deye_dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //Deye禁放(范围是5%和10%,与其他协议分开)
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[1] = (chgVolLimit >> 8) & 0xFF;
|
||
data[2] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[3] = (chgCurLimit >> 8) & 0xFF;
|
||
data[4] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[5] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[6] = dsgVolLimit & 0xFF; //放电电压限制低位
|
||
data[7] = (dsgVolLimit >> 8) & 0xFF;
|
||
CAN1_SendData(0x351, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID = 0x355 --- SOC/SOH
|
||
{
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = 0;
|
||
data[2] = canMem[0].soh & 0xFF; //SOH
|
||
data[3] = 0;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x355, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID = 0x356 --- 总电压/电流/平均温度
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/10); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;//单位0.1
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = (T_Average -2731) & 0xFF;
|
||
data[5] = ((T_Average -2731) >>8) & 0xFF; //温度-平均温度
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x356, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID = 0x35C --- 强充
|
||
{
|
||
if(Deye_dsg_forbidFlg == 1) //Deye独有的强充标志变化值
|
||
{
|
||
RequestFlag = 0x20; //强充请求
|
||
}
|
||
else
|
||
{
|
||
RequestFlag = 0x00; //停止强充
|
||
}
|
||
|
||
data[0] = RequestFlag;
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35C, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==5) //0x35E --- 电池品牌
|
||
{
|
||
data[0] = 0x00;
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35E, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=6)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//MUST 美世乐
|
||
void CAN_Protocol_MUST(void)
|
||
{
|
||
uint8_t data[8];
|
||
// uint16_t totalCapacity;
|
||
|
||
uint16_t tempVol;
|
||
int16_t tempCur;
|
||
|
||
uint16_t chgVolLimit;
|
||
uint16_t dsgVolLimit;
|
||
int16_t chgCurLimit;
|
||
int16_t dsgCurLimit;
|
||
|
||
uint8_t alarmByte1 = 0;
|
||
|
||
int16_t T_Average; // 平均温度
|
||
|
||
|
||
//告警
|
||
// //过压告警
|
||
// if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 |= 0x01;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfe;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfe;
|
||
// }
|
||
|
||
//欠压告警
|
||
if((canMem[0].status_byte3 & 0x0A00) != 0)
|
||
{
|
||
alarmByte1 |= 0x02;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xfd;
|
||
}
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xfb;
|
||
}
|
||
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xf7;
|
||
}
|
||
|
||
//过温告警
|
||
if(((canMem[0].status_byte2 & 0x3300) != 0) || ((canMem[0].status_byte4 & 0x3000) != 0))
|
||
{
|
||
alarmByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xEF;
|
||
}
|
||
|
||
//低温告警
|
||
if(((canMem[0].status_byte2 & 0xCC00) != 0) || ((canMem[0].status_byte4 & 0xC000) != 0))
|
||
{
|
||
alarmByte1 |= 0x20;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xdf;
|
||
}
|
||
// BIT6 short circuit
|
||
if((canMem[0].status_byte1 & 0x20) != 0)
|
||
{
|
||
alarmByte1 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xbf;
|
||
}
|
||
|
||
|
||
if(CAN_SendCount ==0) //ID = 0x00030400 - 电池电压、电流、温度、报警
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/100); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;// 平均温度
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = ((T_Average -2731)/10) & 0xFF;
|
||
data[5] = ((T_Average -2731)/10 >>8) & 0xFF; //温度-暂时取平均温度,具体哪一路需要客户确认 //signed有符号数
|
||
data[6] = alarmByte1;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x00030400, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID = 0x00030500 —— SOC/SOH (修改)
|
||
{
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = 0;
|
||
data[2] = canMem[0].soh & 0xFF; //SOH
|
||
data[3] = 0;
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x00030500, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID = 0x00030200 --- 电池禁用/SOC禁用(先给0x00测试,后换成0xFF测试)
|
||
{
|
||
data[0] = 0x00; //电池禁用标志
|
||
data[1] = 0x00;
|
||
data[2] = 0x00; //SOC禁用标志
|
||
data[3] = 0x00;
|
||
if(chg_forbidFlg == 1)//MUST
|
||
{
|
||
RequestFlag = 0xFF; //禁充
|
||
}
|
||
else
|
||
{
|
||
RequestFlag = 0x00; //充电允许
|
||
}
|
||
data[4] = RequestFlag; //电池充电禁用标志
|
||
data[5] = RequestFlag;
|
||
if(dsg_forbidFlg == 1)//MUST
|
||
{
|
||
RequestFlag = 0xFF; //禁放
|
||
}
|
||
else
|
||
{
|
||
RequestFlag = 0x00; //放电允许
|
||
}
|
||
data[6] = RequestFlag; //电池放电禁用标志
|
||
data[7] = RequestFlag;
|
||
CAN1_SendData(0x00030200, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID = 0x00030100 —— 充放电限压/限流
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //MUST禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //MUST禁放
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[1] = (chgVolLimit >> 8) & 0xFF;
|
||
data[2] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[3] = (chgCurLimit >> 8) & 0xFF;
|
||
data[4] = dsgVolLimit & 0xFF; //放电电压限制低位
|
||
data[5] = (dsgVolLimit >> 8) & 0xFF;
|
||
data[6] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[7] = (dsgCurLimit >> 8) & 0xFF;
|
||
CAN1_SendData(0x00030100, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID = 0x00030700 - 充放电/循环/远程快速停止命令(需要定制,先给0xFF)
|
||
{
|
||
if(chg_forceFlg == 1)//MUST
|
||
{
|
||
RequestFlag = 0xFF; //强充
|
||
}
|
||
else
|
||
{
|
||
RequestFlag = 0x00; //不强充
|
||
}
|
||
|
||
data[0] = RequestFlag; //强充指令
|
||
data[1] = RequestFlag;
|
||
data[2] = 0x00; //强放指令
|
||
data[3] = 0x00;
|
||
data[4] = 0x00; //循环指令
|
||
data[5] = 0x00;
|
||
data[6] = 0x00; //远程快速停止指令
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x00030700, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=5)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//solis 锦浪
|
||
void CAN_Protocol_solis(void)
|
||
{
|
||
uint8_t data[8];
|
||
uint16_t totalCapacity;
|
||
|
||
uint16_t tempVol;
|
||
int16_t tempCur;
|
||
|
||
uint16_t chgVolLimit;
|
||
uint16_t dsgVolLimit;
|
||
int16_t chgCurLimit;
|
||
int16_t dsgCurLimit;
|
||
|
||
uint8_t protectByte1 = 0;
|
||
uint8_t protectByte2 = 0;
|
||
uint8_t alarmByte1 = 0;
|
||
uint8_t alarmByte2 = 0;
|
||
|
||
|
||
int16_t T_Average; // 平均温度
|
||
|
||
|
||
//保护
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温保护
|
||
//under temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x0005) != 0) || ((canMem[0].status_byte4 & 0x0C0C) != 0))
|
||
{
|
||
protectByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xef;
|
||
}
|
||
|
||
//过温保护
|
||
//over temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x000A) != 0) || ((canMem[0].status_byte4 & 0x0303) != 0))
|
||
{
|
||
protectByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfe;
|
||
}
|
||
|
||
//告警
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温告警
|
||
if(((canMem[0].status_byte2 & 0xCC00) != 0) || ((canMem[0].status_byte4 & 0xC000) != 0))
|
||
{
|
||
alarmByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xef;
|
||
}
|
||
|
||
//过温告警
|
||
if(((canMem[0].status_byte2 & 0x3300) != 0) || ((canMem[0].status_byte4 & 0x3000) != 0))
|
||
{
|
||
alarmByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压告警
|
||
if((canMem[0].status_byte3 & 0x0A00) != 0)
|
||
{
|
||
alarmByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压告警
|
||
// if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfe;
|
||
}
|
||
|
||
|
||
if(CAN_SendCount ==0) //ID=0x359 告警
|
||
{
|
||
data[0] = protectByte1; //电芯过压
|
||
data[1] = protectByte2;
|
||
data[2] = protectByte1;
|
||
data[3] = protectByte2;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x359, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID = 0x351 充放电限压/限流
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //GINLONG禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //GINLONG禁放
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[1] = (chgVolLimit >> 8) & 0xFF;
|
||
data[2] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[3] = (chgCurLimit >> 8) & 0xFF;
|
||
data[4] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[5] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[6] = dsgVolLimit & 0xFF; //放电电压限制低位
|
||
data[7] = (dsgVolLimit >> 8) & 0xFF;
|
||
CAN1_SendData(0x351, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID = 0x355 SOC/SOH
|
||
{
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = 0;
|
||
data[2] = canMem[0].soh & 0xFF; //SOH
|
||
data[3] = 0;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x355, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID = 0x356 总电压/电流/温度
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/10); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;// 平均温度
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = (T_Average -2731) & 0xFF;;
|
||
data[5] = ((T_Average -2731) >>8) & 0xFF; //温度-暂时取平均温度,具体哪一路需要客户确认
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x356, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID = 0x35C 强充/满充
|
||
{
|
||
if(chg_forceFlg == 1)//QINLONG
|
||
{
|
||
RequestFlag = 0x20; //强充请求
|
||
}
|
||
else
|
||
{
|
||
RequestFlag = 0x00; //停止强充
|
||
}
|
||
|
||
data[0] = RequestFlag;
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35C, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==5) //0x35E
|
||
{
|
||
totalCapacity = ncc_Ah * OnlineNum; //单位1Ah
|
||
|
||
data[0] = 0x00;
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00; //电池制造商名称
|
||
data[6] = totalCapacity & 0xFF; //容量
|
||
data[7] = (totalCapacity >> 8) & 0xFF;
|
||
CAN1_SendData(0x35E, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==6) //ID = 0x71C
|
||
{
|
||
data[0] = 0x00;
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00; //电池序列号
|
||
data[4] = 0x00;
|
||
data[5] = 0x00; //BMS固件版本
|
||
data[6] = 0x00; //产品型号
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x71C, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=7)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//Growatt 古瑞瓦特
|
||
void CAN_Protocol_Growatt(void) //特改8.8
|
||
{
|
||
uint8_t data[8];
|
||
uint16_t totalCapacity; //总容量
|
||
uint16_t remainCapacity; //剩余容量
|
||
|
||
int16_t tempVol; //总电压
|
||
int16_t tempCur; //总电流
|
||
|
||
uint16_t chgVolLimit; //充电限压
|
||
// uint16_t dsgVolLimit; //放电限压
|
||
uint16_t chgCurLimit; //充电限流
|
||
uint16_t dsgCurLimit; //放电限流
|
||
|
||
uint8_t protectByte1 = 0; //保护位1,与告警位1值相同
|
||
uint8_t protectByte2 = 0; //保护位2,与告警位2值相同
|
||
|
||
uint8_t statusByte1 = 0; //状态位1
|
||
uint8_t statusByte2 = 0; //状态位2
|
||
uint8_t totalNum = 0; //总电池节数
|
||
|
||
int16_t T_Average; // 平均温度
|
||
int16_t T_Max; // 最高温度
|
||
int16_t T_Min; // 最低温度
|
||
uint16_t T_MaxIndex;// 最高温度序号,范围0-6
|
||
uint16_t T_MinIndex;// 最低温度序号,范围0-6
|
||
|
||
uint16_t cellVolMax=0; // 电芯单体最高电压
|
||
uint16_t cellVolMin=0; // 电芯单体最低电压
|
||
uint16_t cellVolMaxIndex; // 电芯单体最高电压序号,范围0-15
|
||
uint16_t cellVolMinIndex; // 电芯单体最低电压序号,范围0-15
|
||
|
||
|
||
//保护、报警赋值:
|
||
//Data0 BIT3 cell uv-under voltage
|
||
if((canMem[0].status_byte1 & 0x02) !=0)
|
||
{
|
||
protectByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xF7;
|
||
}
|
||
//Data0 BIT4 cell ov-over voltage
|
||
if((canMem[0].status_byte1 & 0x01) !=0)
|
||
{
|
||
if(canMem[0].soc < 99)
|
||
{
|
||
protectByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xEF;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xEF;
|
||
}
|
||
//Data0 BIT5 sc-short circuit
|
||
|
||
//Data0 BIT6 occ-charge over current
|
||
if( ((canMem[0].status_byte1 & 0x10) !=0) || ((canMem[0].status_byte4 & 0x10) !=0) )
|
||
{
|
||
protectByte1 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xBF;
|
||
}
|
||
//Data0 BIT7 ocd-discharge over current
|
||
if( ((canMem[0].status_byte1 & 0x2c) !=0) || ((canMem[0].status_byte4 & 0x20) !=0) )
|
||
{
|
||
protectByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0x7F;
|
||
}
|
||
// //Data1 BIT2 cell imbalance
|
||
// if((bmsMem.balanceStatus & 0x01) !=0) //表示开启了均衡
|
||
// {
|
||
// protectByte2 |= 0xFB;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte2 &= 0x04;
|
||
// }
|
||
//Data1 BIT4 cell utc-charge under temp
|
||
if( ((canMem[0].status_byte2 & 0x01) !=0) || ((canMem[0].status_byte4 & 0x04) !=0) )
|
||
{
|
||
protectByte2 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xEF;
|
||
}
|
||
//Data1 BIT5 cell utd-discharge under temp
|
||
if( ((canMem[0].status_byte2 & 0x04) !=0) || ((canMem[0].status_byte4 & 0x08) !=0) )
|
||
{
|
||
protectByte2 |= 0x20;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xDF;
|
||
}
|
||
//Data1 BIT6 cell otc-charge over temp
|
||
if( ((canMem[0].status_byte2 & 0x02) !=0) || ((canMem[0].status_byte4 & 0x01) !=0) )
|
||
{
|
||
protectByte2 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xBF;
|
||
}
|
||
//Data1 BIT7 cell otd-discharge over temp
|
||
if( ((canMem[0].status_byte2 & 0x08) !=0) || ((canMem[0].status_byte4 & 0x02) !=0) )
|
||
{
|
||
protectByte2 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0x7F;
|
||
}
|
||
|
||
|
||
//状态位赋值:
|
||
if(bmsMem.E2_485Snum != 1) //01并机/00单机模式
|
||
{
|
||
statusByte1 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
statusByte1 &= 0xFE;
|
||
}
|
||
if(bCHGING == 1) //充电
|
||
{
|
||
statusByte2 |= 0x02;
|
||
}
|
||
else
|
||
{
|
||
statusByte2 &= 0xFD;
|
||
}
|
||
if(bDSGING == 1) //放电
|
||
{
|
||
statusByte2 |= 0x03;
|
||
}
|
||
else
|
||
{
|
||
statusByte2 &= 0xFC;
|
||
}
|
||
// if((bmsMem.balanceStatus & 0x01) !=0) //均衡状态
|
||
// {
|
||
// statusByte2 |= 0x08;
|
||
// }
|
||
// else
|
||
// {
|
||
// statusByte2 &= 0xF7;
|
||
// }
|
||
|
||
|
||
if(CAN_SendCount ==0) //ID = 0x311
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
//dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 0)
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = 0; //Growatt禁充
|
||
}
|
||
if(dsg_forbidFlg == 0)
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = 0; //Growatt禁放
|
||
}
|
||
|
||
statusByte2 |= 0x60;
|
||
if(chg_forbidFlg == 1)//Growatt
|
||
{
|
||
statusByte2 &= ~0x40; //禁充 bit6
|
||
}
|
||
if(dsg_forbidFlg == 1)//Growatt
|
||
{
|
||
statusByte2 &= ~0x20; //禁放 bit5
|
||
}
|
||
|
||
data[0] = (chgVolLimit >> 8) & 0xFF;
|
||
data[1] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[2] = (chgCurLimit >> 8) & 0xFF;
|
||
data[3] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[4] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[5] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[6] = statusByte1;
|
||
data[7] = statusByte2; //状态位
|
||
CAN1_SendData(0x311, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID = 0x312 - 保护/告警
|
||
{
|
||
data[0] = protectByte1;
|
||
data[1] = protectByte2;
|
||
data[2] = protectByte1;
|
||
data[3] = protectByte2;
|
||
data[4] = OnlineNum;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00; //电池降功率原因(暂无)
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x312, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID = 0x313
|
||
{
|
||
tempVol = (int16_t)(bmsMem.packVoltage/10); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;// 平均温度
|
||
|
||
data[0] = (tempVol >>8) & 0xFF; //电池组电压 0.01
|
||
data[1] = tempVol & 0xFF;
|
||
data[2] = (tempCur >>8) & 0xFF; //电池组电流 0.1
|
||
data[3] = tempCur & 0xFF;
|
||
data[4] = ((T_Average-2731) >>8) & 0xFF;
|
||
data[5] = (T_Average-2731) & 0xFF; //平均温度 0.1
|
||
data[6] = canMem[0].soc & 0xFF; //SOC
|
||
data[7] = canMem[0].soh & 0xFF; //SOH
|
||
CAN1_SendData(0x313, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID = 0x314
|
||
{
|
||
totalCapacity = 100 * fcc_Ah * OnlineNum; //单位0.01Ah
|
||
remainCapacity = 100 * rcc_Ah * OnlineNum; //单位0.01Ah
|
||
|
||
data[0] = (remainCapacity >> 8) & 0xFF;
|
||
data[1] = remainCapacity & 0xFF; //剩余容量 10mAh
|
||
data[2] = (totalCapacity >> 8) & 0xFF;
|
||
data[3] = totalCapacity & 0xFF; //电池满充容量 10mAh
|
||
data[4] = 0x00;
|
||
data[5] = (canMem[0].VolMax - canMem[0].VolMin) & 0xFF; //最大电压差 1mV
|
||
data[6] = 0x00;
|
||
data[7] = 0x00; //循环次数(暂无)
|
||
CAN1_SendData(0x314, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID = 0x319 - 电池最低最高单体电压
|
||
{
|
||
RequestFlag = 0xC0; //充电允许0x80,放电允许0x40,不强充~0x20
|
||
if(chg_forbidFlg == 1)//Growatt
|
||
{
|
||
RequestFlag &= ~0x80; //禁充
|
||
}
|
||
if(dsg_forbidFlg == 1)//Growatt
|
||
{
|
||
RequestFlag &= ~0x40; //禁放
|
||
}
|
||
if(chg_forceFlg == 1)//Growatt
|
||
{
|
||
RequestFlag |= 0x20; //强充
|
||
}
|
||
|
||
cellVolMax = canMem[0].VolMax;
|
||
cellVolMin = canMem[0].VolMin;
|
||
cellVolMaxIndex = canMem[0].VolMaxIndex;
|
||
cellVolMinIndex = canMem[0].VolMinIndex;
|
||
|
||
data[0] = RequestFlag; //充电允许放电允许 电池类型00
|
||
data[1] = (cellVolMax >> 8) & 0xFF;
|
||
data[2] = cellVolMax & 0xFF; //最大单体电压
|
||
data[3] = (cellVolMin >> 8) & 0xFF;
|
||
data[4] = cellVolMin & 0xFF; //最小单体电压
|
||
data[5] = (cellVolMaxIndex+1) & 0xFF; //最大单体电压序号
|
||
data[6] = (cellVolMinIndex+1) & 0xFF; //最小单体电压序号
|
||
data[7] = 0x00; //故障电池地址(暂无)
|
||
CAN1_SendData(0x319, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==5) //ID = 0x320 - 制造商缩写RICN SMART
|
||
{
|
||
data[0] = 'S';
|
||
data[1] = 'R'; //制造商缩写
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x320, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==6) //ID = 0x322 - 电池最低最高单体温度
|
||
{
|
||
T_Max = canMem[0].TempMax; // 最高温度
|
||
T_Min = canMem[0].TempMin; // 最低温度
|
||
T_MaxIndex = canMem[0].TempMaxIndex;// 最高温度序号,范围0-6
|
||
T_MinIndex = canMem[0].TempMinIndex;// 最低温度序号,范围0-6
|
||
|
||
data[0] = ((T_Max -2731) >> 8) & 0xFF;
|
||
data[1] = (T_Max -2731) & 0xFF; //最高单体温度
|
||
data[2] = ((T_Min -2731) >> 8) & 0xFF;
|
||
data[3] = (T_Min -2731) & 0xFF; //最低单体温度
|
||
data[4] = (T_MaxIndex+1) & 0xFF; //最高单体温度序号
|
||
data[5] = (T_MinIndex+1) & 0xFF; //最低单体温度序号
|
||
data[6] = 100; //最大SOC
|
||
data[7] = 0; //最小SOC
|
||
CAN1_SendData(0x322, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==7) //ID = 0x323 - 总电池节数
|
||
{
|
||
totalNum = bmsMem.ucCellNum * OnlineNum;
|
||
|
||
data[0] = totalNum; //总电池节数 1-254 U8
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x323, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=8)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//Aiswei 爱士惟
|
||
void CAN_Protocol_Aiswei(void)
|
||
{
|
||
uint8_t data[8];
|
||
uint16_t totalCapacity;
|
||
|
||
uint16_t tempVol;
|
||
int16_t tempCur;
|
||
|
||
uint16_t chgVolLimit;
|
||
// uint16_t dsgVolLimit;
|
||
uint16_t chgCurLimit;
|
||
uint16_t dsgCurLimit;
|
||
|
||
uint8_t protectByte1 = 0;
|
||
uint8_t protectByte2 = 0;
|
||
|
||
int16_t T_Average; // 平均温度
|
||
int16_t T_Max; // 最高温度
|
||
int16_t T_Min; // 最低温度
|
||
uint16_t T_MaxIndex;// 最高温度序号,范围0-6
|
||
uint16_t T_MinIndex;// 最低温度序号,范围0-6
|
||
|
||
uint16_t cellVolMax=0; // 电芯单体最高电压-Aiswei
|
||
uint16_t cellVolMin=0; // 电芯单体最低电压-Aiswei
|
||
uint16_t cellVolMaxIndex; // 电芯单体最高电压序号,范围0-15-Aiswei
|
||
uint16_t cellVolMinIndex; // 电芯单体最低电压序号,范围0-15-Aiswei
|
||
|
||
|
||
uint8_t alarmByte1 = 0;
|
||
uint8_t alarmByte2 = 0;
|
||
|
||
|
||
//保护
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温保护
|
||
//under temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x0005) != 0) || ((canMem[0].status_byte4 & 0x0C0C) != 0))
|
||
{
|
||
protectByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xef;
|
||
}
|
||
|
||
//过温保护
|
||
//over temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x000A) != 0) || ((canMem[0].status_byte4 & 0x0303) != 0))
|
||
{
|
||
protectByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfe;
|
||
}
|
||
|
||
//告警
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0x7f;
|
||
}
|
||
|
||
//低温告警
|
||
if(((canMem[0].status_byte2 & 0xCC00) != 0) || ((canMem[0].status_byte4 & 0xC000) != 0))
|
||
{
|
||
alarmByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xef;
|
||
}
|
||
|
||
//过温告警
|
||
if(((canMem[0].status_byte2 & 0x3300) != 0) || ((canMem[0].status_byte4 & 0x3000) != 0))
|
||
{
|
||
alarmByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xf7;
|
||
}
|
||
|
||
//欠压告警
|
||
if((canMem[0].status_byte3 & 0x0A00) != 0)
|
||
{
|
||
alarmByte1 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xfb;
|
||
}
|
||
|
||
// //过压告警
|
||
// if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte1 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfd;
|
||
// }
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfe;
|
||
}
|
||
|
||
|
||
if(CAN_SendCount ==0) //ID=0x359 - 保护与警告(与Sol-Ark配置相同)
|
||
{
|
||
data[0] = protectByte1; //电芯过压
|
||
data[1] = protectByte2;
|
||
data[2] = alarmByte1;
|
||
data[3] = alarmByte2;
|
||
data[4] = OnlineNum;
|
||
data[5] = 0x50;
|
||
data[6] = 0x4E;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x359, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID: 0x351 - 充电电压/充电限流/放电限流(前3个与Sol-Ark配置相同,无4)
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
//dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //Aiswei禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //Aiswei禁放
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[1] = (chgVolLimit >> 8) & 0xFF;
|
||
data[2] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[3] = (chgCurLimit >> 8) & 0xFF;
|
||
data[4] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[5] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x351, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID: 0x355 - SOC/SOH(与Sol-Ark配置相同)
|
||
{
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = 0;
|
||
data[2] = canMem[0].soh & 0xFF; //SOH
|
||
data[3] = 0;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x355, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID: 0x356 - 系统电压/系统总电流/平均单体温度(与Sol-Ark配置相同)
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/10); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;// 平均温度
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = (T_Average -2731) & 0xFF;;
|
||
data[5] = ((T_Average -2731) >>8) & 0xFF; //温度-平均温度
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x356, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID: 0x35C - 满充请求/强制充电请求I/强制充电请求II/放电允许/充电允许(与Sol-Ark配置相同)
|
||
{
|
||
RequestFlag = 0xC0; //充电允许0x80,放电允许0x40,不强充~0x20
|
||
if(chg_forbidFlg == 1)//Aiswei
|
||
{
|
||
RequestFlag &= 0x7F; //禁充
|
||
}
|
||
if(dsg_forbidFlg == 1)//Aiswei
|
||
{
|
||
RequestFlag &= 0xBF; //禁放
|
||
}
|
||
if(chg_forceFlg == 1)//Aiswei
|
||
{
|
||
RequestFlag |= 0x20; //强充
|
||
}
|
||
|
||
data[0] = RequestFlag; //充电允许,放电允许
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35C, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==5) //ID: 0x379 - 总容量/当前在线数量(与Sol-Ark配置相同)
|
||
{
|
||
totalCapacity = ncc_Ah * OnlineNum; //单位1Ah
|
||
|
||
data[0] = totalCapacity & 0xFF; //电池容量
|
||
data[1] = (totalCapacity >> 8) & 0xFF;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x379, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==6) //ID: 0x35e - 厂家名称"AISWEI"-ASCII(与Sol-Ark配置相同)
|
||
{
|
||
data[0] = 'B';
|
||
data[1] = 'T';
|
||
data[2] = 'Y';
|
||
data[3] = 'G';
|
||
data[4] = '-';
|
||
data[5] = 'B';
|
||
data[6] = 'M';
|
||
data[7] = 'S';
|
||
CAN1_SendData(0x35e, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==7) //ID = 0x373 - 最大/最小单体电压/温度(与固德威配置相同)
|
||
{
|
||
cellVolMax = canMem[0].VolMax/100;
|
||
cellVolMin = canMem[0].VolMin/100;
|
||
T_Max = canMem[0].TempMax; // 最高温度
|
||
T_Min = canMem[0].TempMin; // 最低温度
|
||
|
||
data[0] = cellVolMin & 0xFF; //最小单体电压
|
||
data[1] = (cellVolMin >> 8) & 0xFF;
|
||
data[2] = cellVolMax & 0xFF; //最大单体电压
|
||
data[3] = (cellVolMax >> 8) & 0xFF;
|
||
data[4] = (T_Min -2731) & 0xFF; //最小单体温度
|
||
data[5] = ((T_Min -2731) >> 8) & 0xFF;
|
||
data[6] = (T_Max -2731) & 0xFF; //最大单体温度
|
||
data[7] = ((T_Max -2731) >> 8) & 0xFF;
|
||
CAN1_SendData(0x373, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==8) //ID: 0x374 - 最大/最小单体温度/电压的ID(与固德威配置相同)
|
||
{
|
||
cellVolMaxIndex = canMem[0].VolMaxIndex;
|
||
cellVolMinIndex = canMem[0].VolMinIndex;
|
||
T_MaxIndex = canMem[0].TempMaxIndex;// 最高温度序号,范围0-6
|
||
T_MinIndex = canMem[0].TempMinIndex;// 最低温度序号,范围0-6
|
||
|
||
data[0] = (cellVolMinIndex+1) & 0xFF; //最小单体电压序号
|
||
data[1] = ((cellVolMinIndex+1) >> 8) & 0xFF;
|
||
data[2] = (cellVolMaxIndex+1) & 0xFF; //最大单体电压序号
|
||
data[3] = ((cellVolMaxIndex+1) >> 8) & 0xFF;
|
||
data[4] = (T_MinIndex+1) & 0xFF; //最小单体温度序号
|
||
data[5] = ((T_MinIndex+1) >> 8) & 0xFF;
|
||
data[6] = (T_MaxIndex+1) & 0xFF; //最大单体温度序号,实际显示从1开始
|
||
data[7] = ((T_MaxIndex+1) >> 8) & 0xFF;
|
||
CAN1_SendData(0x374, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=9)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//Afore 艾伏
|
||
void CAN_Protocol_Afore(void)
|
||
{
|
||
uint8_t data[8];
|
||
|
||
uint16_t tempVol;
|
||
int16_t tempCur;
|
||
|
||
uint16_t chgVolLimit;
|
||
uint16_t dsgVolLimit;
|
||
uint16_t chgCurLimit;
|
||
uint16_t dsgCurLimit;
|
||
|
||
uint8_t protectByte1 = 0; //故障H
|
||
uint8_t protectByte2 = 0; //故障
|
||
uint8_t statusbyte = 0; //故障L
|
||
|
||
uint8_t alarmByte1 = 0; //告警
|
||
uint8_t alarmByte2 = 0;
|
||
|
||
int16_t T_Average; // 平均温度
|
||
int16_t T_Max; // 最高温度
|
||
int16_t T_Min; // 最低温度
|
||
uint16_t T_MaxIndex;// 最高温度序号,范围0-6
|
||
uint16_t T_MinIndex;// 最低温度序号,范围0-6
|
||
|
||
uint16_t cellVolMax=0; // 电芯单体最高电压-Afore
|
||
uint16_t cellVolMin=0; // 电芯单体最低电压-Afore
|
||
uint16_t cellVolMaxIndex; // 电芯单体最高电压序号,范围0-15-Afore
|
||
uint16_t cellVolMinIndex; // 电芯单体最低电压序号,范围0-15-Afore
|
||
|
||
|
||
//保护
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0x7F;
|
||
}
|
||
|
||
//低温保护
|
||
//under temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x0005) != 0) || ((canMem[0].status_byte4 & 0x0C0C) != 0))
|
||
{
|
||
protectByte1 |= 0x20;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xDF;
|
||
}
|
||
|
||
//过温保护
|
||
//over temp at charging or discharging
|
||
if(((canMem[0].status_byte2 & 0x000A) != 0) || ((canMem[0].status_byte4 & 0x0303) != 0))
|
||
{
|
||
protectByte1 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xBF;
|
||
}
|
||
|
||
//总体欠压保护
|
||
if((canMem[0].status_byte1 & 0x0200) !=0)
|
||
{
|
||
protectByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xF7;
|
||
}
|
||
|
||
// //总体过压保护
|
||
// if((canMem[0].status_byte1 & 0x0100) !=0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 |= 0x04;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xFb;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xFb;
|
||
// }
|
||
|
||
//单体欠压保护
|
||
if(((canMem[0].status_byte1 & 0x0002) !=0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte1 |= 0x02;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xFD;
|
||
}
|
||
|
||
// //单体过压保护
|
||
// if(((canMem[0].status_byte1 & 0x0001) !=0) || ((canMem[0].status_byte1 & 0x0040) != 0))
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 |= 0x01;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xFE;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xFE;
|
||
// }
|
||
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xFE;
|
||
}
|
||
|
||
|
||
//告警
|
||
//低温告警
|
||
if(((canMem[0].status_byte2 & 0xCC00) != 0) || ((canMem[0].status_byte4 & 0xC000) != 0))
|
||
{
|
||
alarmByte1 |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0x7F;
|
||
}
|
||
|
||
//过温告警
|
||
if(((canMem[0].status_byte2 & 0x3300) != 0) || ((canMem[0].status_byte4 & 0x3000) != 0))
|
||
{
|
||
alarmByte1 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xBF;
|
||
}
|
||
|
||
//总体欠压告警
|
||
if((canMem[0].status_byte3 & 0x0800) !=0)
|
||
{
|
||
alarmByte1 |= 0x08;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xF7;
|
||
}
|
||
|
||
// //总体过压告警
|
||
// if((canMem[0].status_byte3 & 0x0400) !=0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte1 |= 0x04;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xFb;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xFb;
|
||
// }
|
||
|
||
//单体欠压告警
|
||
if((canMem[0].status_byte3 & 0x0200) !=0)
|
||
{
|
||
alarmByte1 |= 0x02;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xFD;
|
||
}
|
||
|
||
// //单体过压告警
|
||
// if((canMem[0].status_byte3 & 0x0100) !=0)
|
||
// {
|
||
// alarmByte1 |= 0x01;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xFE;
|
||
// }
|
||
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte2 |= 0x02;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xFD;
|
||
}
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xFE;
|
||
}
|
||
|
||
// if((bmsMem.balanceStatus & 0x01) !=0) //均衡状态
|
||
// {
|
||
// statusbyte |= 0x80;
|
||
// }
|
||
// else
|
||
// {
|
||
// statusbyte &= 0x7F;
|
||
// }
|
||
|
||
|
||
if(CAN_SendCount ==0) //ID: 0x350 - 运行信息(系统电压/系统总电流/平均单体温度)
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/100); //单位0.1V
|
||
tempCur = (int16_t)((canMem[0].cur/10) + 5000); //单位0.1A(偏移5000)
|
||
T_Average = (canMem[0].temp + 1000);// 平均温度 单位0.1℃(偏移1000)
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = (T_Average -2731) & 0xFF;;
|
||
data[5] = ((T_Average -2731) >>8) & 0xFF; //温度-平均温度
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x350, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID: 0x351 - 电池信息(SOC/SOH)
|
||
{
|
||
RequestFlag = 0x23; //充电允许0x01,放电允许0x02,不强充~0x04
|
||
if(chg_forbidFlg == 1)//Afore
|
||
{
|
||
RequestFlag &= 0xFE; //禁充
|
||
}
|
||
if(dsg_forbidFlg == 1)//Afore
|
||
{
|
||
RequestFlag &= 0xFD; //禁放
|
||
}
|
||
if(chg_forceFlg == 1)//Afore
|
||
{
|
||
RequestFlag |= 0x04; //强充
|
||
}
|
||
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = canMem[0].soh & 0xFF; //SOH
|
||
data[2] = 0x64; //最大SOC
|
||
data[3] = 0x00; //最小SOC
|
||
data[4] = RequestFlag; //充放电允许及BMS工作状态
|
||
data[5] = 0x00;
|
||
data[6] = bmsMem.ucCellNum; //电芯数量
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x351, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID: 0x352 - 保护参数(充/放电限流/压)
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //Afore禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //Afore禁放
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[1] = (chgCurLimit >> 8) & 0xFF;
|
||
data[2] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[3] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[4] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[5] = (chgVolLimit >> 8) & 0xFF;
|
||
data[6] = dsgVolLimit & 0xFF; //放电电压限制低位
|
||
data[7] = (dsgVolLimit >> 8) & 0xFF;
|
||
CAN1_SendData(0x352, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID: 0x353 - 故障
|
||
{
|
||
data[0] = protectByte1;//故障H
|
||
data[1] = protectByte2;//故障L
|
||
data[2] = 0x00;
|
||
data[3] = statusbyte;
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x353, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID = 0x354 - 单体电压参数(最大/最小单体电压及序号)
|
||
{
|
||
cellVolMax = canMem[0].VolMax;
|
||
cellVolMin = canMem[0].VolMin;
|
||
cellVolMaxIndex = canMem[0].VolMaxIndex;
|
||
cellVolMinIndex = canMem[0].VolMinIndex;
|
||
|
||
data[0] = cellVolMax & 0xFF; //最大单体电压
|
||
data[1] = (cellVolMax >> 8) & 0xFF;
|
||
data[2] = cellVolMin & 0xFF; //最小单体电压
|
||
data[3] = (cellVolMin >> 8) & 0xFF;
|
||
data[4] = (cellVolMaxIndex+1) & 0xFF; //最大单体电压序号
|
||
data[5] = ((cellVolMaxIndex+1) >> 8) & 0xFF;
|
||
data[6] = (cellVolMinIndex+1) & 0xFF; //最小单体电压序号
|
||
data[7] = ((cellVolMinIndex+1) >> 8) & 0xFF;
|
||
CAN1_SendData(0x354, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==5) //ID = 0x355 - 单体温度参数(最大/最小温度及序号)
|
||
{
|
||
T_Max = (canMem[0].TempMax + 1000); // 最高温度 单位0.1℃ (偏移1000)
|
||
T_Min = canMem[0].TempMin; // 最低温度 单位0.1℃ (协议中未要求偏移)
|
||
T_MaxIndex = canMem[0].TempMaxIndex;// 最高温度序号,范围0-6
|
||
T_MinIndex = canMem[0].TempMinIndex;// 最低温度序号,范围0-6
|
||
|
||
data[0] = (T_Max -2731) & 0xFF; //最大单体温度
|
||
data[1] = ((T_Max -2731) >> 8) & 0xFF;
|
||
data[2] = (T_Min -2731) & 0xFF; //最小单体温度
|
||
data[3] = ((T_Min -2731) >> 8) & 0xFF;
|
||
data[4] = (T_MaxIndex+1) & 0xFF; //最大单体温度序号,实际显示从1开始
|
||
data[5] = ((T_MaxIndex+1) >> 8) & 0xFF;
|
||
data[6] = (T_MinIndex+1) & 0xFF; //最小单体温度序号
|
||
data[7] = ((T_MinIndex+1) >> 8) & 0xFF;
|
||
CAN1_SendData(0x355, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==6) //ID = 0x357 - 告警信息
|
||
{
|
||
data[0] = alarmByte1;
|
||
data[1] = alarmByte2;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x357, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==7) //ID: 0x356 - 单体保护参数(因电池特性不同,参数暂未给定)
|
||
{
|
||
data[0] = 0x00;
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x356, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==8) //ID=0x358 - 版本信息
|
||
{
|
||
data[0] = 0x00;//硬件版本V
|
||
data[1] = 0x00;//硬件版本R
|
||
data[2] = 0x00;//软件版本V
|
||
data[3] = 0x00;//软件版本R
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x358, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==9) //ID=0x359 电池SN 0~7
|
||
{
|
||
data[0] = 0x00;
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x359, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==10) //ID=0x35A - 电池SN 8~15
|
||
{
|
||
data[0] = 0x00;
|
||
data[1] = 0x00;
|
||
data[2] = 0x00;
|
||
data[3] = 0x00;
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0x00;
|
||
CAN1_SendData(0x35A, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=11)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//Victron 维克托
|
||
void CAN_Protocol_Victron(void)
|
||
{
|
||
uint8_t data[8];
|
||
uint16_t totalCapacity;//总容量
|
||
|
||
uint16_t tempVol;
|
||
int16_t tempCur;
|
||
|
||
uint16_t chgVolLimit;
|
||
uint16_t dsgVolLimit;
|
||
int16_t chgCurLimit;
|
||
int16_t dsgCurLimit;
|
||
|
||
uint8_t protectByte1 = 0;
|
||
uint8_t protectByte2 = 0;
|
||
uint8_t protectByte3 = 0;
|
||
uint8_t protectByte4 = 0;
|
||
|
||
uint8_t alarmByte1 = 0;
|
||
uint8_t alarmByte2 = 0;
|
||
uint8_t alarmByte3 = 0;
|
||
uint8_t alarmByte4 = 0;
|
||
|
||
|
||
int16_t T_Average = 0;
|
||
int16_t T_Max; // 最高温度
|
||
int16_t T_Min; // 最低温度
|
||
uint16_t T_MaxIndex;// 最高温度序号,范围0-6
|
||
uint16_t T_MinIndex;// 最低温度序号,范围0-6
|
||
|
||
uint16_t cellVolMax=0; // 电芯单体最高电压-Victron
|
||
uint16_t cellVolMin=0; // 电芯单体最低电压-Victron
|
||
uint16_t cellVolMaxIndex_Byte1; // 电芯单体最高电压序号,范围0-15-Victron
|
||
uint16_t cellVolMaxIndex_Byte2;
|
||
uint16_t cellVolMinIndex_Byte1; // 电芯单体最低电压序号,范围0-15-Victron
|
||
uint16_t cellVolMinIndex_Byte2;
|
||
|
||
|
||
//Data0 BIT0.1 General[Cancel] //0000 0010
|
||
protectByte1 |= 0x01;
|
||
|
||
//保护
|
||
//放电高温保护
|
||
//over temp at discharging
|
||
if(((canMem[0].status_byte2 & 0x0008) != 0) || ((canMem[0].status_byte4 & 0x0202) != 0))
|
||
{
|
||
protectByte1 &= 0x7f;
|
||
protectByte1 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xbf;
|
||
protectByte1 |= 0x80;
|
||
}
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte1 &= 0xdf;
|
||
protectByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xef;
|
||
protectByte1 |= 0x20;
|
||
}
|
||
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 &= 0xf7; //去掉leave
|
||
// protectByte1 |= 0x04; //赋值arrive
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfb;
|
||
// protectByte1 |= 0x08;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfb;
|
||
// protectByte1 |= 0x08;
|
||
// }
|
||
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte2 &= 0x7f;
|
||
protectByte2 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xbf;
|
||
protectByte2 |= 0x80;
|
||
}
|
||
|
||
//充电低温保护
|
||
//Data1 BIT4.5 under temp at charging //0001 0000
|
||
if( ((canMem[0].status_byte2 & 0x0001) != 0) || ((canMem[0].status_byte4 & 0x0404) != 0) )
|
||
{
|
||
protectByte2 &= 0xdf;
|
||
protectByte2 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xef;
|
||
protectByte2 |= 0x20;
|
||
}
|
||
|
||
//充电高温保护
|
||
//Data1 BIT2.3 over temp at charging //0000 0100
|
||
if( ((canMem[0].status_byte2 & 0x0002) != 0) || ((canMem[0].status_byte4 & 0x0101) != 0) )
|
||
{
|
||
protectByte2 &= 0xf7;
|
||
protectByte2 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfb;
|
||
protectByte2 |= 0x08;
|
||
}
|
||
|
||
//放电低温保护
|
||
//Data1 BIT0.1 under temp at discharging //0000 0001
|
||
if( ((canMem[0].status_byte2 & 0x0004) != 0) || ((canMem[0].status_byte4 & 0x0808) != 0) )
|
||
{
|
||
protectByte2 &= 0xfd;
|
||
protectByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfe;
|
||
protectByte2 |= 0x02;
|
||
}
|
||
|
||
//短路
|
||
//Data2 BIT4.5 short circuit //0001 0000
|
||
if((canMem[0].status_byte1 & 0x20) != 0)
|
||
{
|
||
protectByte3 &= 0xdf;
|
||
protectByte3 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte3 &= 0xef;
|
||
protectByte3 |= 0x20;
|
||
}
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte3 &= 0xfd;
|
||
protectByte3 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte3 &= 0xfe;
|
||
protectByte3 |= 0x02;
|
||
}
|
||
//Data2 BIT2.3 Contactor[Cancel] //0000 1000
|
||
protectByte3 |= 0x08;
|
||
//Data2 BIT6.7 BMS internal[Cancel] //1000 0000
|
||
protectByte3 |= 0x80;
|
||
// //Data3 BIT0.1 cell imbanlance //0000 0001
|
||
// if((bmsMem.balanceStatus & 0x01) !=0) //0x01表示平衡
|
||
// {
|
||
// protectByte4 &= 0xfe;
|
||
// protectByte4 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte4 &= 0xfd;
|
||
// protectByte4 |= 0x01;
|
||
// }
|
||
|
||
|
||
//告警
|
||
//放电高温告警
|
||
//over temp at discharging
|
||
if(((canMem[0].status_byte2 & 0x2200) != 0) || ((canMem[0].status_byte4 & 0x2000) != 0))
|
||
{
|
||
alarmByte1 &= 0x7f;
|
||
alarmByte1 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xbf;
|
||
alarmByte1 |= 0x80;
|
||
}
|
||
|
||
//欠压告警
|
||
if((canMem[0].status_byte3 & 0x0A00) != 0)
|
||
{
|
||
alarmByte1 &= 0xdf;
|
||
alarmByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xef;
|
||
alarmByte1 |= 0x20;
|
||
}
|
||
|
||
// //过压告警
|
||
// if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte1 &= 0xf7; //去掉leave
|
||
// alarmByte1 |= 0x04; //赋值arrive
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfb;
|
||
// alarmByte1 |= 0x08;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfb;
|
||
// alarmByte1 |= 0x08;
|
||
// }
|
||
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte2 &= 0x7f;
|
||
alarmByte2 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xbf;
|
||
alarmByte2 |= 0x80;
|
||
}
|
||
|
||
//充电低温告警
|
||
//Data1 BIT4.5 under temp at charging //0001 0000
|
||
if( ((canMem[0].status_byte2 & 0x4400) != 0) || ((canMem[0].status_byte4 & 0x4000) != 0) )
|
||
{
|
||
alarmByte2 &= 0xdf;
|
||
alarmByte2 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xef;
|
||
alarmByte2 |= 0x20;
|
||
}
|
||
|
||
//充电高温告警
|
||
//Data1 BIT2.3 over temp at charging //0000 0100
|
||
if( ((canMem[0].status_byte2 & 0x1100) != 0) || ((canMem[0].status_byte4 & 0x1000) != 0) )
|
||
{
|
||
alarmByte2 &= 0xf7;
|
||
alarmByte2 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfb;
|
||
alarmByte2 |= 0x08;
|
||
}
|
||
|
||
//放电低温告警
|
||
//Data1 BIT0.1 under temp at discharging //0000 0001
|
||
if( ((canMem[0].status_byte2 & 0x8800) != 0) || ((canMem[0].status_byte4 & 0x8000) != 0) )
|
||
{
|
||
alarmByte2 &= 0xfd;
|
||
alarmByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfe;
|
||
alarmByte2 |= 0x02;
|
||
}
|
||
|
||
//短路
|
||
//Data2 BIT4.5 short circuit //0001 0000
|
||
if((canMem[0].status_byte1 & 0x20) != 0)
|
||
{
|
||
alarmByte3 &= 0xdf;
|
||
alarmByte3 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte3 &= 0xef;
|
||
alarmByte3 |= 0x20;
|
||
}
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte3 &= 0xfd;
|
||
alarmByte3 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte3 &= 0xfe;
|
||
alarmByte3 |= 0x02;
|
||
}
|
||
|
||
// if((bmsMem.balanceStatus & 0x01) !=0) //0x01表示平衡
|
||
// {
|
||
// alarmByte4 &= 0xfe;
|
||
// alarmByte4 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte4 &= 0xfd;
|
||
// alarmByte4 |= 0x01;
|
||
// }
|
||
|
||
|
||
if(CAN_SendCount ==0) //ID=0x35A - Alarms/Warnings
|
||
{
|
||
data[0] = protectByte1;
|
||
data[1] = protectByte2;
|
||
data[2] = protectByte3;
|
||
data[3] = protectByte4;
|
||
data[4] = alarmByte1; //报警和保护信号相同
|
||
data[5] = alarmByte2;
|
||
data[6] = alarmByte3;
|
||
data[7] = alarmByte4;
|
||
CAN1_SendData(0x35A, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID = 0x351 - 电池充电/放电电压,充电/放电限流
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //Victron禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //Victron禁放
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[1] = (chgVolLimit >> 8) & 0xFF;
|
||
data[2] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[3] = (chgCurLimit >> 8) & 0xFF;
|
||
data[4] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[5] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[6] = dsgVolLimit & 0xFF; //放电电压限制低位
|
||
data[7] = (dsgVolLimit >> 8) & 0xFF;
|
||
CAN1_SendData(0x351, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID = 0x355 - 电量SOC/SOH
|
||
{
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = 0;
|
||
data[2] = canMem[0].soh & 0xFF; //SOH
|
||
data[3] = 0;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x355, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID = 0x356 - 电池电压/电流/温度
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/10); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;//单位0.1
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = (T_Average -2731) & 0xFF;;
|
||
data[5] = ((T_Average -2731) >>8) & 0xFF; //温度-平均温度
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x356, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID = 0x35E - 制造商名称-ASCII
|
||
{
|
||
data[0] = 'B';
|
||
data[1] = 'T';
|
||
data[2] = 'Y';
|
||
data[3] = 'G';
|
||
data[4] = '-';
|
||
data[5] = 'B';
|
||
data[6] = 'M';
|
||
data[7] = 'S';
|
||
CAN1_SendData(0x35E, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==5) //ID = 0x370 - 电池/BMS名称第1部分
|
||
{
|
||
data[0] = 'B';
|
||
data[1] = 'T';
|
||
data[2] = 'Y';
|
||
data[3] = 'G';
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x370, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==6) //ID = 0x371 - 电池/BMS名称第2部分
|
||
{
|
||
data[0] = 'B';
|
||
data[1] = 'M';
|
||
data[2] = 'S';
|
||
data[3] = 0X00;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x371, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==7) //ID = 0x373 - 最大/最小单体电压/温度(与固德威配置相同)
|
||
{
|
||
cellVolMax = canMem[0].VolMax;
|
||
cellVolMin = canMem[0].VolMin;
|
||
T_Max = canMem[0].TempMax/10; // 最高温度
|
||
T_Min = canMem[0].TempMin/10; // 最低温度
|
||
|
||
data[0] = cellVolMin & 0xFF; //最小单体电压
|
||
data[1] = (cellVolMin >> 8) & 0xFF;
|
||
data[2] = cellVolMax & 0xFF; //最大单体电压
|
||
data[3] = (cellVolMax >> 8) & 0xFF;
|
||
data[4] = (T_Min ) & 0xFF; //最小单体温度
|
||
data[5] = ((T_Min ) >> 8) & 0xFF;
|
||
data[6] = (T_Max ) & 0xFF; //最大单体温度
|
||
data[7] = ((T_Max ) >> 8) & 0xFF;
|
||
CAN1_SendData(0x373, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==8) //ID = 0x374 - 最小电池电压地址
|
||
{
|
||
if((canMem[0].VolMinIndex + 1) >= 10)
|
||
{
|
||
cellVolMinIndex_Byte1 = 1;
|
||
cellVolMinIndex_Byte2 = (canMem[0].VolMinIndex+1)-10;
|
||
}
|
||
else
|
||
{
|
||
cellVolMinIndex_Byte1 = 0;
|
||
cellVolMinIndex_Byte2 = (canMem[0].VolMinIndex+1);
|
||
}
|
||
|
||
data[0] = 0x30 + cellVolMinIndex_Byte1;
|
||
data[1] = 0X30 + cellVolMinIndex_Byte2;
|
||
data[2] = 0X00;
|
||
data[3] = 0X00;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x374, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==9) //ID = 0x375 - 最大电池电压地址
|
||
{
|
||
if((canMem[0].VolMaxIndex+1)>= 10)
|
||
{
|
||
cellVolMaxIndex_Byte1 = 1;
|
||
cellVolMaxIndex_Byte2 = (canMem[0].VolMaxIndex+1)-10;
|
||
}
|
||
else
|
||
{
|
||
cellVolMaxIndex_Byte1 = 0;
|
||
cellVolMaxIndex_Byte2 = (canMem[0].VolMaxIndex+1);
|
||
}
|
||
|
||
data[0] = 0x30 + cellVolMaxIndex_Byte1;
|
||
data[1] = 0x30 + cellVolMaxIndex_Byte2;
|
||
data[2] = 0X00;
|
||
data[3] = 0X00;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x375, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==10) //ID = 0x376 - 最小电池温度地址
|
||
{
|
||
T_MinIndex = canMem[0].TempMinIndex;// 最低温度序号,范围0-6
|
||
|
||
data[0] = 0x30 + (T_MinIndex+1);
|
||
data[1] = 0X00;
|
||
data[2] = 0X00;
|
||
data[3] = 0X00;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x376, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==11) //ID = 0x377 - 最大电池温度地址
|
||
{
|
||
T_MaxIndex = canMem[0].TempMaxIndex;// 最高温度序号,范围0-6
|
||
|
||
data[0] = 0x30 + (T_MaxIndex+1);
|
||
data[1] = 0X00;
|
||
data[2] = 0X00;
|
||
data[3] = 0X00;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x377, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==12) //ID = 0x379 --- 容量
|
||
{
|
||
totalCapacity = ncc_Ah * OnlineNum; //单位1Ah
|
||
|
||
data[0] = totalCapacity & 0xFF; //电池容量
|
||
data[1] = (totalCapacity >> 8) & 0xFF;
|
||
data[2] = 0X00;
|
||
data[3] = 0X00;
|
||
data[4] = 0X00;
|
||
data[5] = 0X00;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x379, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=13)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//Sorotec 索瑞德
|
||
void CAN_Protocol_Sorotec(void)
|
||
{
|
||
uint8_t data[8];
|
||
uint16_t totalCapacity;
|
||
|
||
int16_t tempVol;
|
||
int16_t tempCur;
|
||
|
||
uint16_t chgVolLimit;
|
||
uint16_t dsgVolLimit;
|
||
int16_t chgCurLimit;
|
||
int16_t dsgCurLimit;
|
||
|
||
uint8_t protectByte1 = 0;
|
||
uint8_t protectByte2 = 0;
|
||
uint8_t protectByte3 = 0;
|
||
uint8_t protectByte4 = 0;
|
||
|
||
uint8_t alarmByte1 = 0;
|
||
uint8_t alarmByte2 = 0;
|
||
uint8_t alarmByte3 = 0;
|
||
uint8_t alarmByte4 = 0;
|
||
|
||
|
||
int16_t T_Average; // 平均温度
|
||
|
||
|
||
//Data0 BIT0.1 General[Cancel] //0000 0010
|
||
protectByte1 |= 0x01;
|
||
|
||
//保护
|
||
//放电高温保护
|
||
//over temp at discharging
|
||
if(((canMem[0].status_byte2 & 0x0008) != 0) || ((canMem[0].status_byte4 & 0x0202) != 0))
|
||
{
|
||
protectByte1 &= 0x7f;
|
||
protectByte1 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xbf;
|
||
protectByte1 |= 0x80;
|
||
}
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte1 &= 0xdf;
|
||
protectByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte1 &= 0xef;
|
||
protectByte1 |= 0x20;
|
||
}
|
||
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte1 &= 0xf7; //去掉leave
|
||
// protectByte1 |= 0x04; //赋值arrive
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfb;
|
||
// protectByte1 |= 0x08;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte1 &= 0xfb;
|
||
// protectByte1 |= 0x08;
|
||
// }
|
||
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte2 &= 0x7f;
|
||
protectByte2 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xbf;
|
||
protectByte2 |= 0x80;
|
||
}
|
||
|
||
//充电低温保护
|
||
//Data1 BIT4.5 under temp at charging //0001 0000
|
||
if( ((canMem[0].status_byte2 & 0x0001) != 0) || ((canMem[0].status_byte4 & 0x0404) != 0) )
|
||
{
|
||
protectByte2 &= 0xdf;
|
||
protectByte2 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xef;
|
||
protectByte2 |= 0x20;
|
||
}
|
||
|
||
//充电高温保护
|
||
//Data1 BIT2.3 over temp at charging //0000 0100
|
||
if( ((canMem[0].status_byte2 & 0x0002) != 0) || ((canMem[0].status_byte4 & 0x0101) != 0) )
|
||
{
|
||
protectByte2 &= 0xf7;
|
||
protectByte2 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfb;
|
||
protectByte2 |= 0x08;
|
||
}
|
||
|
||
//放电低温保护
|
||
//Data1 BIT0.1 under temp at discharging //0000 0001
|
||
if( ((canMem[0].status_byte2 & 0x0004) != 0) || ((canMem[0].status_byte4 & 0x0808) != 0) )
|
||
{
|
||
protectByte2 &= 0xfd;
|
||
protectByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte2 &= 0xfe;
|
||
protectByte2 |= 0x02;
|
||
}
|
||
|
||
//短路
|
||
//Data2 BIT4.5 short circuit //0001 0000
|
||
if((canMem[0].status_byte1 & 0x20) != 0)
|
||
{
|
||
protectByte3 &= 0xdf;
|
||
protectByte3 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
protectByte3 &= 0xef;
|
||
protectByte3 |= 0x20;
|
||
}
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte3 &= 0xfd;
|
||
protectByte3 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
protectByte3 &= 0xfe;
|
||
protectByte3 |= 0x02;
|
||
}
|
||
//Data2 BIT2.3 Contactor[Cancel] //0000 1000
|
||
protectByte3 |= 0x08;
|
||
//Data2 BIT6.7 BMS internal[Cancel] //1000 0000
|
||
protectByte3 |= 0x80;
|
||
// //Data3 BIT0.1 cell imbanlance //0000 0001
|
||
// if((bmsMem.balanceStatus & 0x01) !=0) //0x01表示平衡
|
||
// {
|
||
// protectByte4 &= 0xfe;
|
||
// protectByte4 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte4 &= 0xfd;
|
||
// protectByte4 |= 0x01;
|
||
// }
|
||
|
||
|
||
//告警
|
||
//放电高温告警
|
||
//over temp at discharging
|
||
if(((canMem[0].status_byte2 & 0x2200) != 0) || ((canMem[0].status_byte4 & 0x2000) != 0))
|
||
{
|
||
alarmByte1 &= 0x7f;
|
||
alarmByte1 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xbf;
|
||
alarmByte1 |= 0x80;
|
||
}
|
||
|
||
//欠压告警
|
||
if((canMem[0].status_byte3 & 0x0A00) != 0)
|
||
{
|
||
alarmByte1 &= 0xdf;
|
||
alarmByte1 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte1 &= 0xef;
|
||
alarmByte1 |= 0x20;
|
||
}
|
||
|
||
// //过压告警
|
||
// if((canMem[0].status_byte3 & 0x0500) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte1 &= 0xf7; //去掉leave
|
||
// alarmByte1 |= 0x04; //赋值arrive
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfb;
|
||
// alarmByte1 |= 0x08;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte1 &= 0xfb;
|
||
// alarmByte1 |= 0x08;
|
||
// }
|
||
|
||
//放电过流告警
|
||
if((canMem[0].status_byte3 & 0x2000) != 0)
|
||
{
|
||
alarmByte2 &= 0x7f;
|
||
alarmByte2 |= 0x40;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xbf;
|
||
alarmByte2 |= 0x80;
|
||
}
|
||
|
||
//充电低温告警
|
||
//Data1 BIT4.5 under temp at charging //0001 0000
|
||
if( ((canMem[0].status_byte2 & 0x4400) != 0) || ((canMem[0].status_byte4 & 0x4000) != 0) )
|
||
{
|
||
alarmByte2 &= 0xdf;
|
||
alarmByte2 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xef;
|
||
alarmByte2 |= 0x20;
|
||
}
|
||
|
||
//充电高温告警
|
||
//Data1 BIT2.3 over temp at charging //0000 0100
|
||
if( ((canMem[0].status_byte2 & 0x1100) != 0) || ((canMem[0].status_byte4 & 0x1000) != 0) )
|
||
{
|
||
alarmByte2 &= 0xf7;
|
||
alarmByte2 |= 0x04;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfb;
|
||
alarmByte2 |= 0x08;
|
||
}
|
||
|
||
//放电低温告警
|
||
//Data1 BIT0.1 under temp at discharging //0000 0001
|
||
if( ((canMem[0].status_byte2 & 0x8800) != 0) || ((canMem[0].status_byte4 & 0x8000) != 0) )
|
||
{
|
||
alarmByte2 &= 0xfd;
|
||
alarmByte2 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte2 &= 0xfe;
|
||
alarmByte2 |= 0x02;
|
||
}
|
||
|
||
//短路
|
||
//Data2 BIT4.5 short circuit //0001 0000
|
||
if((canMem[0].status_byte1 & 0x20) != 0)
|
||
{
|
||
alarmByte3 &= 0xdf;
|
||
alarmByte3 |= 0x10;
|
||
}
|
||
else
|
||
{
|
||
alarmByte3 &= 0xef;
|
||
alarmByte3 |= 0x20;
|
||
}
|
||
|
||
//充电过流告警
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte3 &= 0xfd;
|
||
alarmByte3 |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
alarmByte3 &= 0xfe;
|
||
alarmByte3 |= 0x02;
|
||
}
|
||
|
||
// if((bmsMem.balanceStatus & 0x01) !=0) //0x01表示平衡
|
||
// {
|
||
// alarmByte4 &= 0xfe;
|
||
// alarmByte4 |= 0x02;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte4 &= 0xfd;
|
||
// alarmByte4 |= 0x01;
|
||
// }
|
||
|
||
|
||
if(CAN_SendCount ==0) //ID=0x35a - Alarms/Warnings
|
||
{
|
||
data[0] = protectByte1;
|
||
data[1] = protectByte2;
|
||
data[2] = protectByte3;
|
||
data[3] = protectByte4;
|
||
data[4] = alarmByte1; //报警和保护信号相同
|
||
data[5] = alarmByte2;
|
||
data[6] = alarmByte3;
|
||
data[7] = alarmByte4;
|
||
CAN1_SendData(0x35a, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==1) //ID = 0x351 - 电池充电/放电电压,充电/放电限流
|
||
{
|
||
//充放电电流限制需要有符号区别吗?
|
||
chgVolLimit = bmsMem.inverter_chgVolLimit; //充电电压限制,上位机配置,默认值57.6V
|
||
dsgVolLimit = bmsMem.inverter_dsgVolLimit; //放电电压限制,上位机配置,默认值41.6V
|
||
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
chgCurLimit = 0; //Sorotec禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
dsgCurLimit = 0; //Sorotec禁放
|
||
}
|
||
else
|
||
{
|
||
dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A
|
||
}
|
||
|
||
data[0] = chgVolLimit & 0xFF; //充电电压限制低位
|
||
data[1] = (chgVolLimit >> 8) & 0xFF;
|
||
data[2] = chgCurLimit & 0xFF; //充电电流限制低位
|
||
data[3] = (chgCurLimit >> 8) & 0xFF;
|
||
data[4] = dsgCurLimit & 0xFF; //放电电流限制低位
|
||
data[5] = (dsgCurLimit >> 8) & 0xFF;
|
||
data[6] = dsgVolLimit & 0xFF; //放电电压限制低位
|
||
data[7] = (dsgVolLimit >> 8) & 0xFF;
|
||
CAN1_SendData(0x351, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==2) //ID = 0x355 - 电量SOC
|
||
{
|
||
data[0] = canMem[0].soc & 0xFF; //SOC
|
||
data[1] = 0;
|
||
data[2] = 0X00;
|
||
data[3] = 0X00;
|
||
data[4] = 0X00;
|
||
data[5] = 0x00;
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x355, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==3) //ID = 0x356 - 电池电压/电流/温度
|
||
{
|
||
tempVol = (uint16_t)(bmsMem.packVoltage/10); //单位0.01
|
||
tempCur = (int16_t)(canMem[0].cur/10); //单位0.1
|
||
T_Average = canMem[0].temp;// 平均温度
|
||
|
||
data[0] = tempVol & 0xFF;
|
||
data[1] = (tempVol >>8) & 0xFF; //电池包电压
|
||
data[2] = tempCur & 0xFF;
|
||
data[3] = (tempCur >>8) & 0xFF; //电池包电流
|
||
data[4] = (T_Average -2731) & 0xFF;;
|
||
data[5] = ((T_Average -2731) >>8) & 0xFF; //温度-暂时取平均温度,具体哪一路需要客户确认
|
||
data[6] = 0x00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x356, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==4) //ID = 0x35e - 制造商名称-ASCII
|
||
{
|
||
data[0] = 'B';
|
||
data[1] = 'T';
|
||
data[2] = 'Y';
|
||
data[3] = 'G';
|
||
data[4] = '-';
|
||
data[5] = 'B';
|
||
data[6] = 'M';
|
||
data[7] = 'S';
|
||
CAN1_SendData(0x35e, &data[0]);
|
||
}
|
||
if(CAN_SendCount ==5) //ID = 0x35f - BMS版本号/总容量
|
||
{
|
||
totalCapacity = ncc_Ah * OnlineNum; //单位1Ah
|
||
|
||
data[0] = 0X00;
|
||
data[1] = 0X00;
|
||
data[2] = 0X00; //版本号暂无
|
||
data[3] = 0X00;
|
||
data[4] = totalCapacity & 0xFF; //电池容量
|
||
data[5] = (totalCapacity >> 8) & 0xFF;
|
||
data[6] = 0X00;
|
||
data[7] = 0X00;
|
||
CAN1_SendData(0x35f, &data[0]);
|
||
}
|
||
|
||
if(CAN_SendCount>=6)
|
||
{
|
||
CAN_SendCount = 0;
|
||
}
|
||
}
|
||
|
||
//Modbus:
|
||
//Growatt 古瑞瓦特
|
||
void MOD_Protocol_Growatt(void)
|
||
{
|
||
uint8_t i;
|
||
|
||
uint16_t protectByte = 0;
|
||
uint16_t alarmByte = 0;
|
||
uint16_t statusByte = 0;
|
||
|
||
|
||
//保护
|
||
// //过压保护
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte1 & 0x0141) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// protectByte |= 0x0004;
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte &= 0xFFFB;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// protectByte &= 0xFFFB;
|
||
// }
|
||
|
||
//欠压保护
|
||
//cell_uv+pack_uv+l0v
|
||
if(((canMem[0].status_byte1 & 0x0202) != 0) || ((canMem[0].status_byte3 & 0x0008) != 0))
|
||
{
|
||
protectByte |= 0x0008;
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xFFF7;
|
||
}
|
||
|
||
//放电过流保护
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if( ((canMem[0].status_byte1 & 0x042c) != 0) || ((canMem[0].status_byte2 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0020) != 0))
|
||
{
|
||
protectByte |= 0x0001;
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xFFFE;
|
||
}
|
||
|
||
//充电过流保护
|
||
//charge over current
|
||
if( ((canMem[0].status_byte1 & 0x0010) != 0) || ((canMem[0].status_byte4 & 0x0010) != 0))
|
||
{
|
||
protectByte |= 0x0800;
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xF7FF;
|
||
}
|
||
|
||
//sc-short circuit (测) 短路
|
||
if((canMem[0].status_byte1 & 0x20) != 0)
|
||
{
|
||
protectByte |= 0x0002;
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xFFFD;
|
||
}
|
||
|
||
//放电高温保护
|
||
//discharge over temp
|
||
if( ((canMem[0].status_byte2 & 0x0008) !=0) || ((canMem[0].status_byte4 & 0x0202) !=0) )
|
||
{
|
||
protectByte |= 0x0010;
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xFFEF;
|
||
}
|
||
|
||
//充电高温保护
|
||
//charge over temp 高温
|
||
if( ((canMem[0].status_byte2 & 0x0002) !=0) || ((canMem[0].status_byte4 & 0x0101) !=0) )
|
||
{
|
||
protectByte |= 0x0020;
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xFFDF;
|
||
}
|
||
|
||
//放电低温保护
|
||
//discharge under temp
|
||
if( ((canMem[0].status_byte2 & 0x0004) !=0) || ((canMem[0].status_byte4 & 0x0808) !=0) )
|
||
{
|
||
protectByte |= 0x0040;
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xFFBF;
|
||
}
|
||
|
||
//充电低温保护
|
||
//charge under temp 低温
|
||
if( ((canMem[0].status_byte2 & 0x0001) !=0) || ((canMem[0].status_byte4 & 0x0404) !=0) )
|
||
{
|
||
protectByte |= 0x0080;
|
||
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xFF7F;
|
||
|
||
}
|
||
|
||
//环境低温保护 0x4000
|
||
if((canMem[0].status_byte4 & 0x0C00) !=0) //环境充放电低温
|
||
{
|
||
protectByte |= 0x4000;
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xBFFF;
|
||
}
|
||
|
||
//环境高温保护 0x2000
|
||
if((canMem[0].status_byte4 & 0x0300) !=0) //环境充放电高温
|
||
{
|
||
protectByte |= 0x2000;
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xDFFF;
|
||
}
|
||
|
||
//MOS高温保护 0x1000
|
||
if((canMem[0].status_byte2 & 0x0300) !=0) //MOS充放电高温
|
||
{
|
||
protectByte |= 0x1000;
|
||
}
|
||
else
|
||
{
|
||
protectByte &= 0xEFFF;
|
||
}
|
||
|
||
|
||
//告警
|
||
// //单体过压告警
|
||
// //cell_ov+pack_ov+pf
|
||
// if((canMem[0].status_byte3 & 0x0100) != 0)
|
||
// {
|
||
// if(canMem[0].soc < 99)
|
||
// {
|
||
// alarmByte |= 0x0001;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte &= 0xFFFE;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte &= 0xFFFE;
|
||
// }
|
||
|
||
//单体欠压告警
|
||
//cell_uv+pack_uv+l0v
|
||
if((canMem[0].status_byte3 & 0x0200) != 0)
|
||
{
|
||
alarmByte |= 0x0002;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xFFFD;
|
||
}
|
||
|
||
// //总体过压告警
|
||
// if((canMem[0].status_byte3 & 0x0400) != 0)
|
||
// {
|
||
// alarmByte |= 0x0004;
|
||
// }
|
||
// else
|
||
// {
|
||
// alarmByte &= 0xFFFB;
|
||
// }
|
||
|
||
//总体欠压告警
|
||
if((canMem[0].status_byte3 & 0x0800) != 0)
|
||
{
|
||
alarmByte |= 0x0008;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xFFF7;
|
||
}
|
||
|
||
//放电过流告警
|
||
//discharge over current,SC, OCD1, OCD2
|
||
if((canMem[0].status_byte3 & 0x0200) != 0)
|
||
{
|
||
alarmByte |= 0x0010;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xFFEF;
|
||
}
|
||
|
||
//充电过流告警
|
||
//charge over current
|
||
if((canMem[0].status_byte3 & 0x1000) != 0)
|
||
{
|
||
alarmByte |= 0x0020;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xFFDF;
|
||
}
|
||
|
||
//放电高温告警
|
||
//discharge over temp
|
||
if( ((canMem[0].status_byte2 & 0x2200) !=0) || ((canMem[0].status_byte4 & 0x2000) !=0) )
|
||
{
|
||
alarmByte |= 0x0040;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xFFBF;
|
||
}
|
||
|
||
//充电高温告警
|
||
//charge over temp 高温
|
||
if( ((canMem[0].status_byte2 & 0x1100) !=0) || ((canMem[0].status_byte4 & 0x1000) !=0) )
|
||
{
|
||
alarmByte |= 0x0100;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xFEFF;
|
||
|
||
}
|
||
|
||
//放电低温告警
|
||
//discharge under temp
|
||
if( ((canMem[0].status_byte2 & 0x8800) !=0) || ((canMem[0].status_byte4 & 0x8000) !=0) )
|
||
{
|
||
alarmByte |= 0x0080;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xFF7F;
|
||
}
|
||
|
||
//充电低温告警
|
||
//charge under temp 低温
|
||
if( ((canMem[0].status_byte2 & 0x4400) !=0) || ((canMem[0].status_byte4 & 0x4000) !=0) )
|
||
{
|
||
alarmByte |= 0x0200;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xFDFF;
|
||
}
|
||
|
||
//环境低温告警 0x4000
|
||
if((canMem[0].status_byte4 & 0xC000) !=0) //环境充放电低温
|
||
{
|
||
alarmByte |= 0x4000;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xBFFF;
|
||
}
|
||
|
||
//环境高温告警 0x2000
|
||
if((canMem[0].status_byte4 & 0x3000) !=0) //环境充放电高温
|
||
{
|
||
alarmByte |= 0x2000;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xDFFF;
|
||
}
|
||
|
||
//MOS高温告警 0x1000
|
||
if((canMem[0].status_byte2 & 0x3000) !=0) //MOS充放电高温
|
||
{
|
||
alarmByte |= 0x1000;
|
||
}
|
||
else
|
||
{
|
||
alarmByte &= 0xEFFF;
|
||
}
|
||
|
||
|
||
//状态位赋值:
|
||
if(bmsMem.E2_485Snum != 1) //0100并机/0000单机模式
|
||
{
|
||
statusByte |= 0x0100;
|
||
}
|
||
else
|
||
{
|
||
statusByte &= 0xFEFF;
|
||
}
|
||
if(bCHGING == 1) //充电
|
||
{
|
||
statusByte |= 0x0002;
|
||
}
|
||
else
|
||
{
|
||
statusByte &= 0xFFFD;
|
||
}
|
||
if(bDSGING == 1) //放电
|
||
{
|
||
statusByte |= 0x0003;
|
||
}
|
||
else
|
||
{
|
||
statusByte &= 0xFFFC;
|
||
}
|
||
// if((bmsMem.balanceStatus & 0x01) !=0) //均衡状态
|
||
// {
|
||
// statusByte |= 0x0008;
|
||
// }
|
||
// else
|
||
// {
|
||
// statusByte &= 0xFFF7;
|
||
// }
|
||
if( ((canMem[0].status_byte3 & 0x02) !=0) ) //充电MOS状态 0x0013 Bit6
|
||
{
|
||
statusByte |= 0x0040;
|
||
}
|
||
else
|
||
{
|
||
statusByte &= 0xFFBF;
|
||
}
|
||
if( ((canMem[0].status_byte3 & 0x01) !=0) ) //放电MOS状态 0x0013 Bit5
|
||
{
|
||
statusByte |= 0x0020;
|
||
}
|
||
else
|
||
{
|
||
statusByte &= 0xFFDF;
|
||
}
|
||
|
||
if(chg_forceFlg == 1)//Growatt
|
||
{
|
||
statusByte |= 0x1000; //bit12 强充标志
|
||
}
|
||
else
|
||
{
|
||
statusByte &= 0xEFFF;
|
||
}
|
||
|
||
GrowattMem.status_byte = statusByte; //状态
|
||
GrowattMem.protect_byte = protectByte; //保护
|
||
GrowattMem.alarm_byte = alarmByte; //报警
|
||
|
||
|
||
GrowattMem.soc = (uint8_t)canMem[0].soc; //SOC % 2byte
|
||
GrowattMem.soh = (uint8_t)canMem[0].soh; //SOH % 2byte
|
||
|
||
GrowattMem.packVoltage = (uint16_t)(bmsMem.packVoltage/10); //模块电压 10mV 2byte
|
||
GrowattMem.packCurrent = (int16_t)(canMem[0].cur); //充电电流 10mA 2byte
|
||
|
||
GrowattMem.T_Average = (int16_t)((canMem[0].temp - 2731)/10); //电芯温度 ℃
|
||
GrowattMem.rcc = 100 * ncc_Ah * OnlineNum * GrowattMem.soc/100; //剩余容量 10mAH 2byte
|
||
GrowattMem.fcc = 100 * ncc_Ah * OnlineNum; //满容量 10mAH 2byte
|
||
|
||
GrowattMem.CV_Vol = bmsMem.inverter_chgVolLimit * 10; //CV电压&充电限压,上位机配置,默认值57.6V,10mV
|
||
if(chg_forbidFlg == 1)
|
||
{
|
||
GrowattMem.chgCurLimit = 0; //Growatt_485禁充
|
||
}
|
||
else if(chg_curlimitFlg == 1)
|
||
{
|
||
GrowattMem.chgCurLimit = Inv_curlimit * (OnlineNum-chg_cur0Num); //限流40A*未保护个数
|
||
}
|
||
else
|
||
{
|
||
GrowattMem.chgCurLimit = bmsMem.inverter_chgCurLimit * (OnlineNum-chg_curLimitNum); //充电电流限制,上位机配置,默认值100A
|
||
}
|
||
if(dsg_forbidFlg == 1)
|
||
{
|
||
GrowattMem.dsgCurLimit = 0; //Growatt_485禁放
|
||
}
|
||
else
|
||
{
|
||
GrowattMem.dsgCurLimit = bmsMem.inverter_dsgCurLimit * (OnlineNum-dsg_curLimitNum); //放电电流限制,上位机配置,默认值100A,10mA
|
||
}
|
||
|
||
GrowattMem.Delta = canMem[0].VolMax - canMem[0].VolMin;//压差 V
|
||
GrowattMem.cellVolMax = canMem[0].VolMax ; //单芯最高电压
|
||
GrowattMem.cellVolMin = canMem[0].VolMin ; //单芯最低电压
|
||
GrowattMem.cellVolMaxIndex = canMem[0].VolMaxIndex + 1; //最大电压序号
|
||
GrowattMem.cellVolMinIndex = canMem[0].VolMinIndex + 1; //最小电压序号
|
||
GrowattMem.cellNum = bmsMem.ucCellNum * OnlineNum;
|
||
|
||
for(i=0;i<16;i++)
|
||
{
|
||
GrowattMem.cellVol[i] = bmsMem.vCell[i]; //电池电压 mV
|
||
}
|
||
}
|
||
|
||
//Sorotec 索瑞德
|
||
void MOD_Protocol_Sorotec(void)
|
||
{
|
||
MOD_Protocol_Growatt();
|
||
}
|
||
|
||
//YDN:
|
||
//Pylon 派能(电总协议)
|
||
void YDN_Protocol_Pylon(void)
|
||
{
|
||
YDN();
|
||
}
|
||
|