Stránka 1 z 2
BMS s komunikací RS485/232/Modbus
Napsal: úte úno 23, 2021 2:55 pm
od luky
Přečetl jsem celé forum i spoustu dalšího, ale nejsem z toho moudrej:
Potřebuji ochránit baterii LiFePO 48V/110Ah (16s) a rád bych naměřené SOC, napětí článků, aktuální proud apod. četl pomocí PLC (Domat markMX). Mám k dispozici RS485(+ModbusRTU), RS232, Ethernet (+ModbusTCP).
Existuje nějaká BMS, ke které existuje nějaký rozumný popis komunikace? Jestli to bude balancování + hlídání napětí článků + počítání SOC v jedné nebo 3 krabicích už je celkem jedno.
Re: BMS s komunikací RS485/232/Modbus
Napsal: úte úno 23, 2021 3:33 pm
od xmasin
Pro některé čínské BMS (třeba tyto
https://www.aliexpress.com/item/3287690 ... 4c4dyd8kGQ) existuje dokumentace komunikačního protokolu
https://github.com/simat/BatteryMonitor/wiki
Kolega koupil BMSChargery
http://chargery.com/balancer.asp a kněmu našel také komunikační protokol.
Re: BMS s komunikací RS485/232/Modbus
Napsal: stř úno 24, 2021 9:23 am
od luky
Ano, to první pochází z
lithiumbatterypcb.com. K tomu existuje knihovna pro Arduino. Tedy dalo by se to z toho vyčíst nebo spíš vložit Arduino jako převodník na ModbusRTU. viz.
https://github.com/rahmaevao/JbdBms a
https://hackaday.io/project/162806-jbd-bms-protocol
Bohužel se tohle pro 16s dělá maximálně na 60A, což je pro domácí elektrárnu málo (uvažuju 100A, špičky <2s 200A).
Ještě jsem našel DALY BMS s UARTem nebo RS485
https://www.aliexpress.com/item/4001321 ... 700dKSfzra
...ale k tomu se mi nepodařilo najít popis komunikace nebo zmínku, že by se tím někdo zabýval.
Jedna varianta je i DIYBMS v4. Jestli to dobře chápu, je to napsané v Arduinu, takže přidat tam Modbus komunikaci by neměl být úplně velký problém.
Re: BMS s komunikací RS485/232/Modbus
Napsal: stř úno 24, 2021 10:56 am
od xmasin
Dělají se i varianty s proudem až 250A, stačí hledat na Aliexpresu. V tomhle obchodě mají 100A verzi pro LiFe
https://www.aliexpress.com/item/1005001 ... 3de20g6g5v
K tomuhle popis komunikace mám, jestli jsem to dobře pochopil, tak se jedná o CANbus nad různými fyzickými rozhraními. Jestli chceš, tak můžu poslat, je to ve wordu anglicko-čínsky.
Re: BMS s komunikací RS485/232/Modbus
Napsal: stř úno 24, 2021 12:25 pm
od JiTr
>>> xmasin: Mohl by jsi mi prisimte poslat popis komunikacniho protokolu pres RS232 pro BMS Chargery?
Re: BMS s komunikací RS485/232/Modbus
Napsal: stř úno 24, 2021 2:17 pm
od xmasin
JiTr píše:>>> xmasin: Mohl by jsi mi prisimte poslat popis komunikacniho protokolu pres RS232 pro BMS Chargery?
Popis protokolu je k mání tady:
http://www.chargery.com/uploadFiles/BMS ... 0V1.25.pdf
A našel jsem nějaký projekt, který integruje Chargery BMS do VenusOS od Victronu:
https://github.com/Tobi177/venus-chargerybms
Re: BMS s komunikací RS485/232/Modbus
Napsal: stř úno 24, 2021 4:07 pm
od JiTr
>>> xmasin: Diky
Bonus Chargery BMS vidim v tom, ze umi balancovat proudem 1A ...
Re: BMS s komunikací RS485/232/Modbus
Napsal: čtv úno 25, 2021 8:34 pm
od xmasin
JiTr píše:>>> xmasin: Diky
Bonus Chargery BMS vidim v tom, ze umi balancovat proudem 1A ...
Ten Chargery se mně taky líbí, už ho mám na cestě ve variantě se 100A bočníkem. A pokud bude vyhovvoat, tak objednám ještě dva, aby měl každý ze tří bateriových packů svůj.
Re: BMS s komunikací RS485/232/Modbus
Napsal: ned úno 28, 2021 9:16 am
od luky
xmasin píše:
K tomuhle popis komunikace mám, jestli jsem to dobře pochopil, tak se jedná o CANbus nad různými fyzickými rozhraními. Jestli chceš, tak můžu poslat, je to ve wordu anglicko-čínsky.
Ahoj, prosím o zaslání popisu komunikace pro RS485 na DALY BMS.
Předem díky
L.
Re: BMS s komunikací RS485/232/Modbus
Napsal: pon bře 08, 2021 3:32 pm
od kodl69
Dnes mi přišla reklama z TI na BQ76952PFBR . 1-16s BMS/balance, dají se k tomu připojit snadno mosfety s externími odpory pro balancování větším proudem, má to komunikaci přes I2C, SPI, tj někdo trochu zručný k tomu dopíše komunikaci přes nějakej procesor s čímkoliv, případně nějaký rozhraní s displejem a enkodérem pro nastavení, možností mnoho. Cenovka švába celkem přijatelná, cca 150Kč s DPH, ostatně tohle asi dává číňan do těch "smart BMS" .
Re: BMS s komunikací RS485/232/Modbus
Napsal: pon bře 08, 2021 5:06 pm
od marsal64
luky píše:
Ahoj, prosím o zaslání popisu komunikace pro RS485 na DALY BMS.
Nabízím svůj "překlad" z čínštiny ;-/
Pokud má někdo něco lepšího, můžete to prosím sdílet?
Re: BMS s komunikací RS485/232/Modbus
Napsal: pát črc 16, 2021 2:19 pm
od ViktorEX
ahojte chlapi, nasel jsem toto vlakno ... rozchodil jste to nekdo? trochu programovani, dam, ale nektere veci uz mimo moje chpani resp. bych potreboval poradne nakopnout.
BMS DALY, mam tam vsechna rozhrani (UART/RS482 ... celkem 4 konektory), a rad bych cetl hodnoty arduinem. tj stav napeti, stav jednotlivych clancich atd
dik
Re: BMS s komunikací RS485/232/Modbus
Napsal: pát črc 16, 2021 2:57 pm
od rottenkiwi
Re: BMS s komunikací RS485/232/Modbus
Napsal: sob črc 17, 2021 8:58 am
od marsal64
ViktorEX píše:rozchodil jste to nekdo?
Jasně
, v mém případě jak jinak než na Teco Foxtrotu.
Re: BMS s komunikací RS485/232/Modbus
Napsal: sob črc 17, 2021 11:17 pm
od ViktorEX
hmm, hezky ... ale dal mi to nepomohlo... nemate prosim nekdo nejaky vzorovy programek?
Re: BMS s komunikací RS485/232/Modbus
Napsal: ned črc 18, 2021 7:49 am
od rottenkiwi
Re: BMS s komunikací RS485/232/Modbus
Napsal: ned črc 18, 2021 8:23 am
od marsal64
ViktorEX píše:hmm, hezky ... ale dal mi to nepomohlo... nemate prosim nekdo nejaky vzorovy programek?
Tak je to ten Foxtrot, třeba trochu pomůže pro inspiraci.
Kód: Vybrat vše
VAR_GLOBAL
NUM_DALYS : USINT := 2; // number of Dalys present
CH_DALYS : UINT := CH3_UNI; // UNI channel for the communication
DALYADDR : ARRAY[1..3] of BYTE := [16#40, 16#41, 0]; // Daly addresses
Timeout_recv_Daly : TIME := T#100MS; // How long wait for Daly response
CurrentBatSum : Real; // sum of battery current from all BMS
CurrentBatSum_cl : CL; // color of battery current from all BMS: > 0.5 green; < -0.5 orange; else green
END_VAR
// Structure for receiving and storing raw Daly data
TYPE
DALYBMSDATA : STRUCT
LastError_text : STRING;
LastError_datetime : DT;
ErrorCount : USINT;
LastReceive_datetime : DT;
ReceiveOKCount : USINT; // counter of correct communications
maxvoltage : REAL; // maximum cell voltage
minvoltage : REAL; // minimum cell voltage
totvoltage : REAL; // total battery voltage "pressure"
current : REAL; // proud
SOC : REAL; // SOC
minVcellNo: USINT; // cell no with minimum voltage
maxVcellNo: USINT; // cell no with maximum voltage
temperature : INT; // temperatureplota
state : USINT; // 0 - static 1 - charge 2 - discharge
statea : CL; // rgb
balancing : string[4]; // 16 battery cells in pack expected here
MOScharging : USINT; // 1 - MOS for charging on
MOSLoad : USINT; // 1 - MOS for discharging on
faultstatus1 : string[8]; // bits indicating error
faultstatus2 : string[8]; // bits indicating error 2
END_STRUCT
END_TYPE
// Daly values store
VAR_GLOBAL RETAIN
dalys : ARRAY[1..3] OF DALYBMSDATA;
daly_diffvoltage_1 : real; // difference of voltage between min and max for battery 1
daly_diffvoltage_2 : real; // difference of voltage between min and max for battery 2
END_VAR
Kód: Vybrat vše
// Communicate with Daly BMS
// Expected RS-485, all Dalys to use a single communication channel
// function to calculate checksum
FUNCTION bchksm : USINT
VAR_INPUT
cfrom : PTR_TO USINT; // USINT pointer to start from
numbytes : UINT; // number of bytes
END_VAR
VAR
a : USINT;
END_VAR
REPEAT
a := a + cfrom^;
cfrom := cfrom + 1;
numbytes := numbytes - 1;
UNTIL numbytes = 0 END_REPEAT;
bchksm := a;
END_FUNCTION
// Structure for received message
TYPE
Dalyrecv : STRUCT
error : STRING[250]; // error found, '' if none
status : USINT; // processing status: 0: ready, 1: sending, 2: receiving, 3: result ready, 4: error
lenmesrec : UINT; // length of the raw received message
datarec : STRING[13]; // raw content of the received message
END_STRUCT
END_TYPE
// send and receive one message from/to Daly
FUNCTION_BLOCK fbDalySendRec1
VAR_INPUT
init : BOOL; // trigger to start processing
dst_addr : BYTE; // address of Daly to send data to
data_id : BYTE; // command id
END_VAR
VAR_OUTPUT
rm : Dalyrecv; // Daly status and data structure
END_VAR
VAR
m : STRING[13]; // message data to send
r : STRING[13]; // message data received
pb : PTR_TO BYTE;
pd : PTR_TO DWORD;
// helpers
chs : USINT;
SendToDaly : fbSendTo;
RecvFromDaly : fbRecvFrom;
recvTimer : TON; // receiving timer
END_VAR
// init and send the message?
IF init THEN
recvTimer(IN := False, PT := Timeout_Recv_Daly);
// construct the message to be sent
rm.error := ''; // expect no error
pb := adr(m); // to initial byte
pb^ := 16#A5;
pb := pb + 1; // to communication module address
pb^ := dst_addr;
//pb^ := SHL(dst_addr, 4);
pb := pb + 1; // to data id
pb^ := data_id;
pb := pb + 1; // to data legth
pb^ := 8;
// may process data to send here, if any
pd := pb + 1; // to first data DWORD
pd^ := 0;
pd := pd + 4; // to second data DWORD
pd^ := 0;
pb := pd + 4; // to checksum
pb^ := USINT_TO_BYTE(bchksm(adr(m), 12));
// send
SendToDaly(rq :=True, chanCode := CH_DALYS, lenTx := 13, data := void(m));
// initiate receiving timer
recvTimer(IN := True);
rm.status := 2; // receiving
END_IF;
// exit if the main program did not processed the response (3 = response data, 4 = error), then return without further processing
IF rm.status > 2 THEN
RETURN;
END_IF;
// initiate message receive if status = 2
RecvFromDaly(rq :=True, chanCode := CH_DALYS, lenRx := 13, data := void(r));
// message not received?
IF not RecvFromDaly.mesRec THEN
// timeout?
IF recvTimer.Q THEN
rm.error := 'General receive error: response timeout';
rm.status := 4; // present the error
return;
ELSE
return; // message not received and no timeout - continue waiting for response
END_IF;
ELSE // message received
// message received - check general error
IF RecvFromDaly.error <> 0 THEN
rm.error := concat('General receive error: ', GetLastComErrTxt(RecvFromDaly.error));
rm.status := 4; // indicate the error
return;
END_IF;
// no error, start parsing
rm.lenmesrec := RecvFromDaly.lenData;
// despite potenital error, copy the received data to the output variable, if not too long
IF rm.lenmesrec <= 13 THEN
Memcpy(length := rm.lenmesrec, source := void(r), dest := void(rm.datarec));
END_IF;
pb := adr(rm.datarec); // to start_byte
// check start byte
IF not pb^ = 16#a5 THEN
// first byte is not A5
rm.error := 'Daly receive error: the first byte is not A5';
rm.status := 4; // indicate the error
return;
END_IF;
// verify checksum
pb := pb + 12;
chs := BYTE_TO_USINT(pb^);
IF chs <> bchksm(adr(rm.datarec), 12) THEN
rm.error := 'Daly receive error: checksum verification failed';
rm.status := 4; // indicate the error
return;
ELSE
// indicate correctly received data
rm.status := 3;
END_IF;
END_IF;
END_FUNCTION_BLOCK
PROGRAM DalyBMS
VAR
a : fbDalySendRec1; // function block to send one message to Studer and receive response
s : Dalyrecv; // structure with receive data
tinit : BOOL := True; // for the first run, lanuch
pw : PTR_TO WORD;
pb : PTR_TO BYTE;
pd : PTR_TO DWORD;
daly_id : USINT := 1; //current Daly to process
daly_addr : BYTE ; // current Daly address
COMMAND_MIN : USINT := 16#90; // minimum no of command to be sent
COMMAND_MAX : USINT := 16#98; // maximum no of command to be sent
command_id : USINT := 16#90; // work variable - current command_id
i : USINT;
END_VAR
// if tinit, go to next command or next Daly
if tinit THEN
command_id := command_id + 1;
if command_id > COMMAND_MAX THEN
// first command id
command_id := COMMAND_MIN;
// next daly
daly_id := daly_id + 1;
if daly_id > NUM_DALYS THEN daly_id := 1; END_IF;
end_if;
END_IF;
// take daly address
daly_addr := DALYADDR[daly_id];
// process the current command for the current Daly
a(init := tinit, dst_addr := daly_addr, data_id := USINT_TO_BYTE(command_id), rm => s);
tinit := False; // synchronous - wait for response
// verify if response or came and process
CASE s.status OF
2:
RETURN;
4 :
// mark error to the Daly data
dalys[daly_id].LastError_text := s.error;
dalys[daly_id].LastError_datetime := GetDateTime();
dalys[daly_id].ErrorCount := dalys[daly_id].ErrorCount + 1;
tinit := True;
3 :
// mark last received data to Daly
dalys[daly_id].LastReceive_datetime := GetDateTime();
dalys[daly_id].ReceiveOKCount := dalys[daly_id].ReceiveOKCount + 1;
tinit := True;
// parse - go to the first data byte
pw := adr(s.datarec) + 4;
pb := pw;
pd := pw;
case command_id of
16#90:
dalys[daly_id].totvoltage := int_to_real(int_to_int(word_to_int(pw^))) * 0.1;
pw := pw + 4;
dalys[daly_id].current := - (int_to_real(int_to_int(word_to_int(pw^))) - 30000) * 0.1; // A
pw := pw + 2;
dalys[daly_id].SOC := int_to_real(int_to_int(word_to_int(pw^))) * 0.1; // perc.
16#91:
dalys[daly_id].maxvoltage := int_to_real(int_to_int(word_to_int(pw^))) / 1000; // mV
pb := pw + 2;
dalys[daly_id].maxVcellNo := byte_to_usint(pb^);
pw := pw + 3;
dalys[daly_id].minvoltage := int_to_real(int_to_int(word_to_int(pw^))) / 1000;
pb := pb + 3;
dalys[daly_id].minVcellNo := byte_to_usint(pb^);
16#92:
dalys[daly_id].temperature := byte_to_int(pb^) - 40; // only one thermometer expected here
16#93:
dalys[daly_id].state := byte_to_usint(pb^); // 0 - static 1 - charge 2 - discharge
case dalys[daly_id].state of
// static - grey
0: dalys[daly_id].statea.r := 212;
dalys[daly_id].statea.g := 212;
dalys[daly_id].statea.b := 212;
// charge - green
1: dalys[daly_id].statea.r := 0;
dalys[daly_id].statea.g := 200;
dalys[daly_id].statea.b := 0;
// discharge - orange
2: dalys[daly_id].statea.r := 255;
dalys[daly_id].statea.g := 128;
dalys[daly_id].statea.b := 0;
end_case;
pb := pb + 1;
dalys[daly_id].MosCharging := byte_to_usint(pb^);
pb := pb + 1;
dalys[daly_id].MosLoad := byte_to_usint(pb^);
// force switch to nearest processed command
// switches also 95 and 96 which could not be processes in this program
command_id := 16#96; // will be incremented
16#97:
dalys[daly_id].balancing := word_to_stringf(pw^, '%04X'); // bit = the cell is balancing
16#98:
dalys[daly_id].faultstatus1 := dword_to_stringf(pd^,'%08X');
pd := pd + 4;
dalys[daly_id].faultstatus2 := dword_to_stringf(pd^,'%08X');
END_CASE;
END_CASE;
// calculate total current from batteries
CurrentBatSum := 0;
for i := 1 to NUM_DALYS DO
CurrentBatSum := CurrentBatSum + dalys[i].current;
end_for;
if CurrentBatSum > 0.5 THEN // charge - green
CurrentBatSum_cl.r := 0;CurrentBatSum_cl.g := 200;CurrentBatSum_cl.b := 0;
elsif CurrentBatSum < -0.5 THEN // discharge - orange
CurrentBatSum_cl.r := 255;CurrentBatSum_cl.g := 128;CurrentBatSum_cl.b := 0;
else // static - grey
CurrentBatSum_cl.r := 212;CurrentBatSum_cl.g := 212;CurrentBatSum_cl.b := 212;
end_if;
// actualization of the global variables
daly_diffvoltage_1 := dalys[1].maxvoltage - dalys[1].minvoltage;
daly_diffvoltage_2 := dalys[2].maxvoltage - dalys[2].minvoltage;
END_PROGRAM
Re: BMS s komunikací RS485/232/Modbus
Napsal: stř pro 22, 2021 10:16 am
od pavelsiman
skusal nikto s tych bms tahat data cez modbus a da sa na nich nejako zmenit adresa ? mam loxone a tam by sa to snad dalo
Re: BMS s komunikací RS485/232/Modbus
Napsal: ned úno 06, 2022 4:26 pm
od marsal64
Re: BMS s komunikací RS485/232/Modbus
Napsal: ned úno 27, 2022 10:44 am
od Marcus81
Ja som s tohoto chuj, neviem to rozchodit ani lena na PC. Marsal tam nieco opisuje,ale akosi tomu moc nerozumiem, elektronika nikdy nebola moj kamarat...
Viete mi s tym niekto prosim pomoct ako to zapojit porpipade co na to presne pouzit?
Dakujem