【FPGA/IC】CRC电路的Verilog实现

前言

在通信过程中由于存在各种各样的干扰因素,可能会导致发送的信息与接收的信息不一致,比如发送数据为 1010_1010,传输过程中由于某些干扰,导致接收方接收的数据却成了0110_1010。为了保证数据传输的正确性,工程师们发明了一些检错方法,比如奇偶校验和CRC校验。

CRC校验(Cyclic Redundancy Check,循环冗余校验)是数据传输过程中常用的一种检错方法,针对要发送的数据,其使用一些特定的多项式可以计算出CRC检验结果,CRC校验结果与原始数据一起传输到接收端。

image-20240301220815500

接收端在接收数据的同时按照相同的多项式对接收数据进行校验预算,并将校验结果和接收的结果进行对比,如果二者相同则认为没有发生传输错误;如果不同则认为发生了传输错误。如果发生了错误,接收端可以舍弃该帧数据并通知发送端重新传输数据。

尽管理论上仍然可能存在传输数据有误,但确无法被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参数模型:

image-20240301223516679

CRC算法的完整过程

假设通信双方约定的CRC模型为CRC-5/USB,发送的数据为8bits数据0xAA,即1010_1010。

  1. CRC对应的多项式为0x05,补上省略的高位的1,则为10_0101。

  2. REFIN为ture,所以需要翻转数据,即1010_1010 -> 0101_0101。

  3. 多项式的最高项为5,所以在发送数据末端补5个0,即0101_0101_00000

  4. 发送数据除以多项式,即二者进行模2除法,过程如下(注意需要先异或一次初始值,由于很多模型的初始值为0,因为任何数异或0都等于它本身,所以这一步被省略掉了)。得到结果为00011

  5. 将该结果与XOROUT值做异或运算,即 00011 ^ 11111 = 11100

  6. REFOUT为ture,所以需要翻转数据,即11100 -> 00111。即最终的CRC校验值为00111

image-20240302001850633

CRC算法的Verilog实现

一般有两种电路可以用来实现CRC算法,串行CRC电路和并行CRC电路。

串行CRC

串行CRC电路以LFSR为基础,每个时钟周期输入一个数据的单bit,在数据宽度个周期后移位寄存器的值即为CRC校验值。下图是CRC8-CCITT模型的电路示意图。

image-20240302002435666

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

image-20240302014411091

//串行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 

部分仿真波形如下:

image-20240302142933756

可以看到数据00、01、02、04分别产生的CRC-8校验结果为00、07、0E、09。与这个网站产生的正确结果(CRC(循环冗余校验)在线计算)比对,发现测试结果正确。

同时,Tcl窗口也打印了全部的校验结果(截图只有部分):

image-20240302143420471

并行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······,与正确结果对比后,发现仿真无误。

image-20240302161000934


  • 📣您有任何问题,都可以在评论区和我交流📃!
  • 📣本文由 孤独的单刀 原创,首发于CSDN平台🐵,博客主页:wuzhikai.blog.csdn.net
  • 📣您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐

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

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

相关文章

禁止使用搜索引擎,你了解吗?

员工A&#xff1a;“我今天想搜索的时候&#xff0c;用不了浏览器了&#xff0c;你能用么&#xff1f;” 员工B&#xff1a;“不知道啊我试一下啊” “也不行” 员工C&#xff1a;“为什么啊&#xff1f;” 针对上述对话&#xff0c;我们不禁思考&#xff1a; 公司为什么禁…

python基础9_序列类型

回顾: 什么是变量?,有什么用? 可以变化的量, 就是个容器,多次变化,方便后续使用, 前面介绍了哪些数据类型? bool, str, int, float 用什么函数查看数据的类型? a "hello" print(type(a)) 到了这一步,,我们认识了哪些数据类型呢? int 整型(整数), float…

office下常见问题总结——(持续更新学习记录中......)

目录 Wordword2019中, 当给选定的汉字设置格式后&#xff0c;其他相同汉字也会自动应用相同的格式?在Word中&#xff0c;当输入数字后加上句点&#xff08;.&#xff09;时会自动被识别为标题,如何关闭功能?如何让当前的word中的样式 ,匹配全局模版中的样式?在word中,为什么…

一、NLP中的文本分类

目录 1.0 文本分类的应用场景 1.1 文本分类流程 ​编辑 1.2 判别式模型 1.3 生成式模型 1.4 评估 1.5 参考文献 1.0 文本分类的应用场景 &#xff08;1&#xff09;情感分析&#xff1a;中性&#xff0c;正向评论&#xff0c;负向评论&#xff0c;黄色言论&#xff0c;暴…

Java基础 - 8 - 算法、正则表达式、异常

一. 算法 什么是算法&#xff1f; 解决某个实际问题的过程和方法 学习算法的技巧&#xff1f; 先搞清楚算法的流程&#xff0c;再直接去推敲如何写算法 1.1 排序算法 1.1.1 冒泡排序 每次从数组中找出最大值放在数组的后面去 public class demo {public static void main(S…

Matlab偏微分方程拟合 | 完整源码 | 视频教程

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《复杂函数拟合案例分享》本专栏旨在提供 1.以案例的形式讲解各类复杂函数拟合的程序实现方法&#xff0c;并提供所有案例完整源码&#xff1b;2.…

力扣hot100题解(python版63-68题)

63、搜索插入位置 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输…

【npm】前端工程项目配置文件package.json详解

简言 详细介绍了package.json中每个字段的作用。 package.json 本文档将为您介绍 package.json 文件的所有要求。它必须是实际的 JSON&#xff0c;而不仅仅是 JavaScript 对象文字。 如果你要发布你的项目&#xff0c;这是一个特别重要的文件&#xff0c;其中name和version是…

王升:Audio电感对车载功放EMC的影响 | 演讲嘉宾公布

一、智能车载音频 II 专题论坛 智能车载音频 II 专题论坛将于3月28日同期举办&#xff01; 我们正站在一个前所未有的科技革新的交汇点上&#xff0c;重塑我们出行体验的变革正在悄然发生。当人工智能的磅礴力量与车载音频相交融&#xff0c;智慧、便捷与未来的探索之旅正式扬帆…

若依/RuoYi-Vue使用docker-compose部署

系统需求 JDK > 1.8 MySQL > 5.7 Maven > 3.0 Node > 12 Redis > 3 思路 前端服务器 nginx 后端服务器代码打包 java、maven、node 数据库/缓存 mysql、redis 开始 创建目录ruoyi并进入 克隆若依代码 git clone RuoYi-Vue: &#x1f389; 基于Spring…

试用期自我总结报告10篇

试用期自我总结报告&#xff08;篇1&#xff09; 一转眼试用期的时间飞快就过去了&#xff0c;在这段时间里我学习到了很多&#xff0c;也把自己在过去学习的东西得已融会贯通。能够来到幼儿园里成为一名老师是我一直以来的目标&#xff0c;而我也终于完成了自己的目标&#x…

Winform窗体随着屏幕的DPI缩放,会引起窗体变形及字体变形,superTabControl标签字体大小不匹配

一、前言 superTabControl做的浏览器标签(cefsharp)在缩放比例(125%,150%时字体不协调) 物联网浏览器,定制浏览器,多媒体浏览器(支持H264)参考栏目文章即可 二、配置参数 app.manifest参数 dpiAware =true <application xmlns="urn:schemas-microsoft-c…

用 Axios 提升前端异步请求的效率

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

ubuntu22.01安装及配置

前言 本次安装基于VMware Pro 16进行安装。 ubuntu版本&#xff1a;ubuntu-22.04.3-live-server-amd64.iso 1、下载 1.1官网下载 https://ubuntu.com/download 1.2、清华大学镜像网站下载 https://mirrors.tuna.tsinghua.edu.cn/ 进入网站后搜索ubuntu&#xff0c;选择ubu…

Claude3超大杯发布,将取代ChatGPT4?

演示站点&#xff1a; https://ai.uaai.cn 创作模块 &#xff08;Claude3已接入&#xff0c;欢迎体验&#xff09;官方论坛&#xff1a; www.jingyuai.com 前言 今天【超越GPT-4 接近人类水平&#xff01;Claude 3系列大模型惊艳问世】登上了全网热搜&#xff0c;那么【超…

微信小程序实现上拉加载更多

一、前情提要 微信小程序中实现上拉加载更多&#xff0c;其实就是pc端项目的分页。使用的是scroll-view&#xff0c;scroll-view详情在微信开发文档/开发/组件/视图容器中。每次上拉&#xff0c;就是在原有数据基础上&#xff0c;拼接/合并上本次上拉请求得到的数据。这里采用…

电动机工作原理图

电机&#xff08;俗称“马达”&#xff09;是指依据电磁感应定律实现电能转换或传递的一种电磁装置。它的主要作用是产生驱动转矩&#xff0c;作为用电器或各种机械的动力源。 电动机&#xff0c;转子置于旋转磁场中&#xff0c;在旋转磁场的作用下&#xff0c;获得一个转动力…

SSRF漏洞基础原理(浅层面解释 + 靶场演示)

一、SSRF漏洞的基本概念&#xff1a; SSRF--全名&#xff1a;Server-Side Request Forgery&#xff0c;汉译&#xff1a;服务端请求伪造&#xff0c;漏洞别名“借刀杀人”。 想象以下&#xff0c;现存在一个 Web应用&#xff0c;这个Web应用可以帮助我们能爬取互联网上的其他…

好的软件测试人员简历是什么样子的?

简历是入职职场的一张名片&#xff0c;也是进入职场一块“敲门砖”。从某种角度说&#xff0c;简历也是一张专业人员的说明书。 软件测试人员作为IT行业具有技术含量的职业&#xff0c;一份优秀的简历包含的内容以及如何写好简历尤为重要。接下来从以下两方面来介绍这个话题&a…

cannot import name ‘Flask‘ from partially initialized module ‘flask‘

bug&#xff1a; ImportError: cannot import name Flask from partially initialized module flask (most likely due to a circular import) (G:\pythonProject6\flask.py) 这个是因为包的名字和文件的名字一样 修改文件名&#xff1a; 结果 &#x1f923;&#x1f923;&…