先做簡單介紹
一、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");
}
實現的效果爲: