龙空技术网

C语言与物联网之数据校验算法之循环冗余校验(CRC)

雨风1930 273

前言:

眼前咱们对“crc检验算法”大概比较关心,看官们都想要了解一些“crc检验算法”的相关资讯。那么小编同时在网络上汇集了一些对于“crc检验算法””的相关知识,希望看官们能喜欢,看官们一起来了解一下吧!

循环冗余校验(Cyclic Redundancy Check,简写CRC),是一种常用的、检错能力相当强的校验算法。

本文不详细介绍CRC算法的理论,直接给出计算结果为2个字节的计算流程及实现代码。

计算流程

定义一个16位无符号类型的变量,并初始化为0xFFFF,称之为CRC变量;把数据包中的第一个字节与CRC变量中的低字节进行异或运算,结果存回CRC变量;将CRC变量向右移一位,最高位填以0,最低位移出并检测;如果最低位为0:重复第3步(进行下一次移位);如果最低位为1:将CRC变量与固定值0xA001进行异或运算;重复第3步和第4步直到8次移位,这样就完成了对数据包中第一个字节的处理;重复第2步到第5步来处理数据包中的下一个字节,直到数据包中所有的字节都处理完;最终CRC变量的值就是CRC的值。

用C语言实现

/* 代码片段,摘自:plat_lib.c *//****************************************************************************** *  @fn      uint16_t calc_crc16(uint8_t const *p_data, int32_t data_len) * *  @brief   计算16位的crc校验码 * *  @param   p_data    待校验数据的首地址 *  @param   data_len  数据长度 * *  @return  CRC value, 0x0000 ~ 0xFFFF */uint16_t calc_crc16(uint8_t const *p_data, int32_t data_len){    int32_t i;    uint16_t crc_value = 0xFFFF; /* 定义一个16位无符号类型的变量,并初始化为0xFFFF */    while (data_len--) {        /* 数据包中的字节与CRC变量中的低字节进行异或运算,结果存回CRC变量 */        crc_value ^= *p_data++;        for (i = 0; i < 8; i++) {            if (crc_value & 0x0001) {                /* 如果最低位为1:将CRC变量与固定值0xA001进行异或运算 */                crc_value = (crc_value >> 1) ^ 0xA001;             } else {                /* 如果最低位为0:重复第3步(配合计算流程来阅读代码) */                crc_value >>= 1;            }        }    }    /* 最终CRC变量的值就是CRC的值 */    return crc_value;}

测试代码:

/* 代码片段,摘自:test.c *//****************************************************************************** *  @fn      int main(int argc, char * argv[]) * *  @brief   主函数 * *  @param   argc 命令函传入的参数数量 *  @param   argv 命令行传入的参数字符串数组 * *  @return  0 */int main(int argc, char * argv[]){    uint8_t user_data1[] = {0x01, 0x02, 0x03, 0x04, 0x05};    uint8_t user_data2[] = {0x01, 0x03, 0x02, 0x04, 0x05};    uint16_t crc1, crc2;    crc1 = calc_crc16(user_data1, sizeof(user_data1));    crc2 = calc_crc16(user_data2, sizeof(user_data2));    log_debug("crc1 = %04X, crc2 = %04X\n", crc1, crc2);    return 0;}

Makefile

TARGET = testSOURCE  := $(wildcard *.c) $(wildcard *.cpp)OBJS    := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))$(TARGET): $(OBJS)    gcc -o $@ $(OBJS)clean:    rm -rf *.o $(TARGET)

测试结果

// 编译[root@localhost checksum]# makecc    -c -o protocol.o protocol.ccc    -c -o plat_lib.o plat_lib.ccc    -c -o plat_log.o plat_log.ccc    -c -o test.o test.cgcc -o test protocol.o plat_lib.o plat_log.o test.o// 运行测试程序[root@localhost checksum]# ./testcrc1 = BB2A, crc2 = 877A

优缺点

CRC算法比校验和算法复杂,计算过程会占用较多的计算机资源(比如CPU资源),其优点是检错能力强,举例说明如下,有2份元数据,如下:

虽然只是有2个字节的数据交换了一下位置,但得到了不同的CRC校验码,这是校验和算法或一些其他简单算法做不到的。

补充:

通信协议中,CRC校验码通常按如下方式使用:CRC校验码由发送方计算出来,然后附加到数据包中,接收方在接收数据时以同样的算法重新计算CRC值,然后与接收到的CRC校验码进行比较,如果这两个值不相等,就说明数据传输过程中出现了错误,数据不可靠,直接丢弃不做处理。

标签: #crc检验算法