【FPGA/IC】CRC电路的Verilog实现
前言
在通信过程中由于存在各种各样的干扰因素,可能会导致发送的信息与接收的信息不一致,比如发送数据为 1010_1010,传输过程中由于某些干扰,导致接收方接收的数据却成了0110_1010。为了保证数据传输的正确性,工程师们发明了一些检错方法,比如奇偶校验和CRC校验。
CRC校验(Cyclic Redundancy Check,循环冗余校验)是数据传输过程中常用的一种检错方法,针对要发送的数据,其使用一些特定的多项式可以计算出CRC检验结果,CRC校验结果与原始数据一起传输到接收端。

接收端在接收数据的同时按照相同的多项式对接收数据进行校验预算,并将校验结果和接收的结果进行对比,如果二者相同则认为没有发生传输错误;如果不同则认为发生了传输错误。如果发生了错误,接收端可以舍弃该帧数据并通知发送端重新传输数据。
尽管理论上仍然可能存在传输数据有误,但确无法被CRC校验出来的情况,但是这个概率极低,实际应用过程中基本可以忽略。
简单来讲,CRC校验,就是通信双方事先约定好一个CRC模型(一般来讲这个模型最重要的就是多项式),假如发送的数据除以多项式后得到的余数是X,那么接收方接收到的数据除以同样的多项式后,其得到的余数也应该为A。若二者得到的余数不同,则可认为是传输过程中发生了错误。
CRC参数模型
不同的协议在传输数据时采用了不同的CRC参数模型,模型由以下参数来定义。
-
NAME:模型名称,比如CRC-8,CRC-16/USB,CRC-32等。
-
WIDTH:宽度,即生成的CRC校验位宽,如CRC-8生成的结果为8位。
-
POLY:生成多项式的简写(16进制表示)。省略最高位1,如CRC-8的多项式为 x8 + x2 + x + 1,则二进制为1_0000_0111,省略最高位1,二进制0000_0111转换为十六进制为0x07。
-
INIT:这是算法开始时寄存器的初始化值,十六进制表示。
-
REFIN:true或false,在进行计算之前,原始数据是否翻转。原始数据:0xAA = 1010_1010,如果REFIN为true,则翻转后为0101_0101 = 0x55。
-
XOROUT:计算结果与此参数进行异或运算后得到的CRC值,和WIDTH位宽一致。
-
REFOUT:true或false,运算完成之后,得到的CRC值是否进行翻转,方法同上。
下面是一些常见的CRC参数模型:

CRC算法的完整过程
假设通信双方约定的CRC模型为CRC-5/USB,发送的数据为8bits数据0xAA,即1010_1010。
-
CRC对应的多项式为0x05,补上省略的高位的1,则为10_0101。
-
REFIN为ture,所以需要翻转数据,即1010_1010 -> 0101_0101。
-
多项式的最高项为5,所以在发送数据末端补5个0,即0101_0101_00000。
-
发送数据除以多项式,即二者进行模2除法,过程如下(注意需要先异或一次初始值,由于很多模型的初始值为0,因为任何数异或0都等于它本身,所以这一步被省略掉了)。得到结果为00011。
-
将该结果与XOROUT值做异或运算,即 00011 ^ 11111 = 11100。
-
REFOUT为ture,所以需要翻转数据,即11100 -> 00111。即最终的CRC校验值为00111。

CRC算法的Verilog实现
一般有两种电路可以用来实现CRC算法,串行CRC电路和并行CRC电路。
串行CRC
串行CRC电路以LFSR为基础,每个时钟周期输入一个数据的单bit,在数据宽度个周期后移位寄存器的值即为CRC校验值。下图是CRC8-CCITT模型的电路示意图。

接下来仍然以CRC-8模型为例,编写RTL代码(CRC-8的模型比较简单,没有反转那些步骤):

//串行CRC-8:宽度8,多项式0x07(x^8+x^2+x+1),初始值00,XOROUT00,REFIN/REFOUT均为FALSE
module test(input clk, //时钟input rst, //异步复位input ser_in, //串行输入数据input ser_in_val, //串行输入数据有效output [7:0] crc_data, //CRC校验数据output crc_data_val //CRC校验数据有效
);//定义寄存器变量
reg [7:0] crc; //LFSR寄存器实现移位、异或操作
reg [2:0] cnt; //串行输入数据计数
reg data_val; //数据输出有效信号//连接端口
assign crc_data = crc;
assign crc_data_val = data_val;//构建串行输入LFSR
always @(posedge clk or posedge rst)beginif(rst)crc <= 8'd0; //复位载入初始值else if(data_val) crc <= 8'd0; //校验完成后恢复初始值else if(ser_in_val) begincrc[0] <= crc[7] ^ ser_in;crc[1] <= crc[0] ^ crc[7] ^ ser_in;crc[2] <= crc[1] ^ crc[7] ^ ser_in;crc[3] <= crc[2];crc[4] <= crc[3];crc[5] <= crc[4];crc[6] <= crc[5];crc[7] <= crc[6];endend//串行输入数据计数,0~7共8个周期
always @(posedge clk or posedge rst)beginif(rst)cnt <= 0; else if(ser_in_val) begincnt <= cnt + 1;end
end//输出8个数据后,拉高校验完成信号
always @(posedge clk or posedge rst)beginif(rst)data_val <= 0; else if(ser_in_val && (cnt == 7)) data_val <= 1; //8位串行输入传输完成,则拉高该信号elsedata_val <= 0; //其他时间均为低电平
endendmodule
因为8位输入数据一共只有256个,所以我们可以用穷举法来进行测试,编写TB:依次产生0~255这256个数据并串行输入,CRC转换完成后在窗口打印信息。
`timescale 1ns/1ns
module tb_test();//信号声明
reg clk;
reg rst;
reg ser_in;
reg ser_in_val; wire[7:0] crc_data;
wire crc_data_val;//被测模块实例化
test inst_test(.clk (clk ), //时钟信号.rst (rst ), //时钟信号.ser_in (ser_in ), //串行输入数据.ser_in_val (ser_in_val ), //串行输入数据有效信号.crc_data (crc_data ),.crc_data_val (crc_data_val)
); //生成时钟信号
initial beginclk = 1'b0;forever #5 clk = ~clk;
end//生成复位信号
initial beginrst = 1'b1; //复位#40 rst = 1'b0; //取消复位
end //构建一个生成串行数据的任务
task data_gen(input [7:0] data
);beginfor(integer i=0;i<=7;i=i+1)begin@(posedge clk) ser_in_val <= 1;ser_in <= data[7-i]; #10;endser_in_val <= 0; @(posedge crc_data_val); //当输出数据有效时,打印到窗口$display("data = %h,crc = %h",data,crc_data);#10;
end
endtask //仿真过程
initial beginser_in = 0;ser_in_val = 0;@(negedge rst); //等待复位完成//依次产生0-255这256个8bits数据,通过任务data_gen转换成串行输入for(integer j=0;j<=255;j=j+1)begindata_gen(j);end #10 $stop; //关闭仿真
endendmodule
部分仿真波形如下:

可以看到数据00、01、02、04分别产生的CRC-8校验结果为00、07、0E、09。与这个网站产生的正确结果(CRC(循环冗余校验)在线计算)比对,发现测试结果正确。
同时,Tcl窗口也打印了全部的校验结果(截图只有部分):

并行CRC
了解了串行CRC的结构,实现并行CRC就比较简单了,因为串行CRC是每个时钟周期都寄存了输入数据,然后在各个周期进行计算,那么并行CRC无非就是将电路展开,把所有的运算都放到一个时钟周期来实现。这是一种典型的“面积换时间”,通过增大电路面积来实现低延时latency(即高速率)。
为了说明方便一点,这里选取多项式为 x^4 + x^1 + 1 的CRC4校验来说明,它的串行电路生成部分是这样的:
crc[0] <= crc[3] ^ data ;
crc[1] <= crc[0] ^ crc[3] ^ data;
crc[2] <= crc[1];
crc[3] <= crc[2];
这是时序逻辑,转换成组合逻辑就是当前寄存器的值等于之前寄存器的值和当前输入做运算,用变量init来表示寄存器初始值,然后做8次迭代,
crc[0] = init[3] ^ data ;
crc[1] = init[0] ^ init[3] ^ data;
crc[2] = init[1];
crc[3] = init[2];
为了方便,在crc后面用迭代次数-1表示,那么第1次迭代:输入数据的最高位data[7]和上一轮的LFSR寄存器值(因为才开始,所以是初始值)做异或运算。
data[7]:crc7[0] = init[3] ^ data[7] ;crc7[1] = init[0] ^ init[3] ^ data[7];crc7[2] = init[1];crc7[3] = init[2];
同理,有第2次迭代:输入数据的次高位data[6]和上一轮的LFSR寄存器值(即crc7变量)做异或运算。
data[6]:crc6[0] = crc7[3] ^ data[6] = init[2] ^ data[6];crc6[1] = crc7[0] ^ crc7[3] ^ data[6] = init[3] ^ data[7] ^ init[2] ^ data[6];crc6[2] = crc7[1] = init[0] ^ init[3] ^ data[7];crc6[3] = crc7[2] = init[1];
直到第8次迭代,输入最后一个数据:
data[5]:crc5[0] = crc6[3] ^ data[5] = init[1] ^ data[5];crc5[1] = crc6[0] ^ crc6[3] ^ data[5] = init[2] ^ data[6] ^ init[1] ^ data[5];crc5[2] = crc6[1] = init[3] ^ data[7] ^ init[2] ^ data[6];crc5[3] = crc6[2] = init[0] ^ init[3] ^ data[7];
data[4]:crc4[0] = crc5[3] ^ data[4] = init[0] ^ init[3] ^ data[7] ^ data[4]crc4[1] = crc5[0] ^ crc5[3] ^ data[4] = init[1] ^ data[5] ^ init[0] ^ init[3] ^ data[7] ^ data[4];crc4[2] = crc5[1] = init[2] ^ data[6] ^ init[1] ^ data[5];crc4[3] = crc5[2] = init[3] ^ data[7] ^ init[2] ^ data[6];
data[3]:crc3[0] = crc4[3] ^ data[3] = init[3] ^ data[7] ^ init[2] ^ data[6] ^ data[3]crc3[1] = crc4[0] ^ crc4[3] ^ data[3] = init[0] ^ init[3] ^ data[7] ^ data[4] ^ init[3] ^ data[7] ^ init[2] ^ data[6] ^ data[3]crc3[2] = crc4[1] = init[1] ^ data[5] ^ init[0] ^ init[3] ^ data[7] ^ data[4];crc3[3] = crc4[2] = init[2] ^ data[6] ^ init[1] ^ data[5];
data[2]:crc2[0] = crc3[3] ^ data[2] = init[2] ^ data[6] ^ init[1] ^ data[5] ^ data[2]crc2[1] = crc3[0] ^ crc3[3] ^ data[2] = init[3] ^ data[7] ^ init[2] ^ data[6] ^ data[3] ^ init[2] ^ data[6] ^ init[1] ^ data[5] ^ data[2]crc2[2] = crc3[1] = init[0] ^ init[3] ^ data[7] ^ data[4] ^ init[3] ^ data[7] ^ init[2] ^ data[6] ^ data[3]crc2[3] = crc3[2] = init[1] ^ data[5] ^ init[0] ^ init[3] ^ data[7] ^ data[4]
data[1]:crc1[0] = crc2[3] ^ data[1] = init[1] ^ data[5] ^ init[0] ^ init[3] ^ data[7] ^ data[4] ^ data[1]crc1[1] = crc2[0] ^ crc2[3] ^ data[1] = init[2] ^ data[6] ^ init[1] ^ data[5] ^ data[2] ^ init[1] ^ data[5] ^ init[0] ^ init[3] ^ data[7] ^ data[4] ^ data[1]crc1[2] = crc2[1] = init[3] ^ data[7] ^ init[2] ^ data[6] ^ data[3] ^ init[2] ^ data[6] ^ init[1] ^ data[5] ^ data[2]crc1[3] = crc2[2] = init[0] ^ init[3] ^ data[7] ^ data[4] ^ init[3] ^ data[7] ^ init[2] ^ data[6] ^ data[3]
data[0]:crc0[0] = crc1[3] ^ data[0] = init[0] ^ init[3] ^ data[7] ^ data[4] ^ init[3] ^ data[7] ^ init[2] ^ data[6] ^ data[3] ^ data[0] = init[0] ^ data[4] ^ init[2] ^ data[6] ^ data[3] ^ data[0]crc0[1] = crc1[0] ^ crc1[3] ^ data[0] = init[1] ^ data[5] ^ init[0] ^ init[3] ^ data[7] ^ data[4] ^ data[1] ^ init[0] ^ init[3] ^ data[7] ^ data[4] ^ init[3] ^ data[7] ^ init[2] ^ data[6] ^ data[3] ^ data[0]= init[1] ^ data[5]^ init[3] ^ data[4] ^ data[1]^ data[7] ^ data[4] ^ init[2] ^ data[6] ^ data[3] ^ data[0]crc0[2] = crc1[1] = init[2] ^ data[6] ^ init[1] ^ data[5] ^ data[2] ^ init[1] ^ data[5] ^ init[0] ^ init[3] ^ data[7] ^ data[4] ^ data[1]crc0[3] = crc1[2] = init[3] ^ data[7] ^ init[2] ^ data[6] ^ data[3] ^ init[2] ^ data[6] ^ init[1] ^ data[5] ^ data[2]
把crc0的表达式整理一下:
crc0[0] = data[6] ^ data[4] ^ data[3] ^ data[0] ^ init[0] ^ init[2];
crc0[1] = data[7] ^ data[6] ^ data[5] ^ data[1] ^ data[3] ^ data[0] ^ init[1] ^ init[2] ^ init[3];
crc0[2] = data[7] ^ data[6] ^ data[4] ^ data[2] ^ data[1] ^ init[0] ^ init[2] ^ init[3];
crc0[3] = data[7] ^ data[5] ^ data[3] ^ data[2] ^ init[1] ^ init[3];
和这个网站http://crctool.easics.be/用工具生成的代码(核心部分)做对比,二者结果一致。
newcrc[0] = data[6] ^ data[4] ^ data[3] ^ data[0] ^ crc[0] ^ crc[2];
newcrc[1] = data[7] ^ data[6] ^ data[5] ^ data[3] ^ data[1] ^ data[0] ^ crc[1] ^ crc[2] ^ crc[3];
newcrc[2] = data[7] ^ data[6] ^ data[4] ^ data[2] ^ data[1] ^ crc[0] ^ crc[2] ^ crc[3];
newcrc[3] = data[7] ^ data[5] ^ data[3] ^ data[2] ^ crc[1] ^ crc[3];
接着编写并行CRC-8的代码:
//并行CRC-8:宽度8,多项式0x07(x^8+x^2+x+1),初始值00,XOROUT00,REFIN/REFOUT均为FALSE
module test(input clk, //时钟input rst, //异步复位input [7:0] pal_in, //并行8位输入数据input pal_in_val, //并行输入数据有效output [7:0] crc_data, //CRC校验数据output crc_data_val //CRC校验数据有效
);//定义寄存器变量
reg [7:0] crc; //CRC校验数据
reg data_val; //CRC校验数据输出有效信号localparam CRC_INIT = 8'd0; //LFSR寄存器初始值//连接端口
assign crc_data = crc;
assign crc_data_val = data_val;//并行电路使用函数来构造
function [7:0] CRC8;input [7:0] data; //被校验数据input [7:0] crc_init; //寄存器初值beginCRC8[0] = data[7] ^ data[6] ^ data[0] ^ crc_init[0] ^ crc_init[6] ^ crc_init[7];CRC8[1] = data[6] ^ data[1] ^ data[0] ^ crc_init[0] ^ crc_init[1] ^ crc_init[6];CRC8[2] = data[6] ^ data[2] ^ data[1] ^ data[0] ^ crc_init[0] ^ crc_init[1] ^ crc_init[2] ^ crc_init[6];CRC8[3] = data[7] ^ data[3] ^ data[2] ^ data[1] ^ crc_init[1] ^ crc_init[2] ^ crc_init[3] ^ crc_init[7];CRC8[4] = data[4] ^ data[3] ^ data[2] ^ crc_init[2] ^ crc_init[3] ^ crc_init[4];CRC8[5] = data[5] ^ data[4] ^ data[3] ^ crc_init[3] ^ crc_init[4] ^ crc_init[5];CRC8[6] = data[6] ^ data[5] ^ data[4] ^ crc_init[4] ^ crc_init[5] ^ crc_init[6];CRC8[7] = data[7] ^ data[6] ^ data[5] ^ crc_init[5] ^ crc_init[6] ^ crc_init[7];end
endfunction//当输入有效时进行CRC校验
always @(posedge clk or posedge rst)beginif(rst)crc <= 8'd0; else if(pal_in_val) //输入有效时crc <= CRC8(pal_in,CRC_INIT); //校验结果落后一拍
end//在输入数据有效的下一个周期输出有效
always @(posedge clk or posedge rst)beginif(rst)data_val <= 0; else if(pal_in_val) data_val <= 1; elsedata_val <= 0; //其他时间均为低电平
endendmodule
测试逻辑和上面的串行CRC一样:依次输入0~255这256个数据,观察CRC校验结果:
`timescale 1ns/1ns
module tb_test();//信号声明
reg clk;
reg rst;
reg [7:0] pal_in;
reg pal_in_val; wire[7:0] crc_data;
wire crc_data_val;//被测模块实例化
test inst_test(.clk (clk ), //时钟信号.rst (rst ), //时钟信号.pal_in (pal_in ), //串行输入数据.pal_in_val (pal_in_val ), //串行输入数据有效信号.crc_data (crc_data ),.crc_data_val (crc_data_val)
); //生成时钟信号
initial beginclk = 1'b0;forever #5 clk = ~clk;
end//生成复位信号
initial beginrst = 1'b1; //复位#40 rst = 1'b0; //取消复位
end //生成输入数据与时钟使能信号
always @(posedge clk or posedge rst)beginif(rst)beginpal_in <= 255;pal_in_val <= 0;endelse begin pal_in <= pal_in + 1;pal_in_val <= 1;end
end //仿真过程
initial begin#1000 $stop; //关闭仿真
endendmodule
仿真结果如下,CRC校验结果依次输出00-07-0e-09······,与正确结果对比后,发现仿真无误。

- 📣您有任何问题,都可以在评论区和我交流📃!
- 📣本文由 孤独的单刀 原创,首发于CSDN平台🐵,博客主页:wuzhikai.blog.csdn.net
- 📣您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐!
相关文章:
【FPGA/IC】CRC电路的Verilog实现
前言 在通信过程中由于存在各种各样的干扰因素,可能会导致发送的信息与接收的信息不一致,比如发送数据为 1010_1010,传输过程中由于某些干扰,导致接收方接收的数据却成了0110_1010。为了保证数据传输的正确性,工程师们…...
go语言添加代理
LiteIDE 工具->管理 https://mirrors.aliyun.com/goproxy/或https://goproxy.cn,direct 命令行 go env -w GOPROXYhttps://goproxy.cn,direct...
kafka 可视化工具
kafka可视化工具 随着科技发展,中间件也百花齐放。平时我们用的redis,我就会通过redisInsight-v2 来查询数据,mysql就会使用goland-ide插件来查询,都挺方便。但是kafka可视化工具就找了半天,最后还是觉得redpandadata…...
安康杯安全知识竞赛上的讲话稿
各位领导、同志们: 经过近半个月时间的准备,南五十家子镇平泉首届安康杯安全生产知识竞赛初赛在今天圆满落下帏幕,经过紧张激烈的角逐, 代表队、 代表队和 代表队分别获得本次竞赛的第一、二、三名让我们以热烈的掌声表示祝…...
python 基础知识点(蓝桥杯python科目个人复习计划59)
今日复习内容:做题 例题1:建造房屋 问题描述: 小蓝和小桥是两位年轻的建筑师,他们正在设计一座新的城市。 在这个城市中,有N条街道,每条街道上有M个位置可以建造房屋(一个位置只能建造一个房…...
LCR 179. 查找总价格为目标值的两个商品 - 力扣
1. 题目 购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。 2. 示例 3. 分析 题目有说明为递增数组,所以可以利用单调性双指针解决。跟611. 有效的三角形个数为一类题…...
《汇编语言》- 读书笔记 - 第16章-直接定址表
《汇编语言》- 读书笔记 - 第16章-直接定址表 16.1 描述了单元长度的标号(数据标号)检测点 16.1 16.2 在其他段中使用数据标号assume通过标号取地址检测点 16.2 16.3 直接定址表(Direct Addressing Table)例1分析代码效果 例2分析…...
ChatGPT 新增朗读功能,支持 37 种语言
3 月 5 日消息,OpenAI 为其广受欢迎的聊天机器人 ChatGPT 推出了名为「朗读」(Read Aloud) 的新功能。该功能可以让 ChatGPT 用五种不同的声音朗读其回复,旨在为用户提供更加便捷的交互体验。目前,「朗读」功能已上线 ChatGPT 的网页端、iOS …...
洛谷 P8816 [CSP-J 2022] 上升点列(T4)
目录 题目传送门 算法解析 最终代码 提交结果 尾声 题目传送门 [CSP-J 2022] 上升点列 - 洛谷https://www.luogu.com.cn/problem/P8816 算法解析 k 0 且 xi, yi 值域不大时,这题是非常简单的 DP,类似「数字三角形」。 记 dp(x,y) 为「以 (x,y) …...
python爬虫(2)
继上节 查看数组维数 可以使用数组的ndim属性 代码示例如下: import numpy as np c np.random.randint(1,9,5) print(c.ndim) 结果如下: 当然这些也可以结合前面的各种用法来使用 1、选取数组元素 (1)一维数组的元素…...
外包干了8天,技术退步明显。。。。。
先说一下自己的情况,本科生,19年通过校招进入杭州某软件公司,干了接近3年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…...
浅谈去耦电容的作用、选择、布局及其它电容的区别!
在一些文章资料中,去耦电容器被认为是旁路电容器。在其他资料中,去耦电容和旁路电容的区别在于:“旁路电容以输入信号中的干扰为滤波对象,而去耦电容以输出信号的干扰为滤波对象,防止干扰信号返回到输出端。”力量。”…...
抖音视频评论批量采集软件|视频下载工具
《轻松搞定!视频评论批量采集软件,助您高效工作》 在短视频这个充满活力和创意的平台上,了解用户评论是了解市场和观众心声的重要途径之一。为了帮助您快速获取大量视频评论数据,我们推出了一款操作便捷、功能强大的软件ÿ…...
javaSE-----继承和多态
目录 一.初识继承: 1.1什么是继承,为什么需要继承: 1.2继承的概念与语法: 二.成员的访问: 2.1super关键字 2.2this和super的区别: 三.再谈初始化: 小结: 四.初识多态: 4.1多…...
数据库之Oracle数据导入导出
目录 一、单表导出和导入1、单表导出数据2、单表导入数据二、全表导出和导入1、远程导出全表数据2、导入本地数据三、密码带特殊字符的写法1、Windows OS写法2、Linux/Unix OS写法 四、总结 一、单表导出和导入 1、单表导出数据 --导出远程服务上的表数据 exp 用户名/密码IP…...
nRF52832——GPIOTE与外部中断
这里写目录标题 GPIOTE 原理分析GPIOTE 输入事件应用GPIOTE 事件寄存器应用GPIOTE 事件组件的应用(库函数)GPIOTE PORT 事件应用 GPIOTE 任务应用GPIOTE 任务触发 LED 寄存器操作组件方式进行任务配置 GPIOTE 原理分析 GPIO 任务和时间(GPIO…...
根据用户名称实现单点登录
一、参数格式 二、后端实现 Controller层 public class IAccessTokenLoginController extends BaseController {Autowiredprivate ISysUserService sysUserService;Autowiredprivate ISingleTokenServiceImpl tokenService;/*** 登录方法** return 结果*/PostMapping("/l…...
【设计】855. 考场就座
855. 考场就座 这段代码实现了一个考场安排座位的算法。在这个算法中,考场被模拟成一个从0到n-1的数轴,其中每个位置代表一个座位。目的是在每次学生入座时,找到一个使得所有学生之间距离最大化的座位,并在学生离开时更新座位信息…...
Android中的传感器类型和接口名称
本文将介绍传感器坐标轴、基础传感器和复合传感器(动作传感器、姿势传感器、未校准传感器和互动传感器)。 1. 传感器坐标轴 许多传感器的传感器事件值在相对于设备静止的特定坐标系中表示。 1.1 移动设备坐标轴 Sensor API 仅与屏幕的自然方向相关&a…...
解析进程 /proc/pid/maps 和 /proc/pid/smaps
目录 /proc//maps 背景 具体描述 代码实现 实践 /proc/pid/smaps smaps各子项详解 代码实现 代码调用的路径如下: 小结 /proc/<pid>/maps 背景 相对于/proc/meminfo和dumpsys meminfo可以看到系统整体的内存信息,我们还需要能够具体到…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
