FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(1)

news2024/12/26 15:12:46

FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(1)

  • 单字节写时序
  • 单字节读时序
  • I2C 控制器设计
    • 模块框图
    • scl_high 和 scl_low 产生的时序图
    • 状态转移图
  • Verilog代码

FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(1)
FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(2)
FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(3)

单字节写时序

EEPROM器件或其他不同器件,I2C 器件地址字节不同,这样对于 I2C 单字节写时序就会有所差别,如下图分别为 1 字节地址段器件和 2 字节地址段器件单字节写时序图。
在这里插入图片描述
根据时序图,从主机角度来描述一次写入单字节数据过程如下:
主机设置 SDA 为输出;
主机发起起始信号;
主机传输器件地址字节,其中最低位为 0,表明为写操作;
主机设置 SDA 为三态门输入,读取从机应答信号;
读取应答信号成功,主机设置 SDA 为输出,传输 1 字节地址数据;
主机设置 SDA 为三态门输入,读取从机应答信号;
读取应答信号成功,对于两字节地址段器件,传输地址数据低字节,对于 1字节地址段器件,主机设置 SDA 为输出,传输待写入的数据;
设置 SDA 为三态门输入,读取从机应答信号,对于两字节地址段器件,接着步骤 i;对于 1 字节地址段器件,直接跳转到步骤 k;
读取应答信号成功,主机设置 SDA 为输出,传输待写入的数据(对于两字节地址段器件);
设置 SDA 为三态门输入,读取从机应答信号(两字节地址段器件);
读取应答信号成功,主机产生 STOP 位,终止传输。

单字节读时序

在这里插入图片描述
根据时序图,从主机角度描述一次读数据过程,如下:
主机设置 SDA 为输出;
主机发起起始信号;
主机传输器件地址字节,其中最低位为 0,表明为写操作;
主机设置 SDA 为三态门输入,读取从机应答信号;
读取应答信号成功,主机设置 SDA 输出,传输 1 字节地址数据;
主机设置 SDA 为三态门输入,读取从机应答信号;
读取应答信号成功,主机设置 SDA 输出,对于两字节地址段器件,传输低字节地址数据;对于 1 字节地址段器件,无此步骤,直接跳转到步骤 h;
主机发起起始信号;
主机传输器件地址字节,其中最低位为 1,表明为读操作;
设置 SDA 为三态门输入,读取从机应答信号;
读取应答信号成功,主机设置 SDA 为三态门输入,读取 SDA 总线上的一个字节的数据;
产生无应答信号(高电平)(无需设置为输出高电平,因为总线会被自动拉高);
主机产生 STOP 位,终止传输。

I2C 控制器设计

模块框图

在这里插入图片描述
状态机里面线性序列机思路

在这里插入图片描述

scl_high 和 scl_low 产生的时序图

通过上述的讲述,对 I2C 读写器件数据时序有了一定的了解,下面将开始进行控制程序的设计。根据上面 I2C 的基本概念中有关读写时SDA 与 SCL 时序,不管对于从机还是主机,SDA 上的每一位数据在 SCL 的高电平期间保持不变,而数据的改变总是在 SCL 的低电平期间发生。因此,我们可以选用 2 个标志位对时钟 SCL 的高电平和低电平进行标记,如下图所示:scl_high 对 SCL 高电平期间进行标志,scl_low 对 SCL 低电平期间进行标志。这样就可以在 scl_high 有效时读 SDA 数据,在 scl_low 有效时改变数据

如下图所示
在这里插入图片描述

在状态机中,从主机角度来看,SDA 数据线上在写控制、写数据、读控制状态过程是需要串行输出数据,而在读数据状态过程是需要串行输入数据。根据数据在时钟高电平期间保持不变,改变数据在低电平时期的规则,本设计对时钟信号的高低电平进行计数,从而在指定的计数值进行输出或读取数据实现数据的串行输出和串行输入。串行输出和串行输入数据采用任务的形式进行表示,便于在主状态机中多次的调用。图下为计数的过程以及特定状态变化的时序图,这里的特定状态主要是指读/写控制、读/写地址和读/写数据状态。
在这里插入图片描述

状态转移图

定义
在这里插入图片描述

在这里插入图片描述

独热码
在这里插入图片描述

为了节省资源,可以通过上一个状态一定会执行下一个状态进而连贯在一起弄一个组合拳法

创建任务的思想
对于计数器 halfbit_cnt 只在写控制、写数据、读控制、读数据状态下才进行计数,其他状态为零。代码中 FF 是进行串行输出或输入任务的标志位,当 FF 为1 时表示退出任务,FF 为 0 时表示进入任务。这样便于在状态机中对任务的调用,以及在指定的时间退出任务。

状态机里面线性序列机思路

Verilog代码

module I2C(
	Clk,
	Rst_n,
	
	Rddata_num,
	Wrdata_num,
	Wdaddr_num,
	
	Device_addr,
	Word_addr,
	
	Wr,
	Wr_data,
	Wr_data_vaild,
	Rd,
	Rd_data,
	Rd_data_vaild,
	
	Scl,
	Sda,
	Done
);

//系统时钟采用50MHz
parameter SYS_CLOCK = 50_000_000;
//SCL总线时钟采用400kHz
parameter SCL_CLOCK = 400_000;
//产生时钟SCL计数器最大值
localparam SCL_CNT_M = SYS_CLOCK/SCL_CLOCK;

	input             Clk;          //系统时钟
	input             Rst_n;        //系统复位信号
	
	input     [5:0]   Rddata_num;   //I2C总线连续读取数据字节数
	input     [5:0]   Wrdata_num;   //I2C总线连续读取数据字节数
	input     [1:0]   Wdaddr_num;   //I2C器件数据地址字节数
	
	input     [2:0]   Device_addr;  //I2C器件地址
	input     [15:0]  Word_addr;    //I2C寄存器地址
	
	input             Wr;           //I2C器件写使能
	input     [7:0]   Wr_data;      //I2C器件写数据
	output            Wr_data_vaild;//I2C器件写数据有效标志位
	input             Rd;           //I2C器件读使能
	output reg[7:0]   Rd_data;      //I2C器件读数据
	output reg        Rd_data_vaild;//I2C器件读数据有效标志位
	
	output  reg       Scl;          //I2C时钟线
	inout             Sda;          //I2C数据线
	output  reg       Done;         //对I2C器件读写完成标识位
	
  
	
	//主状态机状态
	localparam  IDLE     = 9'b0_0000_0001,//空闲状态
               WR_START = 9'b0_0000_0010,//写开始状态
               WR_CTRL  = 9'b0_0000_0100,//写控制状态
               WR_WADDR = 9'b0_0000_1000,//写地址状态
               WR_DATA  = 9'b0_0001_0000,//写数据状态
               RD_START = 9'b0_0010_0000,//读开始状态
               RD_CTRL  = 9'b0_0100_0000,//读控制状态
               RD_DATA  = 9'b0_1000_0000,//读数据状态
               STOP     = 9'b1_0000_0000;//停止状态
				
	reg [8:0] main_state;	   //主状态机状态寄存器
	reg       sda_en;          //sda数据总线控制位
	reg       sda_reg;         //sda数据输出寄存器
	reg       W_flag;          //IIC写操作标志位
	reg       R_flag;          //IIC读操作标志位
	reg       FF;              //串行输出输入任务执行标志位
	wire[7:0] wr_ctrl_word;    //写控制数据寄存器
	wire[7:0] rd_ctrl_word;    //读控制数据寄存器
	reg [15:0]scl_cnt;         //SCL时钟计数器
	reg       scl_vaild;       //IIC非空闲时期
	reg       scl_high;        //SCL时钟高电平中部标志位
	reg       scl_low;         //SCL时钟低电平中部标志位	
	reg [7:0] halfbit_cnt;     //串行数据传输计数器
	reg       ack;             //串行输出输入高低电平计数完成标志位
	reg [1:0] waddr_cnt;       //地址字节数计数器
	reg [7:0] wdata_cnt;       //写数据字节数计数器
	reg [7:0] rdata_cnt;       //读数据字节数计数器
	reg [7:0] sda_data_out;    //待输出SDA串行数据
	reg [7:0] sda_data_in;     //SDA串行输入后数据
	wire      rdata_vaild_r; 
	
	//读写控制字
	assign wr_ctrl_word = {4'b1010, Device_addr,1'b0};
	assign rd_ctrl_word = {4'b1010, Device_addr,1'b1};
	
	//I2C数据线采用三态门传输
	assign Sda = sda_en ? sda_reg : 1'bz;
	
	//I2C非空闲时期scl_vaild的产生
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)
			scl_vaild <= 1'b0;
		else if(Wr | Rd)
			scl_vaild <= 1'b1;
		else if(Done)
			scl_vaild <= 1'b0;
		else
			scl_vaild <= scl_vaild;
	end

	//scl时钟计数器
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)
			scl_cnt <= 16'd0;
		else if(scl_vaild)begin
			if(scl_cnt == SCL_CNT_M - 1)
				scl_cnt <= 16'd0;
			else
				scl_cnt <= scl_cnt + 16'd1;
		end
		else
			scl_cnt <= 16'd0;
	end

	//scl时钟,在计数器值到达最大值一半和0时翻转
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)
			Scl <= 1'b1;
		else if(scl_cnt == SCL_CNT_M >>1)
			Scl <= 1'b0;
		else if(scl_cnt == 16'd0)
			Scl <= 1'b1;
		else
			Scl <= Scl;
	end	

	//scl时钟高低电平中部标志位
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)
			scl_high <= 1'b0;
		else if(scl_cnt == (SCL_CNT_M>>2))
			scl_high <= 1'b1;
		else
			scl_high <= 1'b0;
	end
	//scl时钟低电平中部标志位
	//(SCL_CNT_M>>2)和(SCL_CNT_M>>1)+(SCL_CNT_M>>2)分别为 1/4 的 SCL_CNT_M 和 3/4 的SCL_CNT_M 的计数值。
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)
			scl_low <= 1'b0;
		else if(scl_cnt == (SCL_CNT_M>>1)+(SCL_CNT_M>>2))
			scl_low <= 1'b1;
		else
			scl_low <= 1'b0;
	end	

	//主状态机
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)begin
			main_state <= IDLE;
			sda_reg    <= 1'b1;//三态控制信号
			W_flag     <= 1'b0;//写标注      
			R_flag     <= 1'b0;//读标注 			
			Done       <= 1'b0;//完成
			waddr_cnt  <= 2'd1;//地址 
			wdata_cnt  <= 8'd1;//写数据
			rdata_cnt  <= 8'd1;//读数据
		end
		else begin
			case(main_state)
				IDLE:begin//空闲状态
					sda_reg   <= 1'b1;
					W_flag    <= 1'b0;
					R_flag    <= 1'b0;
					Done      <= 1'b0;
					waddr_cnt <= 2'd1;
					wdata_cnt <= 8'd1;
					rdata_cnt <= 8'd1;
					if(Wr)begin
						main_state <= WR_START;
						W_flag     <= 1'b1;
					end
					else if(Rd)begin
						main_state <= WR_START;
						R_flag     <= 1'b1;
					end
					else
						main_state <= IDLE;
				end

				WR_START:begin//写开始状态
					if(scl_low)begin//在scl_low寄存器下个周期发送起始信号
						main_state   <= WR_CTRL;
						sda_data_out <= wr_ctrl_word;
						FF           <= 1'b0;
					end
					else if(scl_high)begin
						sda_reg    <= 1'b0;
						main_state <= WR_START;
					end
					else
						main_state <= WR_START;
				end

				WR_CTRL:begin//写控制状态
					if(FF == 1'b0)
						send_8bit_data;
					else begin
						if(ack == 1'b1) begin//收到响应
							if(scl_low)begin
								main_state   <= WR_WADDR;
								FF           <= 1'b0;
								if(Wdaddr_num == 2'b1)
									sda_data_out <= Word_addr[7:0];
								else
									sda_data_out <= Word_addr[15:8];
							end
							else
								main_state   <= WR_CTRL;
						end
						else//未收到响应
							main_state      <= IDLE;
					end
				end

				WR_WADDR:begin//写地址状态
					if(FF == 1'b0)
						send_8bit_data;
					else begin
						if(ack == 1'b1) begin//收到响应
							if(waddr_cnt == Wdaddr_num)begin
								if(W_flag && scl_low)begin
									main_state   <= WR_DATA;
									sda_data_out <= Wr_data;
									waddr_cnt    <= 2'd1;
									FF           <= 1'b0;
								end
								else if(R_flag && scl_low)begin
									main_state <= RD_START;
									sda_reg    <= 1'b1;
								end
								else
									main_state <= WR_WADDR;
							end
							else begin
								if(scl_low)begin
									waddr_cnt    <= waddr_cnt + 2'd1;
									main_state   <= WR_WADDR;
									sda_data_out <= Word_addr[7:0];
									FF           <= 1'b0;
								end
								else
									main_state   <= WR_WADDR;
							end
						end
						else//未收到响应
							main_state <= IDLE;
					end
				end

				WR_DATA:begin//写数据状态
					if(FF == 1'b0)
						send_8bit_data;
					else begin
						if(ack == 1'b1) begin//收到响应
							if(wdata_cnt == Wrdata_num)begin
								if(scl_low)begin
									main_state <= STOP;
									sda_reg    <= 1'b0;
									wdata_cnt  <= 8'd1;
								end
								else
									main_state <= WR_DATA;
							end
							else begin
								if(scl_low)begin
									wdata_cnt    <= wdata_cnt + 8'd1;
									main_state   <= WR_DATA;
									sda_data_out <= Wr_data;
									FF           <= 1'b0;
								end
								else
									main_state   <= WR_DATA;
							end
						end
						else//未收到响应
							main_state <= IDLE;
					end
				end

				RD_START:begin//读开始状态
					if(scl_low)begin
						main_state   <= RD_CTRL;
						sda_data_out <= rd_ctrl_word;
						FF           <= 1'b0;
					end
					else if(scl_high)begin
						main_state <= RD_START;
						sda_reg    <= 1'b0;
					end
					else
						main_state <= RD_START;
				end

				RD_CTRL:begin//读控制状态
					if(FF == 1'b0)
						send_8bit_data;
					else begin
						if(ack == 1'b1) begin//收到响应
							if(scl_low)begin
								main_state <= RD_DATA;
								FF         <= 1'b0;
							end
							else
								main_state <= RD_CTRL;
						end
						else//未收到响应
							main_state    <= IDLE;
					end
				end
				
				RD_DATA:begin//读数据状态
					if(FF == 1'b0)
						receive_8bit_data;
					else begin
						if(rdata_cnt == Rddata_num)begin
							sda_reg <= 1'b1;
							if(scl_low)begin
								main_state <= STOP;
								sda_reg    <= 1'b0;
							end
							else
								main_state <= RD_DATA;
						end
						else begin
							sda_reg <= 1'b0;
							if(scl_low)begin
								rdata_cnt  <= rdata_cnt + 8'd1;
								main_state <= RD_DATA;
								FF         <= 1'b0;
							end
							else
								main_state <= RD_DATA;
						end
					end
				end

				STOP:begin//结束操作
					if(scl_high)begin
						sda_reg    <= 1'b1;
						main_state <= IDLE;
						Done       <= 1'b1;
					end
					else
						main_state <= STOP;
				end
				
				default:
					main_state <= IDLE;
			endcase
		end
	end
		
	//sda串行接收与发送时scl高低电平计数器根据中计数器 halfbit_cnt 和数据接收方对发送的响应检测标志位 ack 以及串行输出、输入数据任务
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)
			halfbit_cnt <= 8'd0;
		else if((main_state == WR_CTRL)||
		        (main_state == WR_WADDR)||
				  (main_state == WR_DATA)||
				  (main_state == RD_CTRL)||
				  (main_state == RD_DATA))begin
			if(scl_low | scl_high)begin
				if(halfbit_cnt == 8'd17)
					halfbit_cnt <= 8'd0;
				else
					halfbit_cnt <= halfbit_cnt + 8'd1;
			end
			else
				halfbit_cnt <= halfbit_cnt;
		end
		else
			halfbit_cnt <= 8'd0;
	end

	//数据接收方对发送的响应检测标志位
	always@(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)
			ack <= 1'b0;
		else if((halfbit_cnt == 8'd16)&&scl_high&&(Sda==1'b0))
			ack <= 1'b1;
		else if((halfbit_cnt == 8'd17)&&scl_low)
			ack <= 1'b0;
		else
			ack <= ack;
	end
	
   //输出串行数据任务
	task send_8bit_data;
	if(scl_high && (halfbit_cnt == 8'd16))
		FF <= 1;
	else if(halfbit_cnt < 8'd17)begin
		sda_reg <= sda_data_out[7];
		if(scl_low)
			sda_data_out <= {sda_data_out[6:0],1'b0};
		else
			sda_data_out <= sda_data_out;
	end
	else
		;
	endtask
	
	//串行数据输入任务
	task receive_8bit_data;
	if(scl_low && (halfbit_cnt == 8'd15))
		FF <= 1;
	else if((halfbit_cnt < 8'd15))begin
		if(scl_high)
			sda_data_in <= {sda_data_in[6:0],Sda};
		else begin
			sda_data_in <= sda_data_in;
		end
	end
	else
		;
	endtask

	//sda三态使能信号sda_en
	always@(*)
	begin
		case(main_state)
		IDLE:
			sda_en = 1'b0;

		WR_START,RD_START,STOP:
			sda_en = 1'b1;

		WR_CTRL,WR_WADDR,WR_DATA,RD_CTRL:
			if(halfbit_cnt < 16)
				sda_en = 1'b1;
			else
				sda_en = 1'b0;

		RD_DATA:
			if(halfbit_cnt < 16)
				sda_en = 1'b0;
			else
				sda_en = 1'b1;		
		default:

			sda_en = 1'b0;		
		endcase
	end

	//写数据有效标志位
	assign Wr_data_vaild = ((main_state==WR_WADDR)&&
	                       (waddr_cnt==Wdaddr_num)&&
								  (W_flag && scl_low)&&
								  (ack == 1'b1))||
                     	  ((main_state == WR_DATA)&&
								  (ack == 1'b1)&&(scl_low)&&
								  (wdata_cnt != Wrdata_num));

	//读数据有效标志位前寄存器
	assign rdata_vaild_r = (main_state == RD_DATA)
	                        &&(halfbit_cnt == 8'd15)&&scl_low;

	//读出数据有效标志位
	always@(posedge Clk or negedge Rst_n)
	begin
	if(!Rst_n)
		Rd_data_vaild <= 1'b0;
	else if(rdata_vaild_r)
		Rd_data_vaild <= 1'b1;
	else
		Rd_data_vaild <= 1'b0;
	end

	//读出的有效数据
	always@(posedge Clk or negedge Rst_n)
	begin
	if(!Rst_n)
		Rd_data <= 8'd0;
	else if(rdata_vaild_r)
		Rd_data <= sda_data_in;
	else
		Rd_data <= Rd_data;
	end

endmodule 

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

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

相关文章

[Kettle] 生成记录

在数据统计中&#xff0c;往往要生成固定行数和列数的记录&#xff0c;用于存放统计总数 需求&#xff1a;为方便记录1~12月份商品的销售总额&#xff0c;需要通过生成记录&#xff0c;生成一个月销售总额的数据表&#xff0c;包括商品名称和销售总额两个字段&#xff0c;记录…

pycharm2023 实现鼠标点击某行,调试时代码运行至相应行

按下图取消 Breakpoints Over Line Numbers即可&#xff0c;然后调试时点击某行&#xff0c;代码就会运行至某行

变量命名的规则与规范

变量命名的规则与规范 变量命名的规则不能使用关键字字母须区分大小写由字母、数字、_、$组成&#xff0c;且不能以数字开头 变量命名的规范起名须有一定的意义遵守小驼峰命名法 变量命名的规则 不能使用关键字 在JavaScript中声明变量不能使用JavaScript的常用关键字&#x…

利用AlphaMissense准确预测蛋白质组范围内的错义变体效应

Editor’s summary 蛋白质中单个氨基酸的变化有时影响不大&#xff0c;但通常会导致蛋白质折叠、活性或稳定性方面的问题。只有一小部分变体进行了实验研究&#xff0c;但有大量的生物序列数据适合用作机器学习方法的训练数据。程等人开发了AlphaMissense&#xff0c;这是一种…

STM32 SPI

SPI介绍 SPI是Serial Pepheral interface缩写&#xff0c;串行外围设备接口。 SPI接口是一种高速的全双工同步通信总线&#xff0c;已经广泛应用在众多MCU、存储芯片、AD转换器和LCD之间。大部分STM32有3个SPI接口&#xff0c;本实验使用的是SPI1。 SPI同一时刻既能发送数据&…

【23真题】很少见!第6题有点新颖!

今天分享的是23年太原理工大学801的信号与系统试题及解析。 本套试卷难度分析&#xff1a;该学校考察数字电路和信号与系统两部分&#xff0c;数字电路我没有知道&#xff0c;所以不知道难度。但是从信号部分来看&#xff0c;考察的知识点非常常见&#xff0c;对信号时域和频域…

建设城市排水管网监测系统的作用及功能说明

排水管网是由管道、井盖、降水口等组成的系统&#xff0c;用于将城市和建筑物内的污水和降水排放到污水处理厂或主干管道中。排水管网通常包括雨水管网和污水管网两部分。雨水管网用于收集雨水、路面洒水和冷却水等&#xff0c;而污水管网则负责收集排放到厕所、洗涤或过程中产…

Vue3 常用组件

一、Fragment组件 Vue2 的template 模板中必须要有一个根标签&#xff0c;而我们在Vue3 的模板中不需要使用根标签就能渲染&#xff0c;因为Vue3 在内部会将多个标签包含在一个Fragment 虚拟元素中。 好处就在于可以减少标签的层级&#xff0c;减小内存占用。 二、Teleport组…

23.11.19日总结(vue2和vue3的区别,项目中期总结)

经过昨天的中期答辩&#xff0c;其实可以看出来项目进度太慢了&#xff0c;现在是第十周&#xff0c;预计第十四周是终级答辩&#xff0c;在这段时间要把项目写完。 前端要加上一个未登录的拦截器&#xff0c;后端加上全局的异常处理。对于饿了么项目的商品建表&#xff0c;之前…

Java code auditing

1) FindBugs Checkstyle PMD 2) OWASP ZAP Burp Suite (XSS漏洞) 3) SQL注入

【ROS】RViz2源码分析(三):核心类VisualizerApp

【ROS】郭老二博文之:ROS目录 1、简述 VisualizerApp包含了三个主要的功能: QApplication:程序中主要调用app_->processEvents()来处理刷新界面,处理闪屏VisualizationFrame:窗口类都在此;RosClientAbstractionIface包含rclcpp::Node:代表ROS节点2、VisualizationF…

设计模式-迭代器模式-笔记

动机&#xff08;Motivaton&#xff09; 在软件构建过程中&#xff0c;集合对象内部结构常常变化各异。但对于这些集合对象&#xff0c;我们呢希望在不暴露其内部结构的同时&#xff0c;可以让外部客户代码透明地访问其中包含的元素&#xff1b;同时这种“透明遍历”也为“同一…

CXL崛起:2024启航,2025年开启新时代

在2019年&#xff0c;Intel主导联合多家阿里巴巴、Facebook(也就是改名后Meta)、谷歌、Dell、华为、思科、微软、HPE最初的八巨头&#xff0c;发布了新的互联协议CXL&#xff0c;全称Comupte Express Link。由于在服务器领域享有绝对领导地位&#xff0c;Intel一经号令&#xf…

Spring Cloud Stream实践

概述 不同中间件&#xff0c;有各自的使用方法&#xff0c;代码也不一样。 可以使用Spring Cloud Stream解耦&#xff0c;切换中间件时&#xff0c;不需要修改代码。实现方式为使用绑定层&#xff0c;绑定层对生产者和消费者提供统一的编码方式&#xff0c;需要连接不同的中间…

解决Python requests库中的重定向问题

目录 一、默认情况下&#xff0c;requests库如何处理重定向 二、手动处理重定向 三、处理多个重定向 四、注意事项 总结 在Python requests库中&#xff0c;处理重定向是一个常见的问题。默认情况下&#xff0c;requests库会自动处理重定向&#xff0c;并将最终的响应返回…

Vuex 组件间通讯

组件间通讯 Vuex https://vuex.vuejs.org/zh/ 基本原理 数据提取到父级 // index 文件 import Vue from vue import Vuex from "vuex" import tab from ./tab // 引入 modulesVue.use(Vuex) // 全局引入// 创建 Vuex 实例 export default new Vuex.Store({modules: …

力扣刷题-二叉树-二叉树最小深度

给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a;叶子节点是指没有子节点的节点。&#xff08;注意题意&#xff09; 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#x…

Redis篇---第十篇

系列文章目录 文章目录 系列文章目录前言一、怎么提高缓存命中率&#xff1f;二、Redis 如何解决 key 冲突&#xff1f;三、Redis 报内存不足怎么处理&#xff1f; 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分…

基于变形卷积和注意机制的带钢表面缺陷快速检测网络DCAM-Net(论文阅读笔记)

原论文链接->DCAM-Net: A Rapid Detection Network for Strip Steel Surface Defects Based on Deformable Convolution and Attention Mechanism | IEEE Journals & Magazine | IEEE Xplore DCAM-Net: A Rapid Detection Network for Strip Steel Surface Defects Base…

下厨房网站月度最佳栏目菜谱数据获取及分析PLus

目录 概要 源数据获取 写Python代码爬取数据 Scala介绍与数据处理 1.Sacla介绍 2.Scala数据处理流程 数据可视化 最终大屏效果 小结 概要 本文的主题是获取下厨房网站月度最佳栏目近十年数据&#xff0c;最终进行数据清洗、处理后生成所需的数据库表&#xff0c;最终进…