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");
}

 

实现的效果为:

 

 

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小材大用

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值