CRC8 - ich komm nicht dahinter

Hallo Gemeinde,

ich geb’s zu: ich verstehe dieses CRC-Thema nicht :confused:

Aber Tante Google hilft mit Beispielen, die ich aber ob zusätzlicher Array-Verwursterei auch nicht wirklich durchblicke :’(

Ausgangsbasis: ich habe 7 Bytes als Nutzdaten in einem 8-Byte Array, aus denen wird der CRC berechnet und der CRC dann in Position 8 geschrieben.
CRC Startwert ist 0.

Beispiel: 107, 108, 97, 117, 115, 0, 0, 222 (habe ich nicht berechnet sondern als fertige Byte-Folge so bekommen)

Hier habe ich ein nettes Beispiel gefunden:

//CRC-8 - based on the CRC8 formulas by Dallas/Maxim
//code released under the therms of the GNU GPL 3.0 license
byte CRC8(const byte *data, byte len) {
  byte crc = 0x00;
  while (len--) {
    byte extract = *data++;
    for (byte tempI = 8; tempI; tempI--) {
      byte sum = (crc ^ extract) & 0x01;
      crc >>= 1;
      if (sum) {
        crc ^= 0x8C;
      }
      extract >>= 1;
    }
  }
  return crc;
}

Ich verstehe so grob, dass ich an die Funktion mein Array übergebe (wie???) und die Anzahl der Bytes, aus der der CRC berechnet wird. Passt oder liegt ich Lichtjahre daneben?
Der Code selbst ist mir zu kryptisch, da steig ich dann total aus.

Kann mir jemand den Weg verständlich aufzeigen?

Danke
Klaus

Klaus_ww:
Der Code selbst ist mir zu kryptisch, da steig ich dann total aus.

Kann mir jemand den Weg verständlich aufzeigen?

Die von Dir gepostete Funktion ist gut und funktioniert genau so korrekt wie die äquivalente Funktion, die in de rArruino-IDE mitgeliefert wird.

Aber Dein Datenbeispiel ist Schrott und das achte CRC-Byte ist darin falsch.
Jedenfalls dann, wenn es sich um die acht ID bytes eines Maxim-Sensors handeln soll, z.B. DS18B20.

Statt 222 müßte es mit den ersten 7 Bytes eine 243 als CRC im achten Byte sein.

Hast Du auch ein Beispiel mit einem richtigen CRC-Byte?

Und was ist jetzt genau Dein Problem?

Du hast eine gute und gut dokumentierte und gut funktionierende Funktion.
Aber Du hast ein beschissenes und falsches Beispiel mit falschem CRC-Byte, woher auch immer.

Und was möchtest Du nun von den Foren-Teilnehmern?

Der Code selbst ist mir zu kryptisch, da steig ich dann total aus.

Ich finde die Funktion jetzt nicht wirklich "schön", aber auch nicht "kryptisch".

Klaus_ww:
Ich verstehe so grob, dass ich an die Funktion mein Array übergebe (wie???) und die Anzahl der Bytes, aus der der CRC berechnet wird. Passt oder liegt ich Lichtjahre daneben?

Es wird der Zeiger des Feldes übergeben, sieht man am Sternchen, und die Anzahl der Bytes. Stimmt also.

jurs:
Die von Dir gepostete Funktion ist gut und funktioniert genau so korrekt wie die äquivalente Funktion, die in de rArruino-IDE mitgeliefert wird.

Aber Dein Datenbeispiel ist Schrott und das achte CRC-Byte ist darin falsch.
Jedenfalls dann, wenn es sich um die acht ID bytes eines Maxim-Sensors handeln soll, z.B. DS18B20.

Statt 222 müßte es mit den ersten 7 Bytes eine 243 als CRC im achten Byte sein.

Die Funktion liefert tatsächlich 222 zurück. Entweder ist die Funktion kaputt oder der Wert 243 stimmt nicht oder ... ?

agmue:
Es wird der Zeiger des Feldes übergeben, sieht man am Sternchen, und die Anzahl der Bytes. Stimmt also.
Die Funktion liefert tatsächlich 222 zurück. Entweder ist die Funktion kaputt oder der Wert 243 stimmt nicht oder … ?

Alo wenn ich die Testdaten in ein byte-Array packe und die CRC über die ersten sieben Bytes ausgeben lasse mit dem Code :

Serial.println(CRC8(testDaten,7));

dann sehe ich bei mir 143 auf dem seriellen Monitor.

Was mache ich falsch?

byte werte[] = {107, 108, 97, 117, 115, 0, 0, 0};
byte anz = sizeof(werte);

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  werte[anz - 1] = CRC8(werte, anz - 1);
  for (byte j = 0; j < anz; j++) {
    Serial.print(werte[j]);
    Serial.print('\t');
  }
}

void loop() {}

//CRC-8 - based on the CRC8 formulas by Dallas/Maxim
//code released under the therms of the GNU GPL 3.0 license
byte CRC8(const byte *data, byte len) {
  byte crc = 0x00;
  while (len--) {
    byte extract = *data++;
    for (byte tempI = 8; tempI; tempI--) {
      byte sum = (crc ^ extract) & 0x01;
      crc >>= 1;
      if (sum) {
        crc ^= 0x8C;
      }
      extract >>= 1;
    }
  }
  return crc;
}

Ausgabe:

Anfang
107 108 97 117 115 0 0 222

agmue:
Was mache ich falsch?

Du hast alles richtig gemacht und bekommst das richtige heraus: Das CRC-Byte ist korrekt.

Der Fehler liegt bei mir, ich habe einen copy-and-pase Fehler gemacht.

Statt der vom Themenstarter angegebenen Testdaten:
107, 108, 97, 117, 115, 0, 0, 222
hatte ich bei mir versehentlich die erste'1' von der 107 nicht mitkopiert, so dass ich diese Daten hatte:
07, 108, 97, 117, 115, 0, 0, 222
Sorry, falls ich Verwirrung gestiftet habe, aber ich hatte mir falsche Testdaten in meinen Sketch kopiert.

Ihr habt damit praktisch bewiesen, dass die Berechnung Unterschiede in den Daten erkennt :wink:

Gruß Tommy

Schau mal her ob dies zu Erhellung beiträgt:

https://www.ghsi.de/CRC/indexDetails.php?Polynom=100110001&Message=107,108,97,117,115,0,0

LG

jurs:
Du hast alles richtig gemacht und bekommst das richtige heraus: Das CRC-Byte ist korrekt.

Puh, da bin ich dann mal froh :smiley:

Tommy56:
Ihr habt damit praktisch bewiesen, dass die Berechnung Unterschiede in den Daten erkennt :wink:

Es gibt ja viele Formen des Beweises, diesen könnte man ungewollt nennen :slight_smile:

So, möchte mich bei allen bedanken!

Insbesondere natürlich bei Jurs, dessen motivierende Art und Ausdrucksweise mich immer zu besonderen Anstrengungen beflügelt.

@agmue: danke für Deine Verifzierung und den Beispielcode. Durchstiegen hab ich's immer noch nicht ganz, aber ich kann damit arbeiten. Ziel also (fast) erreicht.

Dann mal bis zum nächsten Mal!

Klaus_ww:
Durchstiegen hab ich’s immer noch nicht ganz, …

Dann laß Dir doch von Deinem Rechenknecht helfen, der versteht es ja. Zusammen mit den Erklärungen im Wiki sollte es dann klappen.

Gleiches Programm, mehr Ausgaben:

byte werte[] = {107, 108, 97, 117, 115, 0, 0, 0};
byte anz = sizeof(werte);

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  werte[anz - 1] = CRC8(werte, anz - 1);
  for (byte j = 0; j < anz; j++) {
    binaus(werte[j]);
    Serial.print('\t');
  }
  Serial.println();
  for (byte j = 0; j < anz; j++) {
    Serial.print(werte[j]);
    Serial.print('\t');
  }
  Serial.println();
}

void loop() {}

//CRC-8 - based on the CRC8 formulas by Dallas/Maxim
//code released under the therms of the GNU GPL 3.0 license
byte CRC8(const byte *data, byte len) {
  byte crc = 0x00;
  while (len--) {
    byte extract = *data++;
    Serial.print("extract: ");
    binaus(extract);
    for (byte tempI = 8; tempI; tempI--) {
      byte sum = (crc ^ extract) & 0x01;
      crc >>= 1;
      Serial.print("\tcrc: ");
      binaus(crc);
      Serial.print("\tsum: ");
      Serial.print(sum);
      if (sum) {
        crc ^= 0x8C;
      }
      Serial.print("\tcrc: ");
      binaus(crc);
      extract >>= 1;
    }
    Serial.println();
  }
  Serial.println();
  return crc;
}

void binaus(byte wert) {
  for (byte j = 0; j < 8; j++) {
    Serial.print(wert >> (7 - j) & 0x01, BIN);
  }
}

Danke, Du gibst Dir echt viel Mühe - und bereitest das Mahl mundgerecht gleich auf 8)

Ich werde mir das schon noch zu Gemüte führen, aktuell steht die Praxis aber im Vordergrund. Und so geschmeidig wie Du programmierst … da kann ich immer was lernen! Karma +

Klaus_ww:
… aktuell steht die Praxis aber im Vordergrund.

Dann habe ich noch einen Gang für das Mahl, Du nutzt util/crc16.h:

#include <util/crc16.h>
byte werte[] = {107, 108, 97, 117, 115, 0, 0, 0};
byte anz = sizeof(werte);

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  werte[anz - 1] = checkcrc(werte, anz - 1);
  for (byte j = 0; j < anz; j++) {
    Serial.print(werte[j]);
    Serial.print('\t');
  }
  Serial.println();
}

void loop() {}

int checkcrc(const byte *data, byte len) {
  uint8_t crc = 0, i;
  for (i = 0; i < len; i++) {
    crc = _crc_ibutton_update(crc, data[i]);
  }
  return crc;
}

Hallo,

durch einen Link kam ich hier hin. Ich spiele auch gerade mit crc8 und crc16 rum. Bei der Gegenprüfung wird es über alle Bytes laufen gelassen und am Ende prüft man das Ergebnis nur noch auf 0. Klappt soweit. Was mir jedoch nicht klar ist, welchen Unterschied es für die "Prüfsummensicherheit" macht ob ich crc8 oder crc16 oder crc32 etc. verwende?

To repeat, the probability of detecting any random error increases as the width of the checksum increases. Specifically, a 16-bit checksum will detect 99.9985% of all errors. This is far better than the 99.6094% detection rate of an eight-bit checksum, but not nearly as good as the 99.9999% detection rate of a 32-bit checksum. All of this applies to both CRCs and addition-based checksums.

https://barrgroup.com/Embedded-Systems/How-To/CRC-Math-Theory

Hallo,

aha, dass schlägt ja 2 Fliegen mit einer Klappe. 16 Bit ist schneller in der Berechnung und ist genauer. Schön. 32Bit habe ich nicht probiert.
Danke dir.

Habs mal vermessen. Fertige Funktion wie hier verwendet:
http://www.atmel.com/webdoc/avrlibcreferencemanual/group__util__crc_1ga95371c87f25b0a2497d9cba13190847f.html

Einmal herausgenommen als Funktion und dann nochmal die fertige Lib verwendet. Von den 3 Tests ist die 16Bit CRC mit Lib deutlich am schnellsten.

Datensatz inkl. crc 8 Byte groß

#include <util/crc16.h>

// Berechnung dauert 25,8µs
new_CRC8 = calc_CRC8 (sendDaten.asArray, (sizeof(Nachricht)-sizeof(sendDaten.crc)) );

// Berechnung dauert 38,7µs   
chk_CRC8 = calc_CRC8 (sendDaten.asArray, sizeof(Nachricht));
    

uint8_t calc_CRC8 (byte feld[], byte length)
{
  byte crc = 0x00;          // initial CRC value
  byte b = 0;
  
  while (length--) {
    crc = _crc8_ccitt_update(crc, feld[b++]);
    // gleich schnell wie _crc_ibutton_update
  }
  return crc;
}

Datensatz inkl. crc 9 Byte groß

#include <util/crc16.h>

// Berechnung dauert 14µs
new_CRC16 = calc_CRC16 (sendDaten.asArray, (sizeof(Nachricht)-sizeof(sendDaten.crc)) );

// Berechnung dauert 27µs   
chk_CRC16 = calc_CRC16 (sendDaten.asArray, sizeof(Nachricht));
    

uint16_t calc_CRC16 (byte feld[], byte length)
{
  unsigned int crc = 0xFFFF;          // initial CRC value
  byte b = 0;
  
  while (length--) {
    crc = _crc16_update(crc, feld[b++]);
  }
  return crc;
}
// Berechnung dauert 49,2µs
new_CRC16 = calc_CRC16 (sendDaten.asArray, (sizeof(Nachricht)-sizeof(sendDaten.crc)) );

// Berechnung dauert 60,5µs
chk_CRC16 = calc_CRC16 (sendDaten.asArray, sizeof(Nachricht));  
    

uint16_t calc_CRC16 (byte feld[], byte length)
{
  unsigned int crc = 0xFFFF;          // initial CRC value
  const unsigned int polynom = 0xA001;
  byte b = 0;
  
  while (length--) {
    crc ^= feld[b++];
    for (byte i = 0; i< 8; ++i)
    {
      if (crc & 1)
        crc = (crc >> 1) ^ polynom;    
      else
        crc = (crc >> 1);
    }
  }
  return crc;
}