这个程序写了一天,大概10个小时吧

首先:最重要的就是理解I2C的通讯协议,这点非常重要

I2C:有两个引脚:SCL(时钟) SDA(数据)

下面是我自己画的I2C的协议,

我还是讲讲如何写FPGA的代码吧

SCL时钟频率我设置为:250K

我们还需要一个时钟:CLOCK为:250K*4=1M   ,这个时钟可以通过系统分频产生

写E2PROM的过程:

读E2PROM的过程:

我们需要注意的是SDA是个inout的信号,在从机应答的周期里,记得要提前切换sda的输出方向。

写程序的时候,一定要看时序图。看着时序图写。稳住。

module e2prom(input             clk  ,    input             rst_n, output   [1:0]    led,     output            scl,           //时钟线,作为输出,驱动恶e2prom芯片工作inout             sda,           // 数据线output    [5:0]   seg_sel,       // 数码管位选信号output    [7:0]   seg_led        // 数码管段选信号);wire  clk_div;
wire  read_en;
wire  read_done;
wire [7:0] read_data;
wire [15:0] read_address;
wire  write_en;
wire  write_done;
wire [7:0] write_data;
wire [15:0] write_address;//数码管动态显示模块
seg_num seg_num_inst(.clk           (clk  ),       // 时钟信号.rst_n         (rst_n),       // 复位信号.seg_sel       (seg_sel ),    // 位选.segment       (seg_led ),   // 段选.data          (read_data)   // 显示的数值
);//读写E2PROM中的地址
rw_e2prom rw_e2prom_inst(.clk           (clk_div),     // 时钟信号1M.rst_n         (rst_n),       // 复位信号.read_en       (read_en),.read_done     (read_done),.read_data     (read_data),.read_address  (read_address),.write_en      (write_en),.write_done    (write_done),.write_data    (write_data),.write_address (write_address));//E2PROM I2C驱动代码
e2prom_dri  e2prom_dri_inst( .clk           (clk),         .rst_n         (rst_n),      .led           (led),.scl_clk       (scl),         .sda           (sda),        .read_en       (read_en),.read_done     (read_done),.read_data     (read_data),.read_address  (read_address),.write_en      (write_en),.write_done    (write_done),.write_data    (write_data),.write_address (write_address),.clk_div       (clk_div)
);
endmodule///
module e2prom_dri(input             clk    ,  //50Minput             rst_n  ,  output  reg [1:0] led,       //测试用的ledoutput  reg       scl_clk,   //II2C时钟驱动,inout             sda ,      //数据线input             read_en,   //读使能output  reg       read_done, //读完成,一个脉冲信号output  reg [7:0] read_data, //读出来的数据input    [15:0]   read_address,//读的地址input             write_en,    //写使能output   reg      write_done,  //写完成,一个脉冲信号input       [7:0] write_data,   //写入的数据input    [15:0]   write_address, //要写的地址output   reg      clk_div       //1M时钟信号
);parameter   ADDRESS      =  8'b1010_0000;   //器件地址(7位)+写(0)reg start_flag;
reg start_flag2;
reg sda_dir     ;   // I2C数据(SDA)方向控制
reg sda_out     ;  // SDA输出信号
wire  sda_in    ; // SDA输入信号
reg [4:0] cnt0;
wire add_cnt0;
wire end_cnt0;reg [7:0] cnt1;
wire add_cnt1;
wire end_cnt1;reg [7:0] cnt2;
wire add_cnt2;
wire end_cnt2;//t=20ns
//1us=50*20ns; cnt=50/2
always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt0 <= 0;endelse if(add_cnt0)beginif(end_cnt0)cnt0 <= 0;elsecnt0 <= cnt0 + 1;end
end
assign add_cnt0 = 1;
assign end_cnt0 = add_cnt0 && cnt0== 25-1;//产生1M的信号,周期为1us
always  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginclk_div<=1'b0;endelse if(end_cnt0) beginclk_div<=~clk_div;end
end//写数据
always @(posedge clk_div or negedge rst_n)beginif(!rst_n)begincnt1 <= 0;endelse if(add_cnt1)beginif(end_cnt1)cnt1 <= 0;elsecnt1 <= cnt1 + 1;end
endassign add_cnt1 = start_flag;
assign end_cnt1 = add_cnt1 && cnt1==153-1; //读数据
always @(posedge clk_div or negedge rst_n)beginif(!rst_n)begincnt2 <= 0;endelse if(add_cnt2)beginif(end_cnt2)cnt2 <= 0;elsecnt2 <= cnt2 + 1;end
endassign add_cnt2 = start_flag2;
assign end_cnt2 = add_cnt2 && cnt2== 194-1;   assign  sda     = sda_dir ?  sda_out : 1'bz;     // SDA数据输出或高阻
assign  sda_in  = sda ;                          // SDA数据输入always  @(posedge clk_div or negedge rst_n)beginif(rst_n==1'b0)beginscl_clk<=1;sda_dir<=1;  //刚开始设置为输出sda_out<=1;read_data<=0;endelse if(start_flag)begin    //写数据case(cnt1) 8'd1:scl_clk<=1; 8'd2:sda_out<=1;8'd3:sda_out<=0; 8'd4:scl_clk<=0;8'd5:sda_out<=ADDRESS[7];      //器件地址8'd6:scl_clk<=1;8'd8:scl_clk<=0;8'd9:sda_out<=ADDRESS[6];8'd10:scl_clk<=1;8'd12:scl_clk<=0;8'd13:sda_out<=ADDRESS[5];8'd14:scl_clk<=1;8'd16:scl_clk<=0;8'd17:sda_out<=ADDRESS[4];8'd18:scl_clk<=1;8'd20:scl_clk<=0;8'd21:sda_out<=ADDRESS[3];8'd22:scl_clk<=1;8'd24:scl_clk<=0;8'd25:sda_out<=ADDRESS[2];8'd26:scl_clk<=1;8'd28:scl_clk<=0;8'd29:sda_out<=ADDRESS[1];8'd30:scl_clk<=1;8'd32:scl_clk<=0;8'd33:sda_out<=ADDRESS[0];8'd34:scl_clk<=1;8'd36:begin scl_clk<=0;  sda_dir<=0;end  //应答信号8'd38:scl_clk<=1;8'd40:begin scl_clk<=0;  sda_dir<=1;end8'd41:sda_out<=write_address[15];    //数据地址8'd42:scl_clk<=1;8'd44:scl_clk<=0;8'd45:sda_out<=write_address[14];8'd46:scl_clk<=1;8'd48:scl_clk<=0;8'd49:sda_out<=write_address[13];8'd50:scl_clk<=1;8'd52:scl_clk<=0;8'd53:sda_out<=write_address[12];8'd54:scl_clk<=1;8'd56:scl_clk<=0;8'd57:sda_out<=write_address[11];8'd58:scl_clk<=1;8'd60:scl_clk<=0;8'd61:sda_out<=write_address[10];8'd62:scl_clk<=1;8'd64:scl_clk<=0;8'd65:sda_out<=write_address[9];8'd66:scl_clk<=1;8'd68:scl_clk<=0;8'd69:sda_out<=write_address[8];8'd70:scl_clk<=1;8'd72:begin scl_clk<=0;  sda_dir<=0;end   //应答信号 8'd74:scl_clk<=1;8'd76:begin scl_clk<=0;  sda_dir<=1;end 8'd77:sda_out<=write_address[7];    //数据地址8'd78:scl_clk<=1;8'd80:scl_clk<=0;8'd81:sda_out<=write_address[6];8'd82:scl_clk<=1;8'd84:scl_clk<=0;8'd85:sda_out<=write_address[5];8'd86:scl_clk<=1;8'd88:scl_clk<=0;8'd89:sda_out<=write_address[4];8'd90:scl_clk<=1;8'd92:scl_clk<=0;8'd93:sda_out<=write_address[3];8'd94:scl_clk<=1;8'd96:scl_clk<=0;8'd97:sda_out<=write_address[2];8'd98:scl_clk<=1;8'd100:scl_clk<=0;8'd101:sda_out<=write_address[1];8'd102:scl_clk<=1;8'd104:scl_clk<=0;8'd105:sda_out<=write_address[0];8'd106:scl_clk<=1;8'd108:begin scl_clk<=0;  sda_dir<=0;end  //应答信号 8'd110:scl_clk<=1;8'd112:begin scl_clk<=0;  sda_dir<=1;end8'd113:sda_out<=write_data[7];            //存的数据8'd114:scl_clk<=1;8'd116:scl_clk<=0;8'd117:sda_out<=write_data[6];8'd118:scl_clk<=1;8'd120:scl_clk<=0;8'd121:sda_out<=write_data[5];8'd122:scl_clk<=1;8'd124:scl_clk<=0;8'd125:sda_out<=write_data[4];8'd126:scl_clk<=1;8'd128:scl_clk<=0;8'd129:sda_out<=write_data[3];8'd130:scl_clk<=1;8'd132:scl_clk<=0;8'd133:sda_out<=write_data[2];8'd134:scl_clk<=1;8'd136:scl_clk<=0;8'd137:sda_out<=write_data[1];8'd138:scl_clk<=1;8'd140:scl_clk<=0;8'd141:sda_out<=write_data[0];8'd142:scl_clk<=1;8'd144:begin scl_clk<=0;  sda_dir<=0;end   //应答信号 8'd146:scl_clk<=1;8'd148:begin scl_clk<=0;  sda_dir<=1;end 8'd149:sda_out<=0;8'd150:scl_clk<=1;  8'd151:sda_out<=1;default : ;endcase  endelse if (start_flag2)begin     //读数据case(cnt2) 8'd1:scl_clk<=1; 8'd2:sda_out<=1;8'd3:sda_out<=0; 8'd4:scl_clk<=0;8'd5:sda_out<=ADDRESS[7];      //器件地址8'd6:scl_clk<=1;8'd8:scl_clk<=0;8'd9:sda_out<=ADDRESS[6];8'd10:scl_clk<=1;8'd12:scl_clk<=0;8'd13:sda_out<=ADDRESS[5];8'd14:scl_clk<=1;8'd16:scl_clk<=0;8'd17:sda_out<=ADDRESS[4];8'd18:scl_clk<=1;8'd20:scl_clk<=0;8'd21:sda_out<=ADDRESS[3];8'd22:scl_clk<=1;8'd24:scl_clk<=0;8'd25:sda_out<=ADDRESS[2];8'd26:scl_clk<=1;8'd28:scl_clk<=0;8'd29:sda_out<=ADDRESS[1];8'd30:scl_clk<=1;8'd32:scl_clk<=0;8'd33:sda_out<=ADDRESS[0];  //写状态8'd34:scl_clk<=1;8'd36:begin scl_clk<=0;  sda_dir<=0;end  //应答信号8'd38:scl_clk<=1;8'd40:begin scl_clk<=0;  sda_dir<=1;end8'd41:sda_out<=read_address[15];    //数据地址8'd42:scl_clk<=1;8'd44:scl_clk<=0;8'd45:sda_out<=read_address[14];8'd46:scl_clk<=1;8'd48:scl_clk<=0;8'd49:sda_out<=read_address[13];8'd50:scl_clk<=1;8'd52:scl_clk<=0;8'd53:sda_out<=read_address[12];8'd54:scl_clk<=1;8'd56:scl_clk<=0;8'd57:sda_out<=read_address[11];8'd58:scl_clk<=1;8'd60:scl_clk<=0;8'd61:sda_out<=read_address[10];8'd62:scl_clk<=1;8'd64:scl_clk<=0;8'd65:sda_out<=read_address[9];8'd66:scl_clk<=1;8'd68:scl_clk<=0;8'd69:sda_out<=read_address[8];8'd70:scl_clk<=1;8'd72:begin scl_clk<=0;  sda_dir<=0;end   //应答信号 8'd74:scl_clk<=1;8'd76:begin scl_clk<=0;  sda_dir<=1;end 8'd77:sda_out<=read_address[7];    //数据地址8'd78:scl_clk<=1;8'd80:scl_clk<=0;8'd81:sda_out<=read_address[6];8'd82:scl_clk<=1;8'd84:scl_clk<=0;8'd85:sda_out<=read_address[5];8'd86:scl_clk<=1;8'd88:scl_clk<=0;8'd89:sda_out<=read_address[4];8'd90:scl_clk<=1;8'd92:scl_clk<=0;8'd93:sda_out<=read_address[3];8'd94:scl_clk<=1;8'd96:scl_clk<=0;8'd97:sda_out<=read_address[2];8'd98:scl_clk<=1;8'd100:scl_clk<=0;8'd101:sda_out<=read_address[1];8'd102:scl_clk<=1;8'd104:scl_clk<=0;8'd105:sda_out<=read_address[0];8'd106:scl_clk<=1;8'd108:begin scl_clk<=0;  sda_dir<=0;end  //应答信号 8'd110:scl_clk<=1;8'd112:begin scl_clk<=0;  sda_dir<=1;end8'd114:scl_clk<=1;       //起始信号8'd115:sda_out<=1;8'd116:sda_out<=0;8'd117:scl_clk<=0;8'd118:sda_out<=ADDRESS[7];8'd119:scl_clk<=1;8'd121:scl_clk<=0;8'd122:sda_out<=ADDRESS[6];8'd123:scl_clk<=1;8'd125:scl_clk<=0;8'd126:sda_out<=ADDRESS[5];8'd127:scl_clk<=1;8'd129:scl_clk<=0;8'd130:sda_out<=ADDRESS[4];8'd131:scl_clk<=1;8'd133:scl_clk<=0;8'd134:sda_out<=ADDRESS[3];8'd135:scl_clk<=1;8'd137:scl_clk<=0;8'd138:sda_out<=ADDRESS[2];8'd139:scl_clk<=1;8'd141:scl_clk<=0;8'd142:sda_out<=ADDRESS[1];8'd143:scl_clk<=1;8'd145:scl_clk<=0;8'd146:sda_out<=1;    //读状态8'd147:scl_clk<=1;8'd149:begin scl_clk<=0;  sda_dir<=0;end  //应答信号8'd151:scl_clk<=1;8'd153:begin scl_clk<=0;  sda_dir<=0;end8'd155: scl_clk<=1;8'd156: read_data[7]<=sda_in;8'd157: scl_clk<=0;8'd159: scl_clk<=1;8'd160: read_data[6]<=sda_in;8'd161: scl_clk<=0;8'd163: scl_clk<=1;8'd164: read_data[5]<=sda_in;8'd165: scl_clk<=0;8'd167: scl_clk<=1;8'd168: read_data[4]<=sda_in;8'd169: scl_clk<=0;8'd171: scl_clk<=1;8'd172: read_data[3]<=sda_in;8'd173: scl_clk<=0;8'd175: scl_clk<=1;8'd176: read_data[2]<=sda_in;8'd177: scl_clk<=0;8'd179: scl_clk<=1;8'd180: read_data[1]<=sda_in;8'd181: scl_clk<=0;8'd183: scl_clk<=1;8'd184: read_data[0]<=sda_in;8'd185: begin scl_clk<=0;sda_dir<=1;end8'd186: sda_out<=1;8'd187: scl_clk<=1;8'd189: scl_clk<=0;8'd190: sda_out<=0;8'd191: scl_clk<=1;8'd192: sda_out<=1;default : ;endcase  end
end//给一个写使能信号,脉冲
always  @(posedge clk_div or negedge rst_n)beginif(rst_n==1'b0)beginstart_flag<=0;endelse if(write_en) beginstart_flag<=1;endelse if(end_cnt1) beginstart_flag<=0;end
endalways  @(posedge clk_div or negedge rst_n)beginif(rst_n==1'b0)beginwrite_done<=0;endelse if(end_cnt1) beginwrite_done<=1;endelse beginwrite_done<=0;end
endalways  @(posedge clk_div or negedge rst_n)beginif(rst_n==1'b0)beginread_done<=0;endelse if(end_cnt2) beginread_done<=1;endelse beginread_done<=0;end
end//给一个写使能信号,脉冲
always  @(posedge clk_div or negedge rst_n)beginif(rst_n==1'b0)beginstart_flag2<=0;endelse if(read_en) beginstart_flag2<=1;endelse if(end_cnt2) beginstart_flag2<=0;end
end//测试
always  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginled[0]<=0;endelse if(start_flag) beginled[0]<=1;end
endalways  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginled[1]<=0;endelse if(start_flag2) beginled[1]<=1;end
endendmodule////功能说明:向0--200地址,写入数据之后,然后只读取其中一个地址的值,看看自己是否写对了
module  rw_e2prom(input               clk    ,  //50Minput               rst_n  ,  output reg          read_en,input               read_done,input               read_data,output  reg [15:0]  read_address,output  reg         write_en,input               write_done,output  reg [7:0]   write_data,output  reg [15:0]  write_address
);reg [15:0] cnt2;
wire add_cnt2;
wire end_cnt2;
reg flag;reg [7:0] cnt;
wire add_cnt;
wire end_cnt;reg [7:0] cnt1;
wire add_cnt1;
wire end_cnt1;
reg flag_cnt;reg flag_cnt1;always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt1 <= 0;endelse if(add_cnt1)beginif(end_cnt1)cnt1 <= 0;elsecnt1 <= cnt1 + 1;end
end
assign add_cnt1 = flag_cnt==0;
assign end_cnt1 = add_cnt1 && cnt1==100-1;   always  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginflag_cnt<=0;endelse  if(end_cnt1)beginflag_cnt<=1;end
endalways  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginwrite_en<=0;write_address<=0;write_data<=12;endelse beginif(flag_cnt1==0) beginif(end_cnt1)beginwrite_en<=1;  endelse if(end_cnt2)beginwrite_en<=1;write_address<=write_address+1;write_data<=write_data+1;endelse beginwrite_en<=0;endendelse beginwrite_en<=0;endend
endalways @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt2 <= 0;endelse if(add_cnt2)beginif(end_cnt2)cnt2 <= 0;elsecnt2 <= cnt2 + 1;end
endassign add_cnt2 = flag ;
assign end_cnt2 = add_cnt2 && cnt2==5200-1 ;   always  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginflag<=0;endelse if(write_done) beginflag<=1;   endelse if(end_cnt2) beginflag<=0;   end
endalways  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginflag_cnt1<=0;endelse  if(end_cnt)beginflag_cnt1<=1;end
endalways @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt <= 0;endelse if(add_cnt)beginif(end_cnt)cnt <= 0;elsecnt <= cnt + 1;end
endassign add_cnt = write_done;
assign end_cnt = add_cnt && cnt==200-1;always  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginread_en<=0;read_address<=0;endelse if(end_cnt2)beginread_en<=1;read_address<=2;     //将写入地址2的值读出来,显示到数码管上end else beginread_en<=0;endendendmodule

I2C E2PROM通信相关推荐

  1. 双机通信c语言程序,上传一个自己编写的I2C双机通信程序

    本帖最后由 micro_听海 于 2012-11-24 19:58 编辑 这几天一直在搞AVR的twi(twi就是i2c)双机通信程序,使用的是两块arduino开发板.因为最总要这个通信程序最总是要 ...

  2. 蓝牙BLE芯片PHY6222之I2C主从通信

    蓝牙BLE芯片PHY6222之I2C主从通信 开发环境 I2C主机 I2C从机 注意事项 开发环境 1.PHY6222开发板 2.SDK版本以及路径:SDK\release_bbb_sdk-PHY62 ...

  3. CSR8675学习笔记:I2C Master通信

    为了让CSR867x的开发更容易,现与思度科技联合推出CSR867x学习板[淘宝链接:思度科技CSR开发板]. 技术交流QQ群号:743434463 开发板会员QQ群号:725398389(凭订单号入 ...

  4. STM32F10x_硬件I2C主从通信(轮询发送,中断接收)

    推荐 分享一个大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到人工智能的队伍中来!http://www.captainbed.net/strongerhuang Ⅰ.写在前面 ...

  5. I2C总线通信——时序/示波器分析

    I2C总线通信--时序/示波器分析 通信概述 I2C是一种芯片间的双向数据传输协议. 只需要2根信号线:SCL:串行时钟线:SDA:串行数据线. 时序分析 这里以TM4C123GXL核心板及DY-Ti ...

  6. I2C+E2PROM再回顾ing~

    第二更~~~~ 今天是准备学习A/D,D/A转换的,然后看了一下代码发现用到的都是I2C的底层,那就先回顾一下I2C叭. 1. I2C时序 首先明确I2C总线是由时钟总线SCL和数据总线SDA构成的, ...

  7. .NET Core IoT 入门指南:(三)使用 I2C 进行通信

    什么是 I2C 总线 I2C 总线(Inter-Integrated Circuit Bus)是设备与设备间通信方式的一种.它是一种串行通信总线,由飞利浦公司在1980年代为了让主板.嵌入式系统或手机 ...

  8. FPGA之IIC(I2C)通信EEPROM控制器设计

    关于IIC通信用一个具体实例来进行说明(含设计代码) 几个重要的信号 空闲状态:SDA,SCL均处于高电平状态. 起始信号:SCL为高电平时SDA由高到低跳变 停止信号:SCL为高电平时SDA由低到高 ...

  9. STM32 HAL I2C(IIC)通信的序列传输(restart condition)

    STM32 HAL I2C(IIC)通信的序列(Seq)传输函数(restart condition) neozng1@hnu.edu.cn 文章目录 STM32 HAL I2C(IIC)通信的序列( ...

最新文章

  1. 灰色预测原理及JAVA实现
  2. C#中的where泛型约束中的new()使用(转)
  3. 我做的百度飞桨PaddleOCR .NET调用库
  4. 2019.01.29【NOIP普及组】模拟赛C组总结
  5. 人工智能是一个骗局?
  6. vs2015安装vax助手
  7. java定时任务_定时任务3种实现方式
  8. 生存分析 R语言(六)—— Extended and Stratified Cox
  9. OSWorkflow(转载)
  10. Innodb解决幻读
  11. 用vue写一个npm包(package),发布及引用
  12. 学Linux到底学什么?老司机来告诉你!
  13. java垃圾回收浅析
  14. AutoCAD打开报错,致命错误:无效的配置路径/文件名
  15. 程序员.恋曲.人生(3)
  16. 基于视频流传输 — 在线教育白板技术
  17. 开博记录-二零一捌零柒二捌
  18. python可以考的资格认证有哪些?
  19. C++标准模板库STL学习
  20. 腾讯文档智能表格定时自动提醒如何设置?

热门文章

  1. avl树左旋右旋的理解
  2. Java api 调用Sqoop2进行MySQL--Hive的数据同步
  3. 通过js实现在线计算器
  4. 基于FFMpeg实现音频mp3/aac/wav解码
  5. 华文慕课北大陆俊林计算机组成原理第十章课后习题解析
  6. 两边同时取对数求复合函数_e2x求导(复合函数求导例题大全)
  7. 台达服务器显示al003,台达伺服放大器AL003报警代码|DELTA驱动器低电压故障维修...
  8. 吃一堑长一智!2021最新Java面试真题解析
  9. linux7+恢复密码,CentOS7密码恢复
  10. sinusoidal sweep正弦扫频信号