• 进阶项目(9)IIC通信协议程序设计讲解


    写在前面的话

    IIC的通信协议和通信接口在很多工程中有广泛的应用,如数据采集领域的串行AD,图像处理领域的摄像头配置,工业控制领域的X射线管配置等等。除此之外,由于IIC协议占用的IO资源特别少,连接方便,所以工程中也常选用IIC接口做为不同芯片间的通信协议。

    IIC协议的完成靠的是严紧的时序,一个周期都不能错,这也正是梦翼师兄设置本实验的目的。通过IIC的学习,锻炼大家的时序实现技巧和方法,可以说最佳的案例之一。

    项目需求

    设计IIC接口的驱动电路可以实现单字节数据的读写。

    IIC的原理分析

    本实验,我们采用的外部接口芯片为EEPROM 24LC64,其封装图如下:

    接下来,我们梳理一下各引脚定义:

    A0,A1,A2为24LC64的片选信号,由于IIC总线可以挂载多个IIC接口器件,所以每个器件都应该有自己的“身份标识”,通过对A0,A1,A2输入不同的高低电平,就可以设置该EEPROM的片选信号。

    WP为读写使能信号,当WP悬空或者接地,EEPROM可读可写,当WP接电源,EEPROM只能读不能写。

    SCL为IIC接口的时钟线(根据不同的配置方式,scl的频率是可以改变的,我们采取200K)

    SDA为IIC接口的数据线

    得到了上面的配置信息,那么接下来,看一下我们开发板的配置原理图

    由此可以看出我们的位选信号为“000”,EEPROM可读写。而我们最需要关心的,就是SCL和SDA两条线的时序关系。

    原理图分析完毕,接下来我们学习一下IIC接口的具体时序是什么。IIC读写时序分为随机读写和页面读写,也就是常说的Byte Write/Read 和Page Write/Read。

    我们首先来学习Byte Write/Read时序。Byte Write时序如下:

    由时序图可以看出,如果我们要向EEPROM写入一个字节,那么必须经过以下步骤:

    发送启动信号

    发送控制字

    接收并检测EEPROM发来的应答信号ACK

    发送高字节地址位

    接收并检测EEPROM发来的应答信号ACK

    发送低字节地址位

    接收并检测EEPROM发来的应答信号ACK

    发送8bit有效数据

    接收并检测EEPROM发来的应答信号ACK

    10.发送停止信号

    Byte Read时序如下:

     

    由时序图可以看出,如果我们要从EEPROM读出一个字节,那么必须经过以下步骤:

    1. 发送启动信号

    1. 发送控制字1010_0000
    2. 接收并检测EEPROM发来的应答信号ACK
    3. 发送高字节地址位
    4. 接收并检测EEPROM发来的应答信号ACK
    5. 发送低字节地址位
    6. 接收并检测EEPROM发来的应答信号ACK
    7. 发送启动信号
    8. 发送控制字1010_0001
    9. 接收并检测EEPROM发来的应答信号ACK
    10. 读取一个字节数据
    11. 发送NO ACK信号
    12. 发送停止信号

    那么现在的问题就变成了每个步骤的意义到底是什么呢?各位且听我慢慢道来。

    1.启动信号

     

    SCL保持高电平期间,如果SDA出现由高到低的跳变沿,代表启动信号

    2.控制字

    我们的控制字为1010_0000或1010_0001,其中1010为EEPROM的型号标识,为一组固定的序列,紧接着A2,A1,A0就是我们的片选信号,最后一位为读写控制位,低电平代表写,高电平代表读,我们这里首先需要对EEPROM写入地址位,所以我们最后一位为0。当我们需要读数据时,最后一位为1。

    /低位地址

    由于24LC64有64Kbit的存储空间,所以我们需要13位的地址位宽才能寻址所有的存储空间,由于IIC协议规定只能以字节形式写入,所以必须将13位的地址扩展为16位的地址,分为高八位和低八位,多出来的前三位填充任意数据即可,对我们的寻址地址没有影响。

    3.停止信号

     

    SCL保持高电平期间,如果SDA出现由低到高的跳变沿,代表停止信号

    4.应答信号ACK

    应答信号是由数据接收方发出的,当SCL为高电平期间,如果监测到SDA为低电平,说明有应答信号。

    5.非应答信号NO ACK

    非应答信号也是由数据接收方发出的,当SCL为高电平期间,如果SDA为高电平,说明有非应答信号。

    由于IIC总线协议启动和停止信号都是在SCL高电平期间发生跳变(当不发送或者接收数据的时候scl一直为高电平),这就决定了我们其他数据的改变只能发生在SCL低电平期间,在SCL为高电平期间,数据必须保持稳定。即在SCL低电平改变数据,在SCL高电平采集数据。

    由于读时序和写时序一直到低字节地址的写入之前都是相同的,因此我们设置IIC控制器流程图如下:

    接下来,我们来学习Page Write/Read时序

    Page Write时序如下:

     

    Page Read时序如下:

    由此可以看出,页面读写比随机读写只是多加了几个状态而已,在我们前面设计的基础上加几个状态就可以完成。梦翼师兄把这部分交给大家去发挥。

    架构设计

    根据原理分析,我们设计出架构图如下:

    模块功能介绍

    模块名

    功能描述

    IIC

    iic总线的驱动

    顶层模块端口描述

    端口名

    端口说明

    clk

    系统时钟输入

    rst_n

    系统复位

    key_wr

    写信号(低电平有效)

    key_rd

    读信号(低电平有效)

    data_in[7:0]

    输入数据

    scl

    iic的时钟线

    sda

    iic的数据线

    data_out[7:0]

    输出数据

    代码解释


    iic模块代码

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

     *   Engineer      :   梦翼师兄

     *   QQ             :   761664056

     *   The module function: 产生iic总线的控制信号

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

    000 module iic( 

    001             clk, //外部输入时钟

    002             rst_n,//系统复位

    003             key_wr,//写信号(低电平有效)

    004             key_rd, //读信号(低电平有效)

    005             data_in, //输入数据

    006             scl, //iic的数据线

    007             sda, //iic的时钟线

    008             data_out//输出数据

    009         );

    010     //系统输入

    011     input clk;//外部输入时钟

    012     input rst_n;//系统复位

    013     input key_wr;//写信号(低电平有效)

    014     input key_rd;//读信号(低电平有效)

    015     input [7:0] data_in;//输入数据

    016     //系统输出

    017     output reg scl;//iic的时钟线

    018     output reg [7:0] data_out;//输出数据

    019     

    020     inout sda; //iic的数据线

    021     

    022     reg sda_buffer;//写入数据的中间寄存器

    023     reg flag;//控制系统是否占有总线控制权

    024     

    025     assign sda = (flag) ? sda_buffer : 1'bz;//flag为高电平时,系统拥有总线控制权

    026                                             //并发送sda_buffer中的数据。当flag为低电平时,

    027                                             //释放总线。

    028     

    029     reg [7:0] count;//计数器

    030     reg clk_sys;//系统时钟

    031 //-------------------------------clk_sys

    032     always @ (posedge clk or negedge rst_n)

    033     begin

    034         if (!rst_n)

    035             begin

    036                 clk_sys <= 1'b0;

    037                 count <= 8'd0;

    038             end

    039         else

    040             if (count < 31)//分频成为近800K的时钟

    041                 count <= count + 1;

    042             else

    043                 begin

    044                     count <= 8'd0;

    045                     clk_sys <= ~clk_sys;

    046                 end

    047     end

    048 //-------------------------------   

    049

    050     reg [5:0] state;//状态寄存器

    051

    052 //--------------------------------scl

    053     always @ (negedge clk_sys or negedge rst_n)

    054     begin

    055         if (!rst_n)

    056             begin

    057                 scl <= 1'b1;//复位时,scl为高

    058             end

    059         else

    060             begin

    061                 if (state > 0)//当总线忙的时候,scl为近400K的时钟

    062                     scl <= ~scl;

    063                 else

    064                     scl <= 1'b1;//空闲时,scl为高

    065             end

    066     end

    067 //----------------------------------

    068

    069     reg [1:0] en;//读写使能中间寄存器

    070

    071 //----------------------------------enable

    072     always @ (posedge clk or negedge rst_n)

    073     begin

    074         if (!rst_n)

    075             begin

    076                 en <= 2'b00;//复位时,将中间寄存器置0

    077             end

    078         else

    079             begin

    080                 if (!key_wr)//写有效时

    081                     en <= 2'b01;

    082                 else

    083                     if (!key_rd)//写无效,读有效时

    084                         en <= 2'b10;

    085             end

    086     end

    087 //---------------------------------

    088     

    089     reg [3:0] cnt;//发送或者接收数据的个数

    090     reg [1:0] temp;//读写使能的中间寄存器

    091     reg [7:0] memory;//发送或者接受数据的中间寄存器

    092

    093 always @ (posedge clk_sys or negedge rst_n)

    094     begin

    095         if (!rst_n)

    096             begin

    097                 data_out <= 8'd0;

    098                 flag <= 1'b1;       //复位时,系统获得总线的控制权

    099                 sda_buffer <= 1'b1; //iic的数据线上发送高电平

    100                 state <= 0;

    101                 temp <= 2'b00;

    102             end

    103         else    

    104             case(state)

    105                     0 : begin   

    106                         if(scl)

    107                             begin

    108                                 if(en != temp)//有按键按下

    109                                     begin

    110                                         sda_buffer <= 1'b0;//发送启动信号

    111                                         state <= 1;

    112                                         temp <= en;//将读写信号保存

    113                                         memory <= 8'b10100000;//控制字

    114                                     end

    115                                 else

    116                                     state <= 0;

    117                             end

    118                         else

    119                                 state <= 0;

    120                     end

    121                     

    122                     1 : begin    

    123                         if((scl == 0) && (cnt < 8))//发送八位控制字

    124                             begin

    125                                 sda_buffer <= memory[7];

    126                                 cnt <= cnt + 1;

    127                                 memory = {memory[6:0],memory[7]};

    128                                 state <= 1;

    129                             end

    130                         else

    131                             begin

    132                                 if ((scl == 0) && (cnt == 8))

    133                                     begin

    134                                         cnt <= 0;

    135                                         flag <= 0;//释放总线控制权

    136                                         state <= 2;

    137                                     end

    138                                 else

    139                                     begin

    140                                         state <= 1;

    141                                     end

    142                             end

    143                     end

    144                 2 : begin  

    145                         if(!sda)//检测应答信号

    146                             begin

    147                                 state <= 3;

    148                                 memory <= 8'd0;//高字节地址

    149                             end

    150                         else

    151                             begin

    152                                 state <= 0;

    153                             end

    154                     end

    155                     3 : begin  //发送高字节地址

    156                             if((scl == 0) && (cnt < 8))

    157                             begin

    158                                 flag <= 1;//获得总线控制权

    159                                 sda_buffer <= memory[7];

    160                                 cnt <= cnt + 1;

    161                                 memory = {memory[6:0],memory[7]};

    162                                 state <= 3;

    163                             end

    164                         else

    165                             begin

    166                                 if ((scl == 0) && (cnt == 8))

    167                                     begin

    168                                         cnt <= 0;

    169                                         flag <= 0;//释放总线控制权

    170                                         state <= 4;

    171                                     end

    172                                 else

    173                                     begin

    174                                         state <= 3;

    175                                     end

    176                             end

    177                     end

    178                     4 : begin  

    179                         if(!sda)//检测应答信号

    180                             begin

    181                                 state <= 5;

    182                                 memory <= 8'h00;//低字节地址

    183                             end

    184                         else

    185                             begin

    186                                 state <= 0;

    187                             end

    188                     end

    189                     5 : begin  

    190                             if((scl == 0) && (cnt < 8))//发送低字节地址

    191                             begin

    192                                 flag <= 1;//获得总线控制权

    193                                 sda_buffer <= memory[7];

    194                                 cnt <= cnt + 1;

    195                                 memory = {memory[6:0],memory[7]};

    196                                 state <= 5;

    197                             end

    198                         else

    199                             begin

    200                                 if ((scl == 0) && (cnt == 8))

    201                                     begin

    202                                         cnt <= 0;

    203                                         flag <= 0;//释放总线控制权

    204                                         state <= 6;

    205                                     end

    206                                 else

    207                                     begin

    208                                         state <= 5;

    209                                     end

    210                             end

    211                     end 

    212                     6 : begin  

    213                         if(!sda)//检测应答信号

    214                             begin

    215                                 if (temp == 2'b01)//判断是否为写信号

    216                                     begin

    217                                         state <= 7;

    218                                         memory <= data_in[7:0];//发送数据

    219                                     end

    220                                 if (temp == 2'b10)//判断是否为读信号

    221                                     state <= 11;    

    222                             end

    223                         else

    224                             begin

    225                                 state <= 0;

    226                             end

    227                     end

    228                     

    229                     7 : begin 

    230                         if((scl == 0) && (cnt < 8))//发送数据

    231                             begin

    232                                 flag <= 1;//获得总线控制权

    233                                 sda_buffer <= memory[7];

    234                                 cnt <= cnt + 1;

    235                                 memory <= {memory[6:0],memory[7]};

    236                                 state <= 7;

    237                             end

    238                         else

    239                             begin

    240                                 if ((scl == 0) && (cnt == 8))

    241                                     begin

    242                                         cnt <= 0;

    243                                         flag <= 0;//释放总线控制权

    244                                         state <= 8;

    245                                     end

    246                                 else

    247                                     begin

    248                                         state <= 7;

    249                                     end

    250                             end

    251                     end

    252                     8 : begin 

    253                         if(!sda)//检测应答信号

    254                             begin

    255                                 state <= 9;

    256                             end

    257                         else

    258                             begin

    259                                 state <= 0;

    260                             end

    261                     end

    262                     9 : begin   

    263                             if (scl == 0)

    264                                 begin

    265                                     flag <= 1;//获得总线控制权

    266                                     sda_buffer <= 0;//拉低iic的数据线(为发送停止信号做准备)

    267                                     state <= 10;

    268                                 end

    269                             else

    270                                 state <= 9;

    271                         end

    272                     10 : begin                          

    273                             if (scl == 1)

    274                                 begin

    275                                     sda_buffer <= 1;//发送停止信号

    276                                     state <= 0;

    277                                 end

    278                             else

    279                                 state <= 10;

    280                         end

    281                     //-----------------------------------------

    282                     

    283                     //-------

    284                     11 : begin       

    285                         flag <= 1;//获得总线控制权

    286                         sda_buffer <= 1;//拉高iic的数据线(为发送启动信号做准备)

    287                         state <= 12;

    288                     end

    289                     12 : begin        

    290                         sda_buffer <= 0;//发送启动信号

    291                         state <= 13;

    292                         memory <= 8'b10100001;  //控制字

    293                     end

    294                     13 : begin           

    295                         if((scl == 0) && (cnt < 8))//发送八位控制字

    296                             begin

    297                                 flag <= 1;//获得总线控制权

    298                                 sda_buffer <= memory[7];

    299                                 cnt <= cnt + 1;

    300                                 memory <= {memory[6:0],memory[7]};

    301                                 state <= 13;

    302                             end

    303                         else

    304                             begin

    305                                 if ((scl == 0) && (cnt == 8))

    306                                     begin

    307                                         cnt <= 0;

    308                                         flag <= 0;//释放总线控制权

    309                                         state <= 14;

    310                                     end

    311                                 else

    312                                     begin

    313                                         state <= 13;

    314                                     end

    315                             end

    316                     end

    317                     14 : begin  

    318                         if(!sda)//检测应答信号

    319                             begin

    320                                 state <= 15;

    321                             end

    322                         else

    323                             begin

    324                                 state <= 0;

    325                             end

    326                     end

    327                     15 : begin  

    328                         if((scl == 1) && (cnt < 8))//接收数据

    329                             begin

    330                                 cnt <= cnt + 1;

    331                                 memory <= {memory[6:0],sda};

    332                                 state <= 15;

    333                             end

    334                         else

    335                             begin

    336                                 if ((scl == 0) && (cnt == 8))

    337                                     begin

    338                                         cnt <= 0;

    339                                         flag <= 1;//获得总线控制权

    340                                         state <= 16;

    341                                         sda_buffer <= 1;//发送应答信号        

    342                                     end

    343                                 else

    344                                     state <= 15;

    345                             end

    346                     end

    347                     16 : begin

    348                         data_out <= memory;//输出数据

    349                         state <= 17;

    350                     end

    351                     17 : begin

    352                         if (scl == 0)

    353                             begin   

    354                                 sda_buffer <= 0;//拉低iic的数据线(为发送停止信号做准备)

    355                                 state <= 18;

    356                             end

    357                         else

    358                             state <= 17;

    359                         end

    360                     18 : begin   //发送停止信号

    361                         if (scl == 1)

    362                             begin

    363                                 sda_buffer <= 1;

    364                                 state <= 0;

    365                             end

    366                         else

    367                             state <= 18;

    368                     end

    369

    370                 default : state <= 0 ;

    371                 endcase

    372     end

    373

    374 endmodule 

    112行,将读写信号保存起来是为了读写的时候只进行一次的读写。(按键按下的时间一般大于20ms,如果不进行处理,系统将重复的向同一个地址中写入或者读出数据)。

    我们把13位地址给定了一个确定的数据,并没有通过外部发送给系统,这样可以降低我们理解的难度。有兴趣的同学可以自己尝试一下其他的地址控制方式。

    上述代码在下板实测时可用,仿真时则不能用。在我们的设计中,多次检测应答信号,但是仿真过程中没有真实的器件反馈应答信号,就会导致我们的仿真出错。仿真时应把所有的应答信号直接跳过,如下:

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

     *   Engineer      :   梦翼师兄

     *   QQ             :   761664056

     *   The module function: 产生iic总线的控制信号

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

    000 module iic( 

    001             clk, //外部输入时钟

    002             rst_n,//系统复位

    003             key_wr,//写信号(低电平有效)

    004             key_rd, //读信号(低电平有效)

    005             data_in, //输入数据

    006             scl, //iic的数据线

    007             sda, //iic的时钟线

    008             data_out//输出数据

    009         );

    010     //系统输入

    011     input clk;//外部输入时钟

    012     input rst_n;//系统复位

    013     input key_wr;//写信号(低电平有效)

    014     input key_rd;//读信号(低电平有效)

    015     input [7:0] data_in;//输入数据

    016     //系统输出

    017     output reg scl;//iic的时钟线

    018     output reg [7:0] data_out;//输出数据

    019     

    020     inout sda; //iic的数据线

    021     

    022     reg sda_buffer;//写入数据的中间寄存器

    023     reg flag;//控制系统是否占有总线控制权

    024     

    025     assign sda = (flag) ? sda_buffer : 1'bz;//flag为高电平时,系统拥有总线控制权

    026                                             //并发送sda_buffer中的数据。当flag为低电平时,

    027                                             //释放总线。

    028     

    029     reg [7:0] count;//计数器

    030     reg clk_sys;//系统时钟

    031 //-------------------------------clk_sys

    032     always @ (posedge clk or negedge rst_n)

    033     begin

    034         if (!rst_n)

    035             begin

    036                 clk_sys <= 1'b0;

    037                 count <= 8'd0;

    038             end

    039         else

    040             if (count < 31)//分频成为近800K的时钟

    041                 count <= count + 1;

    042             else

    043                 begin

    044                     count <= 8'd0;

    045                     clk_sys <= ~clk_sys;

    046                 end

    047     end

    048 //-------------------------------   

    049

    050     reg [5:0] state;//状态寄存器

    051

    052 //--------------------------------scl

    053     always @ (negedge clk_sys or negedge rst_n)

    054     begin

    055         if (!rst_n)

    056             begin

    057                 scl <= 1'b1;//复位时,scl为高

    058             end

    059         else

    060             begin

    061                 if (state > 0)//当总线忙的时候,scl为近400K的时钟

    062                     scl <= ~scl;

    063                 else

    064                     scl <= 1'b1;//空闲时,scl为高

    065             end

    066     end

    067 //----------------------------------

    068

    069     reg [1:0] en;//读写使能中间寄存器

    070

    071 //----------------------------------enable

    072     always @ (posedge clk or negedge rst_n)

    073     begin

    074         if (!rst_n)

    075             begin

    076                 en <= 2'b00;//复位时,将中间寄存器置0

    077             end

    078         else

    079             begin

    080                 if (!key_wr)//写有效时

    081                     en <= 2'b01;

    082                 else

    083                     if (!key_rd)//写无效,读有效时

    084                         en <= 2'b10;

    085             end

    086     end

    087 //---------------------------------

    088     

    089     reg [3:0] cnt;//发送或者接收数据的个数

    090     reg [1:0] temp;//读写使能的中间寄存器

    091     reg [7:0] memory;//发送或者接受数据的中间寄存器

    092

    093 always @ (posedge clk_sys or negedge rst_n)

    094     begin

    095         if (!rst_n) begin

    096                 cnt <= 0;

    097                 data_out <= 8'd0;

    098                 flag <= 1'b1;       //复位时,系统获得总线的控制权

    099                 sda_buffer <= 1'b1; //iic的数据线上发送高电平

    100                 state <= 0;

    101                 temp <= 2'b00;

    102             end

    103         else    

    104             case(state)

    105                     0 : begin   

    106                         if(scl)

    107                             begin

    108                                 if(en != temp)//有按键按下

    109                                     begin

    110                                         sda_buffer <= 1'b0;//发送启动信号

    111                                         state <= 1;

    112                                         temp <= en;//将读写信号保存

    113                                         memory <= 8'b10100000;//控制字

    114                                     end

    115                                 else

    116                                     state <= 0;

    117                             end

    118                         else

    119                                 state <= 0;

    120                     end

    121                     

    122                     1 : begin    

    123                         if((scl == 0) && (cnt < 8))//发送八位控制字

    124                             begin

    125                                 sda_buffer <= memory[7];

    126                                 cnt <= cnt + 1;

    127                                 memory = {memory[6:0],memory[7]};

    128                                 state <= 1;

    129                             end

    130                         else

    131                             begin

    132                                 if ((scl == 0) && (cnt == 8))

    133                                     begin

    134                                         cnt <= 0;

    135                                         flag <= 0;//释放总线控制权

    136                                         state <= 2;

    137                                     end

    138                                 else

    139                                     begin

    140                                         state <= 1;

    141                                     end

    142                             end

    143                     end

    144                 2 : begin  

    145 //                      if(!sda)//检测应答信号

    146 //                          begin

    147                                 state <= 3;

    148                                 memory <= 8'd0;//高字节地址

    149 //                          end

    150 //                      else

    151 //                          begin

    152 //                              state <= 0;

    153 //                          end

    154                     end

    155                     3 : begin  //发送高字节地址

    156                             if((scl == 0) && (cnt < 8))

    157                             begin

    158                                 flag <= 1;//获得总线控制权

    159                                 sda_buffer <= memory[7];

    160                                 cnt <= cnt + 1;

    161                                 memory = {memory[6:0],memory[7]};

    162                                 state <= 3;

    163                             end

    164                         else

    165                             begin

    166                                 if ((scl == 0) && (cnt == 8))

    167                                     begin

    168                                         cnt <= 0;

    169                                         flag <= 0;//释放总线控制权

    170                                         state <= 4;

    171                                     end

    172                                 else

    173                                     begin

    174                                         state <= 3;

    175                                     end

    176                             end

    177                     end

    178                     4 : begin  

    179 //                      if(!sda)//检测应答信号

    180 //                          begin

    181                                 state <= 5;

    182                                 memory <= 8'h00;//低字节地址

    183 //                          end

    184 //                      else

    185 //                          begin

    186 //                              state <= 0;

    187 //                          end

    188                     end

    189                     5 : begin  

    190                             if((scl == 0) && (cnt < 8))//发送低字节地址

    191                             begin

    192                                 flag <= 1;//获得总线控制权

    193                                 sda_buffer <= memory[7];

    194                                 cnt <= cnt + 1;

    195                                 memory = {memory[6:0],memory[7]};

    196                                 state <= 5;

    197                             end

    198                         else

    199                             begin

    200                                 if ((scl == 0) && (cnt == 8))

    201                                     begin

    202                                         cnt <= 0;

    203                                         flag <= 0;//释放总线控制权

    204                                         state <= 6;

    205                                     end

    206                                 else

    207                                     begin

    208                                         state <= 5;

    209                                     end

    210                             end

    211                     end 

    212                     6 : begin  

    213 //                      if(!sda)//检测应答信号

    214 //                          begin

    215                                 if (temp == 2'b01)//判断是否为写信号

    216                                     begin

    217                                         state <= 7;

    218                                         memory <= data_in[7:0];//发送数据

    219                                     end

    220                                 if (temp == 2'b10)//判断是否为读信号

    221                                     state <= 11;    

    222 //                          end

    223 //                      else

    224 //                          begin

    225 //                              state <= 0;

    226 //                          end

    227                     end

    228                     

    229                     7 : begin 

    230                         if((scl == 0) && (cnt < 8))//发送数据

    231                             begin

    232                                 flag <= 1;//获得总线控制权

    233                                 sda_buffer <= memory[7];

    234                                 cnt <= cnt + 1;

    235                                 memory <= {memory[6:0],memory[7]};

    236                                 state <= 7;

    237                             end

    238                         else

    239                             begin

    240                                 if ((scl == 0) && (cnt == 8))

    241                                     begin

    242                                         cnt <= 0;

    243                                         flag <= 0;//释放总线控制权

    244                                         state <= 8;

    245                                     end

    246                                 else

    247                                     begin

    248                                         state <= 7;

    249                                     end

    250                             end

    251                     end

    252                     8 : begin 

    253 //                      if(!sda)//检测应答信号

    254 //                          begin

    255                                 state <= 9;

    256 //                          end

    257 //                      else

    258 //                          begin

    259 //                              state <= 0;

    260 //                          end

    261                     end

    262                     9 : begin   

    263                             if (scl == 0)

    264                                 begin

    265                                     flag <= 1;//获得总线控制权

    266                                     sda_buffer <= 0;//拉低iic的数据线(为发送停止信号做准备)

    267                                     state <= 10;

    268                                 end

    269                             else

    270                                 state <= 9;

    271                         end

    272                     10 : begin                          

    273                             if (scl == 1)

    274                                 begin

    275                                     sda_buffer <= 1;//发送停止信号

    276                                     state <= 0;

    277                                 end

    278                             else

    279                                 state <= 10;

    280                         end

    281                     //-----------------------------------------

    282                     

    283                     //-------

    284                     11 : begin       

    285                         flag <= 1;//获得总线控制权

    286                         sda_buffer <= 1;//拉高iic的数据线(为发送启动信号做准备)

    287                         state <= 12;

    288                     end

    289                     12 : begin        

    290                         sda_buffer <= 0;//发送启动信号

    291                         state <= 13;

    292                         memory <= 8'b10100001;  //控制字

    293                     end

    294                     13 : begin           

    295                         if((scl == 0) && (cnt < 8))//发送八位控制字

    296                             begin

    297                                 flag <= 1;//获得总线控制权

    298 sda_buffer <= memory[7];

    299 cnt <= cnt + 1;

    300 memory <= {memory[6:0],memory[7]};

    301 state <= 13;

    302 end

    303 else

    304 begin

    305 if ((scl == 0) && (cnt == 8))

    306 begin

    307 cnt <= 0;

    308 flag <= 0;//释放总线控制权

    309 state <= 14;

    310 end

    311 else

    312 begin

    313 state <= 13;

    314 end

    315 end

    316 end

    317 14 : begin  

    318 // if(!sda)//检测应答信号

    319 // begin

    320 state <= 15;

    321 // end

    322 // else

    323 // begin

    324 // state <= 0;

    325 // end

    326 end

    327 15 : begin  

    328 if((scl == 1) && (cnt < 8))//接收数据

    329 begin

    330 cnt <= cnt + 1;

    331 memory <= {memory[6:0],sda};

    332 state <= 15;

    333 end

    334 else

    335 begin

    336 if ((scl == 0) && (cnt == 8))

    337 begin

    338 cnt <= 0;

    339 flag <= 1;//获得总线控制权

    340 state <= 16;

    341 sda_buffer <= 1;//发送应答信号

    342 end

    343 else

    344 state <= 15;

    345 end

    346 end

    347 16 : begin

    348 data_out <= memory;//输出数据

    349 state <= 17;

    350 end

    351 17 : begin

    352 if (scl == 0)

    353 begin

    354 sda_buffer <= 0;//拉低iic的数据线(为发送停止信号做准备)

    355 state <= 18;

    356 end

    357 else

    358 state <= 17;

    359 end

    360 18 : begin   //发送停止信号

    361 if (scl == 1)

    362 begin

    363 sda_buffer <= 1;

    364 state <= 0;

    365 end

    366 else

    367 state <= 18;

    368 end

    369

    370 default : state <= 0 ;

    371 endcase

    372 end

    373

    374 endmodule

    仿真代码

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

     *   Engineer      :   梦翼师兄

     *   QQ             :   761664056

     *   The module functioniic测试模块

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

    00 `timescale 1ns/1ps

    01

    02 module iic_tb;

    03 //系统输入

    04 reg clk;//外部输入时钟

    05 reg rst_n;//系统复位

    06 reg key_wr;//写信号(低电平有效)

    07 reg key_rd;//读信号(低电平有效)

    08 reg [7:0] data_in;//输入数据

    09 //系统输出

    10 wire scl;//iic的时钟线

    11 wire [7:0] data_out;//输出数据

    12 wire sda; //iic的数据线

    13

    14 iic iic_inst(

    15 .clk(clk), //外部输入时钟

    16 .rst_n(rst_n), //系统复位

    17 .key_wr(key_wr), //写信号(低电平有效)

    18 .key_rd(key_rd), //读信号(低电平有效)

    19 .scl(scl), //iic的时钟

    20 .sda(sda), //iic的数据线

    21 .data_in(data_in),//输入数据

    22 .data_out(data_out)//输出数据

    23 );

    24

    25 initial begin

    26 clk = 1;

    27 rst_n = 0;

    28 key_wr = 1;

    29 key_rd = 1;

    30 data_in = 0;

    31 #1000.1 rst_n = 1;

    32 # 800

    33 #8000 key_wr = 0;//写信号有效

    34 data_in = 8'h23;//输入数据为8’h23

    35 #40000 key_wr = 1;//写信号释放

    36

    37 #1000000

    38 key_rd = 0;//读信号有效

    39 #40000 key_rd = 1;//读写号释放

    40 end

    41

    42 always #10 clk=~clk; //50M的时钟

    43

    44 endmodule

    仿真分析

    1. 发送启动信号
    2. 发送控制字
    3. 接收并检测EEPROM发来的应答信号ACK
    4. 发送高字节地址位
    5. 接收并检测EEPROM发来的应答信号ACK
    6. 发送低字节地址位
    7. 接收并检测EEPROM发来的应答信号ACK
    8. 发送8bit有效数据
    9. 接收并检测EEPROM发来的应答信号ACK
    10. 发送停止信号

    经过一步一步的查看,我们的设计时序是正确的。

    1. 发送启动信号
    2. 发送控制字1010_0000
    3. 接收并检测EEPROM发来的应答信号ACK
    4. 发送高字节地址位
    5. 接收并检测EEPROM发来的应答信号ACK
    6. 发送低字节地址位
    7. 接收并检测EEPROM发来的应答信号ACK
    8. 发送启动信号
    9. 发送控制字1010_0001
    10. 接收并检测EEPROM发来的应答信号ACK
    11. 读取一个字节数据
    12. 发送NO ACK信号
    13. 发送停止信号

     读写的波形与iic原理中的读写时序图一致,证明我们的设计是正确的。




  • 相关阅读:
    word无法启动转换器RECOVR32.CNV
    win10致远OA显示正在转换。请稍等,不能获取office文件转换服务
    视频编辑剪辑软件
    软件质量属性——可修改性
    《架构之美》阅读笔记五
    架构漫谈一
    《架构之美》阅读笔记三
    《架构之美》阅读笔记二
    机器学习七讲——最优化
    机器学习六讲——降维
  • 原文地址:https://www.cnblogs.com/mengyi1989/p/11521054.html
Copyright © 2020-2023  润新知