CRC校验原理及C语言实现指南

林见深
林见深
发布时间:2026-10-15 | 3人浏览过
原创

循环冗余校验(CRC)是确保数据传输完整性的核心技术,广泛应用于以太网、USB及嵌入式串口通信中。文章解析了WIDTH、POLY、INIT等关键参数模型,并通过手算实例与C语言标准库代码,展示从理论理解到工程落地的完整流程。

CRC校验的基础概念

在数据通信中,干扰可能导致比特翻转,造成接收端数据错误。为了保证可靠性,发送端会计算一组校验值附加在数据帧末尾,接收端通过同样的算法验证一致性。

常见的校验方法包括奇偶校验、校验和以及LRC/BCC。然而,简单的方法误码率较高。例如在奇校验中,若原始数据 0001 0011 含有3个“1”(奇数),校验位为0;传输中若发生干扰变为 0010 0011(仍为3个“1”,但第一位出错),奇校验依然通过,导致错误未被发现。

校验和也存在类似的隐蔽性错误风险: 相比之下,CRC基于除法余数原理,检错能力强且易于硬件实现,因此成为计算机领域最普遍的校验方式,如以太网使用的CRC-32配合曼彻斯特编码,极大提升了通信健壮性。

理解CRC参数模型

调用不同函数结果不一致的根源在于未对齐CRC的参数模型。一个标准的CRC配置需包含以下信息:

  • NAME:模型名称(如CRC-8/MAXIM)。
  • WIDTH:生成的CRC位宽(如8位、16位、32位)。
  • POLY:生成多项式。通常省略最高位的1,转换为十六进制表示。例如多项式 $x^8 + x^2 + x + 1$,二进制为 1 0000 0111,省略首位后为 0x07。
  • INIT:初始值,位宽需与WIDTH一致,默认通常为 0x00。
  • REFIN:输入数据是否按位反转。True表示在计算前对每个字节进行翻转。
  • REFOUT:输出结果是否按位反转。True表示计算结束后对CRC值进行翻转。
  • XOROUT:最终结果与多异或运算后的值。

不同协议对应不同的标准模型,常见应用包括:

  • DS2401/18B20:使用CRC-8/MAXIM。
  • SD/MMC卡:使用CRC-7/MMC。
  • Modbus:使用CRC-16/MODBUS。
  • STM32硬件模块:支持CRC-32模型。

多项式的选择涉及复杂的数学推导,工程中建议直接采用经过验证的标准模型以确保检错能力。

CRC计算原理与手算示例

掌握原理的关键在于执行模2除法。我们以CRC-8/MAXIM为例,计算原始数据 0x34 的校验值。

第1步:确认参数配置

CRC-8/MAXIM 的具体参数如下:

  • POLY = 0x31 (1 0011 0001)
  • INIT = 0x00
  • XOROUT = 0x00
  • REFIN = True
  • REFOUT = True

第2步:预处理与移位

  1. 处理INIT:原始数据 0x34 (0011 0100) 与 INIT 00 异或,结果不变。
  2. 数据翻转(REFIN):由于REFIN为True,将 0011 0100 按位翻转得到 0010 1100。
  3. 左移补零:原始数据向左移动WIDTH位(8位),低位补0。结果为 0010 1100 0000 0000。

第3步:模2除法求余数

使用模2除法(实质是无借位减法),将被除数除以多项式 1 0011 0001:

计算得到余数为低8位:1111 1011。

第4步:后处理与最终结果

  1. 异或(XOROUT):余数 1111 1011 与 XOROUT 0000 0000 异或,结果仍为 1111 1011。
  2. 输出翻转(REFOUT):由于REFOUT为True,将 1111 1011 翻转得到 1101 1111,即十六进制 0xDF。

验证工具计算结果如下,确认手算正确:

数据校验机制

发送方将原始数据 0x34 拼接上CRC值 0xDF,组成数据帧 0x34DF。接收端通常有两种校验方式:

方式一:分离比对法
将接收到的帧分为数据和CRC两部分,在本地重新计算数据的CRC,并与接收到的CRC比对。一致则校验通过。

方式二:全帧整除法
将整个数据帧(含原数据和CRC部分)视为被除数,用相同的多项式进行模2除法。由于构造时已将余数拼入,理论上最终余数应为0。若余数不为0,则判定传输出错:

C语言代码实现

在实际开发中,建议使用成熟的开源库。这里以GitHub上的 crc-lib-c 为例,该库封装了常用的CRC算法。

第1步:引入头文件

在项目目录中包含库文件 crcLib.c 和 crcLib.h。

第2步:编写计算逻辑

以下代码演示如何计算长度为10字节的数组的CRC-8/MAXIM值:

#include <stdio.h>
#include <stdlib.h>
#include "crcLib.h"

int main()
{
    uint8_t LENGTH = 10;
    uint8_t data[LENGTH];
    uint8_t crc;

    // 初始化测试数据
    for(int i = 0; i < LENGTH; i++)
    {
        data[i] = i * 5;
        printf("%02x ", data[i]);
    }
    printf("\n");

    // 调用MAXIM标准算法
    crc = crc8_maxim(data, LENGTH);

    printf("CRC-8/MAXIM:%02x\n", crc);
    return 0;
}

第3步:运行验证

编译运行后,控制台输出的CRC结果如下:

辅助工具推荐

在进行底层驱动开发(如Verilog或裸机C代码)时,可利用在线工具作为标准答案进行对照验证:

  • 在线计算:www.ip33.com/crc.html
  • 离线工具:CRC_Calc v0.1.exe、GCRC.exe
  • 格西CRC计算器界面直观,适合快速排查模型参数:

CRC虽不能保证100%捕获所有错误,但在合理位数和多项式下能覆盖绝大多数传输损伤。实际应用中务必严格遵循协议规定的标准参数模型。

以上就是CRC校验原理及其C语言实现详解的详细内容,更多关于C语言 CRC校验的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表