2013-08-28 12 views
6

Ich verwende C#, um über modbus rs485 rs232 mit 2-Phasen-Messgeräten zu kommunizieren, die unter anderem die Netzspannung protokollieren.Modbus Kommunikation

Ich muss Daten über den Bus senden, damit ich die Messwerte erhalten kann.
Ich habe eine normale Leitung angeschlossen und das Senden und Empfangen kurzgeschlossen.

Die Daten empfangen und dieses Ereignis ausgelöst wird:

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    SerialPort sp = (SerialPort)sender; 
    byte[] buff = new byte[sp.BytesToRead]; 

    //Read the Serial Buffer 
    sp.Read(buff, 0, buff.Length); 
    string data= sp.ReadExisting(); 

    foreach (byte b in buff) 
    { 
     AddBuffer(b); //Add byte to buffer 
    } 
} 

Dann wird dieser Puffer auf eine andere Funktion gesendet, die diese ist:

private void AddBuffer(byte b) 
{ 
    buffer.Add(b); 

    byte[] msg = buffer.ToArray(); 

    //Make sure that the message integrity is correct 
    if (this.CheckDataIntegrity(msg)) 
    { 
     if (DataReceived != null) 
     { 
      ModbusEventArgs args = new ModbusEventArgs(); 
      GetValue(msg, args); 
      DataReceived(this, args); 
     } 
     buffer.RemoveRange(0, buffer.Count); 

    } 
} 

Ich denke, dass das Problem bei der Daten liegt Integritätsprüfung:

Es gibt eine CRC-Prüfung und was ist seltsam ist, dass es nie bec omes wahr. Die CRC-Berechnung:

private void GetCRC(byte[] message, ref byte[] CRC) 
{ 

    ushort CRCFull = 0xFFFF; 
    byte CRCHigh = 0xFF, CRCLow = 0xFF; 
    char CRCLSB; 

    for (int i = 0; i < (message.Length) - 2; i++) 
    { 
     CRCFull = (ushort)(CRCFull^message[i]); 

     for (int j = 0; j < 8; j++) 
     { 
      CRCLSB = (char)(CRCFull & 0x0001); 
      CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF); 

      if (CRCLSB == 1) 
       CRCFull = (ushort)(CRCFull^0xA001); 
     } 
    } 
    CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF); 
    CRC[0] = CRCLow = (byte)(CRCFull & 0xFF); 
} 
+0

Gibt es Online-Ressourcen, die eine Abschrift einer typischen Kommunikationssitzung mit dem CRC enthalten? Dann könnten Sie Ihren Algorithmus zumindest auf diese Beispielnachrichten anwenden und sehen, ob Sie mit demselben CRC kommen. –

+1

Was ist die "Puffer" Variable? Ist es eine Liste ? Sind Sie sicher, dass Ihre "msg" Variable immer größer als 6 ist? Warum nicht einfach den Puffer vom seriellen Port verwenden, anstatt ihn in einer Schleife nach Byte zu zerlegen, ihn in einer Liste zu rekonstruieren und ihn dann in ein globales Byte-Array umzuwandeln? Sie rufen auch direkt nach dem Lesen des Pufferinhalts ReadExisting am seriellen Port auf, warum? –

+0

Die CRC scheint richtig zu sein @AndyzSmith. was meinst du reaindaisting nennen wirklich wo kann ich es nennen?und ja Puffer ist eine Liste – Combinu

Antwort

2

Das Problem ist die Verwendung von ReadExisting(). Es sollte nicht auf diese Weise verwendet werden, da der Puffer mit nutzlosen Daten von der seriellen Schnittstelle gefüllt wurde. Dieses Problem wurde von @glace in den Kommentaren identifiziert!

1

Als erstes müssen Sie wie MODPOLL Kommunikation mit Ihren Meter durch einige bestehende MODBUS-Master-Anwendung etablieren. Sobald die Kommunikation funktioniert und Sie gültige Antworten von Ihrem Gerät erhalten haben, können Sie Ihren Code testen. Auf diese Weise stellen Sie sicher, dass das Problem nur in Ihrem Code und sonst nichts sein kann.

Um beispielsweise zwei Slave-Geräte gleichzeitig anzuschließen, muss RS485 anstelle von RS232 verwendet werden. Dies erfordert eine andere Verdrahtung und RS485/RS232-Konverter auf der PC-Seite.

Wenn RX und TX zu Simulationszwecken in RS232 verbunden sind, ist dies keine gute Idee, da jede MODBUS-Nachricht von einem Master (außer Broadcast-Nachrichten) eine Antwort benötigt, die sich vom Nachrichtenecho unterscheidet. Außerdem enthält jede MODBUS-Nachricht von einem Master eine MODBUS-Client-Adresse, die darin eingebettet ist, und nur ein einzelner Client sollte darauf antworten (MODBUS ist ein Single-Master-Multiple-Slave-Protokoll).

Wie für eine CRC-Berechnung, könnte dies für MODBUS RTU helfen Protokoll (ASCII ist verschieden):

function mb_CalcCRC16(ptr: pointer to byte; ByteCount: byte): word; 
var 
    crc: word; 
    b, i, n: byte; 
begin 
    crc := $FFFF; 
    for i := 0 to ByteCount do 
    if i = 0 then   // device id is 1st byte in message, and it is not in the buffer 
     b := mb_GetMessageID; // so we have to calculate it and put it as 1st crc byte 
    else 
     b := ptr^; 
     Inc(ptr); 
    endif; 
    crc := crc xor word(b); 
    for n := 1 to 8 do 
     if (crc and 1) = 1 then 
     crc := (crc shr 1) xor $A001; 
     else 
     crc := crc shr 1; 
     endif; 
    endfor; 
    endfor; 
    Return(crc); 
end; 

function mb_CalcCRC: word; // Calculate CRC for message in mb_pdu 
begin // this message can be one that is just received, or in a reply we have just composed 
    Return(mb_CalcCRC16(@mb_pdu[1], mb_GetEndOfData)); 
end; 

, dass ein Zitat aus einem Arbeits eingebettet AVR-Gerät ist mit implementierten MODBUS-RTU-Slave-Protokoll.

+0

danke für deine Hilfe Ich habe tatsächlich das Problem funktioniert ... scheint, dass ich falsch von der seriellen Schnittstelle gelesen habe! ... aber immer noch viel hilfreich !! – Combinu

+0

@MysticJay ist es möglich, Ihre Lösung als Antwort hinzuzufügen (Sie können Ihre eigene Frage beantworten) und akzeptieren Sie es? Ich denke, dies würde zukünftigen Lesern helfen, wenn sie auf ähnliche Probleme stoßen. (Ich beziehe mich auf [xkcd] (http://xkcd.com/979/) als Referenz) – Default

+0

Ich glaube nicht, das ist C# – mrid