转载博客:https://www.cnblogs.com/liujinggang/p/9656358.html
好怕大神有一天给删除了,我先记下来,留备以后查看。
想简洁一些,不然看得时候不知道重点
一.IIC总线协议介绍:
I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据,并且在硬件上都需要接一个上拉电阻到VCC。
各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,这样,各控制电路虽然挂在同一条总线上,却彼此独立,互不相关。
二.IIC的通信状态
总的来说,IIC总线在通信的过程中一共有一下几种状态:
1、空闲状态
IIC 总线的 SDA 和 SCL 两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
2、起始状态和结束状态
在时钟线 SCL 保持高电平期间,数据线 SDA 上的电平被拉低(即负跳变),定义为 I2C 总线总线的起始信号,它标志着一次数据传输的开始。起始信号是由主控器主动建立的,在建立该信号之前 I2C 总线必须处于空闲状态。
在时钟线 SCL 保持高电平期间,数据线 SDA 被释放,使得 SDA 返回高电平(即正跳变),称为 I2C 总线的停止信号,它标志着一次数据传输的终止。停止信号也是由主控器主动建立的,建立该信号之后,I2C 总线将返回空闲状态。
起始信号和结束信号如下图所示
3、有效的数据位传输
在 IIC 总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在 SCL 串行时钟的配合下,数据在 SDA 上从高位向低位依次串行传送每一位的数据。进行数据传送时,在 SCL 呈现高电平期间,SDA 上的电平必须保持稳定,低电平为数据 0,高电平为数据 1。只有在 SCL 为低电平期间,才允许 SDA 上的电平改变状态。下图是0xaa在IIC总线上有效传输(有效传输是指第9个时钟的高电平期间,从机给主机反馈了一个有效的应答位0)的图示
4、应答信号与非应答信号
I2C 总线上的所有数据都是以 8 位字节传送的,发送器(主机)每发送一个字节,就在第9个时钟脉冲期间释放数据线,由接收器(从机)反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。对于反馈有效应答位 ACK 的要求是,接收器在第 9 个时钟脉冲之前的低电平期间将 SDA 线拉低,并且确保在该时钟的高电平期间为稳定的低电平。
对非应答位(NACK)还要特别说明的是,还有以下四种情况IIC通信过程中会产生非应答位:
1、接收器(从机)正在处理某些实时的操作无法与主机实现IIC通信的时候,接收器(从机)会给主机反馈一个非应答位(NACK)
2、主机发送数据的过程中,从机无法解析发送的数据,接收器(从机)也会给主机反馈一个非应答位(NACK)
3、主机发送数据的过程中,从机无法再继续接收数据,接收器(从机)也会给主机反馈一个非应答位(NACK)
4、主机从从机中读取数据的过程中,主机不想再接收数据,主机会给从机反馈一个非应答位(NACK),注意,这种情况是主机给从机反馈一个非应答位(NACK)
关于有效应答位的图示在上一传输0xaa的图中可以清楚的看到,关于非应答位的图示见下图
三.IIC写数据
1、主机通过IIC总线往从机里面写数据
主机通过IIC总线往从机中写数据的时候,主机首先会发送一个起始信号,接着把IIC从机的7位设备地址后面添一个0(设备地址后面的0表示主机向从机写数据,1表示主机从从机中读数据)组成一个8位的数据,把这个8位的数据发给从机,发完这8位的数据以后主机马上释放SDA信号线等待从机的应答,如果从机正确收到这个数据,从机就会发送一个有效应答位0给主机告诉主机自己已经收到了数据,主机收到从机的有效应答位以后 ,接下来主机会发送想要写入的寄存器地址,寄存器发送完毕以后主机同样会释放SDA信号线等待从机的应答,从机如果正确收到了主机发过来的寄存器地址,从机会再次发送一个有效应答位给主机,主机收到从机的有效应答位0以后,接下来主机就会给从机发送想要写入从机的数据,从机正确收到这个数据以后仍然像之前两次一样会给主机发送一个有效应答位,主机收到这个有效应答位以后给从机发送一个停止信号,整个传输过程就结束了。下图是整个传输过程的示意图:
特别注意:上图中灰色的地方表示主机正在控制SDA信号线,白色的地方表示从机正在控制SDA信号线。
四.IIC读数据
1、主机通过IIC总线从从机里面读数据
主机通过IIC总线从从机中读数据的过程与写数据的过程有相似之处,但是读数据的过程还多了一些额外的步骤。主机从从机读数据时主机首先会发送一个起始信号,接着把IIC从机的7位设备地址后面添一个0(设备地址后面的0表示主机向从机写数据,1表示主机从从机中读数据),把这个8位的数据发给从机,发完这8位的数据以后主机马上释放SDA信号线等待从机的应答,如果从机正确收到这个数据,从机就会发送一个有效应答位0给主机告诉主机自己已经收到了数据,主机收到从机的有效应答位以后 ,接下来主机会发送想要读的寄存器地址,寄存器发送完毕以后主机同样会释放SDA信号线等待从机的应答,从机如果正确收到了主机发过来的寄存器地址,从机会再次发送一个有效应答位给主机,主机收到从机的有效应答位0以后,主机会给从机再次发送一次起始信号,接着把IIC从机的7位设备地址后面添一个1(设备地址后面的0表示主机向从机写数据,1表示主机从从机中读数据),注意,第一次是在设备地址后面添0,这一次是在设备地址后面添1,把这个8位的数据发给从机,发完这8位的数据以后主机马上释放SDA信号线等待从机的应答,如果从机正确收到这个数据,从机就会发送一个有效应答位0给主机告诉主机自己已经收到了数据,接着从机继续占用SDA信号线给主机发送寄存器中的数据,发送完毕以后,主机再次占用SDA信号线发送一个非应答信号1给从机,主机发送一个停止信号给从机结束整个读数据的过程。下图是整个读数据过程的示意图
特别注意:上图中灰色的地方表示主机正在控制SDA信号线,白色的地方表示从机正在控制SDA信号线。
五.具体例子
1、编写IIC总线主机给从机发送数据的代码,实现FPGA(主机)往EEPROM(从机)的0x23这个地址写入0x45这个数据
2、编写IIC总线主机从从机接收数据的代码,实现FPGA(主机)从EEPROM(从机)的0x23这个地址读出0x45这个数据,并用0x45这个数据的低四位驱动4个LED
(5.1) IIC发送模块
发送一个字节的数据之前必须要先发送起始位,然后发送控制字节,接着等待应答,然后在发送字地址,接着在等待应答。数据发送完毕以后,在等待最后一个应答,应答成功后发送停止信号结束整个过程。
抓到的时序图:
为了更清晰的说明上面的时序,我把起始信号,停止信号,每个比特以及应答位全部框出来进一步解释如下:
(5.2) IIC接收模块
接收一个字节的数据的过程与发送一个字节数据相比多了一个第二次的起始信号与控制字节(CONTROL BYTE),而且第二个控制字节(CONTROL BYTE)的最低位应该为1,表示IIC主机(FPGA)从IIC从机(24LC04)中读数据,当主机(FPGA)想结束读数据的过程时,它会给IIC设备发送一个非应答位1,最后在发送停止信号结束整个读数据的过程。
由于EEPROM是一种非易失性存储器,所以做在IIC发送数据的实验中往24LC04的0x23地址中的0x45这个数据在掉电以后并不会丢失。刚好可以通过这个接收模块给读出来,并用读出数据的最低位驱动四个LED灯,如果时序正确的话,四个LED灯会间隔亮起来。下面是我抓到的接收数据时序图:
通过上面的时序图可以清楚的看到成功读出了EEPROM中的0x45这个数据,并且我板子上的四个LED灯也间隔亮了起来。
为了更清晰的说明上面的时序,我把起始信号,停止信号,每个比特,应答位和非应答位全部框出来进一步解释如下:
(8)总结
总结一下,最主要的图。文字必须读,当然要配合着图来读。