CRC Berechnung wie die Funktion aufrufen?

OP #3120481
Lesenswert?

Hab wieder mal ein Problem:
Es geht um eine CRC Berechnung.
Über die suche habe ich schon eine passende Funktion gefunden:
Beitrag "CRC Berechnung"

Jetzt wollte ich von einem String den CRC berechnen:
020600000001 CRC: 4839

Dazu habe ich die Routine kopiert und will sie nun folgendermaßen 
aufrufen:
1
char buffer[6];
2
    int  num;
3
    int temp, temp2;
4

5
buffer[0]= 0x02;
6
    buffer[1]= 0x06;
7
    buffer[2]= 0x00;
8
    buffer[3]= 0x00;
9
    buffer[4]= 0x00;
10
    buffer[5]= 0x01;
11
     num = checkSum(buffer,6);
12

13
      temp = (uint8_t) num; //(Lowbyte. uint8_t oder char typcasten)
14
      temp = (uint8_t) (num>>8); // Highbyte
15
      uart_puts();

Leider sendet die Schnittstelle gleich 16 Zeichen statt nur die zwei CRC 
Werte. Muss ich noch eine typumwandlung vornehmen? Oder wo liegt der 
Fehler?
OP #3120497
Lesenswert?

oh vergessen:
1
/* 9600 baud */
2
#define UART_BAUD_RATE      9600
3

4
int32_t  checkSum(int32_t input[],uint8_t length)
5
{
6
  int32_t crc = 0xFFFF;
7
  int32_t mask = 0x01;
8
  int32_t CRC = 0xA001;
9

10

11

12
  for (uint8_t i=0 ; i<length ; i++)
13
  {
14
    crc = crc ^input[i];
15

16
    for (uint8_t j=0 ; j<8 ; j++)
17
    {
18
      if((crc & mask) == 0)
19
      {
20
        crc = crc >> 1;
21
      }
22
      else
23

24
      {
25
        crc = crc >> 1;
26
        crc = crc ^ CRC;
27
      }
28
    }
29
  }
30

31

32

33

34
return crc;
35

36
}
37

38

39
int main(void)
40
{
41
    unsigned int c;
42
    int buffer[6];
43
    int  num;
44
    int temp, temp2;
45
    /*Sendevariablen*/
46
    char adress ; /* Slave Adresse  02*/
47
    char function ; /* Funktion  04*/
48

49

50
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
51

52
    /*
53
     * now enable interrupt, since UART library is interrupt controlled
54
     */
55
    sei();
56
    buffer[0]= 0x02;
57
    buffer[1]= 0x06;
58
    buffer[2]= 0x00;
59
    buffer[3]= 0x00;
60
    buffer[4]= 0x00;
61
    buffer[5]= 0x01;
62
     num = checkSum(buffer,6);
63

64
      temp = (uint8_t) num; //(Lowbyte. uint8_t oder char typcasten)
65
      temp = (uint8_t) (num>>8); // Highbyte
66
      uart_puts(temp);
Gast #3120507
Lesenswert?

temp = (uint8_t) num; //(Lowbyte. uint8_t oder char typcasten)
 temp = (uint8_t) (num>>8); // Highbyte

ist genauso unsinn, der 2. Anweisung überschreibt die 1.

Dann gibt es die CRC funktion schon in der AVR Lib, die muss man nicht 
kopieren.
Gast #3120513
Lesenswert?

Chris tian schrieb:
> ok das wusste ich nicht. In welcher lib muss ich denn sucehn und wie
schau einfach mal ein den include verzeichniss vom AVR nach, dort liegt 
eine crc header dateien rum.

> heißt die funktion?
keine ahung, steht in der header datei

> Es muss CRC (Modbus) sein. wie man hier berechnen kann:
auch keine Ahnung ob sie gleich sein.


Aber das ändert nichts an den Fehlern in deinem Programm, das senden ist 
falsch.
Gast #3120518
Lesenswert?

Hallo,

du führst eine byte-weise Berechnung einer 16-bit chksum durch,
dann musst du auch die Daten byte-weise anliefern und einen 16-bit Wert 
zurückgeben

also:

> uint16_t  checkSum(uint8_t input[], uint8_t length)
> {
>   int16_t crc = 0xFFFF;
>   int16_t mask = 0x01;
>   int16_t CRC = 0xA001;
>
>
>
>   for (uint8_t i=0 ; i<length ; i++)
>   {
>     crc = crc ^input[i];
>
>     for (uint8_t j=0 ; j<8 ; j++)
>     {
>       if((crc & mask) == 0)
>       {
>         crc = crc >> 1;
>       }
>       else
>
>       {
>         crc = crc >> 1;
>         crc = crc ^ CRC;
>       }
>     }
>   }
>
> return crc;
>
> }

Den Aufruf dementsprechend abändern !!!

Gruss Karlheinz
OP #3121087
Lesenswert?

Hab das jetzt so abgeändert:
1
int16_t  checkSum(int8_t input[],uint8_t length)
2
{
3
  int16_t crc = 0xFFFF;
4
  int16_t mask = 0x01;
5
  int16_t CRC = 0xA001;
6

7

8

9
  for (uint8_t i=0 ; i<length ; i++)
10
  {
11
    crc = crc ^input[i];
12

13
    for (uint8_t j=0 ; j<8 ; j++)
14
    {
15
      if((crc & mask) == 0)
16
      {
17
        crc = crc >> 1;
18
      }
19
      else
20

21
      {
22
        crc = crc >> 1;
23
        crc = crc ^ CRC;
24
      }
25
    }
26
  }
27

28

29

30

31
return crc;
32

33
}

Aufruf:
1
int main(void)
2
{
3
    unsigned int c;
4
    int8_t buffer[6];
5
    int16_t  num;
6
    int8_t temp, temp2;
7
    /*Sendevariablen*/
8
    char adress ; /* Slave Adresse  02*/
9
    char function ; /* Funktion  04*/
10

11

12
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
13

14
    /*
15
     * now enable interrupt, since UART library is interrupt controlled
16
     */
17
    sei();
18
    buffer[0]= 0x02;
19
    buffer[1]= 0x06;
20
    buffer[2]= 0x00;
21
    buffer[3]= 0x00;
22
    buffer[4]= 0x00;
23
    buffer[5]= 0x01;
24
     num = checkSum(buffer,6);
25

26
      temp = (uint8_t) num; //(Lowbyte. uint8_t oder char typcasten)
27
      temp2 = (uint8_t) (num>>8); // Highbyte
28

29
      uart_putc(temp);
30
      uart_putc(temp2);
Jetzt gibt er mir auch nur noch 2 Zeichen aus., Allerdings sidn das noch 
nicht die richtigen
Ausgegeben wird 0x57 0x43 und nicht 0x39 0x48
#3121101
Lesenswert?

Deine Verwendung von

int16_

macht mich nervös.

Wenn du auf Byte-Ebene arbeitest, dann ist der Datentyp der Wahl 
praktisch IMMER ein unsigned Wert. Alle 8 Bit sind gleichberechtigt - es 
gibt keine Sonderfälle, weil eines der Bits die Sonderrolle eines 
Vorzeichenbits hat und anders behandelt werden muss.

uint8_t   bzw.  uint16_t

Was denkst du, was wohl
  crc = crc >> 1;
ergibt, wenn crc den Wert 0xFFFF hat und vom Datentyp int16_t ist? Gut, 
um fair zu sein: Das Ergebnis davon ist laut C-Standard undefiniert, 
aber auf allen Implementierungen, die 2-er Komplement-Arithmetik 
benutzen kommt immer dasselbe raus. Nämlich 0xFFFF. Wodurch sich 
automatisch die Frage ergibt: wozu dann überhaupt schieben, wenn das 
Ergebnis sowieso wieder identisch zum Ausgangspunkt ist?

Der, von dem du die Funktion abgeschrieben hast, war genauso auf einem 
Auge blind und hat sein Heil in der Verwendung eines int32_t(!) gesucht, 
anstatt den Stier bei den Hörnern zu packen und sich darüber klar zu 
werden, dass Datentypen nicht einfach nur eine 'Verzierung' des Codes 
bedeuten sondern dass da etwas dahinter steckt.
#3121124
Lesenswert?

Und gewöhn dir sowas

char buffer[6];

..

   buffer[0]= 0x02;
    buffer[1]= 0x06;
    buffer[2]= 0x00;
    buffer[3]= 0x00;
    buffer[4]= 0x00;
    buffer[5]= 0x01;


ab!

char verwendest du, wenn du es mit Strings, also mit Texten, zu tun 
hast! Und zu sonst nichts anderem.

Für Byte benutzt du immer und ausschliesslich uint8_t und nichts 
anderes. Selbst dann, wenn du von irgendwo Code bekommst, bei dem ein 
char als Ersatz für 'Byte' benutzt wird. Dann siehst du den Code durch, 
ob es irgendwo ein Anzeichen gibt, ob hier ein char als 'signed' 
aufgefasst wird und wenn nicht, dann änderst du das um auf uint8_t.

Am besten du machst es dir zur Regel, dass du 3 'kleine' Datentypen 
hast.

   int8_t       für kleine Zahlen, die ein Vorzeichen brauchen

   uint8_t      für kleine Zahlen, die kein Vorzeichen haben.
                Das ist genau das, was weithin als Byte bekannt ist

   char         Für Zeichen bzw. Texte.


Benutze die Datentypen sinngemäss nach diesem einfachen Schema und du 
hast weniger Probleme.
OP #3121167
Lesenswert?

Danke für deine Hinweise, ich werde versuchen mich daran zu halten.
>>char buffer[6];
 hatte ich in späteren posts schon abgeändert.

ICh muss ja auch zugeben das ich keine ahnung von der CRC Berechnung 
habe.
Aber eshalb habe ich mir auch vermeintlich lauffähige Funktionen 
gesucht, welche ich übernehmen knn und das Rasd nicht nochmal neu 
erfinden.
Da ich dachte das die Funktion läuft wie im anderen Threat beschrieben, 
habe ich einfach diese genommen.
Da sie aber niciht das macht was sie soll hab ich eben hier gefragt, wo 
der Fehler liegt. Da jemand der jeden Tag mit sowas zu tun hat bestimmt 
mehr Ahnung hat.
Ich bin den Anweisungen gefolgt aber es kommt immernoch ein falscher 
Wert raus.
Kann mir jetzt nochmal jemand helfen das Teil zum laufen zu bringen?
#3121183
Lesenswert?

Chris tian schrieb:
> Jetzt gibt er mir auch nur noch 2 Zeichen aus., Allerdings sidn das noch
> nicht die richtigen

Er macht genau das, was du programmiert hast. putc(c) erwartet als 
Parameter ein druckbares Zeichen. Du übergibst aber eine 8-Bit Zahl. 
Also entweder die 8 Bit in zwei HEX Werte wandeln oder per itoa() in 
einen String wandeln und dann ausgeben.
Gast #3121186
Lesenswert?

Georg G. schrieb:
> Er macht genau das, was du programmiert hast. putc(c) erwartet als
> Parameter ein druckbares Zeichen. Du übergibst aber eine 8-Bit Zahl.
> Also entweder die 8 Bit in zwei HEX Werte wandeln oder per itoa() in
> einen String wandeln und dann ausgeben.

er will (vermutlich) es aber als binary übertragen und nicht als Text. 
Das Problem wird wohl die CRC selber und nicht mehr die übertragung 
sein.
Gast #3121385
Lesenswert?

Simon K. schrieb:
> "putc" steht mit Sicherheit für "put char". Und char bedeutet dabei
> Zeichen, wie Karl Heinz dargestellt hat.

es geht aber um die übertragung auf UART und diese kennt keine zeichen. 
Hier gibt es um 8bit. Es macht wenig sinn noch eine Extra funktion für 
unsigned char zu schreiben. Aus dem Grund kann man hier damit leben das 
man der funktion einfach einen uint8 geben kann.
#3121410
Lesenswert?

Simon K. schrieb:
> Peter II schrieb:
>> Peter II schrieb:
>>> erwartet als
>>>> Parameter ein druckbares Zeichen
>>
>> das stimm auch nicht. Er erwartet 8bit und diese werden übertragen.
>
> "putc" steht mit Sicherheit für "put char". Und char bedeutet dabei
> Zeichen, wie Karl Heinz dargestellt hat.

Yep.
Wobei ich das historisch sehen würde. Die Funktion ja schon zu Zeiten 
Kernighan&Ritchies putc geheissen.

> Es macht wenig sinn noch eine Extra funktion für unsigned char zu
> schreiben.

Aber auch nur, weil wir wissen, dass dieses putc zb nach einem CR kein 
LF nachschieben wird und zb XON/XOFF nicht ausfiltert.
Ich kann nur jedem raten: Nehmt die Unterscheidung Zeichen-Byte ernst! 
Und nur weil man bisher mit ignorieren durchgekommen ist, bedeutet das 
nicht, dass das immer so sein wird.
#3121713
Lesenswert?

Chris tian schrieb:
> Es muss CRC (Modbus) sein. wie man hier berechnen kann:

LOL, über 20 Beiträge, was in einem beantwortet werden kann:
http://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf
Schau dir die Seiten 42 und 43 an, da wird dir eine CRC16 Berechnung auf 
Array-Ebene vorgekaut. nur geringfügig anpassen und fertig ist das ganze

Hier sonst noch meine Version (Läuft auf einem STM32 einwandfrei, und 
ist auch mit diversen Modbus-Test-Programmen überprüft worden)
1
sf_uint16 u16GetCRC(sf_uint8* p_pu8Data, sf_uint16 p__u16DataLen)
2
{
3
    static sf_uint8 au8CRCHi[] = {
4
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
5
        0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
6
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
7
        0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
8
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
9
        0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
10
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
11
        0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
12
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
13
        0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
14
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
15
        0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
16
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
17
        0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
18
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
19
        0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
20
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
21
        0x40
22
    };
23
    static sf_int8 an8CRCLo[] = {
24
        0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
25
        0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
26
        0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
27
        0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
28
        0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
29
        0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
30
        0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
31
        0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
32
        0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
33
        0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
34
        0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
35
        0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
36
        0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
37
        0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
38
        0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
39
        0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
40
        0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
41
        0x40
42
    };  
43
  sf_uint8 u8CRCHi = 0xFF ;                                                            /// high byte of CRC initialized 
44
  sf_uint8 u8CRCLo = 0xFF ;                                                            /// low byte of CRC initialized 
45
  sf_uint8 u8Index = 0;                                                               /// will index into CRC lookup table 
46
  
47
  while (p__u16DataLen--)                                                             /// pass through message buffer 
48
  {
49
    u8Index = u8CRCHi ^ *p_pu8Data++ ;                                              /// calculate the CRC 
50
    u8CRCHi = u8CRCLo ^ au8CRCHi[u8Index] ;
51
    u8CRCLo = an8CRCLo[u8Index] ;
52
  }   
53
  return ((u8CRCHi << 8) | u8CRCLo);
54
}
55

56
int main (void)
57
{
58
  sf_uint8 test[] = {0,1,2,3,4,5,6};
59
  sf_uint16 checksum = u16GetCRC(test, (sizeof(test)/sizeof(test[0]));
60
  printf("%x",checksum);
61
  while(1);
62
}
P.S. Ist ziemlich sicher die schnellere Variante.

Gruss
Persönliche Seite #3121783
Lesenswert?

Peter II schrieb:
> Simon K. schrieb:
>> "putc" steht mit Sicherheit für "put char". Und char bedeutet dabei
>> Zeichen, wie Karl Heinz dargestellt hat.
>
> es geht aber um die übertragung auf UART und diese kennt keine zeichen.
> Hier gibt es um 8bit. Es macht wenig sinn noch eine Extra funktion für
> unsigned char zu schreiben. Aus dem Grund kann man hier damit leben das
> man der funktion einfach einen uint8 geben kann.

Du weißt aber doch gar nicht, was putc macht? Vielleicht wandelt es 
Zeichen von lowercase nach uppercase oder ähnliches.

Man macht genau das mit der Funktion, wofür sie gedacht ist. Binärbytes 
übertragen mit dieser Funktion ist das nunmal nicht.
Persönliche Seite #3121801
Lesenswert?

Peter II schrieb:
> Simon K. schrieb:
>> Man macht genau das mit der Funktion, wofür sie gedacht ist. Binärbytes
>> übertragen mit dieser Funktion ist das nunmal nicht.
>
> dann bau doch die Lib um wenn du willst. Ich weiss das sie auch
> Binärbytes sauber überträgt und verwende sie einfach.

Tu das. Nur wunder dich nicht, wenn man über dich flucht, wenn dein 
Programm an jemand mit mehr Anspruch an Struktur und Ordnung gerät.

Stichwort defensives Programmieren. Das sollte so mancher mal hier 
nachschlagen.

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