FPGA控制88E1512 PHY芯片完成网络通信

一、88E1512分析

        本文不对88E1512进行详细解析,仅对调试过程中重点使用的几个寄存器进行说明。

1.1 MDIO时序分析

        根据手册,MDIO时序中,mdc时钟最高为12Mhz。占空比和建立保持时间要求可以观察上述表格。

        MDIO的读数据时序图如下:

        MDIO的写数据时序图如下:

        各字段表示的含义如下:

1.2  寄存器分析

1.2.1 页地址寄存器

        可能是受MDIO寄存器地址字段的位宽限制(5bits),88E1512提供了一个页地址寄存器的功能,可以通过配置任意页的寄存器地址22,实现页的切换,比如从page0,切换到page1,实现远超2^5的寄存器数目的配置。

        通过配置此寄存器,可以完成页的切换,实现不同寄存器的读写。

1.2.2  PHY ID寄存器

        用于验证MDIO总线是否正常,读取page0的寄存器2,若回读数据时0x141,则证明链路正确。(通过也需要确认MDIO时序中的TA字段,是否应答正确)

1.2.3 MAC特定控制寄存器

        本寄存器中,重点关注bit4字段的信息(数据发送时序的控制,有时可能也涉及到bit5字段,数据接收时序的控制),一般FPGA中的MAC会默认增加网络时钟和网络数据的延时,因此88E1512中可以取消其内部的延迟。这个需要根据实际情况进行控制。

        以下重点看一下数据发送的时序图。

        当bit4字段设置为0时,可以从下面的时序图中看到,此时要求88E1512的引脚上,接收到的时钟和数据的时序关系应该为:在时钟的边沿位置,刚好为数据的稳定位置。即此时FPGA侧若进行了时序上的相位处理,那么88E1512则不需要进行内部的延时,就可以达到时序收敛,稳定的接收到发送数据。

        当bit4字段设置为1时,可以从下面的时序图中看到,此时要求88E1512的引脚上,接收到的时钟和数据的时序关系应该为:在时钟的边沿位置,刚好为数据的改变位置。即此时FPGA侧若不进行了时序上的相位处理,时钟和数据为相位对齐关系,那么88E1512则需要进行内部的延时,才可以达到时序收敛,稳定的接收到发送数据。

1.2.4 一般控制器1

        从此寄存器中,可以看到,对于88E1512芯片而言,其默认的工作状态为mode[2:0] = 3'b111,保留状态。而我本次需要的工作状态为RGMII to copper,因此需要进行配置使MODE[2:0]= 3'b000,

        另外需要注意的是,配置完page6和page18的寄存器时,都需要对芯片进行软复位,即bit15的SC字段,需要设置为1‘b1,88E1512会自动释放复位信号。

二、FPGA的代码实现

2.1 MDIO的时序模块实现

        此处也不啰嗦,直接上代码,有兴趣的自行查阅。

`timescale 1ns / 1ps
//
//实现MDC和MDIO时序的SMI接口module phy_smi #(parameter	CLK_FREQ = 100_000_000,//系统时钟频率 100Mparameter	MDC_DIV	= 1000 //MDC分频系数 1000 得到100K时钟
)
(input				clk,input				rst_n,output		reg		mdc,inout				mdio,input		[4:0]	phy_addr, //PHY芯片的地址input		[4:0]	reg_addr, //寄存器地址//wr_req信号上升沿有效input				wr_req,input		[15:0]	wr_data,//rd_req信号上升沿有效input				rd_req,output	reg	[15:0]	rd_data = 16'd0,output	reg			rd_valid = 1'b0,	//接收到的数据有效标志output	reg			rd_error = 1'b0,	//接收数据失败标志output		busy );reg mdc_gen_en = 1'b0; //时钟生成使能,mdc可以不是持续性时钟
reg [15:0] mdc_div_cnt = 0;
wire mdc_pos;//MDC上升沿
wire mdc_neg; //MDC下降沿
wire mdc_hig; //MDC高电平中心位置
wire mdc_low;//MDC低电平中心位置reg	mdio_buf = 1'b0;
reg	mdio_dir = 1'b0;//FPGA是否输出mdio,1'b1表示FPGA控制输出,反之为高阻态//-----------------edge detect---------------------------
reg	wr_req_rise = 1'b0;
reg	wr_req_d0 = 1'b0;
reg	wr_req_d1 = 1'b0;reg	rd_req_rise = 1'b0;
reg	rd_req_d0 = 1'b0;
reg	rd_req_d1 = 1'b0;//---------------------FSM-------------------------------
localparam	[3:0] S_IDLE	= 4'd0;//空闲态
localparam	[3:0] S_PRE_RD	= 4'd1;//前导态
localparam	[3:0] S_RD	= 4'd2;//读状态
localparam	[3:0] S_PRE_WR	= 4'd3;//前导态
localparam	[3:0] S_WR	= 4'd4;//写状态
localparam	[3:0] S_DONE	= 4'd5;//完成态reg		[3:0]	state = S_IDLE;localparam	START_FIELD	= 2'b01; //开始2bits信息,指示开始传输数据
localparam	READ_CODE_FIELD = 2'b10; //读操作码
localparam	WRITE_CODE_FIELD = 2'b01; //写操作码
localparam	TA_FIELD = 2'b10; //turn around。写时,直接发送2'b10即可,读操作时,MDIO控制权交给PHY,此时FPGA的MDIO为高阻reg		[4:0]	bit_cnt;//一次读写正好 32bit Pre + 32bit WR/RDassign mdc_low = (mdc_div_cnt == 16'd0);
assign mdc_hig = (mdc_div_cnt == (MDC_DIV/2) -1);
assign mdc_pos = (mdc_div_cnt == (MDC_DIV/4) -1);
assign mdc_neg = (mdc_div_cnt == (MDC_DIV/2) + (MDC_DIV/4) -1);always @(posedge clk) beginwr_req_d0	<= wr_req;wr_req_d1	<= wr_req_d0;wr_req_rise	<= ~wr_req_d1 & wr_req_d0;rd_req_d0	<= rd_req;rd_req_d1	<= rd_req_d0;rd_req_rise	<= ~rd_req_d1 & rd_req_d0;
endalways @(posedge clk) 
beginif(mdc_gen_en) beginif( mdc_div_cnt <= MDC_DIV - 1)mdc_div_cnt <= mdc_div_cnt + 1'b1;elsemdc_div_cnt <= 0;endelsemdc_div_cnt <= 0;
endalways @(posedge clk) 
beginif(mdc_gen_en) beginif( mdc_pos )mdc <= 1'b1;else if(mdc_neg)mdc <= 1'b0;endelsemdc <= 0;
endalways @(posedge clk or negedge rst_n) 
beginif(~rst_n) beginstate	<= S_IDLE;mdc_gen_en <= 1'b0;rd_valid <= 1'b0;endelse beginrd_valid <= 1'b0;case(state)S_IDLE : beginmdc_gen_en <= 1'b0;bit_cnt <= 0;rd_error <= 1'b0;if(rd_req_rise)state <= S_PRE_RD;else if(wr_req_rise)state <= S_PRE_WR;   endS_PRE_RD : beginmdc_gen_en <= 1'b1;if(mdc_neg) beginif(bit_cnt==5'd31) begin //发送完32个前导1'b1bit_cnt <= 0;state	<= S_RD;endelse beginbit_cnt <= bit_cnt + 1'b1;endend//前导码均为1,FPGA输出mdio_buf <= 1'b1;mdio_dir <= 1'b1;endS_RD : beginmdc_gen_en <= 1'b1;if(mdc_neg) beginif(bit_cnt==5'd31) begin //完成32bits的通信bit_cnt <= 0;state	<= S_DONE;endelse beginbit_cnt <= bit_cnt + 1'b1;endendcase(bit_cnt)5'd0: begin mdio_dir <= 1'b1; mdio_buf	<= START_FIELD[1];end5'd1: begin mdio_dir <= 1'b1; mdio_buf	<= START_FIELD[0];end5'd2: begin mdio_dir <= 1'b1;mdio_buf	<= READ_CODE_FIELD[1];end5'd3: begin mdio_dir <= 1'b1;mdio_buf	<= READ_CODE_FIELD[0];end5'd4: begin mdio_dir <= 1'b1;mdio_buf	<= phy_addr[4];end5'd5: begin mdio_dir <= 1'b1;mdio_buf	<= phy_addr[3];end5'd6: begin mdio_dir <= 1'b1;mdio_buf	<= phy_addr[2];end5'd7: begin mdio_dir <= 1'b1;mdio_buf	<= phy_addr[1];end5'd8: begin mdio_dir <= 1'b1;mdio_buf	<= phy_addr[0];end5'd9: begin mdio_dir <= 1'b1;mdio_buf	<= reg_addr[4];end5'd10: begin mdio_dir <= 1'b1;mdio_buf	<= reg_addr[3];end5'd11: begin mdio_dir <= 1'b1;mdio_buf	<= reg_addr[2];end5'd12: begin mdio_dir <= 1'b1;mdio_buf	<= reg_addr[1];end5'd13: begin mdio_dir <= 1'b1;mdio_buf	<= reg_addr[0];enddefault: begin mdio_dir <= 1'b0;end endcase//MDC下降沿时取数据if(mdc_neg) begincase(bit_cnt)5'd14: rd_error	<= mdio; //若PHY应答,此处会被拉低,否则失败;5'd15: rd_data[15]	<= mdio;5'd16: rd_data[14]	<= mdio;5'd17: rd_data[13]	<= mdio;5'd18: rd_data[12]	<= mdio;5'd19: rd_data[11]	<= mdio;5'd20: rd_data[10]	<= mdio;5'd21: rd_data[9]	<= mdio;5'd22: rd_data[8]	<= mdio;5'd23: rd_data[7]	<= mdio;5'd24: rd_data[6]	<= mdio;5'd25: rd_data[5]	<= mdio;5'd26: rd_data[4]	<= mdio;5'd27: rd_data[3]	<= mdio;5'd28: rd_data[2]	<= mdio;5'd29: rd_data[1]	<= mdio;5'd30:begin rd_data[0]	<= mdio; rd_valid <= 1'b1;enddefault:;endcaseendendS_PRE_WR : beginmdc_gen_en <= 1'b1;if(mdc_neg) beginif(bit_cnt==5'd31) begin //发送完32个前导1'b1bit_cnt <= 0;state	<= S_WR;endelse beginbit_cnt <= bit_cnt + 1'b1;endend//前导码均为1,FPGA输出mdio_buf <= 1'b1;mdio_dir <= 1'b1;endS_WR : beginmdc_gen_en <= 1'b1;if(mdc_neg) beginif(bit_cnt==5'd31) begin //完成32bits的通信bit_cnt <= 0;state	<= S_DONE;endelse beginbit_cnt <= bit_cnt + 1'b1;endendcase(bit_cnt)5'd0: begin mdio_dir <= 1'b1; mdio_buf	<= START_FIELD[1];end5'd1: begin mdio_dir <= 1'b1; mdio_buf	<= START_FIELD[0];end5'd2: begin mdio_dir <= 1'b1;mdio_buf	<= WRITE_CODE_FIELD[1];end5'd3: begin mdio_dir <= 1'b1;mdio_buf	<= WRITE_CODE_FIELD[0];end5'd4: begin mdio_dir <= 1'b1;mdio_buf	<= phy_addr[4];end5'd5: begin mdio_dir <= 1'b1;mdio_buf	<= phy_addr[3];end5'd6: begin mdio_dir <= 1'b1;mdio_buf	<= phy_addr[2];end5'd7: begin mdio_dir <= 1'b1;mdio_buf	<= phy_addr[1];end5'd8: begin mdio_dir <= 1'b1;mdio_buf	<= phy_addr[0];end5'd9: begin mdio_dir <= 1'b1;mdio_buf	<= reg_addr[4];end5'd10: begin mdio_dir <= 1'b1;mdio_buf	<= reg_addr[3];end5'd11: begin mdio_dir <= 1'b1;mdio_buf	<= reg_addr[2];end5'd12: begin mdio_dir <= 1'b1;mdio_buf	<= reg_addr[1];end5'd13: begin mdio_dir <= 1'b1;mdio_buf	<= reg_addr[0];end5'd14: begin mdio_dir <= 1'b1;mdio_buf	<= TA_FIELD[1];end5'd15: begin mdio_dir <= 1'b1;mdio_buf	<= TA_FIELD[0];end5'd16: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[15];end5'd17: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[14];end5'd18: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[13];end5'd19: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[12];end5'd20: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[11];end5'd21: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[10];end5'd22: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[9];end5'd23: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[8];end5'd24: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[7];end5'd25: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[6];end5'd26: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[5];end5'd27: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[4];end5'd28: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[3];end5'd29: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[2];end5'd30: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[1];end5'd31: begin mdio_dir <= 1'b1; mdio_buf	<= wr_data[0];enddefault:;endcaseendS_DONE : beginmdc_gen_en <= 1'b0;state	<= S_IDLE;endendcaseend
endassign busy = (state != S_IDLE);assign mdio = mdio_dir ? mdio_buf : 1'bZ;//wire mdio_in;
//assign mdio_in = mdio;endmodule

2.2 88E1512的控制代码

`timescale 1ns / 1psmodule PHY_88E1512(input clk,input rst_n,output mdc, //inout mdio, //input config_start, //启动88E1512的配置,使FPGA可在RGMII 1G模式下通信output reg link_ok = 1'b0, //读取PHY ID验证链路是否正确output reg link_error = 1'b0, //读取PHY ID验证链路是否正确output reg config_done  //配置完成);localparam PHY_88E1512_ADDR = 5'd0;localparam IDLE_STATE = 4'd0;
localparam ARB_STATE = 4'd1;
localparam LINK_READY_STATE = 4'd2; //读取PHY ID :bit3:18  数值为0x0141即通信链路正常
localparam CFG_READY_STATE = 4'd3;
localparam WR_OP_STATE = 4'd4;
localparam RD_OP_STATE = 4'd5;
localparam LINK_ERR_STATE = 4'd6;
localparam DONE_STATE = 4'd7;reg [3:0] state = IDLE_STATE;reg config_start_d1 = 1'b0;reg [3:0] link_cnt = 4'd0;//链路验证时寄存器计数
reg [3:0] wr_cnt = 4'd0; //写读寄存器计数
reg [15:0] rd_data_latch = 0;//SMI接口信号
//reg [4:0] phy_addr = 5'd0; //PHY芯片的地址
reg [4:0] reg_addr = 5'd0; //寄存器地址//wr_req信号上升沿有效
reg wr_req = 1'b0;
reg [15:0] wr_data = 16'd0;//rd_req信号上升沿有效
reg rd_req = 1'b0;
wire [15:0]rd_data;
wire rd_valid;	//接收到的数据有效标志
wire rd_error;	//接收数据失败标志wire busy ;
reg busy_d1 = 1'b0;always@(posedge clk)
beginbusy_d1 <= busy;
endalways@(posedge clk)
beginconfig_start_d1 <= config_start;
endalways@(posedge clk or negedge rst_n)
beginif(!rst_n) beginstate <= IDLE_STATE;wr_req <= 1'b0;wr_cnt <= 0;rd_req <= 1'b0;link_cnt <= 0;rd_data_latch <= 16'h0;end else begincase(state)IDLE_STATE: beginwr_req <= 1'b0;wr_cnt <= 0;rd_req <= 1'b0;link_cnt <= 0;if(!config_start_d1 & config_start) beginstate <= ARB_STATE;rd_data_latch <= 16'h0;link_ok <= 1'b0;link_error <= 1'b0;config_done <= 1'b0;endendARB_STATE : beginwr_req <= 1'b0;rd_req <= 1'b0;if(link_ok == 1'b0) //先进行链路验证state <= LINK_READY_STATE;else if(config_done == 1'b0) //再配置寄存器state <= CFG_READY_STATE;elsestate <= IDLE_STATE;endLINK_READY_STATE : begincase(link_cnt)4'd0: begin  //首先写寄存器,选中page0link_cnt <= 4'd1;reg_addr <= 5'd22; //寄存器地址22wr_data <= 16'd0;state <= WR_OP_STATE;end4'd1: begin  //其次读取PHY IDlink_cnt <= 4'd2;reg_addr <= 5'd2; //寄存器地址2state <= RD_OP_STATE;end4'd2: begin //验证回读ID是否正确if(rd_data_latch == 16'h0141) beginstate <= ARB_STATE;link_ok <= 1'b1;endelse beginstate <= LINK_ERR_STATE;endenddefault:state <= IDLE_STATE;endcaseendCFG_READY_STATE : beginwr_cnt <= wr_cnt + 4'd1;case(wr_cnt)//-----由于FPGA MAC核已经调整好时序,因此PHY处不需要进行时序延时4'd0: begin  //首先写寄存器,选中page2reg_addr <= 5'd22; //寄存器地址22wr_data <= 16'd2;state <= WR_OP_STATE;end4'd1: begin  //读寄存器reg_addr <= 5'd21; //寄存器地址21state <= RD_OP_STATE;end  4'd2: begin  //取消PHY内部的延时reg_addr <= 5'd21; //寄存器地址21wr_data <= rd_data_latch & 16'hFFEF;//bit4置为0state <= WR_OP_STATE;end      //-----PHY工作在RGMII to Copper模式4'd3: begin  //首先写寄存器,选中page18reg_addr <= 5'd22; //寄存器地址22wr_data <= 16'd18;state <= WR_OP_STATE;end4'd4: begin  //其次配置MODE参数,使PHY工作在RGMII to Copper模式reg_addr <= 5'd20; //寄存器地址20wr_data <= 16'h0;//bit15表示软复位,bit[2:0]表示RGMII to Copper模式,其余为默认值state <= WR_OP_STATE;end4'd5: begin  //其次配置MODE参数,使PHY工作在RGMII to Copper模式reg_addr <= 5'd20; //寄存器地址20wr_data <= 16'h8000;//bit15表示软复位,bit[2:0]表示RGMII to Copper模式,其余为默认值state <= WR_OP_STATE;config_done <= 1'b1;enddefault:state <= IDLE_STATE;endcaseendWR_OP_STATE : beginwr_req <= 1'b1;if(busy_d1 & !busy) //busy下降沿state <= ARB_STATE;endRD_OP_STATE : begin rd_req <= 1'b1;if(rd_valid) beginrd_data_latch <= rd_data;endif(rd_error)state <= LINK_ERR_STATE;else if(busy_d1 & !busy) //busy下降沿state <= ARB_STATE;endLINK_ERR_STATE : beginlink_error <= 1'b1;state <= IDLE_STATE;endDONE_STATE : beginstate <= IDLE_STATE;enddefault : beginstate <= IDLE_STATE;endendcaseend
endphy_smi #(.CLK_FREQ(25_000_000),//系统时钟频率 25M.MDC_DIV(50) //MDC分频系数 50 得到500K时钟
)
phy_smi(.clk(clk),//input				clk,.rst_n(rst_n),//input				rst_n,.mdc(mdc),//output		reg		mdc,.mdio(mdio),//inout				mdio,.phy_addr(PHY_88E1512_ADDR),//input		[4:0]	phy_addr, //PHY芯片的地址.reg_addr(reg_addr),//input		[4:0]	reg_addr, //寄存器地址//wr_req信号上升沿有效.wr_req(wr_req),//input				wr_req,.wr_data(wr_data),//input		[15:0]	wr_data,//rd_req信号上升沿有效.rd_req(rd_req),//input				rd_req,.rd_data(rd_data),//output	reg	[15:0]	rd_data = 16'd0,.rd_valid(rd_valid),//output	reg			rd_valid = 1'b0,	//接收到的数据有效标志.rd_error(rd_error),//output	reg			rd_error = 1'b0,	//接收数据失败标志.busy(busy) //output		busy );
endmodule

2.3 整体网络通信的验证

        网络通信模块,借用了米联客的UDP通信模块。基本上根据根据上述代码部分,应该可以自行完成通信调试,若需要原始工程的,可以自行下载使用。

     https://download.csdn.net/download/yindq1220/91200585

电脑侧IP地址192.168.137.1
电脑侧UDP端口号6001
开发板侧IP地址192.168.137.2
开发板侧UDP端口号6002

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

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

相关文章

Ai大模型 - ocr图像识别形成结构化数据(pp-ocr+nlp结合) 以及训练微调实现方案(初稿)

全局目录,一步到位 功能流程第一阶段 基于现有条件进行 调研,测试与评估1.1 ocr深度学习模型 pp-ocr1.2 nlp结构化模型1.3 硬件要求: 第二阶段 模型训练微调2.1 更换ocr-GPU模型, 下载相关环境2.2 nlp模型 语义训练2.3 最低硬件要求:2.4 样本数据: (重点)2.5 进一步增强模型能力…

【Linux】软硬链接,动静态库

目录 一、认识一下常用指令 1、建立一个软链接 2、建立一个硬链接 3、删除文件的第二种方式&#xff1a;删除链接unlink指令 二、什么是硬链接&#xff1f; 三、软硬链接的原理&#xff1a; 四、应用场景 1、建立一个软链接可以快速在一个比较深的路径中找到目标文件进行…

VRR(可变刷新率)和QMS(快速媒体切换)

&#x1f527; 一、技术原理的本质区别 技术VRR (可变刷新率)QMS (快速媒体切换)核心目标消除动态帧率波动导致的画面撕裂/卡顿消除静态帧率切换时的黑屏中断工作机制实时调整显示器刷新率&#xff08;Hz&#xff09;匹配GPU输出帧率&#xff08;FPS&#xff09;→ 动态延长/缩…

GO 语言学习 之 Map

map 是 Go 语言中非常重要的数据结构&#xff0c;常用于需要快速查找、统计或分组数据的场景。 map定义&#xff1a; package mainimport "fmt"func main() {var m1 map[int]string // 创建一个 mapm2 : make(map[int]string) // 创建一个 map m3…

什么是可观测性?监控、日志、追踪三者之间有什么区别?

一、引言&#xff1a;为什么现代系统需要“看得见”&#xff1f; 你是否遇到过这样的情况&#xff1a;系统运行突然变慢&#xff0c;但没人知道问题出在哪&#xff1f;随着微服务、云原生架构的普及&#xff0c;系统的复杂度越来越高&#xff0c;传统的“靠经验判断”已经无法…

扣子(coze)实战|自动搬运+改写+归档!自媒体矩阵终极方案

今天给大家分享的是用coze做一个工作流来自动提取抖音/小红书视频文案及改写并传入到飞书多维表格&#xff0c;我们先来看案例 上传视频链接即可一键生成&#xff0c;废话不多说&#xff0c;上教程~ 一、整体工作流如下&#xff1a; 二、开发思路&#xff1a; 三、详细工作流分…

K8s环境下基于Nginx WebDAV与TLS/SSL的文件上传下载部署指南

#作者&#xff1a;闫乾苓 文章目录 1.问题及背景2.方案说明3.部署步骤3.1 制作TLS/SSL私有证书3.2 创建访问nginx账户密码文件并创建secret3.3 为TLS/SSL私有证书创建secret3.4 为Nginx 配置文件创建confimap3.5 使用deployment&#xff0c;svc部署nginx3.6 客户端curl上传下载…

【Day 7-N17】Python函数(1)——函数定义、位置参数调用函数、关键字参数调用函数、函数的默认值

挑战14天学会Python&#xff0c;第7天学习笔记&#xff01;加油&#xff01; 一、概述 函数&#xff08;Function&#xff09;是 Python 中用于封装可重用代码块的基本结构。通过定义函数&#xff0c;我们可以将复杂逻辑拆分为更小、更易管理的单元&#xff0c;并通过参数传递…

STM32 驱动 ADS1015 单端 差分 多通道模式 ADC 转换

文章目录 一、ADS1015简介二、引脚功能三、寄存器介绍1.Conversion Register 转化数据存放寄存器2.Config Register 配置寄存器 四、IIC时序1.写寄存器2.读寄存器 五、程序六、实验现象1.单端模式2.差分模式3.伪多通道模式 一、ADS1015简介 ADS1015 是一款由德州仪器&#xff…

RabbitMQ 消费幂等性与消息重放实现

一、幂等性实现 1.1 什么是幂等性&#xff1f; 幂等性是指同一条消息无论被消费多少次&#xff0c;业务结果都只生效一次&#xff0c;防止重复扣款、重复发货等问题。 RabbitMQ 的投递模式是“至少一次交付”(at-least-once delivery)&#xff0c;如果消费者处理失败或者没有及…

【HarmonyOS 5】鸿蒙TEE(可信执行环境)详解

【HarmonyOS 5】鸿蒙TEE&#xff08;可信执行环境&#xff09;详解 一、TEE是什么&#xff1f; 1、TEE的定义&#xff1a; 可信执行环境&#xff08;Trusted Execution Environment&#xff09;&#xff0c;简称TEE&#xff0c;是存在于智能手机、平板或任意移动设备主处理器…

算法: 冒泡排序

冒泡排序是一种简单的排序算法&#xff0c;通过相邻元素的比较和交换&#xff0c;使较大的元素逐渐"浮"到数组末尾。 时间复杂度:最佳 O(n) | 平均 O(n) | 最差 O(n) 空间复杂度:O(1) 稳定性:稳定 应用场景/前提条件 适用于小规模数据对几乎已排序的数据效率较高…

基于SpringBoot的家电销售展示平台

源码编号&#xff1a;S567 源码名称&#xff1a;基于SpringBoot的家电销售展示平台 用户类型&#xff1a;双角色&#xff0c;用户、管理员 数据库表数量&#xff1a;14 张表 主要技术&#xff1a;Java、Vue、ElementUl 、SpringBoot、Maven 运行环境&#xff1a;Windows/M…

java+vue+SpringBoo智慧旅游系统(程序+数据库+报告+部署教程+答辩指导)

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿ppt部署教程代码讲解代码时间修改工具 技术实现 开发语言&#xff1a;后端&#xff1a;Java 前端&#xff1a;vue框架&#xff1a;springboot数据库&#xff1a;mysql 开发工具 JDK版本&#xff1a;JDK1.…

Docker 入门教程(三):镜像操作命令

文章目录 &#x1f433; Docker 入门教程&#xff08;三&#xff09;&#xff1a;镜像操作命令获取镜像&#xff1a;docker pull查看镜像&#xff1a;docker images删除镜像&#xff1a;docker rmi搜索镜像&#xff1a;docker search镜像打标签&#xff1a;docker tag镜像详情与…

如何修改discuz文章标题字数限制 修改成255

在 Discuz! X3.5 中&#xff0c;文章&#xff08;主题&#xff09;标题字数的限制可以通过修改数据库结构以及后台配置来实现&#xff0c;以下是完整的修改方法&#xff0c;将标题长度限制改为 255 个字符&#xff1a; ✅ 一、修改数据库字段长度 Discuz 默认标题字段是 subje…

基于BP神经网络的26个英文字母识别

本课题旨在设计并实现一个基于BP&#xff08;反向传播&#xff09;神经网络的英文字母识别系统&#xff0c;实现对手写或打印的26个英文字母&#xff08;A-Z&#xff09;的自动分类识别。项目首先对字母图像进行预处理&#xff08;如灰度化、归一化、二值化和特征提取&#xff…

系统架构设计师论文分享-论云原生技术的应用

我的软考历程 摘要 2023年2月&#xff0c;我所在的公司做了开发纱线MES系统的决定&#xff0c;该系统为国内纱线工厂提供SAAS服务&#xff0c;旨在提高纱线工厂的智能化和数字化水平。我在该项目中被任命为系统架构设计师&#xff0c;全面掌管该项目的架构设计工作。该项目涉…

重置 MySQL root 密码

引言 在linux可能存在安装mysql安装失败&#xff0c;一直不出现默认密码 /usr/local/mysql/mysql-8.0.26/bin/mysqld --defaults-file/etc/my.cnf --usermysql --basedir/usr/local/mysql/mysql-8.0.26 --datadir/usr/local/mysql/mysql-8.0.26/data --lower-case-table-name…

面试八股---HTML

面试八股 1、HTML 1.1 src和href的区别 src 用于替换当前元素&#xff0c;href 用于在当前文档和引用资源之间确立联系。 核心区别在于 href 关联的资源&#xff08;主要是 CSS&#xff09;是用于描述页面外观的&#xff0c;浏览器可以先生成内容再应用样式&#xff0c;因此…