C語言實現CRC編碼

先做簡單介紹

 

一、CRC編碼簡介

CRC 的英文全稱爲 Cyclic Redundancy Check(Code),中文名稱爲循環冗餘校驗(碼)。它是一類重要的線性分組碼,編碼和解碼方法簡單,檢錯和糾錯能力強,在通信領域廣泛地用於實現差錯控制。

二、CRC編碼過程

以下步驟將描述 6 字節紅外控制碼生成過程:

1.從二維碼的中依次順序提取2 個英文字母、最後 2 個英文字母(X、x 除外,取英文字母 ASCII 值爲原始數據),並從中提取出多項式 g(x)(多項式的最高位爲 x16,最低爲 1);

2.預置 1 個 16 位的寄存器爲十六進制 FFFF(即全爲 1),稱此寄存器爲 CRC 寄存器;

3.把第一個 8 位二進制數據(既原始數據的第一個字節)與 16 位的 CRC 寄存器的低8 位相異或,把結果放於 CRC 寄存器,高八位數據不變;

4.CRC 寄存器向右移一位,MSB(最高位)補零,並檢查右移後的移出位 LSB(最低位)。

5.如果 LSB 爲 0,重複第 4 步;若 LSB 爲 1,CRC 寄存器與多項式碼相異或。

6.重複第 4 與第 5 步直到 8 次移位全部完成。此時一個 8-bit 數據處理完畢。

7.重複第 3 至第 5 步直到將剩下 3 個原始數據全部處理完成。

8.最終 CRC 寄存器的內容即爲 CRC 值。

9.取 CRC 的得高八位作爲紅外控制碼的第一字節,按順序取原始數據爲紅外控制碼的二、三、四、五字節,取 CRC 值的低八位爲紅外控制碼的第六字節。

三、算法示例

從二維碼中提取的字符串數據爲:<Aa12x16,Fg.5tx15/x2+\1/hgBb>,則提取出的 4 個英文字符爲 AaBb,多項式 g(x)=x16+x15+x2+1;

提取原始數據爲 0x41、 0x61、 0x42 、0x62,多項式碼爲 0xA001(由多項式忽略了最高位的"1",得到生成項是 0x8005,其中 0xA001 爲 0x8005 按位顛倒之後的結果);計算得到的 CRC 碼值爲 0x8FF4; 所得 6 字節紅外控制碼爲:0x8f 0x41 0x61 0x42 0x62 0xf4。

依據算法示例寫出代碼爲:

需要說明一下,多項式提取可能有問題,因爲這個文檔中沒有說明多項式提取的具體過程和要求,所以就按照我自己的理解寫出了多項式提取辦法。

如:字符串:<Aa12x16,Fg.5tx15/x2+\1/hgBb>

我會認爲這個字符串中有很多x開頭,並且後面有數字的情況,也就是說這個字符串可能是這樣的:<Ax23a12x16,Fx15g.125tx15/x2+\1/hgBb>

那麼我的理解是這樣的,可以提取爲:x23+12+x16+x15+125+x15+x2+1,經過整合就是這樣子的:

x16+x15+x2+1。說明:因爲沒有x23,所以就留有23,但最後都做了歸一化處理,所以每一項前面的係數都被設置爲1

 

代碼如下:

#include <stdio.h>
#include <string.h>

unsigned short CRC = 0XFFFF;				//	CRC 寄存器 預置爲全F
unsigned short Polynomial_Code = 0X0000;	//	多項式碼
unsigned short Polynomial = 0X0000;			//	多項式碼之前的正序碼

unsigned char source[4] = {0x41,0x61,0x42,0x62};	//	原始數據
unsigned char Infrared_Control_Code[6]={0};			//	紅外控制碼

unsigned char cnt = 0;

unsigned char str[100]= "<Aa12x16,Fg.5tx15/x2+\1/hgBbxxxxXXXXxxx>";    //Aa12x15,Fg.5tx15/x2*x1*x13/x2+\1/hgBbXxx  <Aa12x15,Fg.5tx15/x2*x1*x13/x2+\1/hgBbXx>;"<Aa12x16,Fg.5tx15/x2+\1/hgBb>";

void string_CRC(unsigned char str[]);		//	函數的聲明
void main()
{	
	puts(str);
	string_CRC(str);
}

void string_CRC(unsigned char str[])
{
	int len;
	int i,n=0;
	int cnt_x=0;
	unsigned char str_temp[50];
	char str_temp2[50] = {0};
	unsigned char LSB = 0;
	len = strlen(str);
	
	for(i=0;i<len;i++)
	{
		if('x' == str[i] || 'X' == str[i])
		{
			continue;
		}
		if((str[i]<='z'&&str[i]>='a') || (str[i]<='Z'&&str[i]>='A'))
		{
			str_temp[n] = str[i];
			n++;
		}
	}
	////	4字節提取源碼    start     /////
	source[0] = str_temp[0];
	source[1] = str_temp[1];
	source[2] = str_temp[n-2];
	source[3] = str_temp[n-1];
	////	4字節提取源碼    end      /////
	n = 0;
	
	for(i=0;i<len;i++)
	{
		if('x' == str[i])
		{
			if(str[i+2]>='1' && str[i+2]<='6')
			{
				if('1' == str[i+1])
				{
					str_temp2[n] = (str[i+1]-'0')*10 + (str[i+2]-'0');
					i = i+2;
					n++;
				}
			}
			else
			{
				if(str[i+1]>='1' && str[i+1]<='9')
				{
					str_temp2[n] = str[i+1]-'0';
					i = i+1;
					n++;
				}
			}
			
		}
		else if((str[i] >'0' && str[i] <='9') || (str[i] >0 && str[i] <=9))		//	這裏(str[i] >0 && str[i] <=9)是爲了解決C語言中轉義問題
		{
			str_temp2[n] = -1;
			n++;
		}
	}
	
	for(i=0;i<=n-1;i++)
	{
		printf("%d ",str_temp2[i]);	
	}
	printf("\n");
	
	for(i=0;i<=n;i++)
	{
		switch(str_temp2[i])
		{
			case 16:
				break;
			case 15:
				Polynomial = Polynomial|0X8000;
				Polynomial_Code = Polynomial_Code|0X0001;
				break;
			case 14:
				Polynomial = Polynomial|0X4000;
				Polynomial_Code = Polynomial_Code|0X0002;
				break;
			case 13:
				Polynomial = Polynomial|0X2000;
				Polynomial_Code = Polynomial_Code|0X0004;
				break;
			case 12:
				Polynomial = Polynomial|0X1000;
				Polynomial_Code = Polynomial_Code|0X0008;
				break;
			case 11:
				Polynomial = Polynomial|0X0800;
				Polynomial_Code = Polynomial_Code|0X0010;
				break;
			case 10:
				Polynomial = Polynomial|0X0400;
				Polynomial_Code = Polynomial_Code|0X0020;
				break;
			case 9:
				Polynomial = Polynomial|0X0200;
				Polynomial_Code = Polynomial_Code|0X0040;
				break;
			case 8:
				Polynomial = Polynomial|0X0100;
				Polynomial_Code = Polynomial_Code|0X0080;
				break;
			case 7:
				Polynomial = Polynomial|0X0080;
				Polynomial_Code = Polynomial_Code|0X0100;
				break;
			case 6:
				Polynomial = Polynomial|0X0040;
				Polynomial_Code = Polynomial_Code|0X0200;
				break;
			case 5:
				Polynomial = Polynomial|0X0020;
				Polynomial_Code = Polynomial_Code|0X0400;
				break;
			case 4:
				Polynomial = Polynomial|0X0010;
				Polynomial_Code = Polynomial_Code|0X0800;
				break;
			case 3:
				Polynomial = Polynomial|0X0008;
				Polynomial_Code = Polynomial_Code|0X1000;
				break;
			case 2:
				Polynomial = Polynomial|0X0004;
				Polynomial_Code = Polynomial_Code|0X2000;
				break;
			case 1:
				Polynomial = Polynomial|0X0002;
				Polynomial_Code = Polynomial_Code|0X4000;
				break;
			case -1:
				Polynomial = Polynomial|0X0001;
				Polynomial_Code = Polynomial_Code|0X8000;
				break;
			default:
				break;
		}
	}
	printf("source = ");
	for(i=0;i<4;i++)
	{
		printf("%X ",source[i]);
	}
	printf("\n");
	printf("Polynomial = %X",Polynomial);
	printf("\n");
	printf("Polynomial_Code = %X",Polynomial_Code);
	printf("\n");

	///  CRC 計算
	for(n=0;n<4;n++)
	{
		CRC = CRC^source[n];
		for(i=0;i<8;i++)	
		{	
			LSB = CRC&0X0001;
			CRC = CRC>>1;
			cnt++;
			if(0 == LSB)
			{
				continue;
			}
			else		//	當LSB爲1時
			{
				CRC = CRC^Polynomial_Code;
			}
			if(8 == cnt )
			{
				cnt=0;
				break;
			}
			
		}
	}
	printf("CRC = %X \n",CRC);
	///紅外控制碼計算
	Infrared_Control_Code[0] =  (unsigned char)(CRC>>8) ;
	Infrared_Control_Code[1] = source[0]; 
	Infrared_Control_Code[2] = source[1];
	Infrared_Control_Code[3] = source[2];
	Infrared_Control_Code[4] = source[3];
	Infrared_Control_Code[5] = (unsigned char)CRC;
	printf("Infrared_Control_Code = ");
	for(i=0;i<6;i++)
	{
		printf("%X ",Infrared_Control_Code[i]);
	}
	printf("\n");
}

 

實現的效果爲:

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章