FPGA project : IIC_wr_eeprom

news2024/11/19 0:25:14

简介:

简单双向二线制,同步串行总线。

scl:串行时钟线,用于同步通讯数据。

sda:双向串行数据线。

物理层:

1,支持挂载多设备。

2,二线制。

3,每个设备有其单独的地址。

4,空闲时,sda会被上拉电阻拉高。

5,存在多个主机时,通过仲裁逻辑决定那个主机控制总线。

6,三个速度模式:标准模式(100kb/s);快速模式(400kb/s);高速模式(3.4Mb/s)

地址:

器件地址。7bit,最后1bit为读写控制位。

存储地址:分为单字节和双字节,与存储设备容量有关。就是有多少byte的容量,用几位二进制地址表示。

读写地址。

时序总结:

在scl为高时,若sda变化,则为起始或终止信号。

在scl为低时,(已启动读时隙),sda在scl低电平变化,高电平对sda采样。

读时序:分为随机读(单字节读)和顺序读(页读)。

写时序:单字节写和页写。

框图:

时序图也画了,很多很大,就不放了。

 代码:

iic时序驱动模块+指令控制模块+按键消抖+顶层;

/************************************************************
****************    iic 模块说明    ************************
****************    驱动接口模块    ************************
*输入端口:
*sys_clk    :   1Mhz时钟信号。
*iic_start  :   开始进行读写通信标志信号。
*en_w       :   写使能信号,与iic_start同时拉高,iic模块启动写时序。
*addr       :   地址信号,读写公用一个地址信号。
*data_w     :   要通过iic协议写入从机的8bit数据。
*en_r       :   读使能信号,与iic_start同时拉高,iic模块启动读时序。
*addr_num   :   由于地址有单byte和双byte情况,addr_num == 0表示单。
*输出端口:
*scl        :   iic协议的同步时钟信号。串行时钟线,用于同步通讯数据。时钟频率为250kHz
*sda        :   双向端口,双向串行数据线。
*data_out   :   读取到的1byte数据。
*iic_end    :   完成ibyte数据的读写标志信号。
*/
module iic (
    input       wire            sys_clk     , // 虽然写的是sys_clk但是例化时要接iic_clk
    input       wire            sys_rst_n   ,
    input       wire            iic_start   ,
    input       wire            en_w        ,
    input       wire            en_r        ,
    input       wire    [15:0]  byte_addr   ,
    input       wire    [7:0]   data_w      ,
    input       wire            addr_num    ,

    inout       wire            sda         ,

    output      reg             scl         ,
    output      reg     [7:0]   data_out    ,
    output      reg             iic_end     
);
    // parameter
    parameter   DEVICE_ADDR = 7'b1010_011 ; // 器件地址,最后一位要根据读写,来决定。[6:0]
    wire        [7:0]   FIRST_ADDR        ; // AT24C64
    wire        [7:0]   SECOND_ADDR       ; // 可在此设置读写地址。
    assign      FIRST_ADDR  = byte_addr[15:8] ;
    assign      SECOND_ADDR = byte_addr[ 7:0] ;
    // localparam 
    localparam  IDLE                    =4'b0000 ,
                START1                  =4'b0001 ,
                SEND_DEVICE_ADDR        =4'b0011 ,
                ACK1                    =4'b0010 ,

                SEND_FIRST_ADDR         =4'b0110 ,
                ACK2                    =4'b0111 ,
                SEND_SECOND_ADDR        =4'b0101 ,
                ACK3                    =4'b0100 ,

                WR_DATA                 =4'b1100 ,
                ACK4                    =4'b1101 ,
                STOP                    =4'b1111 ,
                START2                  =4'b1110 ,

                SEND_READ_DEVICE_ADDR   =4'b1010 ,
                ACK5                    =4'b1011 ,
                READ_DATA               =4'b1001 ,
                NO_ACK                  =4'b1000 ; 
    // wire signal define
    wire    sda_en ;
    wire    IDLEtoSTART1                ;             
    wire    START1toSEND_DEVICE_ADDR    ; 
    wire    SEND_DEVICE_ADDRtoACK1      ;   
    wire    ACK1toSEND_FIRST_ADDR       ;
    wire    ACK1toSEND_SECOND_ADDR      ;   
    wire    SEND_FIRST_ADDRtoACK2       ;    
    wire    ACK2toSEND_SECOND_ADDR      ;   
    wire    SEND_SECOND_ADDRtoACK3      ;   
    wire    ACK3toWR_DATA               ;            
    wire    ACK3toSTART2                ;             
    wire    WR_DATAtoACK4               ;            
    wire    ACK4toSTOP                  ;               
    wire    STOPtoIDLE                  ;     
    wire    START2toSEND_READ_DEVICE_ADDR;
    wire    SEND_READ_DEVICE_ADDRtoACK5 ; 
    wire    ACK5toREAD_DATA             ;          
    wire    READ_DATAtoNO_ACK           ;        
    wire    NO_ACKtoSTOP                ;             

    // reg signal define
    reg     [3:0]   state_c ;
    reg     [3:0]   state_n ;
    reg     [1:0]   cnt_iic ; // 关键计数器。很多信号赋值都与他有关。
    reg     [2:0]   cnt_bit ; // bit计数器,计数值0-7
    reg             sda_out ;
/***********************************************************************/
    // 状态机描述
    // reg     [3:0]   state_c ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            state_c <= IDLE ;
        else
            state_c <= state_n ;
    end
    // reg     [3:0]   state_n ;
    always @(*) begin
        case(state_c)
                IDLE                 :  if(IDLEtoSTART1) 
                                            state_n = START1 ;
                                        else 
                                            state_n = IDLE ;
                START1               :  if(START1toSEND_DEVICE_ADDR)
                                            state_n = SEND_DEVICE_ADDR ;
                                        else 
                                            state_n = START1 ;
                SEND_DEVICE_ADDR     :  if(SEND_DEVICE_ADDRtoACK1) 
                                            state_n = ACK1 ;
                                        else 
                                            state_n = SEND_DEVICE_ADDR ;
                ACK1                 :  if(ACK1toSEND_FIRST_ADDR) 
                                            state_n = SEND_FIRST_ADDR ;
                                        else if(ACK1toSEND_SECOND_ADDR)
                                            state_n = SEND_SECOND_ADDR ;
                                        else 
                                            state_n = ACK1 ;
                SEND_FIRST_ADDR      :  if(SEND_FIRST_ADDRtoACK2) 
                                            state_n = ACK2 ;
                                        else 
                                            state_n = SEND_FIRST_ADDR ;
                ACK2                 :  if(ACK2toSEND_SECOND_ADDR) 
                                            state_n = SEND_SECOND_ADDR ;
                                        else 
                                            state_n = ACK2 ;
                SEND_SECOND_ADDR     :  if(SEND_SECOND_ADDRtoACK3) 
                                            state_n = ACK3 ;
                                        else 
                                            state_n = SEND_SECOND_ADDR ;
                ACK3                 :  if(ACK3toWR_DATA) 
                                            state_n = WR_DATA ;
                                        else if(ACK3toSTART2)
                                            state_n = START2 ;
                                        else 
                                            state_n = ACK3 ;
                WR_DATA              :  if(WR_DATAtoACK4) 
                                            state_n = ACK4 ;
                                        else 
                                            state_n = WR_DATA ;
                ACK4                 :  if(ACK4toSTOP) 
                                            state_n = STOP ;
                                        else 
                                            state_n = ACK4 ;
                STOP                 :  if(STOPtoIDLE) 
                                            state_n = IDLE ;
                                        else 
                                            state_n = STOP ;
                START2               :  if(START2toSEND_READ_DEVICE_ADDR) 
                                            state_n = SEND_READ_DEVICE_ADDR ;
                                        else 
                                            state_n = START2 ;
                SEND_READ_DEVICE_ADDR:  if(SEND_READ_DEVICE_ADDRtoACK5) 
                                            state_n = ACK5 ;
                                        else 
                                            state_n = SEND_READ_DEVICE_ADDR ;
                ACK5                 :  if(ACK5toREAD_DATA) 
                                            state_n = READ_DATA ;
                                        else 
                                            state_n = ACK5 ;
                READ_DATA            :  if(READ_DATAtoNO_ACK) 
                                            state_n = NO_ACK ;
                                        else 
                                            state_n = READ_DATA ;
                NO_ACK               :  if(NO_ACKtoSTOP) 
                                            state_n = STOP ;
                                        else 
                                            state_n = NO_ACK ;
                default              :      state_n = IDLE ;
        endcase
    end
    // 状态转移条件赋值:
    assign  IDLEtoSTART1             = (state_c == IDLE  ) && (iic_start == 1'b1) ;
    assign  START1toSEND_DEVICE_ADDR = (state_c == START1) && (cnt_iic == 3)      ;
    assign  SEND_DEVICE_ADDRtoACK1   = (state_c == SEND_DEVICE_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  ACK1toSEND_FIRST_ADDR    = (state_c == ACK1  ) && (cnt_iic == 3 && sda == 1'b0 && addr_num == 1) ; //&& sda == 1'b0 由于仿真模型没有相应ack功能,所以要自己模拟。
    assign  ACK1toSEND_SECOND_ADDR   = (state_c == ACK2  ) && (cnt_iic == 3 && sda == 1'b0 && addr_num == 0) ; //&& sda == 1'b0
    assign  SEND_FIRST_ADDRtoACK2    = (state_c == SEND_FIRST_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  ACK2toSEND_SECOND_ADDR   = (state_c == ACK2  ) && (cnt_iic == 3 && sda == 0) ; //&& sda == 0
    assign  SEND_SECOND_ADDRtoACK3   = (state_c == SEND_SECOND_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  ACK3toWR_DATA            = (state_c == ACK3  ) && (cnt_iic == 3 && en_w && sda == 0) ; // && sda == 0 
    assign  ACK3toSTART2             = (state_c == ACK3  ) && (cnt_iic == 3 && en_r && sda == 0) ; // && sda == 0 
    assign  WR_DATAtoACK4            = (state_c == WR_DATA ) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  ACK4toSTOP               = (state_c == ACK4  ) && (cnt_iic == 3 && sda == 0) ; // && sda == 0
    assign  STOPtoIDLE               = (state_c == STOP  ) && (cnt_iic == 3 && cnt_bit == 3) ;
    assign  START2toSEND_READ_DEVICE_ADDR = (state_c == START2) && (cnt_iic == 3)      ;
    assign  SEND_READ_DEVICE_ADDRtoACK5 = (state_c == SEND_READ_DEVICE_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  ACK5toREAD_DATA          = (state_c == ACK5  ) && (cnt_iic == 3 && sda == 0) ; //&& sda == 0
    assign  READ_DATAtoNO_ACK        = (state_c == READ_DATA) && (cnt_iic == 3 && cnt_bit == 7) ;
    assign  NO_ACKtoSTOP             = (state_c ==  NO_ACK) && (cnt_iic == 3 && sda == 1) ;
    // reg     [1:0]   cnt_iic ; // 关键计数器。很多信号赋值都与他有关。
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_iic <= 2'd0 ;
        else if(state_c != IDLE)
            cnt_iic <= cnt_iic + 1'b1 ;
        else 
            cnt_iic <= 1'b0 ;
    end
    // reg     [2:0]   cnt_bit ; // bit计数器,计数值0-7
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_bit <= 3'd0 ;
        else if(state_c != IDLE && state_c != START1 && state_c != START2 && state_c != NO_ACK && state_c != ACK1 && state_c != ACK2 && state_c != ACK3 && state_c != ACK4 && state_c != ACK5 && cnt_iic == 3)
            cnt_bit <= cnt_bit + 1'b1 ;
        else if(state_c != IDLE && state_c != START1 && state_c != START2 && state_c != NO_ACK && state_c != ACK1 && state_c != ACK2 && state_c != ACK3 && state_c != ACK4 && state_c != ACK5)
            cnt_bit <= cnt_bit ;
        else 
            cnt_bit <= 3'd0 ;
    end
    // reg             sda_out ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            sda_out <= 1'b1 ; 
        else
        case (state_c)
            IDLE                 :  sda_out <= 1'b1 ;
            START1               :  if(cnt_iic == 0) 
                                        sda_out <= 1'b0 ;
                                    else 
                                        sda_out <= sda_out ;
            SEND_DEVICE_ADDR     :  if(cnt_iic == 0 && cnt_bit != 7) 
                                        sda_out <= DEVICE_ADDR[6 - cnt_bit] ;
                                    else if(cnt_iic == 0 && cnt_bit == 7) 
                                        sda_out <= 1'b0 ; // 写控制位。
            ACK1                 :  sda_out <= 1'b0 ;
            SEND_FIRST_ADDR      :  if(cnt_iic == 0)
                                        sda_out <= FIRST_ADDR[7 - cnt_bit] ;
                                    else 
                                        sda_out <= sda_out ;
            ACK2                 :  sda_out <= 1'b0 ;
            SEND_SECOND_ADDR     :  if(cnt_iic == 0)
                                        sda_out <= SECOND_ADDR[7 - cnt_bit] ;
                                    else 
                                        sda_out <= sda_out ;
            ACK3                 :  sda_out <= 1'b0 ;
            WR_DATA              :  if(cnt_iic == 0)
                                        sda_out <= data_w[7 - cnt_bit] ;
                                    else 
                                        sda_out <= sda_out ;
            ACK4                 :  sda_out <= 1'b0 ;
            STOP                 :  if(cnt_iic == 0 && cnt_bit == 0)
                                        sda_out <= 1'b0 ;
                                    else if(cnt_iic == 2 && cnt_bit == 0)
                                        sda_out <= 1'b1 ;
                                    else    
                                        sda_out <= sda_out ;
            START2               :  if(cnt_iic == 0)
                                        sda_out <= 1'b1 ;
                                    else if(cnt_iic == 2)
                                        sda_out <= 1'b0 ;
                                    else 
                                        sda_out <= sda_out ;
            SEND_READ_DEVICE_ADDR:  if(cnt_iic == 0 && cnt_bit != 7) 
                                        sda_out <= DEVICE_ADDR[6 - cnt_bit] ;
                                    else if(cnt_iic == 0 && cnt_bit == 7) 
                                        sda_out <= 1'b1 ; // 读控制位。
            ACK5                 :  sda_out <= 1'b0 ;
            READ_DATA            :  sda_out <= 1'b0 ;
            NO_ACK               :  sda_out <= 1'b1 ;
            default              :  sda_out <= 1'b1 ;
        endcase
    end
    // wire     sda_en 
    assign sda_en = ((state_c == ACK1) || (state_c == ACK2) || (state_c == ACK3) || (state_c == ACK4) || (state_c == ACK5) || (state_c == READ_DATA)) ? 1'b0 : 1'b1 ;
/***************************************************************************/
    // wire            sda         ,
    assign sda = (sda_en == 1) ? sda_out : 1'bz ;
    // reg             scl         ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            scl <= 1'b1 ;
        else 
        if(state_c != IDLE && state_c != STOP && state_c != START1) begin
            if(cnt_iic == 1 || cnt_iic == 3)
                scl <= ~scl ;
            else 
                scl <=  scl ;
        end 
        else if(state_c == IDLE)
                scl <= 1'b1 ;
        else if(state_c == STOP && (cnt_bit == 0 && cnt_iic == 1))
                scl <= 1'b1 ;
        else if(state_c == STOP)
                scl <= scl ;
        else if(state_c == START1 && cnt_iic == 3)
                scl <= ~scl ;
        else if(state_c == START1)
                scl <= scl ;
        else 
            scl <= 1'b1 ;
    end
    // reg     sda_data ;
    // always @(posedge sys_clk or negedge sys_rst_n) begin
    //     if(~sys_rst_n)
    //         sda_data <= 1'b0 ;
    //     else if(state_c == READ_DATA && cnt_iic == 0)
    //         sda_data <= ~sda_data ;
    //     else    
    //         sda_data <=  sda_data ;
    // end
    // reg [7:0]    data_out
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            data_out <= 8'd0 ;
        else if(state_c == READ_DATA && cnt_iic == 2 && scl == 1)
            data_out <= {data_out[6:0],sda} ; // 这里也需要自己模拟 sda_data
        else 
            data_out <= data_out ;
    end
    // wire            iic_end     
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            iic_end <= 1'b0 ;
        else if(state_c == STOP && cnt_iic == 3 && cnt_bit == 3)
            iic_end <= 1'b1 ;
        else    
            iic_end <= 1'b0 ;
    end
endmodule
/************************************************************
****************    iic_instruct 模块说明    ************************
****************    产生接口时序模块的控制信号,并存储读到的数据,并把数据传给数码管显示模块。
*/
module iic_instruct (
    input       wire            sys_clk   , // 20ns
    input       wire            sys_rst_n ,
    input       wire            iic_clk   , // 1000ns
    input       wire            flag_w    ,
    input       wire            flag_r    ,
    input       wire            iic_end   ,
    input       wire    [7:0]   data_r    , // iic 模块读到的1byte数据。

    output      reg             iic_start ,
    output      reg             en_w      , // 写使能,往eeprom中写数据的使能信号。
    output      reg             en_r      , // 读使能,从eeprom中读数据的使能信号。
    output      reg     [15:0]  byte_addr , // 读写操作的数据地址。
    output      reg     [7:0]   data_w    , // 往eeprom中写入的数据。
    output      wire            addr_num  , // eeprom的存储地址是几个byte。
    output      wire    [7:0]   data_out    // 传给数码管显示的数据。
);
    parameter   ADDR_START          = 16'h00_00 ,
                DATA_WRITE          = 8'd00     , // 写入的起始数据。
                CNT_MAX_START       = 49999     , // 5ms
                CNT_MAX_1S          = 1_000_000 ,
                CNT_MAX_WRITE_BYTE  = 10        , 
                CNT_MAX_READ_BYTE   = 10        ; 
/******************************************************/
    // 第一步:处理输入信号,实现快速时钟域标志信号同步到慢速时钟域。  
    // 也就是保证慢速时钟域可以检测到标志信号。
    reg             valid_write ;
    reg     [7:0]   cnt_write   ;
    reg             valid_read  ;
    reg     [7:0]   cnt_read    ;
    reg     [15:0]  cnt_read_byte   ;
    reg     [15:0]  cnt_start       ;
    reg     [15:0]  cnt_write_byte  ; // 写入eeprom字节计数器
	wire	        empty   ;
	wire	        full    ;
	wire	[9:0]   usedw   ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            valid_write <= 1'b0 ;
        else if(flag_w)
            valid_write <= 1'b1 ;
        else if(cnt_write == 199)
            valid_write <= 1'b0 ;
        else 
            valid_write <=  valid_write ;
    end
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_write <= 8'd0 ;
        else if(valid_write && cnt_write == 199)
            cnt_write <= 8'd0 ;
        else if(valid_write)
            cnt_write <= cnt_write + 1'b1 ;
        else 
            cnt_write <= 8'd0 ;
    end
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            valid_read <= 1'b0 ;
        else if(flag_r)
            valid_read <= 1'b1 ;
        else if(cnt_read == 199)
            valid_read <= 1'b0 ;
        else 
            valid_read <=  valid_read ;
    end
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_read <= 8'd0 ;
        else if(valid_read && cnt_read == 199)
            cnt_read <= 8'd0 ;
        else if(valid_read)
            cnt_read <= cnt_read + 1'b1 ;
        else 
            cnt_read <= 8'd0 ;
    end
    assign addr_num = 1'b1 ;
/**********************************************************************************/
    // 第二步:产生写数据相关信号的产生。在iic_clk时钟域下。
    
    // en_w
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            en_w <= 1'b0 ;
        else if(iic_end && (cnt_write_byte == CNT_MAX_WRITE_BYTE - 1))
            en_w <= 1'b0 ;
        else if(valid_write)
            en_w <= 1'b1 ;
        else 
            en_w <= en_w ;
    end
    //reg    iic_start
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            iic_start <= 1'b0 ;
        else if(en_w == 0 && valid_write == 1 || cnt_start == CNT_MAX_START - 1)
            iic_start <= 1'b1 ;
        else 
            iic_start <= 1'b0 ;
    end
    // reg   [15:0]  cnt_start ;
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_start <= 16'd0 ;
        else if(((en_w == 1) && ((cnt_start == CNT_MAX_START - 1)
                || (iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1))) 
                || ((en_r == 1) && ((cnt_start == CNT_MAX_START - 1)
                || (iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1))))
            cnt_start <= 16'd0 ;
        else if(en_w == 1 || en_r)
            cnt_start <= cnt_start + 1'b1 ;
        else 
            cnt_start <= 16'd0 ;
    end
    // [15:0] byte_addr // 目前只完成了写地址,
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            byte_addr <= ADDR_START ;
        else if((iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1) 
                || (iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1))
            byte_addr <= ADDR_START ;
        else if(iic_end == 1)
            byte_addr <= byte_addr + 1'b1 ;
        else 
            byte_addr <= byte_addr ;
    end
    // [7:0]    data_w
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            data_w <= DATA_WRITE ;
        else if(iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1)
            data_w <= DATA_WRITE ;
        else if(en_w && iic_end == 1)
            data_w <= data_w + 1'b1 ;
        else 
            data_w <= data_w ;
    end
    // [15:0]   cnt_write_byte
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_write_byte <= 16'd0 ;
        else if(en_w && iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1)
            cnt_write_byte <= 16'd0 ;
        else  if(en_w && iic_end == 1)
            cnt_write_byte <= cnt_write_byte + 1'b1 ;
        else 
            cnt_write_byte <= cnt_write_byte ;
    end
/*****************************************************************************/
    // 读相关控制信号产生
    // en_r
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            en_r <= 1'b0 ;
        else if(iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1)
            en_r <= 1'b0 ;
        else if(valid_read)
            en_r <= 1'b1 ;
        else 
            en_r <= en_r ;
    end
    // [15:0]  cnt_read_byte 
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_read_byte <= 16'd0 ;
        else if(en_r && iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1)
            cnt_read_byte <= 16'd0 ;
        else  if(en_r && iic_end == 1)
            cnt_read_byte <= cnt_read_byte + 1'b1 ;
        else 
            cnt_read_byte <= cnt_read_byte ;
    end
/*******************************************************************************/
    reg             valid_fifo_read ;
    reg     [19:0]  cnt_1s          ;
    reg             fifo_rd_en      ;
    // valid_fifo_read
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            valid_fifo_read <= 1'b0 ;
        else if(valid_fifo_read == 1 && usedw == 0)
            valid_fifo_read <= 1'b0 ;
        else if(usedw > (CNT_MAX_READ_BYTE - 1))
            valid_fifo_read <= 1'b1 ;
        else 
            valid_fifo_read <= valid_fifo_read ;
    end
    // [19:0]  cnt_1s    
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_1s <= 20'd0 ;
        else if(valid_fifo_read == 1 && cnt_1s == CNT_MAX_1S - 1)
            cnt_1s <= 20'd0 ;
        else if(valid_fifo_read == 1)
            cnt_1s <= cnt_1s + 1'b1 ;
        else 
            cnt_1s <= 20'd0 ;
    end
    // fifo_rd_en
    always @(posedge iic_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            fifo_rd_en <= 1'b0 ;
        else if(valid_fifo_read == 1 && cnt_1s == CNT_MAX_1S - 1)
            fifo_rd_en <= 1'b1 ;
        else 
            fifo_rd_en <= 1'b0 ;
    end

fifo_8x1024 fifo_8x1024_inst(
	.clock       ( iic_clk          ) ,
	.data        ( data_r           ) ,
	.rdreq       ( fifo_rd_en       ) ,
	.wrreq       ( en_r && iic_end  ) ,
	.empty       ( empty            ) ,
	.full        ( full             ) ,
	.q           ( data_out         ) ,
	.usedw       ( usedw            )  
);
endmodule

 

module top (
    input       wire        sys_clk     ,
    input       wire        sys_rst_n   ,
    input       wire        key_write   ,
    input       wire        key_read    ,

    inout       wire        sda         ,
    output      wire        scl         ,
    output      wire        ds          ,
    output      wire        oe          ,
    output      wire        shcp        ,
    output      wire        stcp        
);
    // 例化间连线
    wire            clk_50mHz   ;
    wire            clk_1mHz    ; 
    wire            locked      ;  
    wire            rst_n       ;
    wire            flag_write  ;
    wire            flag_read   ;
    wire    [05:00] point       ;
    wire            sign        ;
    assign          point  = 5'd0 ;
    assign          sign   = 1'b0 ;
    assign          rst_n = sys_rst_n && locked ;

pll pll_isnt(
	.areset                 ( ~sys_rst_n ) ,
	.inclk0                 ( sys_clk    ) ,
	.c0                     ( clk_50mHz  ) ,
	.c1                     ( clk_1mHz   ) ,
	.locked                 ( locked     ) 
);

key_filter key_filter_inst_w(
    .sys_clk                ( clk_50mHz ) ,
    .sys_rst_n              ( rst_n     ) ,
    .key_in                 ( key_write ) ,

    .key_out                ( flag_write)         
);   
key_filter key_filter_inst_r(
    .sys_clk                ( clk_50mHz ) ,
    .sys_rst_n              ( rst_n     ) ,
    .key_in                 ( key_read  ) ,

    .key_out                ( flag_read )         
); 

    wire            iic_start ;
    wire            en_w      ;
    wire            en_r      ;
    wire    [15:0]  byte_addr ;
    wire    [7:0]   data_w    ;
    wire            addr_num  ;
    wire    [7:0]   data_out  ;
    wire            iic_end   ;
    wire    [7:0]   data_r    ;
iic_instruct iic_instruct_inst(
    .sys_clk                ( clk_50mHz  ) , // 20ns
    .sys_rst_n              ( rst_n      ) ,
    .iic_clk                ( clk_1mHz   ) , // 1000ns
    .flag_w                 ( flag_write ) ,
    .flag_r                 ( flag_read  ) ,
    .iic_end                ( iic_end    ) ,
    .data_r                 ( data_r     ) , // iic 模块读到的1byte数据。

    .iic_start              ( iic_start  ) ,
    .en_w                   ( en_w       ) , // 写使能,往eeprom中写数据的使能信号。
    .en_r                   ( en_r       ) , // 读使能,从eeprom中读数据的使能信号。
    .byte_addr              ( byte_addr  ) , // 读写操作的数据地址。
    .data_w                 ( data_w     ) , // 往eeprom中写入的数据。
    .addr_num               ( addr_num   ) , // eeprom的存储地址是几个byte。
    .data_out               ( data_out   )   // 传给数码管显示的数据。
);

iic iic_inst(
    .sys_clk                ( clk_1mHz   ) , // 虽然写的是sys_clk但是例化时要接iic_clk
    .sys_rst_n              ( rst_n      ) ,
    .iic_start              ( iic_start  ) ,
    .en_w                   ( en_w       ) ,
    .en_r                   ( en_r       ) ,
    .byte_addr              ( byte_addr  ) ,
    .data_w                 ( data_w     ) ,
    .addr_num               ( addr_num   ) ,

    .sda                    ( sda        ) ,

    .scl                    ( scl        ) ,
    .data_out               ( data_r     ) ,
    .iic_end                ( iic_end    )     
);

seg_595_dynamic seg_595_dynamic_isnt(
    .sys_clk                ( clk_50mHz ) ,
    .sys_rst_n              ( rst_n     ) ,
    .data                   ( {12'd0,data_out} ) , 
    .point                  ( point     ) ,
    .sign                   ( sign      ) ,
    .seg_en                 ( rst_n     ) ,

    .ds                     ( ds        ) ,      
    .oe                     ( oe        ) ,      
    .shcp                   ( shcp      ) ,      
    .stcp                   ( stcp      )           
);

endmodule




仿真测试,要用到 M24C64仿真模型。

仿真验证通过,上板验证通过。

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

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

相关文章

【已解决】java的gradle项目报错org.gradle .api.plugins .MavenPlugin

我的java的gradle项目经常报错org.gradle .api.plugins .MavenPlugin。报错这个问题是因为依赖起冲突了&#xff0c;我在网上试了很多方法都没有效果&#xff0c;折让小编我很是苦恼&#xff0c;不过还好到最后问题还是解决了。 首先要知道你的项目所使用的gradle版本&#xf…

Webpack十大缺点:当过度工程化遇上简单的静态页面

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

React-Router路由

1.React Router的基本使用 安装&#xff1a;安装时&#xff0c;选择react-router-dom&#xff0c;react-router会包含一些react-native的内容&#xff0c;web开发并不需要&#xff1b; npm install react-router-dom 路径模式 BrowserRouter使用history模式&#xff1b; Hash…

【六:(mock数据)spring boot+mybatis+yml】

目录 1.1、代码编写Demo类User类启动类 APplication 1.2、配置类查询语句的配置 mysql.ymlspringboot的配置 application.yml日志的配置 logback.xml数据库的配置 mybatis-config.xml 1.3、测试&#xff1a;1.3.1、测试获取用户数1.3.2、添加用户1.3.3、数据的更新1.3.4、数据的…

【八:(调springboot+testng+mybatis+数据校验】

目录 1、代码结构configcontrollermodelspringboot启动类 2、配置资源mysql.xmlapplication.ymllogback.xmlmybatis-config.xml数据库配置 3、测试验证 1、代码结构 config package com.course.config; import org.springframework.context.annotation.Bean; import org.sprin…

Linux 进程操作

文章目录 进程的基本知识进程pid进程常用的函数 forkwait和waitpidexec函数簇system函数信号处理signal函数Linux的SIGUSR1SIGUSR2 讨论 进程的基本知识 一个程序的执行称为一个进程&#xff0c;所有的代码都是在进程中执行的&#xff0c;进程是操作系统资源分配的基本单位。 在…

在启智平台上安装anconda(启智平台中新建调试任务,选的基础镜像中有conda的,就无需安装)

安装Anaconda3-5.0.1-Linux-x86_64.sh python版本是3.6 在下面的网站上找到要下载的anaconda版本&#xff0c;把对应的.sh文件下载下来 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 把sh文件压缩成.zip文件&#xff0c;拖到启智平台的调试页面 上传到平台上 un…

tlaplus-vscode插件使用记录

参考官方教程Getting Started 和油管视频A gentle intro to TLA 入门和命令 首先在vscode的扩展里面下载 然后新建一个squares.tla文件 在代码区域先输入module生成上下的分隔符&#xff0c;然后输入pluscal来调用模版&#xff0c;生成一堆预设代码 小改一下&#xff0c;编写一…

WGBS项目文章 | 在缺氮情况下,细胞自噬对植物DNA甲基化会产生怎样的影响?

发表单位&#xff1a;中国科学院江西省庐山植物园 发表日期&#xff1a;2023年9月13日 研究期刊&#xff1a;International Journal of Molecular Sciences&#xff08;IF: 5.6&#xff09; 研究材料&#xff1a;拟南芥 2023年9月13日&#xff0c;中国科学院江西省庐山植物…

【二:Spring-AOP】

目录 一 、AOP1、什么是AOP2、AOP的类型3、AOP&#xff08;底层原理&#xff09;&#xff08;1&#xff09;第一种有接口情况&#xff0c;使用JDK 动态代理&#xff08;2&#xff09;第二种没有接口情况&#xff0c;使用[CGLIB](https://so.csdn.net/so/search?qCGLIB&spm…

【MyBatis进阶】mybatis-config.xml分析以及try-catch新用法

目录 尝试在mybatis项目中书写增删改查 遇见问题&#xff1a;使用mybaties向数据库中插入数据&#xff0c;idea显示插入成功&#xff0c;但是数据库中并没有数据变化? MyBatis核心配置文件剖析 细节剖析&#xff1a; try-catch新用法 截至目前我的项目存在的问题&#xf…

Milk-V Duo快速上手

前言 &#xff08;1&#xff09;此系列文章是跟着汪辰老师的RISC-V课程所记录的学习笔记。 &#xff08;2&#xff09;该课程相关代码gitee链接&#xff1b; &#xff08;3&#xff09;PLCT实验室实习生长期招聘&#xff1a;招聘信息链接 &#xff08;4&#xff09;最近实习需要…

Linux下shell编写脚本指南

文章目录 &#x1f31f; Linux下Shell编写脚本&#x1f34a; 为什么要使用Shell编写脚本&#x1f34a; Shell脚本的基础知识&#x1f389; 基本语法&#x1f389; 常用命令&#x1f389; 脚本文件的执行 &#x1f34a; Shell脚本的编写技巧&#x1f389; 脚本文件的注释&#x…

我总结了3个做好事情的万能动作,简单高效!

01 最近做公众号爆文项目&#xff0c;将用GPT写的文章发布在公众号赚取收益&#xff0c;爆了一篇之后&#xff0c;其他文章的数据并不理想。 同期做的闲鱼小项目很快出单&#xff0c;复盘出单经验&#xff0c;并将这些经验用到公众号爆文项目上&#xff0c;文章的数据又在逐渐好…

彩虹商城知识付费程序

1&#xff0c;下载程序&#xff0c; 2.宝塔新建站点&#xff0c;&#xff0c;自己的域名直接用&#xff08;别忘记解析了&#xff09;教程直接用IP测试。。 3.上传你下载的压缩包&#xff08;这里暂停一下&#xff0c;传好了继续&#xff09;有点慢等不了了&#xff0c; 4.上传…

基础MySQL的语法练习

基础MySQL的语法练习 create table DEPT(DEPTNO int(2) not null,DNAME VARCHAR(14),LOC VARCHAR(13) );alter table DEPTadd constraint PK_DEPT primary key (DEPTNO);create table EMP (EMPNO int(4) primary key,ENAME VARCHAR(10),JOB VARCHAR(9),MGR …

react配置 axios

配置步骤&#xff08;基本配置&#xff09;&#xff1a; 1.安装 axios cnpm install axios --save2.src/utils 新建一个 request.js文件(没有utils就新建一个目录然后再建一个request.js) 3.request代码如下&#xff1a; 这个是最简单的配置了&#xff0c;你可以根据自己的需…

【试题029】C语言Switch case语句小例题

1.题目&#xff1a; #include <stdio.h> void main(){ int i11,j; ji%3; switch(j){ case1: case2:printf("%d\n",j); break; default:printf("%d\n",i); } } 该段代码的输出结果是&#xff1f; 2.代码分析&#xff1a; int i 11, j;j …

切水果游戏开发1

多数无益&#xff0c;上代码&#xff1a; import pygame import random# 初始化pygame pygame.init()# 设置窗口尺寸 window_width 800 window_height 600 window_size (window_width, window_height) window pygame.display.set_mode(window_size)# 设置窗口标题 pygame.…

Leetcode—260.只出现一次的数字III【中等】

2023每日刷题&#xff08;三&#xff09; Leetcode—260.只出现一次的数字III 借助lowbit的解题思想 参考的灵茶山艾府大神的题解 实现代码 /*** Note: The returned array must be malloced, assume caller calls free().*/ int* singleNumber(int* nums, int numsSize, in…