CRC实战宝典:从原理到代码,全面攻克循环冗余校验

CRC实战宝典:从原理到代码,全面攻克循环冗余校验

github开源:CRC软硬件协同测试项目

CRC 简介

CRC(循环冗余校验)是一种强大的错误检测技术,广泛应用于数字网络和存储系统。它是确保数据完整性的重要方法,能够检测传输或存储过程中对原始数据的意外更改。

什么是 CRC?

CRC 是一种数学算法,具有以下特点:

  • 将数据视为有限域中的多项式表示
  • 使用预定义的多项式(称为生成多项式)进行二进制除法
  • 生成固定长度的校验和,附加到消息末尾
  • 能够高概率地检测出常见的传输错误

CRC 的优势在于其能够检测:

  • 所有单比特错误
  • 所有双比特错误(在标准 CRC 中)
  • 任何奇数个比特错误
  • 突发错误(基于多项式长度的一定范围内)

CRC 原理

多项式表示

在 CRC 中,数据和生成多项式都表示为具有二进制系数(0 或 1)的多项式。例如:

  • 二进制序列1101表示多项式 x³ + x² + 1
  • 二进制序列10011表示多项式 x⁴ + x + 1

CRC 参数

完整的 CRC 算法由以下参数定义:

  1. 位宽(Width):CRC 值的比特数
  2. 多项式(Polynomial):用于除法的生成多项式
  3. 初始值(Init):CRC 寄存器的初始值
  4. 输入反转(RefIn):输入字节是否反转(位序反转)
  5. 输出反转(RefOut):最终 CRC 是否反转
  6. 输出异或值(XorOut):与最终 CRC 异或的值

这些参数定义了不同的 CRC 标准(CRC-8、CRC-16、CRC-32 等)

CRC 计算过程

CRC 计算的高级过程包括:

  1. 发送方

    • 在原始数据后附加 k-1 个零(其中 k 是 CRC 的位宽)
    • 使用模 2 除法,用生成多项式除以上述结果
    • 余数即为 CRC 值,附加到原始数据后
  2. 接收方

    • 用相同的生成多项式除以接收到的数据(包括 CRC)
    • 如果余数为零,则认为数据无错误
    • 如果余数非零,则检测到错误

模 2 二进制除法

CRC 计算的核心是模 2 二进制除法,其特点是:

  • 使用异或(XOR)操作代替减法
  • 没有进位或借位操作
  • 按位处理消息
  • 可以在硬件和软件中高效实现

常见 CRC 标准

CRC 类型位宽多项式初始值输入反转输出反转输出异或值常见用途
CRC-880x070x000x00ATM 头部
CRC-8/CDMA200080x9B0xFF0x00移动网络
CRC-16/CCITT160x10210xFFFF0x0000HDLC, 蓝牙
CRC-16/IBM160x80050x00000x0000USB, SCSI
CRC-32320x04C11DB70xFFFFFFFF0xFFFFFFFF以太网, ZIP

Python 实现

核心代码

让我们看看 CRC 在 Python 模型中的实现:

def reverse_bits(x, num_bits):"""反转指定位数的位序"""reversed_x = 0for i in range(num_bits):reversed_x |= ((x >> i) & 1) << (num_bits - 1 - i)return reversed_xdef crc_process_byte(crc, byte, poly, width, refin):"""处理单个字节的CRC计算"""# 1. 如果需要反转输入if refin:byte = reverse_bits(byte, 8)# 2. 直接将字节与CRC高位进行异或(避免一位一位处理)crc ^= (byte << (width - 8))# 3. 处理8个位for _ in range(8):# 判断最高位,使用位移判断避免额外计算if crc & (1 << (width - 1)):# 左移+异或多项式crc = ((crc << 1) ^ poly) & ((1 << width) - 1)else:# 仅左移crc = (crc << 1) & ((1 << width) - 1)return crcdef calculate_crc(data_bytes, width, poly, init, refin, refout, xorout):"""计算字节序列的CRC校验值"""# 确保poly不包含最高位(如果已经包含)poly = poly & ((1 << width) - 1)crc = initfor byte in data_bytes:crc = crc_process_byte(crc, byte, poly, width, refin)if refout:crc = reverse_bits(crc, width)crc ^= xoroutcrc &= (1 << width) - 1  # 确保结果在低width位return crc

关键函数

  1. reverse_bits:反转值的位序(用于 RefIn 和 RefOut)
  2. crc_process_byte:在 CRC 计算过程中处理单个字节:
    • 可选择反转输入字节
    • 将字节与当前 CRC 值异或
    • 使用多项式除法处理每一位
  3. calculate_crc:计算字节序列 CRC 的主函数:
    • 使用 init 值初始化 CRC 寄存器
    • 处理输入数据中的每个字节
    • 可选择反转最终 CRC
    • 将结果与 XorOut 值异或

测试

import crcmoddef reverse_bits(x, num_bits):"""反转指定位数的位序"""reversed_x = 0for i in range(num_bits):reversed_x |= ((x >> i) & 1) << (num_bits - 1 - i)return reversed_xdef crc_process_byte(crc, byte, poly, width, refin):"""处理单个字节的CRC计算"""# 1. 如果需要反转输入if refin:byte = reverse_bits(byte, 8)# 2. 直接将字节与CRC高位进行异或(避免一位一位处理)crc ^= (byte << (width - 8))# 3. 处理8个位for _ in range(8):# 判断最高位,使用位移判断避免额外计算if crc & (1 << (width - 1)):# 左移+异或多项式crc = ((crc << 1) ^ poly) & ((1 << width) - 1)else:# 仅左移crc = (crc << 1) & ((1 << width) - 1)return crcdef calculate_crc(data_bytes, width, poly, init, refin, refout, xorout):"""计算字节序列的CRC校验值"""# 确保poly不包含最高位(如果已经包含)poly = poly & ((1 << width) - 1)crc = initfor byte in data_bytes:crc = crc_process_byte(crc, byte, poly, width, refin)if refout:crc = reverse_bits(crc, width)crc ^= xoroutcrc &= (1 << width) - 1  # 确保结果在低width位return crc# 示例用法
if __name__ == "__main__":# 示例参数(以CRC-8为例)width = 16poly = 0x10c21  # 多项式 x^8 + x^2 + x + 1 (隐式最高位)init = 0xffffxorout = 0x0000# 输入数据(假设输入S018F0转换为字节数组)input_data = [0x71,0xFA,0x96,0x59,0x91,0x93,0xB2,0xD1,0x35]crc_result_standard = calculate_crc(input_data, width, poly, init, False, False, xorout)print(f"CRC结果: 0x{crc_result_standard:02X}")crc_result_reflected = calculate_crc(input_data, width, poly, init, True, True, xorout)print(f"CRC结果: 0x{crc_result_reflected:02X}")crc_result_mixed1=calculate_crc(input_data,width,poly,init,True,False,xorout)print(f"CRC结果: 0x{crc_result_mixed1:02X}")crc_result_mixed2=calculate_crc(input_data,width,poly,init,False,True,xorout)print(f"CRC结果: 0x{crc_result_mixed2:02X}")crc16_func_standard = crcmod.mkCrcFun(poly, initCrc=0xffff, rev=False, xorOut=0x0000)crc16_func_reflected = crcmod.mkCrcFun(poly, initCrc=0xffff, rev=True, xorOut=0x0000)print(f"Expected standard: {crc16_func_standard(bytes(input_data)):04x}")print(f"Expected reflected: {crc16_func_reflected(bytes(input_data)):04x}")

在这里插入图片描述

此外,也可以在CRC在线计算,验证结果

Verilog 实现

硬件实现在 Verilog 中分为两个模块:

主 CRC 模块(crc.v

module crc #(parameter bits =8,parameter poly =8'h33,parameter init =8'hff,parameter [0:0]refin =1'b0,parameter [0:0]refout =1'b0,parameter xorout =8'h00
)(input clk,input rst_n,input data_valid,input start,input [7:0] data_in,output reg crc_ready,output reg [bits-1:0] crc_out
);// 内部寄存器
reg  [bits-1:0] crc_reg;
wire [bits-1:0] crc_next;
reg data_processed;// 实例化字节处理模块
crc_process_byte #(.bits(bits),.poly(poly)) uut (.crc_in(crc_reg),.byte_in(data_in),.refin_in(refin),.crc_out(crc_next)
);// 位翻转函数实现
function [bits-1:0] reflect;input [bits-1:0] data;integer i;beginreflect = 0;for (i = 0; i < bits; i = i + 1)reflect = reflect|(data[i]<<(bits-1-i));end
endfunctionalways @(posedge clk or negedge rst_n) beginif(!rst_n) begincrc_reg <= init;crc_ready <= 0;crc_out <= 0;data_processed <= 0;end else if(start) begin// 开始新的计算crc_reg <= init;crc_ready <= 0;data_processed <= 0;end else if(data_valid) begin// 处理数据crc_reg <= crc_next;crc_ready <= 0;data_processed <= 1;end else if (data_processed && !data_valid && !crc_ready) begin// 数据处理完成if(refout) begincrc_out <= (reflect(crc_reg) ^ xorout) & ((1<<bits)-1);end else begincrc_out <= (crc_reg ^ xorout) & ((1<<bits)-1);endcrc_ready <= 1;end
end
endmodule

字节处理模块(crc_process_byte.v

module crc_process_byte #(parameter bits     = 8,parameter poly     = 8'h33
)
(input  refin_in,input  [8-1:0] byte_in,input  [bits-1:0] crc_in,output  reg [bits-1:0] crc_out
);reg [7:0] byte_reg;
reg [bits-1:0] crc_reg;
integer i;always@(*)beginbyte_reg = refin_in? reflect(byte_in): byte_in;crc_reg = crc_in^(byte_reg<<(bits-8));crc_out = 0;for(i=0;i<8;i=i+1)beginif(crc_reg[bits-1])begincrc_reg=((crc_reg<<1)^poly)&((1<<bits)-1);endelse begincrc_reg=(crc_reg<<1)&((1<<bits)-1);endendcrc_out = crc_reg;
end// 位翻转函数实现
function [7:0] reflect;input [7:0] data;integer i;beginreflect = 0;for (i = 0; i < 8; i = i + 1)reflect = reflect|(data[i]<<(7-i));end
endfunction
endmodule

测试示例(crc_tb.v

`timescale 1ns/1nsmodule crc_tb;// 参数定义parameter CRC_WIDTH = 8;parameter CRC_POLY = 9'h107;parameter CRC_INIT = 8'hff;parameter CRC_REFIN = 0;parameter CRC_REFOUT = 0;parameter CRC_XOROUT = 0;// 信号声明reg clk;reg rst_n;reg data_valid;reg start;reg [7:0] data_in;wire crc_ready;wire [CRC_WIDTH-1:0] crc_out;// 直接实例化CRC模块,不再使用crc_top作为中间层crc #(.bits(CRC_WIDTH),.poly(CRC_POLY),.init(CRC_INIT),.refin(CRC_REFIN),.refout(CRC_REFOUT),.xorout(CRC_XOROUT)) crc_inst (.clk(clk),.rst_n(rst_n),.data_valid(data_valid),.start(start),.data_in(data_in),.crc_ready(crc_ready),.crc_out(crc_out));// 测试流程
initial begin// 复位rst_n = 0;start = 0;data_valid = 0;data_in = 0;#10 rst_n = 1;// 开始新的CRC计算#10 start = 1;#10 start = 0;// 输入数据字节data_in = 8'h01; data_valid = 1; #10 data_valid = 0; #10;data_in = 8'h02; data_valid = 1; #10 data_valid = 0; #10;data_in = 8'h03; data_valid = 1; #10 data_valid = 0; #10;data_in = 8'h04; data_valid = 1; #10 data_valid = 0; #10;data_in = 8'h05; data_valid = 1; #10 data_valid = 0; #20;// 等待结果wait(crc_ready);$display("CRC-8结果: 0x%h", crc_out);end// 时钟生成initial beginclk = 0;forever #5 clk = ~clk; // 10ns周期时钟endendmodule

在这里插入图片描述

输出结果为0x85, 我们用网站进行测试

在这里插入图片描述

输出结果一致

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79638.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大模型】DeepSeek + Coze 打造个人专属AI智能体使用详解

目录 一、前言 二、AI智能体介绍 2.1 什么是AI智能体 2.2 AI智能体核心能力 2.3 AI智能应用场景 三、coze 介绍 3.1 coze是什么 3.1.1 平台概述 3.1.2 平台适用人群 3.2 平台核心功能 3.3 coze可以做什么 3.4 为什么选择coze 四、coze 搭建AI智能体操作实践 4.1 搭…

MySQL入门:数据表的创建

​今天我们来介绍一下除HTML外的另一种语言&#xff1a;MySQL语言&#xff1b; MySQL&#xff1a;即一种用于管理和处理关系数据库的标准语言。要用于执行查询、更新、管理数据库中的数据以及定义和操作数据库结构。 接下来我会逐一介绍它的作用以及其中数据表&#xff0c;数据…

[图论]生成树 引言

生成树 引言 生成树&#xff1a;一个连通图的生成树是该图的一个极小连通子图。生成树中含有图中全部(设 V V V个)顶点及构成一棵树的 V − 1 V-1 V−1条边&#xff0c;且生成树中不应有环。最小生成树(MST)&#xff1a;图的所有生成树中&#xff0c;边权之和最小的生成树。显…

AI调试工具有哪些?

一、深度学习框架专用调试工具 TensorBoard • 功能&#xff1a;实时监控训练指标&#xff08;损失值、准确率&#xff09;、可视化神经网络结构、分析参数分布和梯度信息 • 适用框架&#xff1a;TensorFlow、PyTorch&#xff08;通过插件&#xff09; • 特点&#xff1a;支持…

深入理解 MCP 协议:开启 AI 交互新时代

深入理解 MCP 协议&#xff1a;开启 AI 交互新时代&#x1f680; 在当今人工智能蓬勃发展的时代&#x1f310;&#xff0c;大型语言模型&#xff08;LLM&#xff09;已经在众多领域展现出了强大的能力&#xff0c;令人惊叹&#x1f44f;&#xff01;然而&#xff0c;传统的 LLM…

微信、抖音、小红书emoji符号大全

1、Emoji 日常符号 &#x1f463;&#x1f440;&#x1f441;️&#x1f444;&#x1f48b;&#x1f442;&#x1f9bb;&#x1f443;&#x1f445;&#x1f9e0;&#x1fac0;&#x1fac1;&#x1f9b7;&#x1f9b4;&#x1f4aa;&#x1f9be;&#x1f9bf;&#x1f9b5;&a…

【嵌入式】——Linux系统远程操作和程序编译

目录 一、虚拟机配置网络设置 二、使用PuTTY登录新建的账户 1、在ubuntu下开启ssh服务 2、使用PuTTY连接 三、树莓派实现远程登录 四、树莓派使用VNC viewer登录 五、Linux使用talk聊天程序 1、使用linux自带的talk命令 2、使用c语言编写一个talk程序 一、虚拟机配置网络…

春和景明-C语言简单代码

题目要求&#xff1a; 请在centOS Linux中编写一个C语言程序实现如下功能&#xff1a; 同时创建100个用户&#xff0c;用户的账户名称为&#xff1a;Student01 Student02 … Student100;设置每个用户的初始密码为&#xff1a;stud123456请用gcc编译C的源代码&#xff0c;生…

设计模式之工厂模式(factory pattern):在商品对象创建系统中的应用

目录 一、设计思路 1. 简单工厂模式 2. 工厂方法模式 3. 抽象工厂模式 二、UML类图&#xff08;PlantUML格式&#xff09; 1.简单工厂模式 2.工厂方法模式 3.抽象工厂模式 三、实现过程与结果 1. 简单工厂模式 2. 工厂方法模式 3. 抽象工厂模式 四、总结 在面向对…

Trae,字节跳动推出的 AI 编程助手插件

Trae 插件是 Trae 旗下全新一代的人工智能编程助手&#xff08;前身为 MarsCode 编程助手&#xff09;&#xff0c;以插件形式集成在本地开发环境中&#xff0c;具备极高的兼容性和灵活性&#xff0c;旨在提升开发效率和代码质量。它支持超过100种编程语言&#xff0c;兼容主流…

工作纪实_63-Mac电脑使用brew安装软件

最近在接触kafka&#xff0c;想着在自己的电脑安装一套环境&#xff0c;docker也能行&#xff0c;但是还是想装一些原生的软件试试看&#xff0c;因此便想着整理一下brew的命令&#xff0c;这命令确实是方便&#xff0c;不需要下载tar包乱八七糟的东西&#xff0c;一键安装 bre…

Python语法系列博客 · 第8期[特殊字符] Lambda函数与高阶函数:函数式编程初体验

上一期小练习解答&#xff08;第7期回顾&#xff09; ✅ 练习1&#xff1a;找出1~100中能被3或5整除的数 result [x for x in range(1, 101) if x % 3 0 or x % 5 0]✅ 练习2&#xff1a;生成字符串长度字典 words ["apple", "banana", "grape…

Redis--主从复制

目录 一、配置 1.1 建立复制 1.2 断开复制 1.3 安全性 1.4 只读 1.5 传输延迟 二、拓扑 2.1 一主一从结构 2.2 一主多从结构 2.3 树形主从结构 在分布式系统中为了解决单点问题&#xff0c;通常会把数据复制多个副本部署到其他服务器&#xff0c;满足故障恢 复和负载均衡等需求…

已注册商标如何防止被不使用撤销!

近年来已注册商标被撤销越来越多&#xff0c;不乏著名企业或机构&#xff0c;普推知产商标老杨看到前一阵看到央视和百度等申请的商标也被申请撤销&#xff0c;连续三年不使用撤销也是正常的商标流程。 已注册商标被撤销普推老杨看到案例主要是集中在一些早期申请注册的好记的商…

解密大模型背后的秘密:训练、优化与挑战

解密大模型背后的秘密&#xff1a;训练、优化与挑战 在当今的人工智能领域&#xff0c;大模型&#xff08;Large Language Models, LLMs&#xff09;已经成为了一个不可忽视的存在。从自然语言处理到图像生成&#xff0c;再到推荐系统&#xff0c;大模型以其强大的泛化能力和创…

App自动化测试流程方案与架构设计

App自动化测试流程方案与架构设计 一、核心流程设计 #mermaid-svg-kN4GmIvHb8MMT83M {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-kN4GmIvHb8MMT83M .error-icon{fill:#552222;}#mermaid-svg-kN4GmIvHb8MMT83M .e…

字节跳动发布视频生成基础大模型 Seaweed-7B

近日&#xff0c;字节跳动发布了其全新视频生成基础大模型 Seaweed-7B&#xff0c;该模型由字节 Seed 团队开发&#xff0c;参数量仅为 70 亿&#xff0c;在多个方面展现出卓越性能&#xff0c;为 AI 视频生成领域带来了新的突破。 功能特点 支持多种生成方式&#xff1a;Sea…

如何基于区块链进行虚拟电厂运营平台建设?

本项目旨在基于区块链技术建设虚拟电厂运营平台&#xff0c;以提升省内大用户及工业企业和工业园区的需求响应能力&#xff0c;优化能源结构配置&#xff0c;并推动能源交易、需求响应和现货交易等新型业态的发展。通过建设虚拟电厂&#xff0c;项目将实现工业企业及园区各供用…

LeetCode[459]重复的子字符串(KMP解法)

思路&#xff1a; 最近迷上了KMP算法&#xff0c;所以这道题也是来搞一下KMP算法&#xff0c;总所周知KMP是需要维护一个前缀表&#xff0c;KMP算法不是比较一个字符串包不包含另一个字符串的吗&#xff0c;这个重复字符串的题也能用&#xff1f;猫爷&#xff1a;毋庸置疑&…

spring-batch批处理框架(2)

文章目录 八、作业控制8.1 作业启动8.1.1 SpringBoot 启动8.1.2 Spring 单元测试启动8.1.3 RESTful API 启动 8.2 作业停止方案1&#xff1a;Step 步骤监听器方式方案2&#xff1a;StepExecution停止标记 8.3 作业重启8.3.1 禁止重启8.3.2 限制重启次数8.3.3 无限重启 九、Item…