以太网ICMP协议(ping指令)——FPGA学习笔记25

                                                                                                                        --素材来源原子哥

一、IP协议

1、IP简介

        IP是Internet Protocol(网际互连协议)的缩写。IP 协议是 TCP/IP 协议簇中的核心协议,它为上层协议提供无状态、无连接、不可靠的服务。IP 协议规定了数据传输时的基本单元和格式 。
         IP协议是 OSI 参考模型中网络层的重要成员,与 ICMP协议及 IGMP 协议共同构成OSI 参考模型模型中的网络层 。


 2、OSI参考模型

3、IP协议格式

4、IP包详细格式

        前 20 个字节和紧跟其后的可选字段是 IP 数据报的首部,前 20 个字节是固定的,后面可选字段是可有可无的,首部的每一行以 32 位(4 个字节)为单位。每个字节传输规则为由比特最高位到最低位的顺序逐一进行发送, 4 字节的 32bit 值按照以下次序传输:首先 7-0bit,其次 15-8 bit,然后 23-16bit,最后是 31-24bit。
        版本: 4 位 IP 版本号(Version),这个值设置为二进制的 0100 时表示 IPv4,设置为 0110 时表示 IPv6,目前使用比较多的 IP 协议版本号是 4。
        首部长度: 4 位首部长度(IHL, Internet Header Length),表示 IP 首部一共有多少个 32 位(4 个字节) 。在没有可选字段时, IP 首部长度为 20 个字节, 因此首部长度的值为 5。
        服务类型: 8 位服务类型(TOS, Type of service),该字段被划分成两个子字段: 3 位优先级字段(现在已经基本忽略掉了)和 4 位 TOS 字段,最后一位固定为 0。服务类型为 0 时表示一般服务。
        总长度: 16 位 IP 数据报总长度(Total Length),包括 IP 首部和 IP 数据部分,以字节为单位。我们利用 IP 首部长度和 IP 数据报总长度,就可以知道 IP 数据报中数据内容的起始位置和长度。由于该字段长16bit,所以 IP 数据报最长可达 65535 字节。尽管理论上可以传输长达 65535 字节的 IP 数据报,但实际上还要考虑网络的最大承载能力等因素。
        标识字段: 16 位标识(Identification)字段,用来标识主机发送的每一份数据报。通常每发送一份报文它的值就会加 1。
        标志字段: 3 位标志(Flags)字段,第 1 位为保留位;第 2 位表示禁止分片(1 表示不分片 0:允许分片);第 3 位标识更多分片(除了数据报的最后一个分片外,其它分片都为 1)。
片偏移: 13 位片偏移(Fragment Offset),在接收方进行数据报重组时用来标识分片的顺序。
        生存时间: 8 位生存时间字段, TTL(Time To Live)域防止丢失的数据包在无休止的传播,一般被设置为 64 或者 128。
        协议: 8 位协议(Protocol)类型,表示此数据报所携带上层数据使用的协议类型, ICMP 为 1, TCP 为6, UDP 为 17
        首部校验和: 16 位首部校验和(Header Checksum),该字段只校验数据报的首部,不包含数据部分;校验 IP 数据报头部是否被破坏、篡改和丢失等。
        源 IP 地址: 32 位源 IP 地址(Source Address),即发送端的 IP 地址, 如 192.168.1.123。
        目的 IP 地址: 32 位目的 IP 地址(Destination Address),即接收端的 IP 地址, 如 192.168.1.102。
        可选字段: 是数据报中的一个可变长度的可选信息,选项字段以 32bit 为界,不足时插入值为 0 的填充字节,保证 IP 首部始终是 32bit 的整数倍(一般为0)

5、IP首部校验和

0x4500 + 0x003C + 0x0000 + 0x4000 + 0x4001 + 0x0000(计算时强制置0) + 0xc0a8

+  0x010a + 0xc0a8 + 0x0166 = 0x248FD

进位拿出来与低位相加。

0x0002 + 0x48FD = 0x000048FF(此种情况并未出现进位)

0x0000+ 0x48FF= 0x48FF(此种情况并未出现进位)

check_sum = ~0x48FF(按位取反)= 0xb700

对各个单元采用反码加法运算(即高位溢出位会加到低位,通常的补码运算是直接丢掉溢出的高位)
 

二、ICMP协议

1、简介

        ICMP是Internet Control Message Protocol的缩写,即互联网控制消息协议。它用于TCP/IP网络中发送控制消息,提供可能发生在通信环境中的各种问题反馈,通过这些信息,使网络管理者可以对所发生的问题作出诊断,然后采取适当的措施解决问题。

2、ICMP协议包格式

(1)查询报文

常用类型有:类型 0,代码 0:表示回显应答(ping 应答)。                                                                                      类型 8,代码 0:表示回显请求(ping 请求)。                                                                                      类型 11,代码 0:超时;                                                                                                                    类型 3,代码 0:网络不可达;                                                                                                          类型 3,代码 1:主机不可达;                                                                                                          类型 5,代码 0:重定向。

代码(code):占用了 8 bit 位,根据 ICMP 差错报文的类型,进一步分析错误的原因,代码值不同对应的错误也不同,例如:类型为 11 且代码为 0,表示数据传输过程中超时了,超时的具体原因是 TTL 值为 0,数据报被丢弃。
校验和(checksum):占用了 16 bit 位, 校验的方法同上述 IP 首部校验和的方法一致。 数据发送到目的地后需要对 ICMP 数据报文做一个校验,用于检查数据报文是否有错误。
标识符(Identifier):占用了 16 bit 位,对于每一个发送的数据报进行标识。
序列号(Sequence number):占用了 16 bit 位,对于发送的每一个数据报文进行编号,比如:发送的第一个数据报序列号为 1,第二个序列号为 2。
数据(Data):要发送的 ICMP 数据。


3、常用ICMP报文类型

三、程序设计

目标:电脑ping开发板实现开发板应答

1、整体框图:

2、ICMP编写:

(1)icmp_rx

前导码+帧起始界定符->以太网帧头->IP 首部->ICMP 首->ICMP 数据(有效数据) ->接收结束
 

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/12/26 15:41:37
// Design Name: 
// Module Name: icmp_rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module icmp_rx(input                   clk             ,input                   rst_n           ,input                   gmii_rx_dv      ,input       [ 7:0]      gmii_rxd        ,output  reg             rec_pkt_done    ,   //以太网单包数据接收完成信号output  reg             rec_en          ,   //以太网接收数据使能信号    ---fifo_enoutput  reg [ 7:0]      rec_data        ,   //以太网接收数据    ---fifo_dataoutput  reg [15:0]      rec_byte_num    ,   //以太网接收有效字数    bitoutput  reg [15:0]      icmp_id         ,   //ICMP标识符output  reg [15:0]      icmp_seq        ,   //ICMP序列号output  reg [31:0]      reply_checksum      //接收数据校验
);//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48'h00_11_22_33_44_55;    
//开发板IP地址 192.168.1.10 
parameter BOARD_IP  = {8'd192,8'd168,8'd1,8'd10};   //状态机状态定义
localparam  st_idle         =   7'b000_0001 ;   //初始状态,等待接收前导码
localparam  st_preamble     =   7'b000_0010 ;   //接收前导码状态 
localparam  st_eth_head     =   7'b000_0100 ;   //接收以太网帧头
localparam  st_ip_head      =   7'b000_1000 ;   //接收IP首部
localparam  st_icmp_head    =   7'b001_0000 ;   //接收ICMP首部
localparam  st_rx_data      =   7'b010_0000 ;   //接收有效数据
localparam  st_rx_end       =   7'b100_0000 ;   //接收结束//以太网类型定义
localparam  ETH_TYPE        =   16'h0800   ; //以太网协议类型 IP协议
localparam  ICMP_TYPE       =   8'd1       ; //ICMP协议类型//ICMP报文类型:回显请求
localparam ECHO_REQUEST     =   8'h08       ; reg     [6 :0]  cur_state           ;   //当前状态
reg     [6 :0]  next_state          ;   //下一状态
reg             skip_en             ;   //状态跳转信号
reg             error_en            ;   //状态错误信号
reg     [4 :0]  cnt                 ;   //状态数据计数器
reg     [47:0]  des_mac             ;   //目的MAC
reg     [15:0]  eth_type            ;   //以太网类型
reg     [5 :0]  ip_head_byte_num    ;   //IP首部长度
reg     [15:0]  total_length        ;   //接收数据字节长度
reg     [15:0]  icmp_data_length    ;   //有效数据长度
reg     [31:0]  des_ip              ;   //目的IP
reg     [7 :0]  icmp_type           ;   //ICMP报文类型:用于标识错误类型的差错报文或者查询类型的报告报文
reg     [7 :0]  icmp_code           ;   //ICMP报文代码:根据ICMP差错报文的类型,进一步分析错误的原因,代码值不同对应的错误也不同//例如:类型为11且代码为0,表示数据传输过程中超时了,超时的具体原因是TTL值为0,数据报被丢弃。
reg     [15:0]  icmp_checksum       ;   //接收校验和:数据发送到目的地后需要对ICMP数据报文做一个校验,用于检查数据报文是否有错误
reg     [1 :0]  rec_en_cnt          ;   //8bit转32bit计数器
reg     [15:0]  icmp_rx_cnt         ;   //接收数据计数
reg     [7 :0]  icmp_rx_data_d0     ;
reg     [31:0]  reply_checksum_add  ;//(三段式状态机)同步时序描述状态转移
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincur_state   <=  st_idle     ;end else begincur_state   <=  next_state  ;end
end//
always @(*) beginif (!rst_n) beginnext_state  =  st_idle     ;end else begincase (cur_state)st_idle         :begin                  //等待接收前导码if (skip_en) beginnext_state  =  st_preamble ;end else beginnext_state  =  st_idle     ;  endendst_preamble     :begin                  //接收前导码if (skip_en ) beginnext_state  =  st_eth_head ;end else if(error_en)beginnext_state  =  st_rx_end   ;endelse beginnext_state  =  st_preamble ;endendst_eth_head     :begin                  //接收以太网帧头if (skip_en ) beginnext_state  =  st_ip_head  ;end else if(error_en)beginnext_state  =  st_rx_end   ;endelse beginnext_state  =  st_eth_head ;endendst_ip_head      :begin                  //接收IP首部if (skip_en ) beginnext_state  =  st_icmp_head;end else if(error_en)beginnext_state  =  st_rx_end   ;endelse beginnext_state  =  st_ip_head  ;endendst_icmp_head    :begin                  //接收ICMP首部if (skip_en ) beginnext_state  =  st_rx_data  ;end else if(error_en)beginnext_state  =  st_rx_end   ;endelse beginnext_state  =  st_icmp_head;endendst_rx_data      :begin                  //接收有效数据if (skip_en ) beginnext_state  =  st_rx_end   ;end else beginnext_state  =  st_rx_data  ;endendst_rx_end       :begin                  //接收结束if (skip_en ) beginnext_state  =  st_idle    ;end else beginnext_state  =  st_rx_end  ;endenddefault: next_state  =  st_idle   ;endcaseend
end//
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginskip_en             <= 1'b0     ;error_en            <= 1'b0     ;cnt                 <= 5'd0     ;des_mac             <= 48'd0    ;eth_type            <= 16'd0    ;des_ip              <= 32'd0    ;ip_head_byte_num    <= 6'd0     ;total_length        <= 16'd0    ;icmp_type           <= 8'd0     ;icmp_code           <= 8'd0     ;icmp_checksum       <= 16'd0    ;icmp_id             <= 16'd0    ;icmp_seq            <= 16'd0    ;icmp_rx_data_d0     <= 8'd0     ;reply_checksum      <= 32'd0    ;  //累加reply_checksum_add  <= 32'd0    ;icmp_rx_cnt         <= 16'd0    ;icmp_data_length    <= 16'd0    ;rec_en_cnt          <= 2'd0     ;rec_en              <= 1'b0     ;rec_data            <= 32'd0    ;rec_pkt_done        <= 1'b0     ;rec_byte_num        <= 16'd0    ;end else beginskip_en         <=  1'b0;error_en        <=  1'b0;rec_pkt_done    <=  1'b0;   //以太网单包数据接收完成信号case (cur_state)st_idle         :begin                                          //等待接收前导码if ((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) beginskip_en     <=  1'b1;end else beginskip_en     <=  1'b0;endendst_preamble     :begin                                          //接收前导码if (gmii_rx_dv == 1'b1) begincnt <= cnt + 1'b1;if ((cnt < 5'd6 ) && (gmii_rxd != 8'h55)) beginerror_en    <=  1'b1;endelse if (cnt == 5'd6) begincnt <= 5'd0;if (gmii_rxd == 8'hd5) beginskip_en     <=  1'b1;error_en    <=  1'b0;end else beginskip_en     <=  1'b0;error_en    <=  1'b1;endend else beginskip_en     <=  skip_en ;error_en    <=  error_en;endend else beginskip_en         <=  1'b0;error_en        <=  1'b1;endendst_eth_head     :begin                                          //接收以太网帧头if (gmii_rx_dv == 1'b1) begincnt <= cnt + 1'b1;if (cnt < 5'd6) begindes_mac     <=  {des_mac[39:0],gmii_rxd};end else if( cnt == 5'd12)begineth_type[15:8]  <=  gmii_rxd;endelse if (cnt == 5'd13) begineth_type[ 7:0]  <=  gmii_rxd;cnt             <=  5'd0;if (((des_mac == BOARD_MAC)||(des_mac == 48'hff_ff_ff_ff_ff_ff))&&(eth_type[15:8] == ETH_TYPE[15:8])&&(gmii_rxd == ETH_TYPE[7:0])) beginskip_en     <=  1'b1;error_en    <=  1'b0;end else beginskip_en     <=  1'b0;error_en    <=  1'b1;endend else beginskip_en     <=  skip_en     ;error_en    <=  error_en    ;endend else beginskip_en     <=  1'b0;error_en    <=  1'b1;endendst_ip_head      :begin                                      //接收IP首部if (gmii_rx_dv == 1'b1) begincnt <= cnt + 1'b1;if (cnt == 5'd0) beginip_head_byte_num    <=  {gmii_rxd[3:0],2'd0};end else if (cnt == 5'd2) begintotal_length[15:8]  <=  gmii_rxd    ;endelse if (cnt == 5'd3) begintotal_length[7:0]   <=  gmii_rxd    ;endelse if (cnt == 5'd4) begin             //有效数据字节长度,(IP首部20个字节,icmp首部8个字节,所以减去28)icmp_data_length <= total_length - 16'd28; endelse if (cnt == 5'd9) beginif (gmii_rxd != ICMP_TYPE) begin    //如果当前接收的数据不是ICMP协议,停止解析数据  error_en    <=  1'b1    ;skip_en     <=  1'b0    ;cnt         <=  5'd0    ;end else beginerror_en    <=  1'b0    ;skip_en     <=  skip_en ;endend else if ((cnt >= 5'd16)&&(cnt <= 5'd18)) begindes_ip  <=  {des_ip[23:0],gmii_rxd};endelse if (cnt == 5'd19) begindes_ip  <=  {des_ip[23:0],gmii_rxd};if ({des_ip[23:0],gmii_rxd} == BOARD_IP) beginskip_en     <=  1'b1;error_en    <=  1'b0;cnt         <=  5'd0;end else beginskip_en     <=  1'b0;error_en    <=  1'b1;cnt         <=  5'd0;endend else beginskip_en     <=  skip_en     ;error_en    <=  error_en    ;endend else beginskip_en     <=  1'b0;error_en    <=  1'b1;end endst_icmp_head    :begin                                      //接收ICMP首部if (gmii_rx_dv == 1'b1) begincnt <= cnt + 1 'b1;if (cnt == 5'd0) beginicmp_type   <=  gmii_rxd    ;end else if (cnt == 5'd1) beginicmp_code   <=  gmii_rxd    ;endelse if ((cnt == 5'd2)||(cnt == 5'd3)) beginicmp_checksum   <=  {icmp_checksum[7:0],gmii_rxd}   ;endelse if ((cnt == 5'd4)||(cnt == 5'd5)) beginicmp_id         <=  {icmp_id[7:0],gmii_rxd}   ;endelse if (cnt == 5'd6) beginicmp_seq[15:8]  <=  gmii_rxd    ;end else if (cnt == 5'd7) beginicmp_seq[7:0]   <=  gmii_rxd    ;if (icmp_type == ECHO_REQUEST) beginskip_en     <=  1'b1;error_en    <=  1'b0;cnt         <=  5'd0;end else beginskip_en     <=  1'b0;error_en    <=  1'b1;    cnt         <=  5'd0;endendelse beginskip_en     <=  skip_en     ;error_en    <=  error_en    ;cnt         <=  cnt         ;endend else beginskip_en     <=  1'b0;error_en    <=  1'b1;    cnt         <=  5'd0;endendst_rx_data      :begin                                      //接收有效数据if (gmii_rx_dv == 1'b1) beginrec_en_cnt  <=  rec_en_cnt  + 1'b1  ;icmp_rx_cnt <=  icmp_rx_cnt + 1'b1  ;rec_data    <=  gmii_rxd            ;               //以太网接收数据rec_en      <=  1'b1                ;if (icmp_rx_cnt == icmp_data_length - 1'b1) beginicmp_rx_data_d0 <=  8'd0;if (icmp_data_length[0] == 1'b1) begin  //奇数reply_checksum_add  <=  {8'h0,gmii_rxd} + reply_checksum_add    ;end else begin  //偶数reply_checksum_add  <=  {icmp_rx_data_d0,gmii_rxd} + reply_checksum_add ;endend else if (icmp_rx_cnt < icmp_data_length) beginicmp_rx_data_d0 <=  gmii_rxd    ;icmp_rx_cnt     <=  icmp_rx_cnt + 1'b1  ;if (icmp_rx_cnt[0] == 1'b1) beginreply_checksum_add  <=  {icmp_rx_data_d0,gmii_rxd} + reply_checksum_add ;end else beginreply_checksum_add  <=  reply_checksum_add  ;endendelse beginerror_en    <=  1'b1;endif (icmp_rx_cnt == icmp_data_length - 1'b1) beginskip_en         <=  1'b1;error_en        <=  1'b0;rec_en_cnt      <=  2'd0;rec_pkt_done    <=  1'b1;rec_byte_num    <=  icmp_data_length    ;    end else beginskip_en         <=  1'b0;error_en        <=  1'b1;rec_en_cnt      <=  2'd0;rec_pkt_done    <=  1'b1;rec_byte_num    <=  icmp_data_length    ;    endend else beginerror_en    <=  1'b1;endendst_rx_end       :begin                                      //接收结束rec_en  <=  1'b0;if ((gmii_rx_dv == 1'b0)&&(skip_en  == 1'b0)) beginreply_checksum      <=  reply_checksum_add  ;skip_en             <=  1'b1                ;reply_checksum_add  <=  32'd0               ;end else beginreply_checksum      <=  reply_checksum      ;skip_en             <=  skip_en             ;reply_checksum_add  <=  reply_checksum_add  ;endenddefault:    error_en    =   1'b1    ; endcase    end
endendmodule

(2)icmp_tx

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/12/28 20:19:55
// Design Name: 
// Module Name: icmp_tx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module icmp_tx(    input                clk                ,   //时钟信号input                rst_n              ,   //复位信号,低电平有效input        [31:0]  reply_checksum     ,   //ICMP数据部分校验和input        [15:0]  icmp_id            ,   //ICMP标识符input        [15:0]  icmp_seq           ,   //ICMP序列号input                tx_start_en        ,   //以太网开始发送信号input        [ 7:0]  tx_data            ,   //以太网待发送数据input        [15:0]  tx_byte_num        ,   //以太网发送的有效字节数input        [47:0]  des_mac            ,   //发送的目标MAC地址input        [31:0]  des_ip             ,   //发送的目标IP地址input        [31:0]  crc_data           ,   //CRC校验数据input         [7:0]  crc_next           ,   //CRC下次校验完成数据output  reg          tx_done            ,   //以太网发送完成信号output  reg          tx_req             ,   //读数据请求信号output  reg          gmii_tx_en         ,   //GMII输出数据有效信号output  reg  [7:0]   gmii_txd           ,   //GMII输出数据output  reg          crc_en             ,   //CRC开始校验使能output  reg          crc_clr                //CRC数据复位信号
);//parameter define
//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48'h00_11_22_33_44_55;
//开发板IP地址 192.168.1.10     
parameter BOARD_IP  = {8'd192,8'd168,8'd1,8'd10};
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter DES_MAC   = 48'hff_ff_ff_ff_ff_ff;
//目的IP地址 192.168.1.102     
parameter DES_IP    = {8'd192,8'd168,8'd1,8'd102};//状态机状态定义
localparam st_idle          =   8'b0000_0001    ;   //初始状态,等待开始发送信号
localparam st_check_sum     =   8'b0000_0010    ;   //IP首部校验和
localparam st_check_icmp    =   8'b0000_0100    ;   //ICMP首部+数据校验
localparam st_preamble      =   8'b0000_1000    ;   //发送前导码+帧起始界定符
localparam st_eth_head      =   8'b0001_0000    ;   //发送以太网帧头
localparam st_ip_head       =   8'b0010_0000    ;   //发送IP首部+ICMP首部
localparam st_tx_data       =   8'b0100_0000    ;   //发送数据
localparam st_crc           =   8'b1000_0000    ;   //发送CRC校验值//以太网类型定义
localparam  ETH_TYPE        =   16'h0800        ;  //以太网协议类型 IP协议//以太网数据最小46个字节,IP首部20个字节+ICMP首部8个字节 
//所以数据至少46-20-8=18个字节
localparam  MIN_DATA_NUM    =   16'd18          ;//parameter define
//ICMP报文类型:回显应答
parameter   ECHO_REPLY      =   8'h00           ;reg     [7:0]   cur_state               ;//当前状态
reg     [7:0]   next_state              ;//下一状态
reg             start_en_d0             ;//
reg             start_en_d1             ;//
reg             start_en_d2             ;//
reg     [15:0]  tx_data_num             ;//发送数据长度
reg     [15:0]  total_num               ;//总长度
reg             trig_tx_en              ;//使能触发信号
reg             skip_en                 ;//状态跳转信号
reg     [4:0]   cnt                     ;//发送数据计数器
reg     [31:0]  check_buffer            ;//IP首部校验和
reg     [31:0]  check_buffer_icmp       ;//ICMP首部校验和
reg     [7:0]   preamble    [7:0]       ;//前导码
reg     [7:0]   eth_head    [13:0]      ;//以太网首部
reg     [31:0]  ip_head     [6:0]       ;//IP首部 + ICMP首部 
reg     [1:0]   tx_bit_sel              ;//bit计数器
reg             tx_done_t               ;//发送完成标志
reg     [15:0]  data_cnt                ;//发送数据计数器
reg     [4:0]   real_add_cnt            ;//多发送数据计数器wire    [15:0]  real_tx_data_num    ;   //发送有效长度
wire            pos_start_en        ;   //触发信号上升沿assign  pos_start_en = (~start_en_d2) & start_en_d1;
assign  real_tx_data_num = (tx_data_num >= MIN_DATA_NUM) ? tx_data_num : MIN_DATA_NUM;//采tx_start_en的上升沿
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginstart_en_d0 <= 1'b0;start_en_d1 <= 1'b0;start_en_d2 <= 1'b0;end    else beginstart_en_d0 <= tx_start_en;start_en_d1 <= start_en_d0;start_en_d2 <= start_en_d1;end
end //寄存数据有效字节
always @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_data_num <= 16'd0;total_num <= 16'd0;endelse beginif(pos_start_en && cur_state==st_idle) begin//数据长度tx_data_num <= tx_byte_num;//IP长度:有效数据+IP首部长度(20bytes)+ICMP首部长度(8bytes)total_num <= tx_byte_num + 16'd28;end  else begintx_data_num <=  tx_data_num ;total_num   <=  total_num   ;endend
end//触发发送信号
always @(posedge clk or negedge rst_n) beginif(!rst_n) begintrig_tx_en <= 1'b0;endelse begintrig_tx_en <= pos_start_en;end
end//(三段式状态机)同步时序描述状态转移
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincur_state   <=  st_idle     ;end else begincur_state   <=  next_state  ;end
end//
always @(*) beginnext_state = st_idle;case(cur_state)st_idle     : begin                               //等待发送数据if(skip_en)next_state = st_check_sum;elsenext_state = st_idle;end  st_check_sum: begin                               //IP首部校验if(skip_en)next_state = st_check_icmp;elsenext_state = st_check_sum;end  st_check_icmp: begin                              //ICMP首部校验if(skip_en)next_state = st_preamble;elsenext_state = st_check_icmp;end  st_preamble : begin                               //发送前导码+帧起始界定符if(skip_en)next_state = st_eth_head;elsenext_state = st_preamble;endst_eth_head : begin                               //发送以太网首部if(skip_en)next_state = st_ip_head;elsenext_state = st_eth_head;end              st_ip_head : begin                                //发送IP首部+icmp首部if(skip_en)next_state = st_tx_data;elsenext_state = st_ip_head;endst_tx_data : begin                                //发送数据if(skip_en)next_state = st_crc;elsenext_state = st_tx_data;endst_crc: begin                                     //发送CRC校验值if(skip_en)next_state = st_idle;elsenext_state = st_crc;enddefault : next_state = st_idle;endcase
end//
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginskip_en             <=  1'b0    ; cnt                 <=  5'd0    ;check_buffer        <=  32'd0   ;check_buffer_icmp   <=  32'd0   ;ip_head[1][31:16]   <=  16'd0   ;tx_bit_sel          <=  2'b0    ;crc_en              <=  1'b0    ;gmii_tx_en          <=  1'b0    ;gmii_txd            <=  8'd0    ;tx_req              <=  1'b0    ;tx_done_t           <=  1'b0    ;    data_cnt            <=  16'd0   ;real_add_cnt        <=  5'd0    ;//初始化数组    //前导码 7个8'h55 + 1个8'hd5preamble[0] <= 8'h55;preamble[1] <= 8'h55;preamble[2] <= 8'h55;preamble[3] <= 8'h55;preamble[4] <= 8'h55;preamble[5] <= 8'h55;preamble[6] <= 8'h55;preamble[7] <= 8'hd5;//目的MAC地址   //目的MAC地址 ff_ff_ff_ff_ff_ffeth_head[0] <= DES_MAC[47:40];eth_head[1] <= DES_MAC[39:32];eth_head[2] <= DES_MAC[31:24];eth_head[3] <= DES_MAC[23:16];eth_head[4] <= DES_MAC[15:8];eth_head[5] <= DES_MAC[7:0];//源MAC地址     //开发板MAC地址 00-11-22-33-44-55eth_head[6] <= BOARD_MAC[47:40];eth_head[7] <= BOARD_MAC[39:32];eth_head[8] <= BOARD_MAC[31:24];eth_head[9] <= BOARD_MAC[23:16];eth_head[10] <= BOARD_MAC[15:8];eth_head[11] <= BOARD_MAC[7:0];//以太网类型    //0800 IP协议eth_head[12] <= ETH_TYPE[15:8];eth_head[13] <= ETH_TYPE[7:0];end else beginskip_en     <=  1'b0    ;crc_en      <=  1'b0    ;gmii_tx_en  <=  1'b0    ;tx_done_t   <=  1'b0    ;case (cur_state)st_idle         :beginif (trig_tx_en) beginskip_en <= 1'b1; //版本号:4 首部长度:5(单位:32bit,20byte/4=5)ip_head[0] <= {8'h45,8'h00,total_num};//16位标识,每次发送累加1      ip_head[1][31:16] <= ip_head[1][31:16] + 1'b1;//bit[15:13]: 010表示不分片ip_head[1][15:0] <= 16'h4000;//8'h80:表示生存时间//8'd01:1代表ICMP,2代表IGMP,6代表TCP,17代表UDPip_head[2] <= {8'h80,8'd01,16'h0000};//源IP地址               ip_head[3] <= BOARD_IP;//目的IP地址if (des_ip != 32'd0) beginip_head[4]  <=  des_ip  ;end else beginip_head[4]  <=  DES_IP  ;end// 8位icmp TYPE ,8位 icmp CODE ip_head[5][31:16] <= {ECHO_REPLY,8'h00};//16位identifier 16位sequenceip_head[6] <= {icmp_id,icmp_seq};//更新MAC地址if (des_mac != 48'd0) begin//目的MAC地址eth_head[0] <=  des_mac[47:40]  ;eth_head[1] <=  des_mac[39:32]  ;eth_head[2] <=  des_mac[31:24]  ;eth_head[3] <=  des_mac[23:16]  ;eth_head[4] <=  des_mac[15:8]   ;eth_head[5] <=  des_mac[7:0]    ;end end endst_check_sum    :begin              //IP首部校验cnt <= cnt + 1'b1;if (cnt == 5'd0) begincheck_buffer    <= ip_head[0][31:16] + ip_head[0][15:0]+ ip_head[1][31:16] + ip_head[1][15:0]+ ip_head[2][31:16] + ip_head[2][15:0]+ ip_head[3][31:16] + ip_head[3][15:0]+ ip_head[4][31:16] + ip_head[4][15:0];end else if (cnt == 5'd1) begin                //可能出现进位,累加一次check_buffer    <= check_buffer[31:16] + check_buffer[15:0];endelse if (cnt == 5'd2) begin                //可能再次出现进位,累加一次check_buffer    <= check_buffer[31:16] + check_buffer[15:0];end       else if (cnt == 5'd3) beginskip_en             <=  1'b1    ;cnt                 <=  5'd0    ;ip_head[2][15:0]    <=  ~check_buffer[15:0] ;endelse begincheck_buffer <= check_buffer;endendst_check_icmp   :begin              //ICMP首部+数据校验cnt <=  cnt + 1'b1  ;   if (cnt == 5'd0) begincheck_buffer_icmp   <= ip_head[5][31:16] + ip_head[6][31:16] + ip_head[6][15:0]+ reply_checksum;end else if(cnt == 5'd1) begin                     //可能出现进位,累加一次check_buffer_icmp   <= check_buffer_icmp[31:16] + check_buffer_icmp[15:0];endelse if(cnt == 5'd2) begin                //可能再次出现进位,累加一次check_buffer_icmp   <= check_buffer_icmp[31:16] + check_buffer_icmp[15:0];endelse if(cnt == 5'd3) begin                //按位取反skip_en <= 1'b1;cnt <= 5'd0;// ICMP:16位校验和ip_head[5][15:0]    <= ~check_buffer_icmp[15:0];end  else begincheck_buffer_icmp   <=  check_buffer_icmp;endendst_preamble     :begin              //发送前导码+帧起始界定符gmii_tx_en      <=  1'b1    ;gmii_txd        <=  preamble[cnt];if (cnt == 5'd7) beginskip_en     <=  1'b1    ;   cnt         <=  5'd0    ;end else begincnt         <=  cnt + 1'b1  ;endendst_eth_head     :begin              //发送以太网首部gmii_tx_en      <=  1'b1            ;  crc_en          <=  1'b1            ;gmii_txd        <=  eth_head[cnt]   ;if (cnt == 5'd13) beginskip_en     <=  1'b1    ;cnt         <=  5'd0    ;end else begincnt         <=  cnt + 1'b1  ;endendst_ip_head      :begin              //发送IP+ICMP首部gmii_tx_en      <=  1'b1                    ;  crc_en          <=  1'b1                    ;tx_bit_sel      <=  tx_bit_sel  +   1'b1    ;if (tx_bit_sel == 2'd0) begingmii_txd    <=  ip_head[cnt][31:24]     ;end else if (tx_bit_sel == 2'd1) begingmii_txd    <=  ip_head[cnt][23:16]     ;end  else if (tx_bit_sel == 2'd2) begingmii_txd    <=  ip_head[cnt][15:8]      ;if(cnt == 5'd6)begintx_req  <=  1'b1    ;endendelse if (tx_bit_sel == 2'd3) begin  gmii_txd    <=  ip_head[cnt][7:0]       ;if (cnt == 5'd6) begin      //提前读请求数据,等待数据有效时发送skip_en <=  1'b1    ;cnt     <=  5'd0    ;end else begincnt     <= cnt + 1'b1   ;    endendelse begingmii_txd     <=  gmii_txd    ; endendst_tx_data      :begin              //发送数据gmii_tx_en      <=  1'b1        ;  crc_en          <=  1'b1        ;tx_bit_sel      <=  2'd0        ;gmii_txd        <=  tx_data     ;if (data_cnt    <   tx_data_num - 1'b1) begindata_cnt    <=  data_cnt + 1'b1 ;end else if (data_cnt == tx_data_num - 1'b1) begin//如果发送的有效数据少于18个字节,在后面填补充位//补充的值为最后一次发送的有效数据if (data_cnt + real_add_cnt < real_tx_data_num - 1'b1) beginreal_add_cnt    <=  real_add_cnt + 1'b1 ;end else beginskip_en         <=  1'b1    ;data_cnt        <=  16'd0   ;real_add_cnt    <=  5'd0    ;    endendelse begindata_cnt    <=  data_cnt    ;endif (data_cnt == tx_data_num - 2'd2) begintx_req  <=  1'b0    ;end else begintx_req  <=  tx_req  ;endendst_crc          :begingmii_tx_en <= 1'b1;tx_bit_sel <= tx_bit_sel + 3'd1;tx_req <= 1'b0; if(tx_bit_sel == 3'd0)gmii_txd <= {~crc_next[0], ~crc_next[1], ~crc_next[2],~crc_next[3],~crc_next[4], ~crc_next[5], ~crc_next[6],~crc_next[7]};else if(tx_bit_sel == 3'd1)gmii_txd <= {~crc_data[16], ~crc_data[17], ~crc_data[18],~crc_data[19],~crc_data[20], ~crc_data[21], ~crc_data[22],~crc_data[23]};else if(tx_bit_sel == 3'd2) begingmii_txd <= {~crc_data[8], ~crc_data[9], ~crc_data[10],~crc_data[11],~crc_data[12], ~crc_data[13], ~crc_data[14],~crc_data[15]};endelse if(tx_bit_sel == 3'd3) begingmii_txd <= {~crc_data[0], ~crc_data[1], ~crc_data[2],~crc_data[3],~crc_data[4], ~crc_data[5], ~crc_data[6],~crc_data[7]};tx_done_t <= 1'b1;skip_en <= 1'b1;endelse;enddefault: ;endcase   end
end//发送完成信号及crc值复位信号
always @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_done <= 1'b0;crc_clr <= 1'b0;endelse begintx_done <= tx_done_t;crc_clr <= tx_done_t;end
endendmodule

(3)icmp

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/12/29 15:29:13
// Design Name: 
// Module Name: icmp
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module icmp(input                   sys_clk         ,   //ila系统时钟input                   rst_n           ,   //复位信号,低电平有效//GMII接口          input                   gmii_rx_clk     ,   //GMII接收数据时钟input                   gmii_rx_dv      ,   //GMII输入数据有效信号input        [7:0]      gmii_rxd        ,   //GMII输入数据input                   gmii_tx_clk     ,   //GMII发送数据时钟output                  gmii_tx_en      ,   //GMII输出数据有效信号output       [7:0]      gmii_txd        ,   //GMII输出数据 //用户接口          output                  rec_pkt_done    ,   //以太网单包数据接收完成信号output                  rec_en          ,   //以太网接收的数据使能信号			output       [ 7:0]     rec_data        ,   //以太网接收的数据				output       [15:0]     rec_byte_num    ,   //以太网接收的有效字节数 单位:byteinput                   tx_start_en     ,   //以太网开始发送信号input        [ 7:0]     tx_data         ,   //以太网待发送数据					input        [15:0]     tx_byte_num     ,   //以太网发送的有效字节数 单位:byteinput        [47:0]     des_mac         ,   //发送的目标MAC地址input        [31:0]     des_ip          ,   //发送的目标IP地址output                  tx_done         ,   //以太网发送完成信号output                  tx_req              //读数据请求信号		
);//parameter define
//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48'h00_11_22_33_44_55;    
//开发板IP地址 192.168.1.10     
parameter BOARD_IP  = {8'd192,8'd168,8'd1,8'd10};
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter  DES_MAC  = 48'hff_ff_ff_ff_ff_ff;
//目的IP地址 192.168.1.102     
parameter  DES_IP   = {8'd192,8'd168,8'd1,8'd102};wire          crc_en            ; //CRC开始校验使能
wire          crc_clr           ; //CRC数据复位信号 
wire  [7:0]   crc_d8            ; //输入待校验8位数据wire  [31:0]  crc_data          ; //CRC校验数据
wire  [31:0]  crc_next          ; //CRC下次校验完成数据wire  [15:0]  icmp_id           ; //ICMP标识符:对于每一个发送的数据报进行标识
wire  [15:0]  icmp_seq          ; //ICMP序列号:对于发送的每一个数据报文进行编号//比如:发送的第一个数据报序列号为1,第二个序列号为2
wire  [31:0]  reply_checksum    ; //接收的icmp数据部分校验和assign  crc_d8 = gmii_txd       ;icmp_rx #(.BOARD_MAC      (BOARD_MAC      )   ,    //参数例化.BOARD_IP       (BOARD_IP       )   )
u_icmp_rx(.clk            (gmii_rx_clk    )   ,.rst_n          (rst_n          )   ,.gmii_rx_dv     (gmii_rx_dv     )   ,   //GMII输入数据有效信号.gmii_rxd       (gmii_rxd       )   ,   //GMII输入数据.rec_pkt_done   (rec_pkt_done   )   ,   //以太网单包数据接收完成信号.rec_en         (rec_en         )   ,   //以太网接收数据使能信号         ---fifo_en.rec_data       (rec_data       )   ,   //以太网接收数据                ---fifo_data.rec_byte_num   (rec_byte_num   )   ,   //以太网接收有效字数    bit.icmp_id        (icmp_id        )   ,   //ICMP标识符.icmp_seq       (icmp_seq       )   ,   //ICMP序列号.reply_checksum (reply_checksum )       //接收数据校验
);icmp_tx#( .BOARD_MAC      (BOARD_MAC      )   ,    //参数例化.BOARD_IP       (BOARD_IP       )   ,.DES_MAC        (DES_MAC        )   ,.DES_IP         (DES_IP         )   )
u_icmp_tx(    //input.clk            (gmii_tx_clk    )   ,   //时钟信号.rst_n          (rst_n          )   ,   //复位信号,低电平有效.reply_checksum (reply_checksum )   ,   //ICMP数据部分校验和.icmp_id        (icmp_id        )   ,   //ICMP标识符.icmp_seq       (icmp_seq       )   ,   //ICMP序列号.tx_start_en    (tx_start_en    )   ,   //以太网开始发送信号.tx_data        (tx_data        )   ,   //以太网待发送数据.tx_byte_num    (tx_byte_num    )   ,   //以太网发送的有效字节数.des_mac        (des_mac        )   ,   //发送的目标MAC地址.des_ip         (des_ip         )   ,   //发送的目标IP地址.crc_data       (crc_data       )   ,   //CRC校验数据.crc_next       (crc_next       )   ,   //CRC下次校验完成数据//output.tx_done        (tx_done        )   ,   //以太网发送完成信号.tx_req         (tx_req         )   ,   //读数据请求信号.gmii_tx_en     (gmii_tx_en     )   ,   //GMII输出数据有效信号.gmii_txd       (gmii_txd       )   ,   //GMII输出数据.crc_en         (crc_en         )   ,   //CRC开始校验使能.crc_clr        (crc_clr        )        //CRC数据复位信号
);crc32_d8 u_crc32_d8(.clk            (gmii_tx_clk    )   ,  //时钟信号.rst_n          (rst_n          )   ,  //复位信号,低电平有效.data           (crc_d8         )   ,  //输入待校验8位数据.crc_en         (crc_en         )   ,  //crc使能,开始校验标志.crc_clr        (crc_clr        )   ,  //crc数据复位信号            .crc_data       (crc_data       )   ,  //CRC校验数据.crc_next       (crc_next       )      //CRC下次校验完成数据
);endmodule

3、整体代码框架

四、下载测试

五、工程源码、项目移植请后台私信 

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

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

相关文章

XIAO ESP32 S3网络摄像头——2视频获取

本文主要是使用XIAO Esp32 S3制作网络摄像头的第2步,获取摄像头图像。 1、效果如下: 2、所需硬件 3、代码实现 3.1硬件代码: #include "WiFi.h" #include "WiFiClient.h" #include "esp_camera.h" #include "camera_pins.h"// 设…

数据看板如何提升决策效率?

数据看板作为一种直观、高效的数据可视化工具&#xff0c;在这一过程中发挥着至关重要的作用。以一家中型制造企业为例&#xff0c;每天面临着生产计划的安排、原材料的采购、产品质量的把控以及市场销售的策略制定等诸多业务场景。在生产线上&#xff0c;需要确保设备的高效运…

javaEE-文件操作和IO-文件

目录 一.什么是文件 1.文件就是硬盘(磁盘)上的文件。 2.计算机中存储数据的设备&#xff1a; 3.硬盘的物理特征 4.树型结构组织和⽬录 5.文件路径 文件路径有两种表示方式&#xff1a; 6.文件的分类 二、java中文件系统的操作 1.File类中的属性&#xff1a; 2.构造方…

【网络安全 | 漏洞挖掘】JS Review + GraphQL滥用实现管理面板访问

未经许可,不得转载。 正文 在映射目标范围后,我发现了一个用于管理的控制台界面,但没有注册功能。 于是我开始尝试: 1、模糊测试注册端点 -> 失败 2、在请求中将登录替换为注册 -> 再次失败 尝试均未奏效后,我决定冷静下来,重新思考方法并利用技术手段。 我观察…

【使用命令配置java环境变量永久生效与脚本切换jdk版本】

java配置环境变量命令与脚本切换jdk版本 新建用户环境变量永久生效 setx JAVA8_HOME "D:\Java\jdk8" setx JAVA17_HOME "d:\Java\jdk-17" setx JAVA_HOME %JAVA8_HOME% setx CLASSPATH ".;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;"…

RabbitMq的Java项目实践

在现代软件开发中&#xff0c;消息队列&#xff08;Message Queue&#xff0c;简称MQ&#xff09;作为一种重要的组件&#xff0c;承担着上下游消息传递和通信的重任。RabbitMQ作为一款流行的开源消息队列中间件&#xff0c;凭借其高可用性、可扩展性和易用性等特点&#xff0c…

《代码随想录》Day25打卡!

《代码随想录》回溯算法&#xff1a;递增子序列 本题的完整题目如下&#xff1a; 本题的完整思路如下&#xff1a; 1.本题使用递归和回溯来求解&#xff0c;所以分为三部&#xff1a; 2.第一步&#xff1a;确定递归函数的返回值和参数&#xff1a;返回值无&#xff0c;参数为原…

Lucas-Kanade光流法详解

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正。 光流&#xff08;Optical Flow&#xff09;描述的是图像序列中各像素点随时间的运动情况&#xff0c;是计算机视觉中的基本问题之一。光流问题涉及尝试找出一幅图像中的许多点在第二幅图像中移动的…

电脑里msvcr120.dll文件丢失怎样修复?

电脑里msvcr120.dll文件丢失的修复指南 在电脑的日常使用中&#xff0c;我们可能会遇到各种各样的系统文件丢失问题&#xff0c;其中msvcr120.dll文件的丢失就是较为常见的一种。作为一名在软件开发领域深耕多年的从业者&#xff0c;我将为大家详细解析msvcr120.dll文件的重要…

windows终端conda activate命令行不显示环境名

问题&#xff1a; 始终不显示环境名 解决 首先需要配置conda的环境变量 确保conda --version能显示版本 然后对cmd进行初始化&#xff0c;如果用的是vscode中的终端&#xff0c;那需要对powershell进行初始化 Windows CMD conda init cmd.exeWindows PowerShell conda …

django vue3实现大文件分段续传(断点续传)

前端环境准备及目录结构&#xff1a; npm create vue 并取名为big-file-upload-fontend 通过 npm i 安装以下内容"dependencies": {"axios": "^1.7.9","element-plus": "^2.9.1","js-sha256": "^0.11.0&quo…

黑马跟学.苍穹外卖.Day01

黑马跟学.苍穹外卖.Day01 苍穹外卖-day01课程内容1. 软件开发整体介绍1.1 软件开发流程1.2 角色分工1.3 软件环境 2. 苍穹外卖项目介绍2.1 项目介绍2.2 产品原型2.3 技术选型 3. 开发环境搭建3.1 前端环境搭建3.2 后端环境搭建3.2.1 熟悉项目结构3.2.2 Git版本控制3.2.3 数据库…

基于动力学的MPC控制器设计盲点解析

文章目录 Apollo MPC控制器的设计架构误差模型和离散化预测模型推导目标函数和约束设计优化求解优化OSQP求解器参考文献 Apollo MPC控制器的设计架构 误差模型和离散化 状态变量和控制变量 1、Apollo MPC控制器中状态变量主要有如下6个 matrix_state_ Matrix::Zero(basic_stat…

2025/1/1 路由期末复习作业二

呼呼呼祝大家元旦节快乐啦&#xff01;&#xff08;我顶着我超重的黑眼圈说&#xff09; 昨天一个人在寝室一边吃泡面&#xff0c;一边看步步惊心&#xff0c;一边吃一边哭呜呜呜呜呜若曦为什么不和八爷在一起好好爱&#xff0c;就因为他不当皇帝蛮&#xff01;难测最是帝王心…

面试题解,JVM中的“类加载”剖析

一、JVM类加载机制说一下 其中&#xff0c;从加载到初始化就是我们的类加载阶段&#xff0c;我们逐一来分析 加载 “加载 loading”是整个类加载&#xff08;class loading&#xff09;过程的一个阶段&#xff0c;加载阶段JVM需要完成以下 3 件事情&#xff1a; 1&#xff0…

后端开发-Maven

环境说明&#xff1a; windows系统&#xff1a;11版本 idea版本&#xff1a;2023.3.2 Maven 介绍 Apache Maven 是一个 Java 项目的构建管理和理解工具。Maven 使用一个项目对象模型&#xff08;POM&#xff09;&#xff0c;通过一组构建规则和约定来管理项目的构建&#xf…

UML之泛化、特化和继承

在UML&#xff08;统一建模语言&#xff09;中&#xff0c;泛化&#xff08;Generalization&#xff09;和特化&#xff08;Specialization&#xff09;是面向对象思想中继承&#xff08;Inheritance&#xff09;关系的重要概念&#xff0c;它们描述类与类&#xff08;或用例与…

【时时三省】(C语言基础)常见的动态内存错误2

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 对非动态开辟空间内存使用free释放 示例&#xff1a; 这个arr数组是在栈上的 *p指向的就是arr 对非动态空间也用了free ferr只能在动态开辟空间使用 使用free释放一块动态开辟空间的一部分…

leecode718.最长重复子数组

二维空间版 class Solution { public:int findLength(vector<int>& nums1, vector<int>& nums2) {int mnums1.size(),nnums2.size();vector<vector<int>> dp(m,vector<int>(n));int result0;for(int i0;i<m;i)if(nums1[i]nums2[0]){…

「Mac畅玩鸿蒙与硬件54」UI互动应用篇31 - 滑动解锁屏幕功能

本篇教程将实现滑动解锁屏幕功能&#xff0c;通过 Slider 组件实现滑动操作&#xff0c;学习事件监听、状态更新和交互逻辑的实现方法。 关键词 滑动解锁UI交互状态管理动态更新事件监听 一、功能说明 滑动解锁屏幕功能包含以下功能&#xff1a; 滑动解锁区域&#xff1a;用…