文章目录[隐藏]
目录
I2C总线的概念
I²C(Inter-Integrated Circuit),中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,是由飞利浦公司在1980年代初设计的,方便了主板、嵌入式系统或手机与周边设备组件之间的通讯。由于其简单性,它被广泛用于微控制器与传感器阵列,显示器,IoT设备,EEPROM等之间的通信。
I2C总线支持任何IC生产过程(NMOS、CMOS、双极性)。两线——串行数据(SDA)和串行时钟(SCL)线存在连接到总线的器件间传递信息。每个器件都有唯一的地址识别(无论是微控制器、LCD驱动器、存储器或者键盘接口),而且都可以作为一个发送器或接收器(由器件的共能决定)。很明显,LCD驱动器只是一个接收器,而存储器则既可以接收又可以发送数据。除了发送器和接收器外,器件在执行数据传输时也可以被看作是主机或从机(见下表)。主机是初始化总线的数据传输并产生允许传输的时钟信号的器件。此时,任何被寻址的器件都被认为是从机。
术语 | 描述 |
发送器 | 发送数据到总线的器件 |
接收器 | 从总线接收数据的器件 |
主机 |
初始化发送、产生时钟信号和终止发送的器件 |
从机 |
被主机寻址的器件 |
多主机 | 同时有多于一个主机尝试控制总线,但不破坏报文 |
仲裁 | 是一个在有多主机同时尝试控制总线,但只允许其中一个控制总线并使报文不被破坏的过程 |
同步 | 两个或者多个器件同步时钟信号的过程 |
I2C最重要的功能包括:
- 只需要两条总线
- 没有严格的波特率要求,例如使用RS232,主设备生成总线时钟
- 所有组件之间都存在简单的主/从关系,连接到总线的每个设备均可通过唯一的地址进行软件寻址
- I2C是真正的多主设备总线,可提供仲裁和冲突检测
- 传输速度
- 标准模式:100kbit/s
- 快速模式:400kbit/s
- 高速模式:3.4Mbit/s
- 最大主设备数:无限制
- 最大从机数:理论上是127
以上是I2C的一些重要特点,下面会对I2C作进一步介绍。
任何一个通信协议,分析起来主要分为物理层(硬件层)和协议层(软件层)
I2C协议仅需要一个SDA和SCL引脚。SDA是串行数据总线的缩写,而SCL是串行时钟线的缩写。这两条数据线需要接上拉电阻。设备间的连接如下所示:
使用I2C,可以将多个从机(Slave)连接到单个主设备(Master),并且还可以有多个主设备(Master)控制一个或者多个从机(Slave).
假如希望有多个微控制器(MCU)将数据记录到单个存储卡或将文本显示到单个LCD时,这个功能就非常有用。
I2C总线(SDA,SCL)内部都使用漏极开路驱动器(开漏驱动),因此SDA和SCL可以被拉低为低电平,但是不能被驱动为高电平(PS:不知道原因的建议回去看下数电),所以每天线上都要使用一个上拉电阻,默认情况下将其保持在高电平。
上拉电阻的取值取决于很多因素,德州仪器TI建议使用以下公式来计算正确的上拉电阻值:经验值
Rp(min)=VDD−VOL(max)/IOL
Rp(min)=0.8473xCbtr
其中VOL是逻辑低电压,IOL是逻辑低电流,tr是信号的最大上升时间
Cb是总线电容
I2C的物理层
I2C一共只有两根总线:一条是双向的串行数据线SDA,一条是串行时钟线SCL
- SDA(Serial data)是数据线,D代表Data也就是数据,Send Data也就是用来传输数据的
- SCL (Serial clock line)是时钟线,C代表Clock也就是时钟,也就是控制数据发送的时序的
所有连接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。I2C总线上的每个设备都自己一个唯一的地址,来确保不同设备之间访问的准确性。
I2C主要特点:
通常我们为了方便把I2C设备分为主设备和从设备,基本上谁控制时钟线(即控制SCL的电平高低变换)谁就是主设备。
- I2C主设备功能:主要产生时钟,产生起始信号和停止信号
- I2C从设备功能:可编程的I2C地址检测,停止位检测
- I2C的一个优点是它支持多主控(multi mastering),其中任何一个能够进行发送和接受的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。
- 支持不同速率的通讯速度,标准速度为100kbit/s,快速为400kbit/s,最大为3.4Mbit/s
- SCL和SDA都需要借上拉电阻(大小由速度和容性负载决定,一般在3.3K到10K之间)保证数据的稳定性,减少干扰。
- I2C是半双工,而不是全双工,同一时间只可以单向通信
- 为了避免总线信号的混乱,要求各设备连接到总线的输出端时必须是漏极开路(OD)输出或者集电极开路(OC)输出,这一点在下面会进行讲解。
I2C的高阻态
漏极开路(Open Drain)即高阻状态,适用于输入/输出,其可以独立输入/输出低电平和高阻状态,若需要产生高电平,则需使用外部上拉电阻。
高阻状态:高阻状态是三态门电路的一种状态。逻辑门的输出除有高、低电平两种状态外,还有第三种状态——高阻状态的门电路。电路分析时高阻态可以做开路理解。
我们知道I2C的所有设备是连接在一根总线上的,那么我们进行通信的时候往往只是几个设备进行通信,那么这时候其余的空闲设备可能会受到总线干扰,或者干扰总线,怎么办呢?
为例避免总线信号的混乱,I2C的空闲状态只能有外部上拉,而此时空闲设备被拉到高阻态,也就是相当于断路,整个I2C总线也只有开启了的设备才会正常进行通信,而不会干扰到其他设备。
I2C器件地址:每一个I2C器件都有一个器件地址,有的器件地址在出厂的时候就设定好了,用户不可以更改,比如OV7670的地址为0x42。有的器件例如EEPROM,前四个地址已经确定好为1010,后三个地址是由硬件连接确定的,所以I2C总线最多能够连8个EEPROM芯片。
I2C物理层总结:
I2C总线在物理连接上非常简单,分别由SDA和SCL及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传输。在总线空闲状态时,SCL和SDA被上拉电阻Rp拉高,使得SDA和SCL线都保持高电平。
I2C的通信方式为半双工,只有一根SDA线,同一时间只可以单向通信,485也为半双工,SPI和UART通信为全双工。
主机和从机的概念:
主机就是负责整个系统的任务协调与分配,从机一般是通过主机的指令从而完成某些特定的任务,主机和从机之间可以通过总线连接,进行数据通信。
- 发布主要命令的称为主机
- 接受命令的称为从机
I2C的协议层
I2C总线在传递数据的过程中共有三种类型的信号,它们分别是:开始信号,结束信号,应答信号。
- 开始信号:SCL为高电平,SDA由高电平向低电平跳变,开始传送数据
- 结束信号:SCL为高电平,SDA由低电平向高电平跳变,结束传送数据
- 应答信号:接收数据的IC在接收到8bit数据之后,向发送数据的IC发出特定的低电平脉冲,表示已经收到数据。CPU向受控单元发出一个信号之后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。
I2C总线时序图
下面我们来讲I2C的通信协议流程:
初始(空闲)状态
因为I2C的SCL和SDA都需要接上拉电阻,保证空闲状态的稳定性,所以I2C总线在空闲状态下的SCL和SDA都保持高电平
/*产生I2C起始信号*/
/*1、先拉高SDA,再拉高SCL,空闲状态*/
/*2、拉低SDA*/
void I2C_Start() //启动信号
{
SDA = 1; //确保SDA线为高电平
delay_us(5);
SCL = 1; //确保SCL高电平
delay_us(5);
SDA = 0; //在SCL为高时拉低SDA线,即为起始信号
dealy_us(5);
}
开始信号:
SCL保持高电平,SDA由高电平变为低电平后,延时(>4.7us),SCL变为低电平。
停止信号
停止信号:SCL保持高电平,SDA由低电平变为高电平
在起始条件产生之后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线;而在停止条件产生之后,本次数据传输的主从设备将释放总线,总线再次处于空闲状态。
数据有效性
I2C信号在数据传输过程中,当SCL=1高电平时,SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
SCL=1时,数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号。
也就是在I2C传输数据的过程中,SCL时钟线会频繁的转换电平,以保证数据的传输。
应答信号
每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据。
应答信号:主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答
- 应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功的接收了该字节
- 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
每发送一个字节(8bit)在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须回一个ACK应答信号给发送器,这样才能进行数据传输。
应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答
I2C数据传送
数据传送格式
SDA线上的数据在SCL时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或者“低”状态才可以改变。输出到SDA线上的每个字节必须是8位的,数据传送时,先传送最高位(MSB),每个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
当一个字节数据位从高位到低位的顺序传输完成之后,紧接着从设备将拉低SDA线,回传给主设备一个应答位(ACK),此时才认为一个字节真正的被传输完成,如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。
I2C写数据
多数从设备的地址为7位或者10位,一般都用7位。
八位设备地址=7位从机地址+读/写地址
再给地址添加一个方向位用来表示接下来数据的传输方向
- 0表示主设备向从设备(write)写数据
- 1表示主设备向从设备(read)读数据
I2C的每一帧数据由9bit组成
如果是发送数据,则包含8bit数据+1bit数据ACK
如果是设备地址数据,则8bit包含7bit设备地址1bit方向(PS:其实地址就是一个特殊的数据)
在起始信号后必须传送一个从机地址(7位)1~7位为7位接收器地址,第8位为读写位,用0表示主机发送数据,1表示主机接收数据,第九位为ACK应答位,紧接着的为第一个数据字节,然后是一位应答位,后面继续第二个数据字节
I2C发送数据
Start:I2C起始信号,表示开始传输
DEVICE_ADDRESS:从设备地址,就是7位从机地址
R/W:W为写,R为读
WORD_ADDRESS:从机中对应的寄存器地址,比方说访问OLED中的某个寄存器
DATA:发送的数据
STOP:停止信号,结束I2C
主机要向从机写数据时:
- 主机首先产生START信号
- 然后紧接着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方向位(R/W),0表示主机发送数据,1表示主机接收数据(读)
- 主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,根据R/T位将自己确定为发送器和接收器
- 这时候主机等待从机的应答信号(A)
- 当主机收到应答信号时,发送要访问从机的哪个地址,继续等待从机的应答信号
- 当主机接收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号
- 主机产生停止信号,结束传送过程
I2C读数据:
主机要从从机读数据时:
- 主机首先产生START信号
- 然后紧接着发送一个从机地址,注意此时该地址的第8位为0,表明是向从机写命令
- 这时候主机等待从机的应答信号(ACK)
- 当主机收到应答信号时,发送要访问的地址,继续等待从机的应答信号
- 当主机收到应答信号后,主机要改变通信模式(主机将由发送变为接收,从机将由接受变为发送)所以主机重新发送一个START信号,然后紧接着发送一个从机地址,注意此时该地址的第8位为1,表明将主机设置成接收模式开始读取数据
- 这时候主机等待从机的应答信号,当主机收到应答信号时,就可以接收一个字节的数据,当接受完成后,主机发送非应答信号,表示不再接收数据
- 主机进而产生停止信号,结束传送过程
以EEPROM的AT24C02为例子
AT24C02是一个2K bit的串行EEPROM存储器(掉电不丢失),内部含有256个字节。在这里面有一个8字节的页写缓冲器
A0,A1,A2:硬件地址引脚
WP:写保护引脚,接高电平只读,接地允许读和写
SCL和SDA:I2C总线
以看出对于不同大小的24Cxx,具有不同的从器件地址。由于24C02为2K容量,也就是说只需要参考图中第一行的内容:
芯片的寻址:
AT24C设备地址如下,前四位固定为1010,A2~A0由管脚电平决定。AT24Cxx EEPROM Board模块中默认接地。A2~A0为000,最后一位表示读写操作。所以AT24CXX的读地址为0xA1,写地址为0xA0.
也就是说
写24C02时,从器件的地址为10100000(0xA0)
读24C02时,从器件的地址为10100001(0xA1)
芯片内寻址可对内部的256byte的任意一个进行读/写操作,其寻址范围为00~FF,共256个寻址单位。
对应的修改A2A1A0三位数据即可。
向AT24C02中写数据
操作时序:
- MCU先发送一个开始信号(START)启动总线
- 接着跟上首字节,发送器件写操作地址(DEVICE_ADDRESS)+写数据(0XA0)
- 等待应答信号
- 发送数据的存储地址。24C02一共有256个字节的存储空间,地址从0x00~0xFF,想把数据存储在哪个位置,此刻写的就是哪个地址。
- 发送要存储的数据第一字节,第二字节,注意在写数据的过程中,E2PROM每个字节都会回应一个应答位0,告诉我们写E2PROM数据成功,如果没有应答位,说明写入不成功
- 发送结束信号,停止总线
注意:在写数据的过程中,每写入一个字节,E2PROM存储空间地址就会加1,当加到0xFF后,再写入一个字节,地址就会溢出又变成0x00
写数据的时候需要注意,E2PROM是先写入到缓冲区,然后再搬运到掉电非易失区。这个过程需要一定的时间,AT24C02这个过程是不超过5ms
所以,当我们在写多个字节时,写入一个字节之后,再写入一个字节之前,必须延时,这里我用的另一种方法,不用延时。
//等待EEPROM内部时序完成
void EEPROM_WaitForWriteEnd(void)
{
do{
//I2C发送起始信号
I2C_GenerateSTART(EEPROM_I2C, ENABLE);
//检测EV5事件
while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_SB) == RESET);
//EV5事件被检测到,I2C发送设备地址
I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDR, I2C_Direction_Transmitter);
}while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_ADDR) == RESET);
//内部时序完成
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
}
从AT24C02中读取数据
1、读取当前地址的数据
2、读取随即地址的数据
- MCU先发送一个开始信号(START)启动总线
- 接着跟上首字节,发送器件写操作地址(DEVICE ADDRESS)+写数据(0xA0)
注意:这里写操作是为了要把所要读的数据的存储地址先写进去,告诉E2PROM要读取哪个地址的数据。
3.发送要读取内存的地址(WORD ADDRESS),通知E2PROM读取要哪个地址的信息。
4.重新发送开始信号(START)
5.发送设备读操作地址(DEVICE ADDRESS)对E2PROM进行读操作 (0xA1)
6. E2PROM会自动向主机发送数据,主机读取从器件发回的数据,在读一个字节后,MCU会回应一个应答信号(ACK)后,E2PROM会继续传输下一个地址的数据,MCU不断回应应答信号可以不断读取内存的数据
7.如果不想读了,告诉E2PROM不想要数据了,就发送一个“非应答位NAK(1)”。发送结束信号(STOP)停止总线
3、连续读数据
E2PROM支持连续写操作,操作和单个字节类似,先发送设备写操作地址(DEVICE ADDRESS),然后发送内存起始地址(WORD ADDRESS),MCU会回应一个应答信号(ACK)后,E2PROM会继续传输下一个地址的数据,MCU不断回应应答信号可以不断读取内存的数据。E2PROM的地址指针会自动递增,数据会依次保存在内存中。不应答发送结束信号后终止传输。
软件I2C和硬件I2C
I2C分为软件I2C和硬件I2C
软件I2C:软件I2C通信指的是用单片机的两个I/O端口模拟出来的I2C,用软件控制管脚状态以模拟I2C通信波形,软件模拟寄存器的工作方式
硬件I2C:一块硬件电路,硬件I2C对应芯片上的外设,有相应的I2C驱动电路,其所使用的I2C管脚也是专用的,硬件I2C直接调用内部寄存器进行配置。
硬件I2C的效率要远高于软件的,而软件I2C由于不受管脚限制,接口比较灵活。
版权声明:本文为CSDN博主「~Old」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43460068/article/details/122358142
暂无评论