ich würde gerne meinen SMA Wechselrichter (SMA STP 80) der an unserer Fotovoltaik Anlage hängt, mittels Arduino auslesen.
Der Wechselrichter selbst hat eine RS485 Schnittstelle.
Jetzt hab ich bereits die technische Info über die Register gefunden.
Darin ist als Protokoll das „modbus Protokoll“ erwähnt wobei dieses mit gerätespezifischen Modbus-Profilen funktioniert (SMA Modbus-Profil und das SunSpec Modbus-Profil)
Da ich RS485 und modbus noch recht unerfahren bin, versteh ich nur Bahnhof.
Hardware hab ich bereits.
Zum Testen zwei Nanos mit RS485 TTL umsetzen.
Hat auch gut funktioniert. (Aber waren sehr einfache Beispiele).
Kann mir jemand einen Tipp geben?
Bei Onkel google komm ich irgendwie nicht weiter…
RS485 ist die technische Übertragung, Modbus das Protokoll. Das hat nix mit Ports zu tun, du hängst quasi an einem seriellen Bus mit mehreren Teilnehmern. Das funktioniert, weil Modbus regelt, dass immer nur ein Client (bist in dem Falle du mit deinem Arduino) eine Frage stellen darf (Request) und ein angesprochener Server (dein Wechselrichter) antworten soll (Response).
Auf Grundlage des Verlinkten Beispieles habe ich folgenden Sketch:
/* *******************************************************
Serial Interface
* **************************************************** */
#include <SoftwareSerial.h>
constexpr uint8_t rxPin = 10; // for Softserial
constexpr uint8_t txPin = 11;
SoftwareSerial mySerial(rxPin, txPin);
/* **************************************************** *
Modbus
* **************************************************** */
#include <ModbusMaster.h> // Modbus Master 2.0.0 by Doc Walker - install with Library Manager
constexpr uint8_t modbusEnablePin = 255; // The GPIO used to control the MAX485 TX pin. Set to 255 if you are not using RS485 or a selfsensing adapter
constexpr uint32_t modbusBaud = 1200; // use slow speeds with SoftSerial
constexpr uint16_t modbusRestTx = 15000; // rest time between transmissions - microseconds
uint32_t modbusPreviousTx = 0; // timestamp of last transmission - microseconds
ModbusMaster serverA; // instantiate ModbusMaster object - slave - node
// this function will be called before the client transmits data
void preTransmission()
{
while (micros() - modbusPreviousTx < modbusRestTx) // check last transmission end and wait if the call was to early
{
yield(); // wait some time and allow background tasks
}
digitalWrite(modbusEnablePin, HIGH);
}
// this function will be called after the transmission
void postTransmission()
{
digitalWrite(modbusEnablePin, LOW);
modbusPreviousTx = micros(); // remember last timestamp
}
// do all the settings for the Modbus
void modbusInit()
{
mySerial.begin(modbusBaud); // initialize Modbus communication baud rate
serverA.begin(3, mySerial); // communicate with Modbus server ID over the given Serial interface
pinMode(modbusEnablePin, OUTPUT); // Init enable pins for modbus master library
digitalWrite(modbusEnablePin, LOW);
serverA.preTransmission(preTransmission); // Callbacks allow us to configure the RS485 transceiver correctly
serverA.postTransmission(postTransmission);
}
// getdata from Modubs Server(Slave) and print to Serial
void requestData()
{
constexpr uint16_t interval = 5000; // interval of modbus requests
static uint32_t previousMillis = -interval; // timestamp of last request
static uint8_t actual = 0; // actual iteration
uint32_t currentMillis = millis();
if (currentMillis - previousMillis > interval) // set the interval in ms
{
previousMillis = currentMillis;
uint16_t reg = 0x7837;
int result;
result = serverA.readInputRegisters(reg, 2); // request from startregster, n Registers
if (result == serverA.ku8MBSuccess) // do something if read is successfull
{
Serial.print(F("Register 1: ")); Serial.println(serverA.getResponseBuffer(0x00));
Serial.print(F("Register 2: ")); Serial.println(serverA.getResponseBuffer(0x01));
}
else
{
Serial.print(F(" ServerA no success register ")); Serial.print(reg, HEX); Serial.print(F(" result=")); Serial.println(result, HEX);
}
}
}
/* **************************************************** *
setup and loop
* **************************************************** */
void setup()
{
Serial.begin(115200);
Serial.println(F("Modbus Client Example D 485 halfduplex"));
modbusInit();
}
void loop()
{
requestData();
}
Im Seriellen Monitor bekomm ich nur die Meldung:
Die TX LED auf dem Adapter geht aber schön im Rythmus an.
Hat einer eine Idee wo der Fehler liegt?
(ja ich weiß, ca. 70cm vor dem Monitor )
Bei ModbusMaster ist der Fehlercode E2 als ku8MBResponseTimedOut = 0xE2; definiert. Da fühlt sich also niemand angrsprochen. Server-ID, Baudrate etc. hast du gecheckt?
vieleicht die Anschlüsse A / B mal drehen.
mal GND weglassen
auch wenns entgegen der Doku ist, mal mit id 1 oder 2 probieren (was sie da mit den Unit-ID's im Kapitel 3.4.1 meinen kann ich noch nicht ganz nachvollziehen).
Hast du einen USB-RS485 Wandler? Kannst mal direkt mit dem PC versuchen ein Paket zu senden?
@nasly-one
Bilder von der Verkabelung wären auch nicht schlecht.
Welchen Arduino verwendest du?
Hat der 485 Adapter irgendwelche LEDs die bei Kommunikation blinken sollen - und was tun sie wirklich?
P.S.: du bist zwar noch nicht so weit, aber als Input Register musst du vermutlich nicht 0x7837 sondern ich glaube eher 30775-30001 = 774 (dec) angeben. ... Die "Adresse" 30775 steht eigentlich bei Unit=2.
Morgen zusammen,
also viel neue Erkenntnisse gibt es bei mir nicht.
Ich schreib euch mal was ich versucht habe.
Habe auch Kombinationen aus 1, 2 und 3 Pobiert…
Bezüglich des RS485 Moduls habe ich RX und TX getauscht, RX und TX zusammen verbunden.
ohne Erfolg.
Natürlich ändert sich dann die Anzeige der LEDs entsprechend, aber mehr auch nicht.
Hab mit der Bautrate und mit der ID (wobei man dieses Kombinationsspiel ja endlos treiben könnte)
auch ohne Erfolg.
Ich hab die Verkabelung von A und B getauscht.
hier bekomm ich dann die Fehlermeldung im Seriellen Monitor E0.
Irgendwie komm ich da nicht weiter.
Kann man eigentlich irgendwie feststellen ob am anderen Ende überhaupt „jemand ist“?
Wenn ich zum Beispiel die Spannung zwischen A und B messe, habe ich 5V > das sollte doch soweit stimmen oder?
Die Spannung ist weitgehend egal, da die RS485-Übertragung auf Spannungsdifferenz beruht.
Hast du ein Oszi verfügbar, mit dem du das Differenzsignal zwischen A und B sichtbar machen kannst?
wenn du mehrere RS485 - TTL board hättest, könntest du auf einem anderen Nano einen einfachen Passthrough sketch laden und diesen auch in den Bus hängen.
Dann
in einem anderen seriellen Monitor mitlesen was dein Master raussendet und eventuell etwas vom Slave hören.
und ob es in der Variante A/B getauscht und Fehlermeldung "0xE0" - tatsächlich etwas vom Slave war
/**
ModbusMaster invalid response slave ID exception.
The slave ID in the response does not match that of the request.
@ingroup constant
*/
static const uint8_t ku8MBInvalidSlaveID = 0xE0;
weiters hast du noch nicht geschrieben was passiert wenn du Slave 1 oder 2 addressierst.