Forum: Mikrocontroller und Digitale Elektronik Modbus RTU CRC16 treibt mich in den Wahnsinn.


von Weingut P. (weinbauer)


Lesenswert?

Hallo Forum, ich tüftle schon seit Stunden an der Ansteuerung
eines Modbus Devices von Vögtlin Instruments ... grrr

Also, ich habe auf dem Bus mal gelauscht und folgende Sequenz 
herausgefiltert, die auch, wenn ich die direkt aus VB6 sende einwandfrei 
funktioniert:

01;10;00;06;00;02;04;3E;99;99;9A;44;79

01 Slave
10 Kommando
00 Startadr. Hi
06 Startadr. low
00 Anzahl Register Highbyte
02 Anzahl Register Lowbyte
04 Anzahl der zu sendenden Bytes (2x 16-Bit)
3E; 99; 99; 9A 4 Bytes einer Single Variablen, = 0,3
44 ; 79 Checksumme ... CRC16

Und in den letzten Beiden liegt der Hund begraben.
Die werden in umgekehrter Reihenfolge geschickt, soviel hab ich
in der Doku gefunden, aber die Generierung klemmt einfach.

Bis zu diesem Code bin ich schon gekommen:

Public Function CRC16(ar() As Byte, lbuf As Byte) As Integer

Dim CRC1 As Long
Dim b As Boolean
Dim i As Long, j As Byte, Odd As Boolean

    CRC16 = -1
    For i = 0 To lbuf
        CRC16 = (CRC16 And &HFF00) Or ((CRC16 And 255) Xor ar(i))
        For j = 1 To 8
            Odd = CRC16 And 1
            CRC16 = ((CRC16 And &HFFFE) \ 2) And &H7FFF 'shift right
            If Odd Then CRC16 = &HA001 Xor CRC16
        Next
        'Debug.Print CStr(i) + " " + Hex(ar(i)) + " " + Hex(CRC16)
    Next
End Function

Aber der Rückgabewert passt nicht: 9F26 ... oder halt Protokollkonform

26; 9F

Hat von Euch schon jemand Erfahrungen mit den Reglern und / oder hat nen 
Tip für mich?

von Weingut P. (weinbauer)


Lesenswert?

AAAAAAAARRRGH ... nach dem Absenden den Fehler gesehen ...

--> For i = 0 To lbuf     Da isster

Mein Array fängt bei 1 an ....grrrrrrr


Dieser Code funktioniert ... falls den mal noch jemand brauchen sollte:

Public Function CRC16(ar() As Byte, lbuf As Byte) As Integer

Dim CRC1 As Long
Dim b As Boolean
Dim i As Long, j As Byte, Odd As Boolean

    CRC16 = -1
    For i = 1 To lbuf
        CRC16 = (CRC16 And &HFF00) Or ((CRC16 And 255) Xor ar(i))
        For j = 1 To 8
            Odd = CRC16 And 1
            CRC16 = ((CRC16 And &HFFFE) \ 2) And &H7FFF 'shift right
            If Odd Then CRC16 = &HA001 Xor CRC16
        Next
        'Debug.Print CStr(i) + " " + Hex(ar(i)) + " " + Hex(CRC16)
    Next
End Function

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

ich habe die Routine mal in C übersetzt (nicht optimiert)
1
unsigned int crc_16 (unsigned char buffer[],int bufferlen) 
2
{    
3
unsigned int CRC=0xffff ;
4
unsigned char i,j;
5
bit odd; 
6
for (i=1;bufferlen;i++) // for i= 1 to bufferlen
7
        {
8
        CRC=(CRC & 0xFF00)|((CRC & 0xFF)^buffer[i]); // CRC = (CRC And &HFF00) Or ((CRC And 255) Xor bufferlen (i))
9
        for (j=1;8;j++)   // For j = 1 To 8
10
                {
11
                odd = CRC & 1;   //    Odd = CRC And 1
12
                CRC = ((CRC & 0xFFFE) / 2) & 0x7FFF ;   //    CRC = ((CRC And &HFFFE) \ 2) And &H7FFF 'shift right             
13
                if (odd)        //    If Odd
14
                        {       // Then
15
                        CRC = 0xA001 ^ CRC;  //   CRC = &HA001 Xor CRC
16
                        };  // Endif
17
                }        // Next j
18
        }       //Next i
19
return CRC;
20
}

von Chris (Gast)


Lesenswert?

Hi

Ich habe gesehen, dass der Eintrag zwar schon einige Monate her ist, 
aber kannst du mir vielleicht beim Code helfen?

Ich versuche seit Juli schon einen einfachen Motor anzusteuern (also 
gernauer gesagt den Frequenzumrichter).
Allerdings scheitere ich kläglich.

Ich meinte, mittlerweile den Syntax draussen zu haben. Aber über die 
Schnittstelle läuft nichts. Oder falls da doch was läuft, ist es nur 
Mist.

Wenn ich die Bauteile für das Telegramm (Adresse, Befehl, Register, 
Werte) zusammenstelle und versuche den CRC16-Wert zu errechnen, erhalte 
ich, glaube ich zumindest, einen Wert. Aber dann kann ich die Kette 
nicht verknüpfen und erhalte dementsprechend keine Antwort.

Jetzt weiss ich nicht, ob ich die Kette korrekt erstellt habe, die 
Zeichen richtig an die Schnittstelle übergeben werden und wie ich das 
ganze verkette.

Einige Schwierigkeiten, bei denen ich für Rat sehr dankbar wäre.

Ich hoffe, du kannst und möchtest mir helfen.

Danke

Chris

von Weingut P. (weinbauer)


Lesenswert?

Hast Du evtl. nen Link zu der Bedienungsanleitung von dem Teil??

Schau mal ob es zu dem FU evtl. vom Hersteller ne Software gibt, dann 
kannst Du mal auf dem Bus mitloggen was da hin und her geht, das kann 
schonmal zum Eingrenzen ob die Kommunikation prinzipiell läuft oder 
schon in der Schnittstelle der Wurm drinnen ist, gut sein.

von Chris (Gast)


Lesenswert?

Hi

Ich habe einen Link gefunden.
http://www.spoerk.at/wp-content/uploads/2011/05/V1000_QSG_DE_TOGP_C710606_15C_3_0.pdf

Dummerweise musste ich das Teil gestern zurückgeben. Ich kann nur noch 
theoretisch daran arbeiten. Muss erst wieder etwas Geld aufbringen, um 
das Teil noch einmal mieten zu können oder eines zu kaufen.
Aber das will ich erst, wenn ich weiss, dass das Telegramm auch 
funktionieren würde.

Chris

von Jeff (Gast)


Lesenswert?

Hi,

wozu dient eigentlich die Zeile

CRC=(CRC & 0xFF00)|((CRC & 0xFF)^buffer[i]);

Es werden doch ohnehin nur die "unteren" 8 bit verarbeitet?! In einem 
anderen Beispiel 
(http://www.camillebauer.com/src/download/Modbus_Grundlagen.pdf, Seite 
3) fand ich stattdessen

crc = ((crc^data) | 0xFF00) & (crc | 0x00FF);

dessen Sinn sich mir auch nicht richtig erschließt. Gerade aus (crc | 
0x00ff) ergibt sich doch für die hier relevanten Bits immer 0xFF?

Warum also reicht nicht (crc^data)?

von Dieter W. (dds5)


Lesenswert?

Jeff schrieb:
> Gerade aus (crc | 0x00ff) ergibt sich doch für die hier relevanten
> Bits immer 0xFF?

Das siehst Du falsch. Die relevanten Bits stecken bei den | 
Verknüpfungen hinter den 00 und der Rest muss auf FF stehen damit bei 
der nachfolgenden & Verknüpfung die Daten nicht auf Null gebügelt 
werden.

: Bearbeitet durch User
von Jeff (Gast)


Lesenswert?

Hmmm, okay. So gesehen hast Du recht, auch wenn ich den zitierten Satz 
anders gemeint, doch leider missverständlich formuliert habe.

Der Kern aber bleibt:
Warum ist (crc^data) (bzw. (crc^buffer[i])) nicht ausreichend? In 
welchen Fällen also müssen die beiden Bytes im Int16 explizit separat 
behandelt werden?

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Winfried J. schrieb:
> for (i=1;bufferlen;i++) // for i= 1 to bufferlen

autsch. Never ending ...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.