Hallo! Ich muss leider noch einmal einen CRC Beitrag aufmachen. Nachdem ich nun das gesamte Wochenende gesucht und gelesen habe komme ich trotzdem nicht darauf was in meiner Berechnung falsch ist. Und zwar soll für eine serielle Kommunikation ein CRC16 nach CCiTT berechnet werden und den Daten vorweg gestellt werden. Um die CRC zu berechnen nutze ich eine Tabelle. Wenn ich nun genau ein ASCII Zeichen an meine CRC Funktion übergebe dann wird der CRC korrekt berechnet. Also es kommt das raus was auch bei dem Rechner von "Breitbandkatze" rauskommt. Wenn ich nun aber 2 oder mehr Zeichen in die Berechnug einfüge dann kommt nur Mist raus. Vor allem das Ergebnis ist nicht ein 4 Byte CRC sondern ein 5 Byte. Was mich doch sehr verwundert. Denn spätestens in der sprintf() Funktion sollte das ja auf 4 Zeichen gekappt werden. Anbei ein kleiner Auszug meines Quellecodes. Das ganze senden und empfangen über die UART hab ich mal ausgelassen. Und alles am Ende steht eigentlich in einer Header Datei crc.h die in der main.c eingebunden wird. Vielen Dank schomal für Eure Mühe. Wird bestimmt nur ein kleiner Fehler sein, aber an denen hockt man ja bekanntlich am längsten. Gruß Björn Niethammer Hab gerade moch gesehen das ich in der angehängten Datei nur ein Zeichen mit dem CRC berechne. Wenn ich also den CRC über alle Zeichen will würde cih folgenden Code einfügen: crc = updcrc(crc, dest[0]); crc = updcrc(crc, dest[1]); crc = updcrc(crc, quelle[0]); crc = updcrc(crc, quelle[1]); crc = updcrc(crc, befehl[0]);
Warum nicht erst den String zusammennageln und zum Schluß den CRC berechnen? z.b. so:
1 | int main(void) |
2 | {
|
3 | // Variablen
|
4 | // Initialisierung
|
5 | |
6 | // String zusammenbaun
|
7 | memset(word_out, 0 , 255); |
8 | sprintf(&word_out[2], start, 1); // word_out[0] und ...[1] reserviert f. CRC |
9 | strncat(&word_out[2], crc_char, 4); // crc_char ist nicht initialisiert! |
10 | strncat(&word_out[2], dest, 2); |
11 | strncat(&word_out[2], quelle, 2); |
12 | strncat(&word_out[2], befehl, 1); |
13 | strncat(&word_out[2], ende, 1); |
14 | |
15 | crc = updcrc(&word_out[2], 11); // 11 = Länge des Strings ohne CRC |
16 | word_out[0] = crc >> 8; // Hi-Byte |
17 | word_out[1] = (char)crc; // Lo-Byte |
18 | ....
|
19 | }
|
20 | |
21 | int updcrc(const char *zeichen, int length) |
22 | {
|
23 | int i; |
24 | unsigned char temp; |
25 | |
26 | for(i = 0; i < length; i++) |
27 | {
|
28 | temp = (crc >> 8) ^ zeichen[2+i]; |
29 | crc = (crc << 8) ^ crctab[temp]; |
30 | }
|
31 | |
32 | return(crc); |
33 | }
|
Sowas ungefähr. Verstehense?
Hallo Hegy! Klar hab ich auch schon daran gedacht den String erst zusammen zu kopieren und dann den CRC zu berechnen. Das Protokoll sieht aber vor den CRC ohne Start und Stop Value zu berechenen. Ich müsste dann also erst alle Info Values zusammenkopieren. Dann CRC berechnen lassen und dann das Start Value vorweg zu stellen und den Stop Value ans Ende kopieren. Wenn ich dies mache kommt aber der gleiche falsche CRC Wert raus. Der Fehler liegt also woanders. Ich denke mal das irgendwo ein Pufferüberlauf stattfindet oder aber die Tabelle falsch ist bzw. falsch ausgelesen wird. Nur leider finde ich nirgends einen solchen Fehler. Deswegen hab ich mich damit ans Forum hier gewandt. Gruß Björn Niethammer
Hallo Björn nimm doch zum Vergleich einen Algorithmus, der nur Bitoperationen macht und keine Tabelle benutzt. Bei nichttrivialen Rechnungen ist es zur Validierung immer gut, mehrere Algorithmen nebeneinander zu halten. Schöne Grüße, Peter
So ganz gerafft habbich das nicht wirklich. Ich vermute mal, du willst sowas: Am Anfang war NICHTS. Dann war da ein Byte, aus dem wurde eine CRC berechnet. Dann kam noch ein Byte und wieder wurde mit dem schon vorhandenem Daten eine CRC berechnet, wobei der alte CRC-Wert überschrieben wurde. Sowas rekursives eben. 1) CRC aus (A) 2) CRC aus (CRC von 1) + (A) + (B) 3) CRC aus (CRC aus 2) + (A) + (B) + (C) ... Der vorangegangene CRC-Wert wird also immer mitgeschliffen zur Berechnung? Außerdem habe ich damals meine CRC-Berechnung nicht mit Tabelle wie du sondern mit Bitoperation in C-Funktion realisiert. Funxoniert 1A. Außerdem spielt im Gegensatz zu anderen Checksummen-Algos die Position der einezelnen Bytes bei CRC eine Rolle. Also bekommst du zwei verschiedene Chksum bei diesen Dingern raus 0x58 0xE3 0x08 0x58 0x08 0xE3 So, muß wech....
Guten Morgen! Genau sowas rekursives soll es werden. Laut Protokoll werden über alle Bits zwischen dem Startzeichen und dem Endezeichen eine CRC16 nach CCiTT gemacht und den Info-Bits vorneweg gestellt. Ich hatte auch schon alles am laufen. Allerdings auf einem kleinen ATmega128 Prozessor. Leider hat sich nur im laufe des Projekts herausgestellt das der mit allem doch ein wenig überfordert ist und ich etwas viel größeres brauche. Also hab ich ein ARM Entwicklungsboard bestellt und entwickel nun darauf. Dort läuft ein kleines Minilinux drauf. Nun hab ich meinen Code vom ATmega genommen die UART Geschichten angepasst und compiliert. Die UART kann er auch richtig ansprechen. Allerdings berechnet er jetzt die CRC falsch. Auf dem kleinen ATmega hat er sie richtig berechnet. Wenn ich nun den CRC per Hand einfüge also einfach crc = <wert> eingebe dann klappt auch alles Problemlos. Nur soll er ja nicht nur für genau eine Info alles machen sondern die Info soll Variabel sein. Deswegen muss er den CRC schon selbst berechen. Mein Gedanke ist, dass er mit dem neunen Board falsch rechnet, weil irgendeine Variable einen anderen Wertebereich hat wie auf dem ATmega. Nur welche??? Hab gestern nochmal so einiges ausprobiert, bin aber immer zu einem falschen CRC Wert gekommen. Bastel gerad auch noch an ein paar anderen Baustellen rum. Deswegen dauerts manchmal bis ich hier wieder reinschaue. Als Entwicklungsboard habe ich jetzt das Digi ConnectCore 9P. Die Routine zur Berechnung des CRC habe ich aus der Doku des Protokolls welches in programmieren will. Da sie ja auch auf dem ATmega schon mal lief denke ich nicht das darin der Fehler zu suchen ist. Aber sicher bin ich mir natürlich nicht. Vielleicht hat ja jemand Erfahrungen mit dem ATmega und ARM Entwicklung und weiß wodrinn die Unterschiede liegen. Gruß Björn Niethammer
Hallo Björn, ach so ist das. Mit Deiner neuen Plattform hat sich der int auf 32 Bit vergrößert. Nimm uint16_t um den alten Code für die CRC-16 weiter zu nutzen. Schöne Grüße, Peter
Vielen, vielen Danke an alle die mitgeholfen haben! Es klappt nun endlich. War wie "Freizeitbastler" schon sagte die Größe von den integer Variablen. Auf dem kleine ATmega nur 16 bit breit und nun auf dem ARM Board 32 bit breit. Hab alle integer zu short gewandelt und nun rechnet er auch wieder "richtig". Der vorsatz mit uint16_t hat leider nicht geklappt. Den kennt mein Compiler so nicht wohl. Aber ich konnte es ja trotzdem lösen. Gruß Björn Niethammer
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.