⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c_top.v

📁 VHDL语言写的IIC实现EEPROM
💻 V
字号:

`timescale 1ns/1ns

module i2c_top(clk, 
               rst_n,
               sda, 
               scl, 
               data_rep
              // hc_cp, 
              // hc_si
              );
  input  clk;
  input  rst_n;
  inout  sda;
  output scl;
  output data_rep;
 // output hc_cp;
 // output hc_si;

  reg  wr;  //write eeprom command
  reg  rd;  //read eeprom command
  reg  [10:0] addr;   //write or read address.
  reg  [7:0]  data_w; //write data to eeprom
  wire ack;           //i2c write or read complete
  wire [7:0] data_r;  //read data from eeprom
 
  reg [15:0] data_rep; //存储显示在七段数码管上的数据
  reg show_ok;   //正确显示后的标志
  reg wr_flag;   //记录是否已经发送过write,read command
  
  reg [6:0]  cs,ns;
  parameter  IDLE    = 7'b0000001,
             WR_BYTE = 7'b0000010,
             WR_ACK  = 7'b0000100,
             DELAY   = 7'B0001000,
             RD_BYTE = 7'b0010000,
             RD_ACK  = 7'b0100000,
             SHOW    = 7'b1000000;
             

  //-------------产生时钟clk分频-----------------------------------------------
  reg [11:0] clk_cnt; 
  reg [12:0] clk_div_cnt;
  reg clk_div;
  always @ (posedge clk or negedge rst_n)
    if (!rst_n) 
      clk_cnt <= 12'd0;
    else if (clk_cnt == 12'd1250)  //get 20khz SCL clock  
      clk_cnt <= 12'd0;
    else 
      clk_cnt <= clk_cnt + 1'b1;
      
  always @ (posedge clk or negedge rst_n)
    if (!rst_n)
      clk_div <= 1'b0;
    else if (clk_cnt == 12'd1250)
      clk_div <= ~clk_div;       //20khz
      
  always @ (posedge clk_div or negedge rst_n)
    if (!rst_n)
      clk_div_cnt <= 13'd0;
    else
      clk_div_cnt <= clk_div_cnt + 1'b1;
      
  //---------State machine------------------
  always @ (posedge clk_div or negedge rst_n)
    if (!rst_n)
      cs <= IDLE;
    else 
      cs <= ns;
      
  always @ ( * )
    case (cs)
      IDLE:
        if (clk_div_cnt == 13'd1000)
          ns = WR_BYTE;
        else
          ns = IDLE;
      WR_BYTE:
        if (ack)
          ns = WR_ACK;
        else
          ns = WR_BYTE;
      WR_ACK:
        if (!ack)
            ns = DELAY;
        else
          ns = WR_ACK;
      DELAY://eeprom写数据需要时间,故:等待数据写完后再进行读操作
        if (clk_div_cnt == 13'd1300)
          ns = RD_BYTE;
        else
          ns = DELAY;
      RD_BYTE:
        if (ack)
          ns = RD_ACK;
        else
          ns = RD_BYTE;
      RD_ACK:
        if (!ack)
          ns = SHOW;
        else
          ns = RD_ACK;
      SHOW:
        if (show_ok)
          ns = IDLE;
        else
          ns = SHOW;
      default:
        ns = IDLE;
    endcase
    
  always @ (posedge clk_div or negedge rst_n)
    if (!rst_n)
      begin
        wr <= 1'b0;
        rd <= 1'b0;
        addr <= 11'd0;
        data_w <= 8'd0;
//        data_w <= 8'h58;
        show_ok <= 1'b0;
        wr_flag <= 1'b0;
      end
    else if (data_w == 8'd255) //计数到255就重新开始
      begin
        addr <= 11'd0;
        data_w <= 8'd0;
//        data_w <= 8'h58;
      end
    else
      case (cs)
        IDLE:
          begin
            wr <= 1'b0;
            rd <= 1'b0;
            show_ok <= 1'b0;
            wr_flag <= 1'b0;
          end
        WR_BYTE:
          if (wr_flag == 1'b0)
            begin
              wr <= 1'b1;
              wr_flag <= 1'b1;
            end
          else
            wr <= 1'b0;
        WR_ACK:
          wr_flag <= 1'b0;
        DELAY:
          begin
            wr <= 1'b0;
            rd <= 1'b0;
            show_ok <= 1'b0;
            wr_flag <= 1'b0;
          end
        RD_BYTE:
          if (wr_flag == 1'b0)
            begin
              rd <= 1'b1;
              wr_flag <= 1'b1;
            end
          else
            rd <= 1'b0;
        RD_ACK:
          begin
            wr_flag <= 1'b0;
            show_ok <= 1'b1; 
          end
        SHOW:
          begin
            show_ok <= 1'b0;
            addr <= addr + 1'b1;
            data_w <= data_w + 1'b1;
          end
        default:
          begin
            wr <= 1'b0;
            rd <= 1'b0;
            show_ok <= 1'b0;
            wr_flag <= 1'b0;
          end
      endcase
      
  always @ (posedge clk_div or negedge rst_n)
    if (!rst_n)
      data_rep <=16'h0000;
    else if (show_ok)
      data_rep <= {data_w,data_r}; //将写入eeprom和从eeprom中读出的数据进行对比输出
    
  // ---------------------------------------------------------------------------
  // 例化EEPROM: 24C02的驱动程序
  // ---------------------------------------------------------------------------
  i2c_wr	i2c_wr_inst(
      .clk          (clk_div),
      .rst_n        (rst_n),
      .wr           (wr),
	    .rd           (rd),
	    .addr         (addr),
	    .data_w       (data_w),
	    .data_r       (data_r),
	    .ack          (ack),
      .scl          (scl),
      .sda          (sda)
	    );

  // ---------------------------------------------------------------------------
  // 例化hc164的驱动程序
  // ---------------------------------------------------------------------------

//  hc164_driver hc164_driver_inst(
//      .clk         ( clk ),
//      .rst_n       ( rst_n ),
//      .led         ( {4{ ack }} ),
//      .dot         ( 4'b0000 ),
//      .seg_value   ( data_rep ),
//      .hc_cp       ( hc_cp ), 
//      .hc_si       ( hc_si )  
//      );
      
      
endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -