ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

17_IIC协议与FPGA驱动AT24C04

2022-02-20 17:34:51  阅读:213  来源: 互联网

标签:SCL begin end 17 FPGA db else AT24C04 sda


17_IIC协议与FPGA驱动AT24C04

实验原理

什么是IIC

IIC即I2C,一种总线结构。IIC 即Inter-Integrated Circuit,这种总线类型是由菲利浦半导体公司在八十年代初设计出来的,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实施数据传输的控制源。这种方式简化了信号传输总线。例如:内存中的SPD信息,通过IIC,与BX芯片组联系,IIC 存在于英特尔PIIX4结构体系中。  

随着大规模集成电路技术的发展,把CPU和一个单独工作系统所必需的ROM、RAM、I/O端口、A/D、D/A等外围电路集成在一个单片内而制成的单片机或微控制器愈来愈方便。目前,世界上许多公司生产单片机,品种很多。其中包括各种字长的CPU,各种容量的ROM、RAM以及功能各异的I/O接口电路等等,但是,单片机的品种规格仍然有限,所以只能选用某种单片机来进行扩展。扩展的方法有两种:一种是并行总线,另一种是串行总线。由于串行总线的连线少,结构简单,往往不用专门的母板和插座而直接用导线连接各个设备。因此,采用串行线可大大简化系统的硬件设计。PHILIPS公司早在十几年前就推出了I2C串行总线,利用该总线可实现多主机系统所需的裁决和高低速设备同步等功能。因此,这是一种高性能的串行总线。  

飞利浦电子公司日前推出新型二选一I2C主选择器,可以使两个I2C主设备中的任何一个与共享资源连接,广泛适用于从MP3播放器到服务器等计算、通信和网络应用领域,从而使制造商和终端用户从中获益。PCA9541可以使两个I2C主设备在互不连接的情况下与同一个从设备相连接,从而简化了设计的复杂性。此外,新产品以单器件替代了I2C多个主设备应用中的多个芯片,有效节省了系统成本。

 

IIC的硬件结构

I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。  

为了避免总线信号的混乱,要求各设备连接到总线的输出端时必须是漏极开路(OD)输出或集电极开路(OC)输出。设备上的串行数据线SDA接口电路应该是双向的,输出电路用于向总线上发送数据,输入电路用于接收总线上的数据。而串行时钟线也应是双向的,作为控制总线数据传送的主机,一方面要通过SCL输出电路发送时钟信号,另一方面还要检测总线上的SCL电平,以决定什么时候发送下一个时钟脉冲电平;作为接受主机命令的从机,要按总线上的SCL信号发出或接收SDA上的信号,也可以向SCL线发出低电平信号以延长总线时钟信号周期。总线空闲时,因各设备都是开漏输出,上拉电阻Rp使SDA和SCL线都保持高电平。任一设备输出的低电平都将使相应的总线信号线变低,也就是说:各设备的SDA是"与"关系,SCL也是"与"关系。  

总线对设备接口电路的制造工艺和电平都没有特殊的要求(NMOS、CMOS都可以兼容)。在I2C总线上的数据传送率可高达每秒十万位,高速方式时在每秒四十万位以上。另外,总线上允许连接的设备数以其电容量不超过400pF为限。  

总线的运行(数据传输)由主机控制。所谓主机是指启动数据的传送(发出启动信号)、发出时钟信号以及传送结束时发出停止信号的设备,通常主机都是微处理器。被主机寻访的设备称为从机。为了进行通讯,每个接到I2C总线的设备都有一个唯一的地址,以便于主机寻访。主机和从机的数据传送,可以由主机发送数据到从机,也可以由从机发到主机。凡是发送数据到总线的设备称为发送器,从总线上接收数据的设备被称为接受器。  

I2C总线上允许连接多个微处理器以及各种外围设备,如存储器、LED及LCD驱动器、A/D及D/A转换器等。为了保证数据可靠地传送,任一时刻总线只能由某一台主机控制,各微处理器应该在总线空闲时发送启动数据,为了妥善解决多台微处理器同时发送启动数据的传送(总线控制权)冲突,以及决定由哪一台微处理器控制总线的问题,I2C总线允许连接不同传送速率的设备。多台设备之间时钟信号的同步过程称为同步化。

IIC的数据传输

在I2C总线传输过程中,将两种特定的情况定义为开始和停止条件(见下图):当SCL保持"高"时,SDA由"高"变为"低"为开始条件;当SCL保持"高"且SDA由"低"变为"高"时为停止条件。开始和停止条件均由主控制器产生。使用硬件接口可以很容易地检测到开始和停止条件,没有这种接口的微机必须以每时钟周期至少两次对SDA取样,以检测这种变化。

SDA线上的数据在时钟"高"期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的"高"或"低"状态才可以改变。输出到SDA线上的每个字节必须是8位,每次传输的字节不受限制,但每个字节必须要有一个应答ACK。如果一接收器件在完成其他功能(如一内部中断)前不能接收另一数据的完整字节时,它可以保持时钟线SCL为低,以促使发送器进入等待状态;当接收器准备好接受数据的其它字节并释放时钟SCL后,数据传输继续进行。   

数据传送具有应答是必须的。与应答对应的时钟脉冲由主控制器产生,发送器在应答期间必须下拉SDA线。当寻址的被控器件不能应答时,数据保持为高并使主控器产生停止条件而终止传输。在传输的过程中,在用到主控接收器的情况下,主控接收器必须发出一数据结束信号给被控发送器,从而使被控发送器释放数据线,以允许主控器产生停止条件。   

I2C总线在开始条件后的首字节决定哪个被控器将被主控器选择,例外的是"通用访问"地址,它可以在所有期间寻址。当主控器输出一地址时,系统中的每一器件都将开始条件后的前7位地址和自己的地址进行比较。如果相同,该器件即认为自己被主控器寻址,而作为被控接收器或被控发送器则取决于R/W位。

基于AT24C04的IIC通信协议

在使用开发板做实验之前,希望大家先对IIC协议有足够的了解。我们的开发板是基于AT24C02的IIC通信协议。如果对IIC的协议不是很熟悉的同学,可以先去看我们附带的文档资料或者上网了解IIC。

在我们实验之前,我们还是先回顾下基于AT24C02的IIC通信协议。下图分别为单字节写时序和随机读时序。

单字节写时序

 

随机读时序

IIC通信中只涉及两条信号线,即时钟线SCL和数据线SDA。时钟线为高电平时均可所存数据,即时钟线上升沿和下降沿之间。当时钟线SCL为高电平时,如果把数据线SDA从高电平拉到低电平,则表示通信开始;如果把数据线SDA从低电平拉到高电平,则表示通信结束。器件地址(DEVICE ADDRESS)的定义如下图所示。最低位(LSB)R/W表示读或者写状态,1表示读,0表示写。

器件地址字节定义

 

硬件原理图

实验代码

顶层原理图设计

IIC

/********************************版权声明**************************************

** 大西瓜团队

**

**----------------------------文件信息--------------------------

** 文件名称:

** 创建日期:2012.10.9

** 功能描述:

** 操作过程:

** 硬件平台:大西瓜第3代开发板

** 版权声明:本代码属个人知识产权,本代码仅供交流学习.

**---------------------------修改文件的相关信息----------------

** 修改人:

** 修改日期:        

** 修改内容:

*******************************************************************************/

 

module iic_com(

            clk,rst_n,

            sw1,sw2,

            scl,sda,

            dis_data

        );

 

input clk;        // 50MHz

input rst_n;    //复位信号,低有效

input sw1,sw2;    //按键1、2,(1按下执行写入操作,2按下执行读操作)

output scl;        // 24C02的时钟端口

inout sda;        // 24C02的数据端口

output[7:0] dis_data;    //数码管显示的数据

 

 

//按键检测

reg sw1_r,sw2_r;    //键值锁存寄存器,每20ms检测一次键值

reg[19:0] cnt_20ms;    //20ms计数寄存器

 

always @ (posedge clk or negedge rst_n)

begin

    if(!rst_n)

cnt_20ms <= 20'd0;

    else

cnt_20ms <= cnt_20ms+1'b1;    //不断计数

end

 

always @ (posedge clk or negedge rst_n)

begin

if(!rst_n)

begin

sw1_r <= 1'b1;    //键值寄存器复位,没有键盘按下时键值都为1

sw2_r <= 1'b1;

end

else if(cnt_20ms == 20'hfffff)

begin

sw1_r <= sw1;    //按键1值锁存

sw2_r <= sw2;    //按键2值锁存

end

end

//---------------------------------------------

//分频部分

reg[2:0] cnt;     // cnt=0:scl上升沿,cnt=1:scl高电平中间,cnt=2:scl下降沿,cnt=3:scl低电平中间

reg[8:0] cnt_delay;    //500循环计数,产生iic所需要的时钟

reg scl_r;        //时钟脉冲寄存器

 

always @ (posedge clk or negedge rst_n)

begin

if(!rst_n)

cnt_delay <= 9'd0;

else if(cnt_delay == 9'd499)

cnt_delay <= 9'd0;    //计数到10us为scl的周期,即100KHz

else

cnt_delay <= cnt_delay+1'b1;    //时钟计数

end

 

always @ (posedge clk or negedge rst_n)

begin

    if(!rst_n)

cnt <= 3'd5;

    else

begin

case (cnt_delay)

9'd124:    cnt <= 3'd1;    //cnt=1:scl高电平中间,用于数据采样

9'd249:    cnt <= 3'd2;    //cnt=2:scl下降沿

9'd374:    cnt <= 3'd3;    //cnt=3:scl低电平中间,用于数据变化

9'd499:    cnt <= 3'd0;    //cnt=0:scl上升沿

default: cnt <= 3'd5;

endcase

end

end

`define SCL_POS        (cnt==3'd0)        //cnt=0:scl上升沿

`define SCL_HIG        (cnt==3'd1)        //cnt=1:scl高电平中间,用于数据采样

`define SCL_NEG        (cnt==3'd2)        //cnt=2:scl下降沿

`define SCL_LOW        (cnt==3'd3)        //cnt=3:scl低电平中间,用于数据变化

 

 

always @ (posedge clk or negedge rst_n)

begin

    if(!rst_n)

scl_r <= 1'b0;

    else if(cnt==3'd0)

scl_r <= 1'b1;    //scl信号上升沿

    else if(cnt==3'd2)

scl_r <= 1'b0;    //scl信号下降沿

end

assign scl = scl_r;    //产生iic所需要的时钟

//---------------------------------------------

        //需要写入24C02的地址和数据

                

`define    DEVICE_READ        8'b1010_0001    //被寻址器件地址(读操作)

`define DEVICE_WRITE    8'b1010_0000    //被寻址器件地址(写操作)

`define    WRITE_DATA        8'b1101_0001    //写入EEPROM的数据

`define BYTE_ADDR        8'b0000_0011    //写入/读出EEPROM的地址寄存器    

reg[7:0] db_r;        //在IIC上传送的数据寄存器

reg[7:0] read_data;    //读出EEPROM的数据寄存器

 

//---------------------------------------------

        //读、写时序

parameter     IDLE     = 4'd0;

parameter     START1     = 4'd1;

parameter     ADD1     = 4'd2;

parameter     ACK1     = 4'd3;

parameter     ADD2     = 4'd4;

parameter     ACK2     = 4'd5;

parameter     START2     = 4'd6;

parameter     ADD3     = 4'd7;

parameter     ACK3    = 4'd8;

parameter     DATA     = 4'd9;

parameter     ACK4    = 4'd10;

parameter     STOP1     = 4'd11;

parameter     STOP2     = 4'd12;

 

reg[3:0] cstate;     //状态寄存器

reg sda_r;        //输出数据寄存器

reg sda_link;    //输出数据sda信号inout方向控制位        

reg[3:0] num;    

 

 

always @ (posedge clk or negedge rst_n) begin

    if(!rst_n) begin

            cstate <= IDLE;

            sda_r <= 1'b1;

            sda_link <= 1'b0;

            num <= 4'd0;

            read_data <= 8'b0000_0000;

        end

    else     

        case (cstate)

            IDLE:    begin

                    sda_link <= 1'b1;            //数据线sda为output

                    sda_r <= 1'b1;

                    if(!sw1_r || !sw2_r) begin    //SW1,SW2键有一个被按下            

                        db_r <= `DEVICE_WRITE;    //送器件地址(写操作)

                        cstate <= START1;        

                        end

                    else cstate <= IDLE;    //没有任何键被按下

                end

            START1: begin

                    if(`SCL_HIG) begin        //scl为高电平期间

                        sda_link <= 1'b1;    //数据线sda为output

                        sda_r <= 1'b0;        //拉低数据线sda,产生起始位信号

                        cstate <= ADD1;

                        num <= 4'd0;        //num计数清零

                        end

                    else cstate <= START1; //等待scl高电平中间位置到来

                end

            ADD1:    begin

                    if(`SCL_LOW) begin

                            if(num == 4'd8) begin    

                                    num <= 4'd0;            //num计数清零

                                    sda_r <= 1'b1;

                                    sda_link <= 1'b0;        //sda置为高阻态(input)

                                    cstate <= ACK1;

                                end

                            else begin

                                    cstate <= ADD1;

                                    num <= num+1'b1;

                                    case (num)

                                        4'd0: sda_r <= db_r[7];

                                        4'd1: sda_r <= db_r[6];

                                        4'd2: sda_r <= db_r[5];

                                        4'd3: sda_r <= db_r[4];

                                        4'd4: sda_r <= db_r[3];

                                        4'd5: sda_r <= db_r[2];

                                        4'd6: sda_r <= db_r[1];

                                        4'd7: sda_r <= db_r[0];

                                        default: ;

                                        endcase

                            //        sda_r <= db_r[4'd7-num];    //送器件地址,从高位开始

                                end

                        end

            //        else if(`SCL_POS) db_r <= {db_r[6:0],1'b0};    //器件地址左移1bit

                    else cstate <= ADD1;

                end

            ACK1:    begin

                    if(/*!sda*/`SCL_NEG) begin    //注:24C01/02/04/08/16器件可以不考虑应答位

                            cstate <= ADD2;    //从机响应信号

                            db_r <= `BYTE_ADDR;    // 1地址        

                        end

                    else cstate <= ACK1;        //等待从机响应

                end

            ADD2:    begin

                    if(`SCL_LOW) begin

                            if(num==4'd8) begin    

                                    num <= 4'd0;            //num计数清零

                                    sda_r <= 1'b1;

                                    sda_link <= 1'b0;        //sda置为高阻态(input)

                                    cstate <= ACK2;

                                end

                            else begin

                                    sda_link <= 1'b1;        //sda作为output

                                    num <= num+1'b1;

                                    case (num)

                                        4'd0: sda_r <= db_r[7];

                                        4'd1: sda_r <= db_r[6];

                                        4'd2: sda_r <= db_r[5];

                                        4'd3: sda_r <= db_r[4];

                                        4'd4: sda_r <= db_r[3];

                                        4'd5: sda_r <= db_r[2];

                                        4'd6: sda_r <= db_r[1];

                                        4'd7: sda_r <= db_r[0];

                                        default: ;

                                        endcase

                            //        sda_r <= db_r[4'd7-num];    //送EEPROM地址(高bit开始)        

                                    cstate <= ADD2;                    

                                end

                        end

            //        else if(`SCL_POS) db_r <= {db_r[6:0],1'b0};    //器件地址左移1bit

                    else cstate <= ADD2;                

                end

            ACK2:    begin

                    if(/*!sda*/`SCL_NEG) begin        //从机响应信号

                        if(!sw1_r) begin

                                cstate <= DATA;     //写操作

                                db_r <= `WRITE_DATA;    //写入的数据                            

                            end    

                        else if(!sw2_r) begin

                                db_r <= `DEVICE_READ;    //送器件地址(读操作),特定地址读需要执行该步骤以下操作

                                cstate <= START2;        //读操作

                            end

                        end

                    else cstate <= ACK2;    //等待从机响应

                end

            START2: begin    //读操作起始位

                    if(`SCL_LOW) begin

                        sda_link <= 1'b1;    //sda作为output

                        sda_r <= 1'b1;        //拉高数据线sda

                        cstate <= START2;

                        end

                    else if(`SCL_HIG) begin    //scl为高电平中间

                        sda_r <= 1'b0;        //拉低数据线sda,产生起始位信号

                        cstate <= ADD3;

                        end    

                    else cstate <= START2;

                end

            ADD3:    begin    //送读操作地址

                    if(`SCL_LOW) begin

                            if(num==4'd8) begin    

                                    num <= 4'd0;            //num计数清零

                                    sda_r <= 1'b1;

                                    sda_link <= 1'b0;        //sda置为高阻态(input)

                                    cstate <= ACK3;

                                end

                            else begin

                                    num <= num+1'b1;

                                    case (num)

                                        4'd0: sda_r <= db_r[7];

                                        4'd1: sda_r <= db_r[6];

                                        4'd2: sda_r <= db_r[5];

                                        4'd3: sda_r <= db_r[4];

                                        4'd4: sda_r <= db_r[3];

                                        4'd5: sda_r <= db_r[2];

                                        4'd6: sda_r <= db_r[1];

                                        4'd7: sda_r <= db_r[0];

                                        default: ;

                                        endcase                                    

                                //    sda_r <= db_r[4'd7-num];    //送EEPROM地址(高bit开始)        

                                    cstate <= ADD3;                    

                                end

                        end

                //    else if(`SCL_POS) db_r <= {db_r[6:0],1'b0};    //器件地址左移1bit

                    else cstate <= ADD3;                

                end

            ACK3:    begin

                    if(/*!sda*/`SCL_NEG) begin

                            cstate <= DATA;    //从机响应信号

                            sda_link <= 1'b0;

                        end

                    else cstate <= ACK3;         //等待从机响应

                end

            DATA:    begin

                    if(!sw2_r) begin     //读操作

                            if(num<=4'd7) begin

                                cstate <= DATA;

                                if(`SCL_HIG) begin    

                                    num <= num+1'b1;    

                                    case (num)

                                        4'd0: read_data[7] <= sda;

                                        4'd1: read_data[6] <= sda;

                                        4'd2: read_data[5] <= sda;

                                        4'd3: read_data[4] <= sda;

                                        4'd4: read_data[3] <= sda;

                                        4'd5: read_data[2] <= sda;

                                        4'd6: read_data[1] <= sda;

                                        4'd7: read_data[0] <= sda;

                                        default: ;

                                        endcase                                                                        

                    //                read_data[4'd7-num] <= sda;    //读数据(高bit开始)

                                    end

                //                else if(`SCL_NEG) read_data <= {read_data[6:0],read_data[7]};    //数据循环右移

                                end

                            else if((`SCL_LOW) && (num==4'd8)) begin

                                num <= 4'd0;            //num计数清零

                                cstate <= ACK4;

                                end

                            else cstate <= DATA;

                        end

                    else if(!sw1_r) begin    //写操作

                            sda_link <= 1'b1;    

                            if(num<=4'd7) begin

                                cstate <= DATA;

                                if(`SCL_LOW) begin

                                    sda_link <= 1'b1;        //数据线sda作为output

                                    num <= num+1'b1;

                                    case (num)

                                        4'd0: sda_r <= db_r[7];

                                        4'd1: sda_r <= db_r[6];

                                        4'd2: sda_r <= db_r[5];

                                        4'd3: sda_r <= db_r[4];

                                        4'd4: sda_r <= db_r[3];

                                        4'd5: sda_r <= db_r[2];

                                        4'd6: sda_r <= db_r[1];

                                        4'd7: sda_r <= db_r[0];

                                        default: ;

                                        endcase                                    

                                //    sda_r <= db_r[4'd7-num];    //写入数据(高bit开始)

                                    end

            //                    else if(`SCL_POS) db_r <= {db_r[6:0],1'b0};    //写入数据左移1bit

                                 end

                            else if((`SCL_LOW) && (num==4'd8)) begin

                                    num <= 4'd0;

                                    sda_r <= 1'b1;

                                    sda_link <= 1'b0;        //sda置为高阻态

                                    cstate <= ACK4;

                                end

                            else cstate <= DATA;

                        end

                end

            ACK4: begin

                    if(/*!sda*/`SCL_NEG) begin

//                        sda_r <= 1'b1;

                        cstate <= STOP1;                        

                        end

                    else cstate <= ACK4;

                end

            STOP1:    begin

                    if(`SCL_LOW) begin

                            sda_link <= 1'b1;

                            sda_r <= 1'b0;

                            cstate <= STOP1;

                        end

                    else if(`SCL_HIG) begin

                            sda_r <= 1'b1;    //scl为高时,sda产生上升沿(结束信号)

                            cstate <= STOP2;

                        end

                    else cstate <= STOP1;

                end

            STOP2:    begin

                    if(`SCL_LOW) sda_r <= 1'b1;

                    else if(cnt_20ms==20'hffff0) cstate <= IDLE;

                    else cstate <= STOP2;

                end

            default: cstate <= IDLE;

            endcase

end

assign sda = sda_link ? sda_r:1'bz;

assign dis_data = read_data;

endmodule

 

串口通信的发送机

/********************************版权声明**************************************

** 大西瓜团队

**

**----------------------------文件信息--------------------------

** 文件名称: uart_txd.v

** 创建日期:

** 功能描述:串口通信的发送机

** 硬件平台:大西瓜第三代开发板,http://daxiguafpga.taobao.com

** 版权声明:本代码属个人知识产权,本代码仅供交流学习.

**---------------------------修改文件的相关信息----------------

** 修改人:

** 修改日期:    

** 修改内容:

*******************************************************************************/

module uart_txd(clk,rst,data_bus,host_ready,load_tram_datareg,serial_out);

input clk; //时钟信号

input rst; //复位

input[7:0] data_bus; //数据信号,输入数据总线数据,8bit

input host_ready; //控制信号,为高电平表示主机数据准备完毕

input load_tram_datareg; //控制信号,为高电平表示输入数据寄存器从数据数据总线取数据

output serial_out; //数据信号,UART发送的数据信号

 

 

reg[7:0] tram_datareg; //UART发送数据寄存器

reg[8:0] tram_shiftreg; //UART发送数据移位寄存器

reg load_tram_shiftreg; //装载移位寄存器标志位

reg[1:0] state;

reg[1:0] next_state;

reg[3:0] count;

reg clear; //对count计数器清零

reg shift; //寄存器移位信号

reg start; //开始发送数据信号

 

//三种状态:空闲、等待、发送状态

parameter[1:0] idle=2'b00;

parameter[1:0] waiting=2'b01;

parameter[1:0] sending=2'b10;

 

assign serial_out=tram_shiftreg[0]; //移位寄存器最低位输出

 

always@(posedge clk)

begin

if(!rst)

next_state<=idle;

state=next_state;

case(state)

idle:

begin //空闲

clear=0;

shift=0;

start=0;

if(host_ready)

begin

load_tram_shiftreg<=1;

next_state<=waiting;

end

end

waiting:

begin //等待

start<=1;

next_state<=sending;

end

sending:

begin //发送

if(count!=9)

shift<=1;

else

begin

clear<=1;

next_state<=idle;

end

end

default:next_state<=idle;

endcase

end

always@(posedge clk)

begin

if(!rst)

begin

tram_shiftreg<=9'b1_1111_1111; //移位寄存器内容复位

count<=0;

end

else

begin

if(load_tram_datareg)

tram_datareg<=data_bus; //取数据总线

if(load_tram_shiftreg)

tram_shiftreg<={tram_datareg,1'b1};

if(start)

tram_shiftreg[0]<=0; //开始传输信号,起始位为0

if(clear)

count<=0; //计数器清空

else if(shift)

count<=count+1;

if(shift)

tram_shiftreg<={1'b1,tram_shiftreg[8:1]};

end

end

endmodule

 

串口通讯的波特率选择

/********************************版权声明**************************************

** 大西瓜团队

**

**----------------------------文件信息--------------------------

** 文件名称: speed_select.v

** 创建日期:

** 功能描述:串口通讯的波特率选择,该波特率为9600bit/s

** 操作过程:可以根据通讯所需的波特率修改程序

** 硬件平台:大西瓜第三代开发板,http://daxiguafpga.taobao.com

** 版权声明:本代码属个人知识产权,本代码仅供交流学习.

**---------------------------修改文件的相关信息----------------

** 修改人:

** 修改日期:    

** 修改内容:

*******************************************************************************/

module speed_select(clk,sclk,rst);

input clk;

input rst;

output sclk;

reg sclk;

reg [12:0] count;

 

always@(posedge clk or negedge rst)

begin

if(!rst)

begin

count<=13'b0_0000_0000_0000;

sclk<=1'b0;

end

else

begin

if(count<=5208)

begin

count<=count+13'b0_0000_0000_0001;

if(count<=2604)

sclk<=1'b1;

else

sclk<=1'b0;

end

else

count<=13'b0_0000_0000_0000;

end

end

endmodule

实验操作

本实验中,主要学习使用基于AT24C04的IIC通信协议。实验中,我们使用到了两个按键sw1和sw2,当sw1按下时进行的是写入操作,当sw2按下时进行的是读出操作。在实验中我们添加串口通讯的模块,利用串口调试助手,把我们IIC写入的数据读出后,显示于PC机上。

步骤1:烧入程序,打开串口调试助手。

 

步骤2:按下复位键,再下显示键(实质是让串口发送数据),观察PC机显示结果。

结果显示的数据都为00,因为此时还没有进行写操作 。

 

步骤3:按下写操作键,再按下读操作键,观看PC显示结果。

结果显示的是0xD1 ,这与我们程序发送的数据一致。同学们可以在程序里修改发送数据再观察是否正确。

 

 

 

 

大西瓜FPGA-->https://daxiguafpga.taobao.com

配套开发板:https://item.taobao.com/item.htm?spm=a1z10.1-c.w4004-24211932856.3.489d7241aCjspB&id=633897209972

博客资料、代码、图片、文字等属大西瓜FPGA所有,切勿用于商业! 若引用资料、代码、图片、文字等等请注明出处,谢谢!

   

每日推送不同科技解读,原创深耕解读当下科技,敬请关注微信公众号"科乎"。

标签:SCL,begin,end,17,FPGA,db,else,AT24C04,sda
来源: https://www.cnblogs.com/logic3/p/15915923.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有