EEPROM读写实验——FPGA学习笔记18

news2024/10/6 1:07:25

一、EEPROM简介

        Electrically Erasable Progammable Read Only Memory:是指带电可擦可编程只读存储器,是一种常用的非易失性存储器(掉电数据不丢失)

EEPROM发展历史

        我们这次实验所用的AT24C64存储容量为64Kbit,内部分成256页,每页32字节,共有8192个字节,且其读写操作都是以字节为基本单位。可以把AT24C64看作一本书,那么这本书有256页,每页有32行,每行有8个字,总共有256*32*8=65536个字,对应着AT24C6464*1024=65536bit。
        读是从起始读到最大,回到起始; 写是写到一页的结束;

24C02:

片内地址寻址:

读写操作:

二、IIC简介

1、简介

        IIC即Inter-Integrated Circuit(集成电路总线),是由Philips半导体公司(现在的NXP半导体公司)在八十年代初设计出来的一种简单、双向、二线制总线标准。

2、 IIC结构示意

3、IIC协议时序

时钟线为低电平可以变化数据,时钟线为高电平不允许变化数据,只能保持。

 4、器件地址

5、字寄存器地址 (24C64)

6、单次写(字节写)

7、连续写(页写)

8、读当前地址:

9、任意地址单次读(随机读)

10、从xxx地址开始连续读

三、试验任务

        本节的实验任务是先向E2PROMAT24C64)的存储器地址0255分别写入数据0~255;写完之后再读取存储器地址0~255中的数据,若读取的值全部正确则LED灯常亮,否则LED灯闪烁。

四、程序设计

 1、整体框图

2、IIC_my

状态机:

代码:

`timescale 1ns / 1ps

module iic_my#(
    parameter integer WMEN_LEN = 8'd1   ,   //写长度,以字节为单位,包含器件地址
    parameter integer RMEN_LEN = 8'd0   ,   //读长度,以字节为单位,不包含器件地址
    parameter integer CLK_DIV  = 16'd499    //IIC时钟分频系数
)
(
input   wire                            I_clk               ,       //系统时钟输入
input   wire                            I_rstn              ,       //系统复位,低电平有效
output  reg                             O_iic_scl = 1'b0    ,       //I2C时钟SCL
inout   wire                            IO_iic_sda          ,       //I2C 数据总线
input   wire    [WMEN_LEN*8-1'b1:0]     I_wr_data           ,       //写数据寄存器,其中WMEN_LEN设置了最大支持的数据字节数,越大占用的FPGA资源越多
input   wire    [7:0]                   I_wr_cnt            ,       //写数据计数器,代表写了多少个字节
output  reg     [RMEN_LEN*8-1'b1:0]     O_rd_data = 0       ,       //读数据寄存器,其中RMEN_LEN设置了最大支持的数据字节数,越大占用的FPGA资源越多
input   wire    [7:0]                   I_rd_cnt            ,       //读数据计数器
input   wire                            I_iic_req           ,       //I_iic_req == 1 使能I2C传输
input   wire                            I_iic_mode          ,       //I_iic_mode = 1 随机读   I_iic_mode = 0 读当前寄存器或者页读
output  reg                             O_iic_busy = 1'b0   ,       //I2C控制器忙
output  reg                             O_iic_bus_error     ,       //I2C总线,无法读到正确ACK出错
output  reg                             IO_iic_sda_dg               //数据总线上的数据
);

localparam IDLE     =    4'd0   ;       //I2C 总线空闲状态
localparam START    =    4'd1   ;       //I2C 总线启动
localparam W_WAIT   =    4'd2   ;       //I2C 总线等待写完成
localparam W_ACK    =    4'd3   ;       //I2C 总线等待写WACK
localparam R_WAIT   =    4'd4   ;       //I2C 总线等待读完成 
localparam R_ACK    =    4'd5   ;       //I2C 总线等待读RACK 
localparam STOP1    =    4'd6   ;       //I2C 总线产生停止位
localparam STOP2    =    4'd7   ;       //I2C 总线产生停止位   

localparam SCL_DIV  =   CLK_DIV/2   ;

localparam OFFSET   =   SCL_DIV - SCL_DIV/4 ;   //设置I2C总线的SCL时钟的偏移,以满足SCL和SDA的时序要求,外部的SCL延迟内部的半周期的四分之三

reg         [2:0 ]  IIC_S   =   4'd0    ;   //I2C 状态机
//generate  scl 
reg         [15:0]  clkdiv  =   16'd0   ;   //I2C 时钟分频寄存器
reg                 scl_r   =   1'b1    ;   //I2C控制器的SCL内部时钟
reg                 sda_o 	=   1'b0    ;   //I2C控制器的SDA
reg                 scl_clk =   1'b0    ;   //I2C控制器内部SCL时钟,与外部时钟存在OFFSET参数设置的相位偏移
reg         [7:0]   sda_r   =   8'd0    ;   //发送寄存器
reg         [7:0]   sda_i_r =   8'd0    ;   //接收寄存器
reg         [7:0]   wcnt    =   8'd0    ;   //发送数据计数器,以byte为单位
reg         [7:0]   rcnt    =   8'd0    ;   //接收数据计数器,以byte为单位
reg         [2:0]   bcnt    =   3'd0    ;   //bit计数器
reg                 rd_req  =   1'b0    ;   //读请求,当判断到需要读数据,内部状态机中设置1
wire                sda_i               ;   //sda 输入
wire                scl_offset          ;   //scl 时钟偏移控制





assign  sda_i       = (IO_iic_sda == 1'b0)  ?  1'b0 : 1'b1  ;       //读总线 
assign  IO_iic_sda  = (sda_o == 1'b0)       ?  1'b0 : 1'bz  ;       //写总线,1'bz代表高阻,I2C外部通过上拉电阻,实现总线的高电平

PULLUP PULLUP_inst (.O(iic_sda));//仅对仿真有效,仿真设计iic_sda状态为高阻,模拟上拉电阻 

//scl 时钟分频器
always@(posedge I_clk)begin
    if(clkdiv < SCL_DIV)    
        clkdiv <= clkdiv + 1'b1;
    else begin
        clkdiv <= 16'd0; 
        scl_clk <= !scl_clk;
    end
end

assign  scl_offset  =   (clkdiv == OFFSET)    ;   //设置scl_offset的时间参数

always @(posedge I_clk)begin
    O_iic_scl <=  scl_offset ?  scl_r : O_iic_scl; //O_iic_scl延迟scl_offset时间的scl_r
end

//当IIC_S状态机处于,同时空闲状态,设置SCL为高电平,同时也是空闲,停止状态,用于产生起始位和停止位时序,否则寄存scl_clk时钟
always @(*) begin
    if(IIC_S == IDLE || IIC_S == STOP1 || IIC_S == STOP2)
        scl_r <= 1'b1;
    else 
        scl_r <= scl_clk;
end

//当进入IIC_S状态为启动、停止设置sda=0,结合scl产生起始位,或者(IIC_S == R_ACK && (rcnt != I_rd_cnt) sda=0,用于产生读操作的ACK
always @(*) begin
    if(IIC_S == START || IIC_S == STOP1 || (IIC_S == R_ACK && (rcnt != I_rd_cnt)))begin
        sda_o <= 1'b0;
    end
    else if(IIC_S == W_WAIT)begin
        sda_o <= sda_r[7]; 
    end
    else begin
        sda_o <= 1'b1;                          //否则其他状态都为1,当(IIC_S == R_ACK && (rcnt == I_rd_cnt) 产生一个NACK 
    end
end

//I2C数据发送模块,所有的写数据都通过此模块发送
always @(posedge scl_clk) begin
    if(IIC_S == W_ACK || IIC_S == START)begin   //IIC_S=START和W_ACK,把需要发送的数据,寄存到sda_r
        sda_r <= I_wr_data[(wcnt*8) +: 8];      //寄存需要发发送的数据到sda_r
        if( rd_req ) begin
            sda_r <= {I_wr_data[7:1],1'b1};     //对于读操作,rd_req由内部代码产生,当写完第一个数据(器件地址),后通过判断I_rd_cnt,确认是否数据需要读
        end
    end
    else if(IIC_S == W_WAIT)begin               //当W_WAT状态,通过移位操作,把数据发送到数据总线
        sda_r <= {sda_r[6:0],1'b1};             //移位操作
    end
    else begin
        sda_r <= sda_r;
    end
end

//I2C数据接收模块,I2C读期间,把数据通过移位操作,移入O_rd_data
always @(negedge scl_clk)begin
    if(IIC_S == R_WAIT ) begin                  //当IIC_S == R_WAIT ||IIC_S == W_ACK(如果读操作,第1个BIT是W_ACK这个状态读)启动移位操作
        sda_i_r <= {sda_i_r[6:0],sda_i};
    end
    else if(IIC_S == R_ACK) begin               //当IIC_S == R_ACK,完成一个BYTE读,把数据保存到O_rd_data
        O_rd_data[((rcnt-1'b1)*8) +: 8] <= sda_i_r[7:0];
    end
    else if(IIC_S == IDLE)begin                 //空闲状态,重置sda_i_r
        sda_i_r <= 8'd0;
    end
end

//总线忙状态
always @(posedge scl_clk or negedge I_rstn )begin
	if(I_rstn == 1'b0)begin
    	O_iic_busy <= 1'b0; 
    end
	else begin
    	if((I_iic_req == 1'b1 || rd_req == 1'b1 || O_iic_bus_error))begin//I_iic_req == 1'b1 || rd_req == 1'b1总线进入忙状态
    	    O_iic_busy <= 1'b1; 
        end
        else if(IIC_S == IDLE)begin
        	O_iic_busy <= 1'b0;
        end
    end 		
end

//总线错误状态
always @(negedge scl_clk or negedge I_rstn )begin
	if(I_rstn == 1'b0)begin
    	O_iic_bus_error <= 1'b0;
    end  	
	else begin
    	if(IIC_S  == W_ACK && sda_i == 1'b1)begin//I_iic_req == 1'b1 || rd_req == 1'b1总线进入忙状态
    	    O_iic_bus_error <= 1'b1; 
        end
        else if(I_iic_req == 0)begin
        	O_iic_bus_error <= 1'b0;
        end
    end 		
end




//状态机
always @(posedge scl_clk or negedge I_rstn) begin
    if (!I_rstn) begin
        wcnt    <=  8'd0    ;
        rcnt    <=  8'd0    ;
        rd_req  <=  1'd0    ;
        IIC_S   <=  IDLE    ;
    end 
    else begin
        case (IIC_S)                        //sda = 1   scl = 1
            IDLE:begin
                if ((I_iic_req == 1'b1)||(rd_req == 1'b1) )begin    //当I_iic_req == 1'b1代表启动传输 当 rd_req == 1'b1 代表读操作需要产生repeated start 重复启动  
                    IIC_S <= START;         //进入总线启动
                end 
                else begin
                    wcnt <= 8'd0;
                    rcnt <= 8'd0;
                end
            end 
            START:begin                     //这个状态,前面的代码,先设置sda = 0,scl_offset参数设置了scl_clk时钟的偏移,之后 scl_clk =0 即scl =0 产生起始位或者重复起始位
                bcnt <= 3'd7;               //设置bcnt的初值
                IIC_S <= W_WAIT;            //进入发送等待
            end         
            W_WAIT:begin                    //等待发送完成,这里发送8bits 数据,写器件地址,写寄存器地址,写数据,都在这个状态完成
                if (bcnt > 3'd0) begin      //如果8bits没发送完,直到发送完
                    bcnt <= bcnt - 1'b1;    //bcnt计数器,每发送1bit减1
                end 
                else begin                  //8bits发送完毕
                    wcnt <= wcnt + 1'b1;    //wcnt计数器,用于记录已经写了多少字节
                    IIC_S <= W_ACK;         //进入W_ACK状态
                end
            end 
            W_ACK:begin                     //等待WACK,此阶段,也判断是否有读操作
                if (wcnt < I_wr_cnt) begin  //判断是否所有数据发送(写)完成
                    bcnt <= 3'd7;           //如果没有写完,重置bcnt
                    IIC_S <= W_WAIT;        //继续回到W_WAIT等待数据发送(写)完成
                end 
                else if(I_rd_cnt > 3'd0)begin
                    if ((rd_req == 1'b0) && (I_iic_mode == 1'b1)) begin
                        rd_req  <=  1'b1  ;     //请求读操作
                        IIC_S   <=  IDLE  ;     //设置状态进入IDLE,根据rd_req的值会重新产生一次为读操作进行的repeated重复start
                    end 
                    else begin
                        IIC_S   <=  R_WAIT  ;   //进入读等待
                        bcnt    <=  3'd7    ;   
                    end
                end
                else begin
                    IIC_S <= STOP1;             //如果所有的发送完成,也没数据需要读,进入停止状态
                end
            end 
            R_WAIT:begin
                rd_req  <=  1'b0        ;       //重置读请求 
                bcnt    <=  bcnt - 1'b1 ;
                if (bcnt == 3'd0) begin
                    rcnt    <=  ( rcnt < I_rd_cnt ) ? ( rcnt + 1'b1 ) : rcnt ; //判断是否还有数据需要读
                    IIC_S   <=  R_ACK ;
                end
            end 
            R_ACK:begin
                bcnt    <=  3'd7 ;                                             //重置读请求bcnt计数器
                IIC_S   <=  ( rcnt < I_rd_cnt ) ? R_WAIT : STOP1    ;           //如果所有数据读完,进入停止状态 
            end 
            STOP1:begin //产生停止位 sda = 0 scl = 1
                rd_req  <=  1'b0    ;   
                IIC_S   <=  STOP2   ;   
            end 
            STOP2:begin //产生停止位  sda = 1 scl = 1
                IIC_S <= IDLE;
            end 
            default:begin                 
                IIC_S <= IDLE;
            end
        endcase
    end
end



endmodule

3、

状态机:

代码

`timescale 1ns / 1ps

module eeprom_rt
(
    input   wire            I_sysclk    ,   //系统时钟输入
    output  wire            O_iic_scl   ,   // I2C SCL时钟
    inout   wire            IO_iic_sda  ,   //I2C SDA数据总线
    output  wire    [3:0]   test_led    ,   //测试LED
    output  wire            led             //error LED
);

localparam  SYSCLKHZ    =   100_000_000;
localparam  T500MS_CNT  =   (SYSCLKHZ / 2 - 1) ;

reg     [8 :0] 	    rst_cnt   	 = 9'd0     ;   //延迟复位计数器
reg     [25:0]      t500ms_cnt	 = 26'd0    ;   //500ms计数器
reg     [19:0]      delay_cnt 	 = 20'd0    ;   //eeprom每次读写完后,延迟操作计数器
reg     [2 :0]	    TS_S 	  	 = 2'd0     ;   // 读写EEPROM状态机
reg     		    iic_req 	 = 1'b0     ;   //i2c总线,读/写请求信号
reg     [31:0]	    wr_data   	 = 32'd0    ;   //写数据寄存器
reg     [7 :0]	    wr_cnt 	  	 = 8'd0     ;   //写数据计数器
reg     [7 :0]	    rd_cnt 	  	 = 8'd0     ;   //读数据计数器
wire     		    iic_busy                ;   // i2c总线忙信号标志
wire    [31:0]      rd_data                 ;   // i2c读数据
wire    		    t500ms_en               ;   // 500ms延迟到使能

wire                IO_iic_sda_dg           ;
wire                iic_bus_error           ;   //i2c总线错误
reg                 iic_error = 1'b0        ;   //i2c 读出数据有错误

assign  test_led    =   rd_data[3:0]            ;//测试LED输出
assign  led         =   iic_error               ;//通过LED显示错误标志
assign  t500ms_en   =   (t500ms_cnt==T500MS_CNT);//500ms 使能信号

//系统复位计数器
always @(posedge I_sysclk ) begin
    if (!rst_cnt[8]) begin
        rst_cnt <= rst_cnt + 1'b1;
    end
end

//I2C总线延迟间隔操作,该时间约不能低于500us,否则会导致EEPROM操作失败
always@(posedge I_sysclk) begin
    if(!rst_cnt[8])begin
        delay_cnt <= 0;
    end
    else if((TS_S == 3'd0 || TS_S == 3'd2 )) begin
        delay_cnt <= delay_cnt + 1'b1;
    end
    else begin 
        delay_cnt <= 0;
    end
end

//每间隔500ms状态机运行一次
always@(posedge I_sysclk) begin
    if(!rst_cnt[8])begin
        t500ms_cnt <= 0;
    end
    else if(t500ms_cnt == T500MS_CNT) begin
        t500ms_cnt <= 0;
    end
    else begin 
        t500ms_cnt <= t500ms_cnt + 1'b1;
    end
end

//状态机实现每次写1字节到EEPROM然后再读1字节
always @(posedge I_sysclk ) begin
    if (!rst_cnt[8]) begin
        iic_req     <=  1'b0    ;
        wr_data     <=  32'd0   ;
        rd_cnt      <=  8'd0    ;
        wr_cnt      <=  8'd0    ;
        iic_error   <=  1'b0    ;
        TS_S        <=  3'd0    ;
    end 
    else begin
        case (TS_S)
            0:begin     
                if (!iic_busy) begin        //当总线不忙,可以开启一次IIC数据操作
                    iic_req <=  1'b1    ;   //请求发送数据
                                            //数据寄存器中8'b10100000代表需要写的器件地址,第一个wr_data[15:8]代表了EEPROM内存地址,第二个wr_data[15:8]代表了写入数据   
                    wr_data <= {8'hfe,wr_data[15:8],wr_data[15:8],8'b10100000}; 
                    rd_cnt  <=  8'd0    ;   //不需要读数据
                    wr_cnt  <=  8'd3    ;   //需要写入3个BYTES数据,包含一个器件地址,1个EEPROM寄存器地址,一个数据
                    TS_S    <=  3'd1    ;        
                end
            end
            1:begin
                if (iic_busy == 1'b1) begin
                    iic_req <=  1'b0    ;
                    TS_S    <=  3'd2    ;
                end 
            end
            2:begin
                if ((!iic_busy) && (delay_cnt[19] == 1'b1)) begin//当总线非忙,可以开始一次I2C数据操作,该时间约不能低于500us,否则会导致EEPROM操作失败
                    iic_req <=  1'b1    ;   //请求接收数据
                    rd_cnt  <=  8'd1    ;   //需要读取一个字节
                    wr_cnt  <=  8'd2    ;   //需要写两个byte  一个器件地址8’d1010_0000 一个寄存器地址 wr_data[15:8] (I2C控制器会自定设置读写标志位)
                    TS_S    <=  3'd3    ;    
                end 
            end
            3:begin
                if (iic_busy == 1'b1) begin
                    iic_req <=  1'b0    ;
                    TS_S    <=  3'd4    ;
                end
            end
            4:begin
                if (!iic_busy) begin        //当总线非忙,代表前面读数据完成       
                    if (wr_data[23:16] != rd_data[7:0]) begin   //对比数据是否正确
                        iic_error   <=  1'b1    ;
                    end 
                    else begin
                        iic_error   <=  1'b0    ;
                    end
                    wr_data[15:8]   <=  wr_data[15:8] + 1'b1    ;   //地址和数据都加1
                    TS_S            <=  3'd5    ;
                end
            end
            5:begin
                if(t500ms_en == 1'b1)begin
                    TS_S    <=  3'd0;
                end
            end
            default: TS_S   <=  3'd0;
        endcase
    end
end

// 以下代码为在线逻辑分析仪观察调试部分
reg scl_r = 1'b0;
always @(posedge I_sysclk)begin //对O_iic_scl寄存1次
 scl_r <= O_iic_scl; 
end

//产生一个触发时钟,这个时钟是系统时钟的512倍分频,这样抓取总线的时候,可以看到更多I2C的有效信号
reg [8:0] dg_clk_cnt;
wire dg_clk = (dg_clk_cnt==0);//用scl_dg即O_iic_scl的跳变沿作为触发信号
always@(posedge I_sysclk) begin
    dg_clk_cnt <= dg_clk_cnt+ 1'b1;
end

ila_0 ila_debug (
	.clk(I_sysclk),//在线逻辑分析仪的时钟
	.probe0({rd_data[7:0],wr_data[23:0],TS_S,iic_error,iic_req,scl_r,IO_iic_sda_dg,iic_bus_error,dg_clk,t500ms_en}) // 需要观察的调试信号
);

//例化I2C控制模块
iic_my#
(
.WMEN_LEN   (4              )   ,   //最大支持一次写入4BYTE(包含器件地址)
.RMEN_LEN   (4              )   ,   //最大支持一次读出4BYTE(包含器件地址)
.CLK_DIV    (SYSCLKHZ/100000)       //100KHZ I2C总线时钟
)
u_iic_my
(
    .I_clk              (I_sysclk       )   ,   //系统时钟
    .I_rstn             (rst_cnt[8]     )   ,   //系统复位
    .O_iic_scl          (O_iic_scl      )   ,   //I2C SCL总线时钟
    .IO_iic_sda         (IO_iic_sda     )   ,   //I2C SDA数据总线
    .I_wr_data          (wr_data        )   ,   //写数据寄存器
    .I_wr_cnt           (wr_cnt         )   ,   //需要写的数据BYTES
    .O_rd_data          (rd_data        )   ,    //读数据寄存器
    .I_rd_cnt           (rd_cnt         )   ,   //需要读的数据BYTES
    .I_iic_req          (iic_req        )   ,   //I2C控制器请求
    .I_iic_mode         (1'b1           )   ,   //读模式
    .O_iic_busy         (iic_busy       )   ,   //I2C控制器忙
    .O_iic_bus_error    (iic_bus_error  )   ,   //总线错误信号标志
    .IO_iic_sda_dg      (IO_iic_sda_dg  )       //debug IO_iic_sda
); 

endmodule

五、仿真验证

发送器件地址:

发送片内地址:

随机读:

六、上板验证

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

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

相关文章

PELT算法

PELT算法的范畴 PELT算法&#xff08;Pruned Exact Linear Time&#xff09;属于时间序列分析和变点检测&#xff08;Change Point Detection&#xff09;范畴的算法。 从更广泛的角度来看&#xff0c;PELT算法还可以归类为以下几类算法的子集&#xff1a; 1. 时间序列分析&…

SpringBoot在校园健康信息管理中的创新

第5章 系统详细设计 5.1管理员功能模块 管理员登录&#xff0c;通过填写注册时输入的用户名、密码、角色进行登录&#xff0c;如图5-1所示。 图5-1管理员登录界面图 管理员登录进入师生健康信息管理系统可以查看个人中心、学生管理、教师管理、数据收集管理、问卷分类管理、…

昇思学习打卡营学习记录:DCGAN生成漫画头像

DCGAN原理 DCGAN&#xff08;深度卷积对抗生成网络&#xff0c;Deep Convolutional Generative Adversarial Networks&#xff09;是GAN的直接扩展。不同之处在于&#xff0c;DCGAN会分别在判别器和生成器中使用卷积和转置卷积层。 它最早由Radford等人在论文Unsupervised Re…

【STM32开发之寄存器版】(四)-独立看门狗IWDG

一 、前言 独立看门狗简介&#xff1a; STM32F103ZET6内置两个看门狗&#xff0c;提供了更高的安全性、时间的精确性和使用的灵活性。两个看门狗设备(独立看门狗和窗口看门狗)可用来检测和解决由软件错误引起的故障。 独立看门狗主要性能&#xff1a; 自由运行的递减计数器时钟…

【C++11】C++11的新语法

文章目录 统一的列表初始化std::initializer_list 变量类型推导autodecltype STL中的一些变化 统一的列表初始化 在C98中&#xff0c;标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。 C11扩大了用大括号括起的列表(初始化列表)的使用范围&#xff0c;使其…

在 MySQL 中处理和优化大型报告查询经验分享

在 MySQL 数据库的使用过程中&#xff0c;我们经常会遇到需要生成大型报告的情况&#xff0c;这些查询可能涉及大量的数据和复杂的计算&#xff0c;对数据库的性能提出了很高的要求。 一、问题背景 大型报告查询通常具有以下特点&#xff1a; 数据量大&#xff1a;涉及大量的…

ConcurrentHashMap在JDK1.7和1.8的区别,详解

目录 1.了解HashMap底层插入原理 2.ConcurrentHashMap 是什么&#xff1f; HashTable的实现 3.ConcurrentHashMap 1.7和1.8的区别 4、JDK1.7 中的ConcurrentHashMap实现原理 6、JDK1.8中的ConcurrentHashMap 7.链表转红黑树条件 1.8 put方法 8.并发扩容 9.总结 首先呢…

Windows 11 24H2 v26100.1742 官方简体中文版

‌Windows 11 24H2是微软最新推出的操作系统更新&#xff0c;其在人工智能&#xff08;AI&#xff09;领域的创新为用户带来了显著的体验提升。该版本的一大亮点是AI Copilot&#xff0c;它能够智能地根据剪贴板内容调整操作上下文菜单&#xff0c;实现更智能化的交互。 此外&…

第33次CCF计算机软件能力认证【T1~T3】:词频统计、相似度计算、化学方程式配平

题目概括词频统计枚举相似度计算STL工具&#xff08;tranform()转换大小写&#xff09; 模拟化学方程式配平大模拟高斯消元 1、词频统计 在学习了文本处理后&#xff0c;小 P 对英语书中的 n 篇文章进行了初步整理。 具体来说&#xff0c;小 P 将所有的英文单词都转化为了整数…

Linux中的多线程

Linux线程概念 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序 列” 进程是系统分配资源的基本实体 线程是CPU调度的基本单位 POSIX线程库 创建线程 功能&#xff1a;创建一个新的线程 原…

执行路径带空格的服务漏洞

原理 当系统管理员配置Windows服务时&#xff0c;必须指定要执行的命令&#xff0c;或者运行可执行文件的路径。 当Windows服务运行时&#xff0c;会发生以下两种情况之一。 1、如果给出了可执行文件&#xff0c;并且引用了完整路径&#xff0c;则系统会按字面解释它并执行 …

算法修炼之路之滑动窗口

目录 一&#xff1a;滑动窗口的认识及模板 二&#xff1a;LeetcodeOJ练习 1.第一题 2.第二题 3.第三题 4.第四题 5.第五题 6.第六题 7.第七题 一&#xff1a;滑动窗口的认识及模板 这里先通过一道题来引出滑动窗口 LeetCode 209 长度最小的子数组 画图分析&…

软件验证与确认实验一:静态分析

目录 1. 实验目的及要求.................................................................................................... 3 2. 实验软硬件环境.................................................................................................... 3 …

(C语言贪吃蛇)15.贪吃蛇吃食物

目录 前言 注意事项⚠️ 效果预览 实现方法 运行效果 新的问题&#x1f64b; 最终效果 总结 前言 我们上一节实现了解决了贪吃蛇不合理走位的情况&#xff0c;不理解的再回去看看(传送门&#xff1a;解决贪吃蛇不合理走位)&#xff0c;那么贪吃蛇自然是要吃食物的啊&…

springboot系列--web相关知识探索四

一、前言 web相关知识探索三中研究了请求中所带的参数是如何映射到接口参数中的&#xff0c;也即请求参数如何与接口参数绑定。主要有四种、分别是注解方式、Servlet API方式、复杂参数、以及自定义对象参数。web相关知识探索三中主要研究了注解方式以及Servlet API方式。本次…

基于springboot vue 电影推荐系统

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm 等开发框架&#xff09; vue .net php python(flask Django) 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找…

DatePicker 日期控件

效果&#xff1a; 要求&#xff1a;初始显示系统当前时间&#xff0c;点击日期控件后修改文本控件时间。 目录结构&#xff1a; activity_main.xml(布局文件)代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:and…

环境可靠性

一、基础知识 1.1 可靠性定义 可靠性是指产品在规定的条件下、在规定的时间内完成规定的功能的能力。 可靠性的三大要素&#xff1a;耐久性、可维修性、设计可靠性 耐久性&#xff1a;指的是产品能够持续使用而不会故障的特性&#xff0c;或者说是产品的使用寿命。 可维修性&a…

1.MySQL存储过程基础(1/10)

引言 数据库管理系统&#xff08;Database Management System, DBMS&#xff09;是现代信息技术中不可或缺的一部分。它提供了一种系统化的方法来创建、检索、更新和管理数据。DBMS的重要性体现在以下几个方面&#xff1a; 数据组织&#xff1a;DBMS 允许数据以结构化的方式存…

【C++ STL】手撕vector,深入理解vector的底层

vector的模拟实现 前言一.默认成员函数1.1常用的构造函数1.1.1默认构造函数1.1.2 n个 val值的构造函数1.1.3 迭代器区间构造1.1.4 initializer_list 的构造 1.2析构函数1.3拷贝构造函数1.4赋值运算符重载 二.元素的插入,删除,查找操作2.1 operator[]重载函数2.2 push_back函数:…