Modbus RTU CRC16 treibt mich in den Wahnsinn.

OP #2219167
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?
OP #2219172
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
(Firma: Nisch-Aufzüge) Persönliche Seite #3157822
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
}
Gast #3438909
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
OP #3438920
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.
Gast #3441459
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
Gast #3486923
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)?
Gast #3488225
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren