8-bitars CRC-kod

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

8-bitars CRC-kod

Inlägg av jesse »

Ofta överför man ju data fram och tillbaks mellan kretsar och kort med olika metoder. t.ex SPI eller UART.
Flera av dessa metoder saknar ju någon form av felkoll, så jag har gjort en enkel rutin för att beräkna en 8-bitars crc-kod, för att använda vid dataöverföring.

funktionen används så här:

1) du sätter den globala variabeln crc till 0xff (eller annan valfri startkod, dock helst ej 0x00 - se nedan)
2) för varje byte du sänder så anropas funktionen med databyten som argument.
3) när sista byten är överförd skickar du crc. (man kan också välja att skicka t.ex. 0xff - crc eller liknande)

konstanten CRCPOLYNOM kan ha olika värden, men inte vilket värde som helst. Det finns regler för det. 0x07 motsvarar polynomet x8+x2+x+1 vilket förekommer inbyggt i en del kretsar, t.ex. AD-omvandlare med SPI-buss.

på mottagarsidan gör du exakt samma sak, fast med de mottagna byten. Du måste ha en bestämd längd på datapaketet, alternativ ange antalet bytes i början, så att du vet när du ska förvänta dig en crc.
när du tar emot crc-koden gör du en koll om den stämmer med din globala variabel crc. Jag brukar returnera skillnaden från mottagarrutinen så att jag får ett värde som skiljer sig från noll om det blivit fel.

Man kan faktiskt använda crc-koden för att göra enkel diagnostik: om alla data består av 0xff så kommer du att få samma kod (om du har ett fixt antal bytes), likaså för 0x00. Dessa situationer uppstår oftare än andra, t.ex. pga en oansluten enhet, strömbortfall, logisk felkoppling eller kapad kabel. Då kan man i mjukvaran skilja på dessa tillstånd och andra överföringsfel. Att man inte ska använda 0x00 som startvärde beror på att crc alltid kommer att bli 0x00 om alla data också är 0x00... det är ju inte så osannolikt att alla data blir 0x00 om man saknar ett pull-up motstånd t.ex. Då är det tråkigt om mjukvaran inte detekterar det felet.

Här kommer beräkningsfunktionen:

Kod: Markera allt

uint8_t crc; // global variabel

void crccalc(uint8_t data) { // 8 bitars CRC rutin
	// crc ändras för varje databyte in, startvärde ska vara 0.
	// argument: data = inkommen / skickad byte
	#define CRCPOLYNOM 0x07
	uint8_t i, bit;
	for (i=7;i<8;i--) {
		bit = ( crc ^ data );
		crc<<=1;
		data<<=1;
		if (bit & 0x80 )
			crc^= CRCPOLYNOM; 
	}
}
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: 8-bitars CRC-kod

Inlägg av blueint »

Man bör nog använda minst CRC 16-bit för att det ska ge någon vettig garanti mot fel.
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Re: 8-bitars CRC-kod

Inlägg av vfr »

Både ja och nej. Egentligen håller jag med. 16-bit is the shit. Å andra sidan så är 8-bit CRC mycket bättre än 8-bit summering eller XOR som man ofta ser. Dom reagerar ö.h.t inte på en nollbyte, vilket gör att man kan bara tappa bort en nollbyte utan att märka det i checksumman.

Jag har kört en del på alla varianterna och allting numera i mina protokolldefinitioner är 16-bitars CRC.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: 8-bitars CRC-kod

Inlägg av jesse »

16-bitars crc funktioner finns färdiga i biblioteken för AVR GCC tror jag. 8-bitars är väl en kompromiss egentligen, men som sagt bättre än checksumma. Det kan vara bra med 8-bitars crc om det är lite tidskritiskt.
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 7487
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Re: 8-bitars CRC-kod

Inlägg av Marta »

T.ex. DS18B20 temperatursensor och även andra s.k. one-wire-bus produkter därifrån använder 8-bit CRC. Dessvärre initierad till 0, av någon anledning. En finess med 0-initiering på denna är att crc stannar på just 0 när det är rätt om mottagaren räknar crc på alla inkomna bytes inklusive den avslutande crc. När meddelandet inte börjar med nulls så är det inget problem vad beträffar överföringsfel. Polynomet de använder brukar kallas DOW-CRC där bokstäverna lär stå för Dallas One Wire.

Skall det gå snabbt så är tabell-crc det bästa. I fallet 8-bit blir det då bara att göra EOR med den ackumulerade crc'n och sedan använda resultatet för att indexera i en tabell för att få nästa crc.

Det går att göra både crc16 och crc32 med tabell. Med 8-bit ingångsvärde är det alltid 256 platser i tabellen som då är 16 eller 32 bitar bred. Det behövs även lite EOR och annat för de bredare varianterna.
Användarvisningsbild
mri
Inlägg: 1165
Blev medlem: 15 mars 2007, 13:20:50
Ort: Jakobstad, Finland
Kontakt:

Re: 8-bitars CRC-kod

Inlägg av mri »

Vad vinner du på att skriva for-loopen som:

Kod: Markera allt

uint8_t i, bit;
for (i=7;i<8;i--) {
förutom att göra den svårläst?
Användarvisningsbild
Icecap
Inlägg: 26658
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: 8-bitars CRC-kod

Inlägg av Icecap »

Den är väl ganska tydlig tycker jag.

Den räknar ner till och med noll och när den overflower kommer värdet definitivt att vara större än 8.

Men det hade faktisk varit mycket mer "normalt" att läsa med
for(i = 0; i < 8; i++) och resultatet hade blivit det samma.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: 8-bitars CRC-kod

Inlägg av jesse »

haha, det tänkte jag inte på. Det var några månader sedan jag gjorde koden, och vi hade en diskussion på forumet om hur man optimerar snabbaste loopen i C eller hur det nu var. Detta måste varit en relik från då. Nu hade jag skrivit "som vanligt"... Tror inte maskinkoden blir bättre på något vis av denna formulering, det enda är väl som sagt att den blir svårläst. :)
Användarvisningsbild
mri
Inlägg: 1165
Blev medlem: 15 mars 2007, 13:20:50
Ort: Jakobstad, Finland
Kontakt:

Re: 8-bitars CRC-kod

Inlägg av mri »

Icecap: Loopen antyder att programmeraren förstått hur språket och variabler fungerar på en mer detaljerad och lägre nivå, dvs att en unsigned variabel vid 0 slår runt till ett stort positivt tal, osv.
Men, om man inte har väldigt goda skäl att göra på det här sättet skall man definitivt hålla sig till "standardsättet" för att göra koden lättläst för andra och inte minst för sig själv! I det här fallet vill man ju bara loopa 8 gånger.
Tycker man om sådana här udda sätt att skriva i övrigt enkla saker på har man nog levt i sin egen lilla bubbla för länge. :)
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: 8-bitars CRC-kod

Inlägg av jesse »

Det visade sig att jag råkade kopiera en testversion istället för originalet, där jag hade experimenterat lite med hur det kompilerades och hur det betedde sig vid olika formuleringar. Sedan har det senaste exemplet helt enkelt legat kvar och jag råkade leta upp den versionen när jag skrev inlägget. Verkar ju annars lite vansinnigt att skriva så.... :roll:
Mr M
Inlägg: 165
Blev medlem: 20 januari 2006, 21:35:14

Re: 8-bitars CRC-kod

Inlägg av Mr M »

mri skrev:Vad vinner du på att skriva for-loopen som:

Kod: Markera allt

uint8_t i, bit;
for (i=7;i<8;i--) {
förutom att göra den svårläst?
For-loopen körs inte eftersom variabel i redan är mindre än 8. :lol:
snigelen
Inlägg: 815
Blev medlem: 8 maj 2009, 11:02:14
Ort: Lund

Re: 8-bitars CRC-kod

Inlägg av snigelen »

Jodå. Prova så får du se. Den körs så länge i är mindre än 8. Dvs ända tills i blir 0-1=255 (för uint8_t).
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: 8-bitars CRC-kod

Inlägg av jesse »

jag tror nog att for-loopen körs, eftersom den används i flera av mina applikationer, och gör rätt.
Skriv svar