目录
I2C通信协议:
(同步,半双工,带应答,一主多从,多主多从)
通信线:
SCL:串行时钟线
SDA:串行数据线(发+收)
所有I2C设备的SCL连在一起,SDA连在一起,均要配置成开漏输出(防止电源短路)。
各添加一个上拉电阻,4.7K左右。
时序:
起始条件:SCL高电平期间,SDA从高电平切换到低电平。
终止条件:SCL高电平期间,SDA从低电平切换到高电平。
SCL低电平:放置(变换)数据。 SCL高电平:读取数据。 |
发送一个字节:
SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),
然后释放SCL(置高电平),从机将在SCL高电平期间读取数据位
所以SCL高电平期间SDA不允许有数据变化,循环上述过程8次
即可发送一个字节。
接收一个字节:
SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),
然后释放SCL(置高电平),主机将在SCL高电平期间读取数据位
所以SCL高电平期间SDA不允许有数据变化,循环上述过程8次
即可接收一个字节(主机在接收之前,主机需要释放SDA,若不释放,不论从机发送什 么,SDA始终都是低电平)。
应答机制:
发送应答:主机接收完一个字节后,在下个时钟发送一位数据,数据0表示
应答,1表示非应答。
接收应答:主机发送完一个字节后,在下个时钟接收一位数据,判断从机
是否应答,数据0表示应答,1表示非应答(主机在接收之前,
主机需要释放SDA)。
从机设备地址:
主机根据从机的地址与从机通信。
在I2C协议里,分为7位和10位地址,大多使用7位。每个设备出厂时,都会被分配一个地址。若相同芯片接同一个总线,可手动改变(改变从机某个引脚的电平)最后几位地址。
-
指定地址写:
对于指定设备,在指定地址下写入指定数据。
首先进行起始时序,SCL高电平期间,主机拉低SDA。起始时序之后,必须是发送一个字节的时序,字节内容:从机地址位(7位:1101000)+读写位(1位)=8位。
(入图所示:字节内容转化为16进制,高位先行,即11010000转变为0xD0.
读写位:0表示之后主机进行写操作。1表示之后主机进行读操作。)
紧跟着,就是接收从机的应答位(RA):主机释放SDA,从机立刻拉低SDA,所以RA=0。SCL高电平期间,主机读取SDA ,发现是0,代表从机产生了应答。
由于之前读写位为0,所以主机继续发送字节,可送到从机内部。00011001即主机向从机发送了0x19这个数据。(操作MPU60500的x19寄存器)
第三个字节,10101010即主机将0xAA写入0x19寄存器。
最后产生终止时序,先拉低SDA,然后释放SCL,主机在SCL高电平期间,拉高SDA。
总结: 对于指定设备(地址为1101000),在指定地址(其内部0x19寄存器)下写入指定数据(0xAA)。
当前地址读:
对于指定设备,在当前地址指针指示的地址下,读取从机数据。
参考“指定地址写”的内容,产生起始时序。第一个字节:从机地址(1101000)+读写位(1:读)。产生应答。开始接收一个字节的时序:从机在SCL低电平期间,写入SDA。主机在SCL高电平期间,读取SDA,00001111即0x0F。
那么就产生一个问题:0x0F是从机的哪个寄存器的内容呢,主机寻址之后立马开始读的操作,并没有指定读哪个寄存器。 解决问题的关键在于当前地址指针:在从机中,所有的寄存器被分配到一个线性区域中,会有一个单独的指针变量,指针默认指向0地址,在每写入或读出一个字节后,指针都会自增1,移动到下一个寄存器。在调用当前地址读的时序时,就会读出指针此时指示的寄存器中的内容。若刚刚在0x19的地址下写入0xAA,那么此时若进行当前地址读,指针就会自增1,移动到0x1A,读出0x1A中的内容。
指定地址读:
对于指定设备,在指定地址下,读取从机数据。
复合格式:起始条件~~发送第一个字节(寻址从机+读写位为0)~~应答~~发送第二个字节(指定从机内的地址即从机的寄存器,此时便将指针指向了人为指定的寄存器)~~再来个起始条件~~发送第三个字节(寻址从机+读写位为1)~~主机接收一个字节(即指定的寄存器下的数据)~~终止时序
注意事项,若想停止读,一定给从机发送一个非应答,即该主机应答的时候,主机不把SDA拉低,从机读到SDA为1,就会释放总线,把SDA的控制权交还给主机。如果不给非应答,从机就会继续发送数据,有可能将SDA拉低,是主机无法将SDA弹回高电平,也就无法产生终止时序。