CRC 原理概述

article/2025/6/25 5:09:06

CRC 原理概述

       摘要:循环冗余校验(CRC, Cyclic Redundancy Check)是一种基于多项式除法(modulo-2)的差错检测码。它将数据视为一个二进制多项式 D(x),生成多项式为 G(x),通过“除法”得到的余数 R(x)即为 CRC:

  1. 将 D(x) 左移 k 位(在二进制串末尾补 k个 0),其中 k = deg⁡G(x)。
  2. 用 G(x)对扩展后的多项式做模 2 除法(每步减法即异或,不带借位),得到余数 R(x),deg⁡R(x) < k。
  3. 将 R(x)R(x)R(x) 附加到原始数据后(或与原数据一起传输/存储),接收端做同样的除法检查余数是否为 0。

一、以 CRC-8 为例(常用多项式 0x07)

我们选用最常见的 CRC-8 生成多项式:

G(x)=x^8+x^2+x+1

  • 二进制表示(含最高次项)为
1000 00111

通常在硬件/软件里只存低 8 位:0x07,最高的 x8x^8x8 隐式存在。

  • 数据宽度:32 bit
  • CRC 宽度:8 bit

记 payload 二进制为

D[31] D[30] … D[0]

我们在数据后面补 8 个 “0” 得到 40 位的除数。

二、寄存器移入算法(LFSR 风格)

不必手工做 40 步“长除法”,常用移位寄存器算法:

寄存器 R ← 0x00// 1) 处理每个数据位
for i = 31 … 0:fb = (R[7] ⊕ D[i])            // 反馈 = 高位和当前输入位异或R = (R << 1) & 0xFF           // 左移,低位补 0if fb == 1:R = R ⊕ 0x07              // 多项式低 8 位// 2) 处理填入的 8 个 “0” 位
for i = 7 … 0:fb = R[7]                     // 此时数据位总是 0R = (R << 1) & 0xFFif fb == 1:R = R ⊕ 0x07// R 最终即为 CRC-8 余数
CRC = R
  • R[7] 表示寄存器的最高位(MSB)。
  • “⊕” 表示按位异或。
  • (R<<1)&0xFF 保证寄存器只保留 8 位。

三、示例:演示首 8 步与尾 8 步

  • 我们取一个示例 32‐bit payload(十六进制):
D = 0x1234_5678
  • 其二进制(MSB 开头)前 8 位为
D[31:24] = 0001 0010
  • 末 8 位补 0 的过程模拟如下(只列首 8 步和尾 8 步,中间同理):
步骤输入位 D[i]R[7] prevfb = R[7]⊕D[i]R<<1R′ = (R<<1)⊕0x07 (if fb)R_after
1D[31]=000⊕0=00x000x00
2D[30]=0000x000x00
3D[29]=0000x000x00
4D[28]=1010x000x00⊕0x07=0x070x07
5D[27]=00 (R[7])00x0E0x0E
6D[26]=0000x1C0x1C
7D[25]=1010x380x38⊕0x07=0x3F0x3F
8D[24]=0000x7E0x7E

(中间 24 步略)

  • 下传完所有 D[31:0] 后,再“送入”8 个 0:
步骤输入位=0R[7] prevfbR<<1R′R_after
330x7E→ MSB=00⊕0=00xFC0xFC
34110xF80xF8⊕0x07=0xFF0xFF
40(…whatever)CRC
  • 最终 R 的值就是那 8 位余数——即 CRC-8

注意:上面给出的是一种“无初始值、无反射、无末尾异或”的简单 CRC-8 计算。
实际协议(如 SMBus、Maxim-Dallas、X-25)常在此基础上加

  • Initial XOR(预置寄存器为 0xFF)
  • Bit-reflect(输入/输出比特顺序翻转)
  • Final XOR(余数再与 0xFF 异或)
    等处理,详情请参见各协议规范。

四、总结

  • CRC 把二进制串看成多项式,用 G(x) 做模 2 除法,余数即校验码。
  • 对 32 bit payload、8 bit CRC,多项式常用x^8+x^2+x+1(0x07)。
  • 移位寄存器算法每送入一位都做一次“反馈”判断 + 条件异或,简洁且易硬件/软件实现。
  • 最后不断移入 k 个 0,就得到长度为 k的余数。

五、Verilog生成CRC代码

       下面给出一个纯组合并行计算 CRC-8 的 Verilog 示例,针对固定 32 位 payload、常用多项式 x^8+x^2+x+1(多项式低 8 位=0x07),算法完全对应上面讲的 LFSR 移位除法:

5.1 LFSR 移位除法:

//-----------------------------------------------------------------------------
// Module : crc8_parallel
// 
// 计算 32‐bit data_in 的 CRC‐8 余数 (多项式 x^8 + x^2 + x + 1)
// 完全组合逻辑实现,仿真时一个 delta‐cycle 内算出结果
//-----------------------------------------------------------------------------module crc8_parallel (input  wire [31:0] data_in,output wire [7:0]  crc_out
);// CRC‐8 多项式 (低 8 位,高位 x^8 隐式存在)localparam [7:0] POLY = 8'h07;// LFSR 一步更新函数:cur 是当前寄存器,bit_in 是移入的新数据位function [7:0] next_crc;input [7:0] cur;input       bit_in;reg         fb;beginfb       = cur[7] ^ bit_in;         // MSB ⊕ 输入位 = 反馈next_crc = {cur[6:0], 1'b0};        // 左移一位if (fb)next_crc = next_crc ^ POLY;       // 有反馈时再与多项式异或endendfunctioninteger i;reg [7:0] crc;// 组合逻辑:先把 data_in[31] … data_in[0] 串行送入 LFSR,// 然后不断注入 8 个 0(相当于 data << 8),最终 crc 就是余数always @* begincrc = 8'h00;                         // 初始余数全 0// 1) 串行处理 32 位数据for (i = 31; i >= 0; i = i - 1) begincrc = next_crc(crc, data_in[i]);end// 2) 注入 8 个 0for (i = 7; i >= 0; i = i - 1) begincrc = next_crc(crc, 1'b0);endendassign crc_out = crc;endmodule

5.2 时序版(cycle-by-cycle)实现

       如果你需要时序版(cycle-by-cycle)实现,也很简单,只要用一个 8 位寄存器串行移入 40 位就行。下面给出一个带启动/就绪信号、每时钟处理一位的版本:

//-----------------------------------------------------------------------------
// Module : crc8_serial
//   时序版 CRC‐8 计算器:一个时钟一个 bit,总共 40 个时钟计算完毕
// Ports:
//   clk, rst_n      - 同步复位
//   start           - 置 1 时开始计算,内部会捕捉 data_in
//   data_in         - 32 位待校验数据
//   busy            - 高电平表示正在计算
//   crc_out         - 计算完毕后的 CRC‐8
//-----------------------------------------------------------------------------module crc8_serial (input  wire        clk,input  wire        rst_n,input  wire        start,input  wire [31:0] data_in,output reg         busy,output reg  [7:0]  crc_out
);localparam [7:0] POLY = 8'h07;reg [7:0] crc_reg;reg [5:0] bit_cnt;        // 0…39// 计算一步 LFSRfunction [7:0] next_crc;input [7:0] cur;input       bit_in;reg         fb;beginfb       = cur[7] ^ bit_in;next_crc = {cur[6:0], 1'b0};if (fb)next_crc = next_crc ^ POLY;endendfunction// 状态机:idle → busy 40 个周期 → donealways @(posedge clk) beginif (!rst_n) beginbusy    <= 1'b0;crc_reg <= 8'h00;bit_cnt <= 6'd0;crc_out <= 8'h00;end else beginif (start && !busy) begin// 启动:捕捉初始状态busy    <= 1'b1;crc_reg <= 8'h00;bit_cnt <= 6'd39;              // 32+8-1 = 39end else if (busy) begin// 送入第 bit_cnt 位:前 32 周期送 data_in[31:0],// 后 8 周期送 0if (bit_cnt >= 8)crc_reg <= next_crc(crc_reg, data_in[bit_cnt-1]);  elsecrc_reg <= next_crc(crc_reg, 1'b0);if (bit_cnt == 0) beginbusy    <= 1'b0;crc_out <= crc_reg;          // 最终余数endbit_cnt <= bit_cnt - 1;endendendendmodule

以上两种实现:

  • 并行版crc8_parallel)一次性在组合逻辑里跑完,延迟约为 40 级异或/移位链。
  • 时序版crc8_serial)40 个时钟周期内完成,用流水寄存器拆分了逻辑深度,更易综合并节省面积。

 5.3 参数化的时序(serial)CRC 模块

       下面给出一个参数化的时序(serial)CRC 模块,它支持任意宽度的输入、任意次方的生成多项式、可配置的初始值和输出异或。核心思路与前面讲的 LFSR 相同,只是把常数硬编码改成了参数。

//-----------------------------------------------------------------------------
// Module : crc_serial_param
// Description : 可配置 DATA_WIDTH、CRC_WIDTH、生成多项式 POLY(低 CRC_WIDTH
// 位)、初始寄存器值 INIT、最终输出异或值 FINAL_XOR 的串行 CRC 计算器。
// 每个时钟处理一位 bit,总共 DATA_WIDTH+CRC_WIDTH 个周期完成。
//-----------------------------------------------------------------------------module crc_serial_param #(//—— 参数化接口 ——parameter integer DATA_WIDTH  = 32,             // 待校验数据位宽parameter integer CRC_WIDTH   = 8,              // 余数位宽// 生成多项式低 CRC_WIDTH 位,多项式最高 x^CRC_WIDTH 隐式存在parameter [CRC_WIDTH-1:0] POLY       = 8'h07,   parameter [CRC_WIDTH-1:0] INIT       = {CRC_WIDTH{1'b0}}, // 初始寄存器值parameter [CRC_WIDTH-1:0] FINAL_XOR  = {CRC_WIDTH{1'b0}}  // 输出前的异或
)(input  wire                 clk,input  wire                 rst_n,input  wire                 start,              // 高脉冲开始一次 CRC 计算input  wire [DATA_WIDTH-1:0] data_in,           // 待校验数据output reg                  busy,               // 计算中output reg  [CRC_WIDTH-1:0] crc_out             // 计算结果
);//—— 内部状态 —— reg [CRC_WIDTH-1:0] crc_reg;integer             bit_cnt;    // 从 DATA_WIDTH+CRC_WIDTH-1 递减到 0//—— LFSR 一步更新函数 —— function [CRC_WIDTH-1:0] next_crc;input [CRC_WIDTH-1:0] cur;input                 bit_in;reg                   fb;reg [CRC_WIDTH-1:0]   tmp;beginfb  = cur[CRC_WIDTH-1] ^ bit_in;      // MSB ⊕ 新输入tmp = {cur[CRC_WIDTH-2:0], 1'b0};      // 左移一位if (fb)tmp = tmp ^ POLY;                   // 根据多项式条件异或next_crc = tmp;endendfunction//—— 状态机/计数器 —— always @(posedge clk) beginif (!rst_n) beginbusy    <= 1'b0;crc_reg <= INIT;bit_cnt <= DATA_WIDTH + CRC_WIDTH - 1;crc_out <= {CRC_WIDTH{1'b0}};end else beginif (start && !busy) begin// 启动计算:复位 CRC 寄存器、设置计数器、置 busybusy    <= 1'b1;crc_reg <= INIT;bit_cnt <= DATA_WIDTH + CRC_WIDTH - 1;endelse if (busy) begin// 逐位喂入:高 DATA_WIDTH 周期取 data_in,高位先入if (bit_cnt >= CRC_WIDTH)crc_reg <= next_crc(crc_reg, data_in[bit_cnt - CRC_WIDTH]);elsecrc_reg <= next_crc(crc_reg, 1'b0);  // 补 CRC_WIDTH 个“0”// 计数到 0 时结束if (bit_cnt == 0) beginbusy    <= 1'b0;crc_out <= crc_reg ^ FINAL_XOR;       // 最终输出可再异或endbit_cnt <= bit_cnt - 1;endendendendmodule

如何使用

       举例生成一个常见的 CRC-8 (x⁸ + x² + x + 1),对 32 位 数据,初始寄存器全 0xFF,输出再异或 0x55

crc_serial_param #(.DATA_WIDTH (32),.CRC_WIDTH  (8),.POLY       (8'h07),    // 低 8 位:x^8+x^2+x+1.INIT       (8'hFF),    // 常见预置 0xFF.FINAL_XOR  (8'h55)     // 最终取反异或
) u_crc (.clk   (clk),.rst_n (rst_n),.start (start),.data_in(data32),.busy  (busy),.crc_out(crc8)
);
  • 改变 POLY 参数即可支持不同生成多项式(例如 CRC-16 的 16'h1021[15:0])。
  • INITFINAL_XOR 也可按协议需求调整。

       这样,你就得到了一个高度可复用的串行 CRC 计算核,既可综合,也易于集成到各种总线和协议中。

七、代码详解

       在那段参数化的串行 CRC 代码里,next_crc 这个函数正是把「当前的 CRC 寄存器值」和「新送入的一位数据」合成成「下一时刻的 CRC 寄存器值」,也就是常说的 LFSR(线性反馈移位寄存器)那一步更新逻辑。


1. 数学上,它在做什么?


2. 代码里如何映射这一步?

function [CRC_WIDTH-1:0] next_crc;input [CRC_WIDTH-1:0] cur;    // 上一时刻的寄存器 Rinput                bit_in; // 新送入的数据位 dreg                  fb;     // feedbackreg [CRC_WIDTH-1:0]  tmp;
beginfb  = cur[CRC_WIDTH-1] ^ bit_in;       // ① 反馈 = R 的 MSB ⊕ dtmp = {cur[CRC_WIDTH-2:0], 1'b0};       // ② 左移一位: x·R(x)if (fb)tmp = tmp ^ POLY;                    // ③ 如果 fb=1,就多项式减(⊕)一次next_crc = tmp;                        // ④ 得到新余数
end
endfunction
  • ① 反馈位 (fb)
    在做多项式除法时,最高次项系数 rn−1与当前输入位 d 异或,决定是否要用 G(x) 去“减”一次。
  • ② 左移一位
    相当于多项式乘以 x。
  • ③ 条件异或多项式
    如果反馈位为 1,才把移位后的结果与 POLY(多项式的低 nnn 位)异或,完成一次模 2 的除法(减法)。
  • ④ 返回新寄存器值
    这就是下一时刻的 CRC 寄存器状态。

3. 为什么这么做能实现 CRC?

  • 模 2 除法中的 减法 就是异或。
  • 每送入一位数据,就相当于先把余数乘 x(左移),再加上这位数据;如果新的最高次项系数变成了 1,就要减一次生成多项式,保持余数次数 < n。
  • LFSR 正是这个思路的硬件实现:一个 n 位移位寄存器+若干 Tap 处的反馈异或。

4. 举个 4 位宽的小例子


5. 小结

  • next_crc(cur, bit_in) 抽象了一次「左移+条件异或」的 LFSR 步骤。
  • 它保证:每把一位数据喂进去,CRC 寄存器就恰好做了一次多项式模 2 除法。
  • 串行地调用 DATA_WIDTH+CRC_WIDTH 次,就完成了对整帧数据的 CRC 计算。

http://www.hkcw.cn/article/gnLVeOsNdG.shtml

相关文章

风控研发大数据学习路线

在如今信息爆炸时代&#xff0c;风控系统离不开大数据技术的支撑&#xff0c;大数据技术可以帮助风控系统跑的更快&#xff0c;算的更准。因此&#xff0c;风控技术研发需要掌握大数据相关技术。然而大数据技术栈内容庞大丰富&#xff0c;风控研发同学很可能会面临以下这些痛点…

美载有2.5亿只蜜蜂卡车翻车 养蜂专家紧急救援

美国华盛顿州近日发生了一起罕见事故,一辆载有约2.5亿只蜜蜂的半挂卡车在行驶途中翻覆,导致大量蜜蜂倾巢而出。事故地点靠近加拿大边境,距离温哥华仅约48公里。当地警方迅速封锁道路,并呼吁民众远离蜂群,同时紧急召集养蜂专家到场协助处理。怀特康郡警局发布公告称,事故发…

MySQL垂直分库(基于MyCat)

参考资料&#xff1a; 参考视频 参考博客 Mycat基本部署 视频参考资料&#xff1a;链接: https://pan.baidu.com/s/1xT_WokN_xlRv0h06b6F3yg 提取码: aag3 概要&#xff1a; 本文的垂直分库&#xff0c;全部是基于前文部署的基本架构进行的 垂直分库&#xff1a; 垂直分库…

MySQL 核心知识整理【一】

一、MySQL存储引擎对比&#xff1a;InnoDB vs MyISAM 在使用MySQL时&#xff0c;选择合适的存储引擎对性能影响很大。最常见的两个引擎是 InnoDB 和 MyISAM&#xff0c;它们各自的设计目标不同&#xff0c;适用场景也不一样。 事务与数据安全性方面&#xff0c;InnoDB 支持事…

MySQL下载安装配置环境变量

MySQL下载安装配置环境变量 文章目录 MySQL下载安装配置环境变量一、安装MySQL1.1 下载1.2 安装 二、查看MySQL服务是否启动三、配置环境变量四、验证 一、安装MySQL 1.1 下载 官网社区版&#xff08;免费版&#xff09;&#xff1a;https://dev.mysql.com/downloads/mysql/ …

火语言UI组件--文件夹对话框

【组件功能】&#xff1a;选择单个或多个文件的对话框。 样式预览 设置 基础设置 属性名称属性释义输入值类型标题(title)对话框的标题字符串类型默认路径(defaultPath)对话框的默认展示路径字符串类型多选(multiSelections)是否允许多选布尔型(true / false)显示隐藏文件(s…

海底三维可视化平台

1. 摘要 本文作者为视觉分析构建了一个真实海底的“虚拟世界”。在3D环境中导入底部轮廓。在该模型中&#xff0c;通过地震反射获得的海床地层剖面被数字化为离散点&#xff0c;并用克里金算法进行插值&#xff0c;以在每个地层中产生均匀的网格。然后在每一层构建 Delaunay三…

联合国裁员计划曝光 预算削减20%

多家媒体29日披露的联合国内部文件显示,联合国秘书处计划削减20%预算,并裁员6900人,约占员工总数的20%。根据法新社和路透社获取的联合国内部备忘录,负责财政事务的联合国助理秘书长钱德拉穆利拉马纳坦本周向各部门负责人发出信函,要求执行联合国秘书长安东尼奥古特雷斯提…

一村民鸡舍惊现50斤重蟒蛇 民警与捕蛇师傅联手救助

6月1日清晨,当小朋友们正享受儿童节的快乐时,五华县公安局丁畲派出所接到了村民温先生的紧急求助电话。温先生称自家鸡舍里钻进了一条大蛇,吓得鸡和鹅四处逃窜。接到报警后,丁畲派出所的值班民辅警迅速行动,并联系了专业的捕蛇师傅一同前往现场。到达后,他们发现大蛇蜷缩…

朋友圈哪些内容不能随便晒 保护隐私安全

端午假期即将来临,许多人计划出行并准备在朋友圈分享快乐。然而,过度分享可能带来隐私泄露的风险。有些内容不宜随意晒出。例如,火车票、飞机票、登机牌、家门钥匙、车牌等含有个人信息的物品,一旦发布,可能会被不法分子利用高科技手段窃取,导致个人隐私泄露。身份证、护…

火出圈的“苏超”不只是有梗 比赛第一,友谊第十四!

“友谊第一,比赛第二”这句话在江苏省首届城市足球联赛中被重新演绎为“比赛第一,友谊第十四”,这句口号迅速在网络上走红。这个被球迷称为“苏超”的足球联赛近日火出圈。“苏超”是江苏省体育局与各设区市政府联合主办的江苏省首届城市足球联赛,共有13个设区市派出队伍参…

电影《女足》杀青 星爷新作引期待

6月2日,周星驰执导的电影《女足》正式杀青。该片结合了少林功夫与足球元素,围绕女子足球队展开,讲述了一群热爱足球的女孩如何克服困难,追求梦想的故事。剧情紧凑,笑点与泪点并存,令人期待。全组历时3个月拍摄,迪丽热巴于6月2日完成个人戏份,其他主演如张小斐、张艺兴也…

6月起全国推广免陪照护服务 缓解家庭陪护压力

俗话说“久病床前无孝子”,这句话反映了家庭在面对病人陪护时的无奈与压力。特别是随着老龄化社会的到来以及独生子女政策的影响,父母住院时的陪护问题变得愈发困难。如果医院能够提供标准化的照护服务,将大大减轻家庭负担。国家卫健委等三部委近期印发了一份方案,计划于6月…

python打卡 DAY 19 常见的特征筛选算法

目录 特征筛选算法笔记 一、方差筛选 (Variance Threshold) 1.1 基本原理 1.2 实现代码 1.3 注意事项 二、皮尔逊相关系数筛选 2.1 基本原理 2.2 实现代码 2.3 优缺点 三、Lasso回归筛选 3.1 基本原理 3.2 实现代码 3.3 参数选择 四、树模型特征重要性 4.1 基本…

三菱整数乘法出现小数点的原因分析 以及工程设置

三菱 PLC 中出现30*100029999.994的计算误差&#xff0c;主要与浮点数在计算机中的二进制表示方式有关。以下是详细解释和解决方案&#xff1a; 原因分析 浮点数二进制存储的精度限制 浮点数&#xff08;如三菱 PLC 使用的 IEEE 754 单精度浮点数&#xff09;在计算机中以二进制…

Git 第三讲---核心篇 git的远程管理

前言&#xff1a; 在上一讲《Git 第二讲 — 提高篇&#xff1a;Git的分支管理》中&#xff0c;我们掌握了如何通过分支实现代码的并行开发&#xff0c;学会了创建、切换、合并分支以及解决冲突的核心技巧。分支管理是Git强大功能的基石&#xff0c;但它更多聚焦于本地仓库的操…

Java网络编程API 1

Java中的网络编程API一共有两套&#xff1a;一套是UDP协议使用的API&#xff1b;另一套是TCP协议使用的API。这篇文章我们先来介绍UDP版本的API&#xff0c;并尝试来写一个回显服务器&#xff08;接收到的请求是什么&#xff0c;返回的响应就是什么&#xff09;。 UDP数据报套…

window ollama部署模型

注意去官网下载ollama,这个win和linux差别不大,win下载exe,linux用官网提供的curl命令 模型下载表:deepseek-r1 使用命令:Ollama API 交互 | 菜鸟教程 示例: 1.查看已加载模型: 2.文本生成接口 curl -X POST http://localhost:11434/v1/completions -H "Conte…

MySQL安装及启用详细教程(Windows版)

MySQL安装及启用详细教程&#xff08;Windows版&#xff09; &#x1f4cb; 概述 本文档将详细介绍MySQL数据库在Windows系统下的下载、安装、配置和启用过程。 &#x1f4e5; MySQL下载 官方下载地址 官方网站: https://dev.mysql.com/downloads/社区版本: https://dev.my…

vscode中的markdown表格列宽

vscode中的markdown表格列宽 当然&#xff0c;这个问题在csdn中应该是没有的&#xff0c;csdn是自适应文档页面的。这个自适应在vscode中好像不太好实现&#xff0c;至少目前我没能实现。 表格生成如上图&#xff0c;缩在一起&#xff0c;当然也会随着表格中录入数据自适应…