Hello.
I still can't get teensy 3.6, so the Simpbms code doesn't work on teensy 4.0 or 4.1 that are available.
I am writing a little code in Arduino nano, to test the balance of each individual module.
Although the Arduino nano is very slow, it loses frames, but it works fine with a battery module.
With the SimpBMS can all the modules be connected even if they have repeated addresses?
After 10 hours the result was acceptable, I put a 4mV differential with respect to the minimum voltage.
Code: Select all
// CAN readout of VW type 5 modules
// ------- Programa adaptado por Alfonso para comunicar las celdas SDI de VW a 15-04-2022
// ------- Funciona con un Arduino nano, y el MCP2515, la interrupción del integrado interrumpe algunos comandos, pero en general va respondiendo con 1 módulo solo conectado.
//
// Link información muy útil: https://openinverter.org/wiki/VW_Hybrid_Battery_Packs
//
// Revisión programa 0.1: Balanceo para 1 módulo solo, no se ha probado con más módulos.
// La equivalencia con la tabla balanceBMS no coincide con el cmcID , por lo que he ajustado a ojo.
// Hay que hacer pruebas con todos los módulos que tengo de stock, para ver si todos los CMC responden bien a los comandos de balanceo.
//
//
//
#include <mcp_can.h>
#include <SPI.h>
long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128]; // Array to store serial string
unsigned long looptime = 0;
#define CAN0_INT 2 // Set INT to pin 2
MCP_CAN CAN0(10); // Set CS to pin 9 de[ending on shield used
int controlid = 0x0BA;
int controlid2 = 0x0BB;
long cmcID[] = {0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x1cc};
long controlbms1[] = {0x1A55540A, 0x1A55540C, 0x1A555410, 0x1A555412, 0x1A555414, 0x1A555416, 0x1A555418 };
long balanceBMS[8][2] = {0x1A55540A, 0x1A55540B, 0x1A55540C, 0x1A55540D, 0x1A555410, 0x1A555411, 0x1A555412, 0x1A555413, 0x1A555414, 0x1A555415, 0x1A555416, 0x1A555417, 0x1A555418, 0x1A555419, 0x1A55541A, 0x1A55541B};
long moduleidstart, CMC;
char mes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
char mes2[8], mes3[8];
int minimoVoltage, inicioVoltage;
long mesBalanceo[14];
boolean necesitaBalanceo;
uint16_t voltage[30][14];
int modulespresent = 0;
int sent = 0;
int debug = 0;
void setup()
{
Serial.begin(115200);
// Can0.begin(500000);
Serial.println("Inicio programa ...");
// Initialize MCP2515 running at 8MHz with a baudrate of 500kb/s and the masks and filters disabled.
if (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
Serial.println("MCP2515 Initialized Successfully!");
else
Serial.println("Error Initializing MCP2515...");
CAN0.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP2515 sends acks to received data.
pinMode(CAN0_INT, INPUT); // Configuring pin for /INT input
//Serial.println("Time Stamp,ID,Extended,Bus,LEN,D1,D2,D3,D4,D5,D6,D7,D8");
//Serial.println("Vcell 1, Vcell 2, Vcell 3, Vcell 4, Vcell 5, Vcell 6, Vcell 7, Vcell 8, Vcell 9, Vcell 10, Vcell 11, Vcell 12");
}
void loop()
{
if (CAN0.checkReceive() == 3){ // If CAN0_INT pin is low, read receive buffer
// Serial.print(CAN0.checkReceive()); // Si lee 3 quiere decir que ha recibido un mensaje, decodifica a ver si es relevante o no.
candecode();
}
if (Serial.available() > 0){
menu(); // Un menú, que no funciona, pero está en el código.
}
if (millis() > looptime + 1000){
looptime = millis();
for(int i=0;i<8;i++){
if(CMC == cmcID[i]){
Serial.println();
Serial.print("CMC = ");
CMC = i;
Serial.println(CMC+1);
//Serial.println(" Buscando tabla de balanceo ...");
}
}
for (int y = 0; y < modulespresent; y++){
//Serial.println();
Serial.print("Module ");
Serial.print(y+1);
Serial.print(" Voltages : ");
Serial.print("");
minimoVoltage = voltage[y][1]; // OK, guarda el mínimo
// Serial.print( inicioVoltage);
for (int i = 1; i < 13; i++){
//Serial.print("");
if(voltage[y][i] <= minimoVoltage){ // Busca el mínimo voltage
minimoVoltage = voltage[y][i]; // Guarda el valor mínimo
//Serial.print("_Min_");
}
Serial.print(voltage[y][i]);
Serial.print("mV ");
if( i<12 ){ Serial.print(","); }
}
Serial.print(" R.Balanceo: ");
for (int i = 1; i < 13; i++){
if(voltage[y][i] > minimoVoltage + 4){ // Diferencial de 4mV para dejar de equalizar respecto al valor mínimo
mesBalanceo[i-1] = 0x01;
necesitaBalanceo = 1;
Serial.print("O");
}else{
mesBalanceo[i-1] = 0x00;
Serial.print(".");
}
}
}
//Serial.print();
//Serial.print(" Voltaje minimo celdas = ");
//Serial.print(minimoVoltage);
//Serial.print(" Balanceo: ");
//Serial.println(necesitaBalanceo);
if(necesitaBalanceo){
sendcommandbalance();
}
sendcommand();
}
}
void menu()
{
byte incomingByte = Serial.read(); // read the incoming byte:
switch (incomingByte)
{
case 's': //
sendcommand();
break;
}
}
void sendcommandbalance(){
mes[0] = mesBalanceo[0];
mes[1] = mesBalanceo[1];
mes[2] = mesBalanceo[2];
mes[3] = mesBalanceo[3];
mes[4] = mesBalanceo[4];
mes[5] = mesBalanceo[5];
mes[6] = mesBalanceo[6];
mes[7] = mesBalanceo[7];
CAN0.sendMsgBuf(balanceBMS[CMC-1][0], 1, 8, mes);
mes[0] = mesBalanceo[8];
mes[1] = mesBalanceo[9];
mes[2] = mesBalanceo[10];
mes[3] = mesBalanceo[11];
mes[4] = 0x00;
mes[5] = 0x00;
mes[6] = 0x00;
mes[7] = 0x00;
CAN0.sendMsgBuf(balanceBMS[CMC-1][1], 1, 8, mes);
}
void sendcommand()
{
mes[0] = 0x00;
mes[1] = 0x00;
mes[2] = 0x00;
mes[3] = 0x00;
mes[4] = 0x00;
mes[5] = 0x00;
mes[6] = 0x00;
mes[7] = 0x00;
CAN0.sendMsgBuf(controlid, 0, 8, mes);
mes[0] = 0x45;
mes[1] = 0x01;
mes[2] = 0x28;
mes[3] = 0x00;
mes[4] = 0x00;
mes[5] = 0x00;
mes[6] = 0x00;
mes[7] = 0x30;
CAN0.sendMsgBuf(controlid, 0, 8, mes);
sent = 1;
// Serial.println();
// Serial.print("Command Sent");
// Serial.print(" Present Modules: ");
// Serial.print(modulespresent);
// Serial.println();
modulespresent = 0;
}
void candecode()
{
CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
//Serial.print(rxId, HEX);
//Serial.print("=");
//Serial.print(rxId);
//Serial.print(" / ");
if (sent == 1){
moduleidstart = rxId;
sent = 0;
debug = 0; // Activa depuración, para ver las tramas que recibe
}
if (rxId < 1024){
//Serial.print(" ");
sent = 0;
int ID = rxId - moduleidstart;
//Serial.print(ID);
//Serial.print(",");
CMC = moduleidstart;
switch (ID){
case 0:
voltage[modulespresent][1] = uint16_t(rxBuf[1] >> 4) + uint16_t(rxBuf[2] << 4) + 1000;
voltage[modulespresent][3] = uint16_t(rxBuf[5] << 4) + uint16_t(rxBuf[4] >> 4) + 1000;
voltage[modulespresent][2] = rxBuf[3] + uint16_t((rxBuf[4] & 0x0F) << 8) + 1000;
voltage[modulespresent][4] = rxBuf[6] + uint16_t((rxBuf[7] & 0x0F) << 8) + 1000;
break;
case 1:
voltage[modulespresent][5] = uint16_t(rxBuf[1] >> 4) + uint16_t(rxBuf[2] << 4) + 1000;
voltage[modulespresent][7] = uint16_t(rxBuf[5] << 4) + uint16_t(rxBuf[4] >> 4) + 1000;
voltage[modulespresent][6] = rxBuf[3] + uint16_t((rxBuf[4] & 0x0F) << 8) + 1000;
voltage[modulespresent][8] = rxBuf[6] + uint16_t((rxBuf[7] & 0x0F) << 8) + 1000;
break;
case 2:
voltage[modulespresent][9] = uint16_t(rxBuf[1] >> 4) + uint16_t(rxBuf[2] << 4) + 1000;
voltage[modulespresent][11] = uint16_t(rxBuf[5] << 4) + uint16_t(rxBuf[4] >> 4) + 1000;
voltage[modulespresent][10] = rxBuf[3] + uint16_t((rxBuf[4] & 0x0F) << 8) + 1000;
voltage[modulespresent][12] = rxBuf[6] + uint16_t((rxBuf[7] & 0x0F) << 8) + 1000;
modulespresent++;
sent =1;
break;
}
}
if (debug == 1) // If CAN0_INT pin is low, read receive buffer
{
Serial.print(millis());
if ((rxId & 0x80000000) == 0x80000000) // Determine if ID is standard (11 bits) or extended (29 bits)
sprintf(msgString, " Extended ID: 0x%.8lX DLC: %1d Data:", (rxId & 0x1FFFFFFF), len);
else
sprintf(msgString, ",0x%.3lX,false,%1d", rxId, len);
Serial.print(msgString);
if ((rxId & 0x40000000) == 0x40000000) { // Determine if message is a remote request frame.
sprintf(msgString, " REMOTE REQUEST FRAME");
Serial.print(msgString);
} else {
for (byte i = 0; i < len; i++) {
sprintf(msgString, " , 0x%.2X", rxBuf[i]);
Serial.print(msgString);
}
}
Serial.println();
}
}
/*********************************************************************************************************
END FILE
*********************************************************************************************************/