链接2
的博客,上面讲的很详细,从奇偶校验、累加和校验、模2运算到CRC校验和优化。并提供了相应的参考链接,很值得参考。如果要深入理解算法的实现原理需要参考链接1
参考
crc16代码
/*
* download from : https://www.cnblogs.com/youthshouting/p/4388232.html
* another link : http://mdfs.net/Info/Comp/Comms/CRC16.htm
* another link : https://blog.csdn.net/liyuanbhu/article/details/7882789
*/
#include
int CalCrc(int crc, const char *buf, int len)
{
unsigned int byte;
unsigned char k;
unsigned short ACC,TOPBIT;
// unsigned short remainder = 0x0000;
unsigned short remainder = crc;
TOPBIT = 0x8000;
for (byte = 0; byte < len; ++byte)
{
ACC = buf[byte];
remainder ^= (ACC <<8);
for (k = 8; k > 0; --k)
{
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^0x8005;
}
else
{
remainder = (remainder << 1);
}
}
}
remainder=remainder^0x0000;
return remainder;
}
int main(int argc, char* argv[])
{
char buffer[22] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x02, 0x03, 0x04};
unsigned short crc = CalCrc(0, buffer, 20);//计算得到的16位CRC校验码
buffer[21] = (char)crc;//取校验码的低八位
buffer[20] = (char)(crc >> 8);//取校验码的高八位
//接收方在接收到buffer中的数据时,代入CalCrc进行计算,若result的值为0,则说明数据传输过程无误
unsigned short result = CalCrc(0, buffer, 22);
if (result == 0){
printf("crc result is right\n");
}
return 0;
}
crc.h
/*
* copy from : https://blog.csdn.net/liyuanbhu/article/details/7882789
* refer from book : Programming Embedded Systems in C and C++, section 6
*/
/*
crc.h
*/
#ifndef CRC_H_INCLUDED
#define CRC_H_INCLUDED
/*
* The CRC parameters. Currently configured for CCITT.
* Simply modify these to switch to another CRC Standard.
*/
/*
#define POLYNOMIAL 0x8005
#define INITIAL_REMAINDER 0x0000
#define FINAL_XOR_VALUE 0x0000
*/
#define POLYNOMIAL 0x1021
#define INITIAL_REMAINDER 0xFFFF
#define FINAL_XOR_VALUE 0x0000
/*
#define POLYNOMIAL 0x1021
#define POLYNOMIAL 0xA001
#define INITIAL_REMAINDER 0xFFFF
#define FINAL_XOR_VALUE 0x0000
*/
/*
* The width of the CRC calculation and result.
* Modify the typedef for an 8 or 32-bit CRC standard.
*/
typedef unsigned short width_t;
#define WIDTH (8 * sizeof(width_t))
#define TOPBIT (1 << (WIDTH - 1))
/**
* Initialize the CRC lookup table.
* This table is used by crcCompute() to make CRC computation faster.
*/
void crcInit(void);
/**
* Compute the CRC checksum of a binary message block.
* @para message, 用来计算的数据
* @para nBytes, 数据的长度
* @note This function expects that crcInit() has been called
* first to initialize the CRC lookup table.
*/
width_t crcCompute(unsigned char * message, unsigned int nBytes);
#endif // CRC_H_INCLUDED
crc.c
/*
* copy from : https://blog.csdn.net/liyuanbhu/article/details/7882789
* refer from book : Programming Embedded Systems in C and C++, section 6
*/
/*
*crc.c
*/
#include "crc.h"
/*
* An array containing the pre-computed intermediate result for each
* possible byte of input. This is used to speed up the computation.
*/
static width_t crcTable[256];
/**
* Initialize the CRC lookup table.
* This table is used by crcCompute() to make CRC computation faster.
*/
void crcInit(void)
{
width_t remainder;
width_t dividend;
int bit;
/* Perform binary long division, a bit at a time. */
for(dividend = 0; dividend < 256; dividend++)
{
/* Initialize the remainder. */
remainder = dividend << (WIDTH - 8);
/* Shift and XOR with the polynomial. */
for(bit = 0; bit < 8; bit++)
{
/* Try to divide the current data bit. */
if(remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = remainder << 1;
}
}
/* Save the result in the table. */
crcTable[dividend] = remainder;
}
} /* crcInit() */
/**
* Compute the CRC checksum of a binary message block.
* @para message, 用来计算的数据
* @para nBytes, 数据的长度
* @note This function expects that crcInit() has been called
* first to initialize the CRC lookup table.
*/
width_t crcCompute(unsigned char * message, unsigned int nBytes)
{
unsigned int offset;
unsigned char byte;
width_t remainder = INITIAL_REMAINDER;
/* Divide the message by the polynomial, a byte at a time. */
for( offset = 0; offset < nBytes; offset++)
{
byte = (remainder >> (WIDTH - 8)) ^ message[offset];
remainder = crcTable[byte] ^ (remainder << 8);
}
/* The final remainder is the CRC result. */
return (remainder ^ FINAL_XOR_VALUE);
} /* crcCompute() */
main.c
/*
* copy from : https://blog.csdn.net/liyuanbhu/article/details/7882789
* refer from book : Programming Embedded Systems in C and C++, section 6
*/
#include "crc.h"
#include
int main(int argc, char* argv[])
{
char buffer[22] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x02, 0x03, 0x04};
crcInit();
width_t crc = crcCompute(buffer, 20);
//unsigned short crc = CalCrc(0, buffer, 20);//计算得到的16位CRC校验码
buffer[21] = (char)crc;//取校验码的低八位
buffer[20] = (char)(crc >> 8);//取校验码的高八位
//接收方在接收到buffer中的数据时,代入CalCrc进行计算,若result的值为0,则说明数据传输过程无误
width_t result = crcCompute(buffer, 22);
//unsigned short result = CalCrc(0, buffer, 22);
if (result == 0){
printf("crc result is right\n");
}
return 0;
}
参考
代码
下面的代码总共使用了四种产生crc校验码的方法
/*
* download from : http://www.zorc.breitbandkatze.de/crctester.c
* a link is : http://www.zorc.breitbandkatze.de/crc.html
*/
// ----------------------------------------------------------------------------
// CRC tester v1.3 written on 4th of February 2003 by Sven Reifegerste (zorc/reflex)
// This is the complete compilable C program, consisting only of this .c file.
// No guarantee for any mistakes.
//
// changes to CRC tester v1.2:
//
// - remove unneccessary (!(polynom&1)) test for invalid polynoms
// (now also XMODEM parameters 0x8408 work in c-code as they should)
//
// changes to CRC tester v1.1:
//
// - include an crc&0crcmask after converting non-direct to direct initial
// value to avoid overflow
//
// changes to CRC tester v1.0:
//
// - most int's were replaced by unsigned long's to allow longer input strings
// and avoid overflows and unnecessary type-casting's
// ----------------------------------------------------------------------------
// includes:
#include
#include
// CRC parameters (default values are for CRC-32):
const int order = 32;
const unsigned long polynom = 0x4c11db7;
const int direct = 1;
const unsigned long crcinit = 0xffffffff;
const unsigned long crcxor = 0xffffffff;
const int refin = 1;
const int refout = 1;
// 'order' [1..32] is the CRC polynom order, counted without the leading '1' bit
// 'polynom' is the CRC polynom without leading '1' bit
// 'direct' [0,1] specifies the kind of algorithm: 1=direct, no augmented zero bits
// 'crcinit' is the initial CRC value belonging to that algorithm
// 'crcxor' is the final XOR value
// 'refin' [0,1] specifies if a data byte is reflected before processing (UART) or not
// 'refout' [0,1] specifies if the CRC will be reflected before XOR
// Data character string
const unsigned char string[] = {"123456789"};
// internal global values:
unsigned long crcmask;
unsigned long crchighbit;
unsigned long crcinit_direct;
unsigned long crcinit_nondirect;
unsigned long crctab[256];
// subroutines
unsigned long reflect (unsigned long crc, int bitnum) {
// reflects the lower 'bitnum' bits of 'crc'
unsigned long i, j=1, crcout=0;
for (i=(unsigned long)1<<(bitnum-1); i; i>>=1) {
if (crc & i) crcout|=j;
j<<= 1;
}
return (crcout);
}
void generate_crc_table() {
// make CRC lookup table used by table algorithms
int i, j;
unsigned long bit, crc;
for (i=0; i<256; i++) {
crc=(unsigned long)i;
if (refin) crc=reflect(crc, 8);
crc<<= order-8;
for (j=0; j<8; j++) {
bit = crc & crchighbit;
crc<<= 1;
if (bit) crc^= polynom;
}
if (refin) crc = reflect(crc, order);
crc&= crcmask;
crctab[i]= crc;
}
}
unsigned long crctablefast (unsigned char* p, unsigned long len) {
// fast lookup table algorithm without augmented zero bytes, e.g. used in pkzip.
// only usable with polynom orders of 8, 16, 24 or 32.
unsigned long crc = crcinit_direct;
if (refin) crc = reflect(crc, order);
if (!refin) while (len--) crc = (crc << 8) ^ crctab[ ((crc >> (order-8)) & 0xff) ^ *p++];
else while (len--) crc = (crc >> 8) ^ crctab[ (crc & 0xff) ^ *p++];
if (refout^refin) crc = reflect(crc, order);
crc^= crcxor;
crc&= crcmask;
return(crc);
}
unsigned long crctable (unsigned char* p, unsigned long len) {
// normal lookup table algorithm with augmented zero bytes.
// only usable with polynom orders of 8, 16, 24 or 32.
unsigned long crc = crcinit_nondirect;
if (refin) crc = reflect(crc, order);
if (!refin) while (len--) crc = ((crc << 8) | *p++) ^ crctab[ (crc >> (order-8)) & 0xff];
else while (len--) crc = ((crc >> 8) | (*p++ << (order-8))) ^ crctab[ crc & 0xff];
if (!refin) while (++len < order/8) crc = (crc << 8) ^ crctab[ (crc >> (order-8)) & 0xff];
else while (++len < order/8) crc = (crc >> 8) ^ crctab[crc & 0xff];
if (refout^refin) crc = reflect(crc, order);
crc^= crcxor;
crc&= crcmask;
return(crc);
}
unsigned long crcbitbybit(unsigned char* p, unsigned long len) {
// bit by bit algorithm with augmented zero bytes.
// does not use lookup table, suited for polynom orders between 1...32.
unsigned long i, j, c, bit;
unsigned long crc = crcinit_nondirect;
for (i=0; i<len; i++) {
c = (unsigned long)*p++;
if (refin) c = reflect(c, 8);
for (j=0x80; j; j>>=1) {
bit = crc & crchighbit;
crc<<= 1;
if (c & j) crc|= 1;
if (bit) crc^= polynom;
}
}
for (i=0; i<order; i++) {
bit = crc & crchighbit;
crc<<= 1;
if (bit) crc^= polynom;
}
if (refout) crc=reflect(crc, order);
crc^= crcxor;
crc&= crcmask;
return(crc);
}
unsigned long crcbitbybitfast(unsigned char* p, unsigned long len) {
// fast bit by bit algorithm without augmented zero bytes.
// does not use lookup table, suited for polynom orders between 1...32.
unsigned long i, j, c, bit;
unsigned long crc = crcinit_direct;
for (i=0; i<len; i++) {
c = (unsigned long)*p++;
if (refin) c = reflect(c, 8);
for (j=0x80; j; j>>=1) {
bit = crc & crchighbit;
crc<<= 1;
if (c & j) bit^= crchighbit;
if (bit) crc^= polynom;
}
}
if (refout) crc=reflect(crc, order);
crc^= crcxor;
crc&= crcmask;
return(crc);
}
int main() {
// test program for checking four different CRC computing types that are:
// crcbit(), crcbitfast(), crctable() and crctablefast(), see above.
// parameters are at the top of this program.
// Result will be printed on the console.
int i;
unsigned long bit, crc;
// at first, compute constant bit masks for whole CRC and CRC high bit
crcmask = ((((unsigned long)1<<(order-1))-1)<<1)|1;
crchighbit = (unsigned long)1<<(order-1);
// check parameters
if (order < 1 || order > 32) {
printf("ERROR, invalid order, it must be between 1..32.\n");
return(0);
}
if (polynom != (polynom & crcmask)) {
printf("ERROR, invalid polynom.\n");
return(0);
}
if (crcinit != (crcinit & crcmask)) {
printf("ERROR, invalid crcinit.\n");
return(0);
}
if (crcxor != (crcxor & crcmask)) {
printf("ERROR, invalid crcxor.\n");
return(0);
}
// generate lookup table
generate_crc_table();
// compute missing initial CRC value
if (!direct) {
crcinit_nondirect = crcinit;
crc = crcinit;
for (i=0; i<order; i++) {
bit = crc & crchighbit;
crc<<= 1;
if (bit) crc^= polynom;
}
crc&= crcmask;
crcinit_direct = crc;
}
else {
crcinit_direct = crcinit;
crc = crcinit;
for (i=0; i<order; i++) {
bit = crc & 1;
if (bit) crc^= polynom;
crc >>= 1;
if (bit) crc|= crchighbit;
}
crcinit_nondirect = crc;
}
// call CRC algorithms using the CRC parameters above and print result to the console
printf("\n");
printf("CRC tester v1.1 written on 13/01/2003 by Sven Reifegerste (zorc/reflex)\n");
printf("-----------------------------------------------------------------------\n");
printf("\n");
printf("Parameters:\n");
printf("\n");
printf(" polynom : 0x%x\n", polynom);
printf(" order : %d\n", order);
printf(" crcinit : 0x%x direct, 0x%x nondirect\n", crcinit_direct, crcinit_nondirect);
printf(" crcxor : 0x%x\n", crcxor);
printf(" refin : %d\n", refin);
printf(" refout : %d\n", refout);
printf("\n");
printf(" data string : '%s' (%d bytes)\n", string, strlen(string));
printf("\n");
printf("Results:\n");
printf("\n");
printf(" crc bit by bit : 0x%x\n", crcbitbybit((unsigned char *)string, strlen(string)));
printf(" crc bit by bit fast : 0x%x\n", crcbitbybitfast((unsigned char *)string, strlen(string)));
if (!(order&7)) printf(" crc table : 0x%x\n", crctable((unsigned char *)string, strlen(string)));
if (!(order&7)) printf(" crc table fast : 0x%x\n", crctablefast((unsigned char *)string, strlen(string)));
return(0);
}