一般标准的通讯协议中都需要有校验方法来校验通讯过程中的数据的正确性,如我们工程中用的标准MODBUS串行通讯网络采用两种错误校验方法,奇偶校验可以用于检验每一个字符,信息帧校验(LRC或CRC)使用于整个信息的校验,字符校验和信息帧校验均由主机设备产生,并在传送前加到信息中去。从机设备在接收信息过程中校验每个字符和整个信息。
CRC校验(循环冗余校验)是现代通信领域的重要技术之一。掌握CRC的算法与实现方法,在通信系统的设计、通信协议的分析以及软件保护等诸多方面,能发挥很大的作用。
CRC的代数的一般性算法网上的内容很多,在这里不在赘述。一般CRC的C语言有两种实现算法:比特型算法和字节型算法,由于比特型算法需要逐位进行计算,效率比较低,不适合高速通讯的场合,所以我们一般采用字符型算法,下面重点介绍字符型算法的CRC校验。
1、 实现原理:
循环冗余校验CRC区为2个字节,含一个16位二进制数据。由发送设备计算CRC值,并计算CRC值,并把计算值附在信息中,接收设备在接收信息时,重新计算CRC的值,并把计算值与接收的在CRC区中的实际值进行比较,若两者不相同,则产生一个错误。
2、CRC的产生
(1)把16位CRC寄存器置成全1,即0xffff。
(2)第一个8位数据与CRC寄存器低8位进行异或运算,把结果存入CRC寄存器。
char rs485Arg[32]; /* RS-485参数缓存*/
/*
* 初始化UART0
*/
UartInit(UART0, uartInitArg, NULL); /* 初始化UART0 */
sprintf(rs485Arg, "RS485Dir=%u", P0_04); /* 获取RS-485方向控制引脚*/
UartSetMode(UART0, SET_RS485, rs485Arg); /* 使能RS-485设置其方向控制引脚 */
SetVICIRQ(UART0_IRQ_CHN, 8, (uint32)UART0_ISR);
while (1) {
crc=crc16byte(cStrTmp,6); (1)
crch=(crc&0xff00)>>8; (2)
crcl=(crc&0x00ff); (3)
cStrTmp[6]=crch; (4)
cStrTmp[7]=crcl;
UartWrite(UART0, (uint8 *)cStrTmp,8, NULL); (5)
OSTimeDly(OS_TICKS_PER_SEC);
}
}
做几点说明:
我们在工程中通常会碰到这样的问题,比如驱动电机,你需要在用主机对从机发送转动指令包括是正转还是反转,转动多少,这就需要我们发送一帧经CRC校验好的指令信息。上面的任务程序就简单的实现了这一点。
(1)对除校验位以外的6为数据计算校验码
(2)计算出来的16位校验值取其高字节并右移8位放入crch
(3)计算出来的16位校验值取其低字节放入crcl
(4)将计算出来的高低位分别放入待发送信息的最后2位,这样cStrTmp内8位数据信息的校验值就为0了。
(5)校验好的信息通过UART0发送至从机。
在此,做一点补充,包括前面的日志所用的数据类型都是根据μcos系统的定义来的具体如下:
typedef unsigned char BOOLEAN; /* 布尔变量 */
typedef unsigned char INT8U; /* 无符号8位整型变量 */
typedef signed char INT8S; /* 有符号8位整型变量 */
typedef unsigned short INT16U; /* 无符号16位整型变量*/
typedef signed short INT16S; /* 有符号16位整型变量 */
typedef unsigned long INT32U; /* 无符号32位整型变量 */
typedef signed long INT32S; /* 有符号32位整型变量 */
typedef float FP32; /* 单精度浮点数(32位长度) */
typedef double FP64 /* 双精度浮点数(64位长度) */
计算机内存中的数据都是以二进制的形式存在的,各种类型的数据譬如无符号整型数具体是多少位二进制跟cpu的位数有关。
二进制、16进制与10进制的关系:以一个十六进制的数为例
1111 1111 1111 1111 二进制
0xffff 16进制
0xff*256+0xff 十进制
xucun915_925777961 2011-9-6 16:12