Il principio di CRC
consiste nel
trattare le sequenze binarie come dei polinomi binari, cioè dei
polinomi i cui
coefficienti corrispondono alla sequenza binaria.
Così la sequenza binaria 0110101001
può
essere rappresentata con la forma polinomiale seguente:
0*X9 + 1*X8 + 1*X7 + 0*X6 + 1*X5 + 0*X4 + 1*X3 + 0*X2 + 0*X1 + 1*X0 ovvero
X8 + X7 + X5 + X3 + X0 ovvero
X8 + X7 + X5 + X3 + 1
In questa modo, il bit
di peso minore della
sequenza (il bit più a destra) rappresenta il grado 0 del polinomio
(X0 = 1), il quarto bit partendo da destra
rappresenta il grado 3
del polinomio (X3)…
Una sequenza di n
bits costituisce
quindi un polinomio di grado massimo n-1.
Tutte
le espressioni
polinomiali sono manipolate successivamente con l'aritmentica modulo
2.
Normalmente
come Polinomio
Generator G si sceglie un numero primo che inizi e finisca con 1,
alcuni esempi
sono:
1001
- 11101 -
1100000001111 (CRC12) - 11000000000000101 (CRC16)
Sia M il messaggio da
trasmettere di valore:
1010
0011 1010 1100
Si assume che G
sia 11010
Chiamiamo M'
il messaggio con associato
il CRC.
Il CRC saràM / G.
Il codice CRC
è così uguale al resto
della divisione polinomiale di M
/
G dove ad M sono stati concatenati n
bits nulli (0)
corrispondenti al grado di G.
Dato che nel nostro caso G
= 11010 si
dice che è di grado 4
per cui si ha
che G(bit)=4
quindi si tratta di
aggiungere 4 bits
a 0 ad M che diventa:
M = 1010 0011 1010 11000000.
Qui sotto c'è l'esempio su come calcolare il CRC.
zzzzz
Per creare
M' basta
concatenare il CRC
così ottenuto, ai bits del messaggio da
trasmettere M
:
M' = 1010 0011
1010
1100 + 1010
M' = 1010 0011
1010
1100 1010
In generale l'algoritmo
usato può essere
rappresentato come sotto.
0 == CRC che essendo zero è OK
I polinomi generatori più frequentemente impiegati sono :
/* bit by bit
* The width of the CRC calculation and result.
* Modify the typedef for a 16 or 32-bit CRC standard.
*/
typedef uint8_t crc;
#define WIDTH (8 * sizeof(crc))
#define TOPBIT (1 << (WIDTH - 1))
crc
crcSlow(uint8_t const message[], int nBytes)
{
crc remainder = 0;
/*
* Perform modulo-2 division, a byte at a time.
*/
for (int byte = 0; byte < nBytes; ++byte)
{
/*
* Bring the next byte into the remainder.
*/
remainder ^= (message[byte] << (WIDTH - 8));
/*
* Perform modulo-2 division, a bit at a time.
*/
for (uint8_t bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}
}
/*
* The final remainder is the CRC result.
*/
return (remainder);
} /* crcSlow() */
crc crcTable[256];
void
crcInit(void)
{
crc remainder;
/*
* Compute the remainder of each possible dividend.
*/
for (int dividend = 0; dividend < 256; ++dividend)
{
/*
* Start with the dividend followed by zeros.
*/
remainder = dividend << (WIDTH - 8);
/*
* Perform modulo-2 division, a bit at a time.
*/
for (uint8_t bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}
/*
* Store the result into the table.
*/
crcTable[dividend] = remainder;
}
} /* crcInit() */
crc
crcFast(uint8_t const message[], int nBytes)
{
uint8_t data;
crc remainder = 0;
/*
* Divide the message by the polynomial, a byte at a time.
*/
for (int byte = 0; byte < nBytes; ++byte)
{
data = message[byte] ^ (remainder >> (WIDTH - 8));
remainder = crcTable[data] ^ (remainder << 8);
}
/*
* The final remainder is the CRC.
*/
return (remainder);
} /* crcFast() */
Esempio Loop driven eTable driven pronto all'uso fatto per
Windows sviluppato
usando Dev-C++
per scaricarlo
cliccate qui.
Il Dev-C++
è free ad è possibile
prenderlo qui,
se volete la mia
versione di Dev-C++
clicate qui.
Il sito originale dell'esempio del CRC sopra menzionato è: http://www.netrino.com/code/crc.zip
// Programma che calcola il CRC di una sequenza di caratteri
// immessi da tastiera, terminati con EOF
#include <stdio.h>
#define PG 0x11021 /* Polinomio generatre */
int crc(int oldcrc, unsigned char toadd); /* Aggiunge toadd al CRC calcolato */
main()
{
int resto=0; // CRC
int c; // Carattere letto
int i = 0; // Contatore dei caratteri
printf("Inserisci una sequenza di caratteri: ");
while((c=getchar())!=EOF)
{
resto=crc(resto,c); // Agginge il carattere letto al CRC dei precedenti
i++; // Conta i caratteri letti
}
resto=crc(resto,0); // Agginge al CRC i primi otto zeri
resto=crc(resto,0); // Agginge al CRC i secondi otto zeri in fondo
printf("\nLetti %d caratteri, CRC calcolato: %x\n", i, resto);
}
/* Aggiunge i bit del codice oldcrc al dividendo, per
* calcolare il nuovo CRC
*/
int crc(int oldcrc, unsigned char toadd)
{
int i; // Indice del bit
// I bit del carattere vanno trattati dal piu' significativo al meno
for(i=0;i<8;i++) // Per ogni bit del byte
{
oldcrc= (oldcrc<<1) | (toadd>>7); // Aggiunge il bit piu' significativo
// del codice in fondo al CRC,
// spostando a sinistra i bit del CRC
toadd <<= 1; // Toglie il bit gestito dal codice
if((oldcrc & 0x10000) != 0) // Se il divisore ci sta' (alla sua maniera)
{
oldcrc=oldcrc^PG; // Allora lo toglie (sottrazione senza riporti,
// quindi XOR
}
}
return oldcrc; // Restituisce il CRC ricalcolato
}
Polynomial: x16 + x12 + x5 + 1
Start Value: 0xFFFF
CRC_POLYNOM = 0x8408;
CRC_PRESET = 0xFFFF;
C-Example:
unsigned internal CRC = CRC_PRESET;
for (i = 0; i < cnt; i++) /* cnt = number of protocol bytes
without CRC
*/
{
crc ^= DATA[i];
for (j = 0; j < 8; j++)
{
if (crc
& 0x0001)
crc = (crc >> 1) ^
CRC_POLYNOM;
else
crc = (crc >> 1);
}
}