文章目录
1. I2C通信概述
I2C(Inter-Integrated Circuit)和和SPI一样,都是实现主控芯片和外挂芯片之间的数据交流。
通信线
- SCL(Serial Clock):串行时钟线。
- SDA(Serial Data):串行数据线。
特性
- 同步:I2C总线是同步通信。
- 半双工:数据可以在两个方向传输,但不能同时进行。
数据应答:I2C总线支持数据应答机制。
支持多设备
- 一主多从:一个主设备可以连接多个从设备。
- 多主多从:多个主设备可以连接多个从设备。
起始条件:在SCL高电平期间,SDA从高电平切换到低电平,表示通信的开始。
终止条件:在SCL高电平期间,SDA从低电平切换到高电平,表示通信的结束。
时序单元:每个时序单元从SCL的低电平开始,并以低电平结束。
从设备限制:从设备不允许产生起始和终止条件。
2. 硬件电路
所有I2C设备的SCL连在一起,SDA连在一起,并且设备的SCL和SDA均要配置成开漏输出模式
SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右
3. I2C时序基本单元
起始条件:SCL高电平期间,SDA从高电平切换到低电平
终止条件:SCL高电平期间,SDA从低电平切换到高电平
发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
主机发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答。
- 准备数据:
- 主机拉低SCL,将数据放在SDA线上。
- 发送数据位:
- SCL低电平期间:
- 若要发送0,主机将SDA拉低到低电平。
- 若要发送1,主机释放SDA,SDA回弹到高电平。
- SCL低电平期间允许改变SDA的电平。
- SCL高电平期间:
- 主机松开SCL,SCL回弹到高电平。
- 从机在SCL高电平期间读取SDA上的数据位。
- SCL高电平期间,SDA电平不允许变化。
- SCL低电平期间:
- 完成数据位传输:
- 主机在松开SCL一段时间后,继续拉低SCL,准备传输下一位。
- 该过程在SCL同步下循环8次,传输完成一个字节(8位数据)。
从机接收数据
接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
- 准备接收:
- 主机拉低SCL,将数据位依次放到SDA线上。
- 读取数据位:
- SCL高电平期间:
- 主机在SCL高电平期间读取SDA上的数据位。
- SCL高电平期间,SDA电平不允许变化。
- SCL高电平期间:
- 完成数据位接收:
- 从机在SCL低电平期间,将下一位数据放到SDA线上。
- 该过程在SCL同步下循环8次,从机接收一个字节(8位数据)。
应答机制
在I2C通信中,主机发送一个数据后会立即接收一个位作为应答位,用来判断从机是否正确接收到数据。
从机地址
- 发送从机地址:
- 主机在起始条件之后,先发送一个字节(从机地址)。
- 所有从机会接收该字节,并与自己的地址进行比较。
- 如果地址匹配,相应的从机会响应主机的读写操作。
- 唯一地址:
- 同一条I2C总线上的每个设备地址必须唯一,以防止主机发送一个地址时有多个设备响应。
I2C地址类型
- 7位地址:常用的I2C地址格式。
- 10位地址:用于一些特殊情况下的I2C地址格式。
设备地址分配
- 每个I2C设备在出厂时由厂商分配一个7位地址。例如,MPU6050的地址是1101 000。
- 不同型号的设备地址不同,相同型号的设备地址相同。
地址可变部分
- 对于挂在同一条总线上的相同型号设备,可以利用设备地址的可变部分来区分。
- MPU6050:
- 地址的最后一位由板上的AD0引脚确定。
- AD0引脚接低电平,地址为1101 000。
- AD0引脚接高电平,地址为1101 001。
通过这种方式,可以在同一条I2C总线上挂载多个相同型号的设备,并通过改变引脚电平来分配不同的地址,避免地址冲突。
4. I2C时序
4.1 指定地址写
对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)
对于指定设备(从机地址),在指定地址(寄存器地址)下写入数据。
空闲状态
-
两条总线(SCL和SDA)都是高电平。
产生起始条件
-
主机在SCL高电平期间拉低SDA,产生起始条件。
-
在起始条件之后,主机发送一个字节,该字节内容为从机地址和读写位(从机地址是7位,读写位是1位,总共8位)。
发送从机地址和读写位
-
发送从机地址:确定通信的对象。
-
发送读写位:确认接下来是写入还是读出(0表示写入,1表示读出)。
接收应答位
-
主机发送从机地址和读写位后,释放SDA。
-
从机响应后会拉低SDA,产生应答位。
-
应答位产生后,从机释放SDA的控制权。
发送数据
-
主机再次发送第二个字节,通常为寄存器地址或控制字。
-
接着发送第三个字节,表示要写入寄存器地址中的数据值。
产生停止条件
-
主机拉低SDA,为后续的上升沿做准备。
-
然后依次释放SCL和SDA,产生SCL高电平期间的SDA上升沿,表示停止条件。
示例
对于从机地址为1101000的设备,在其内部0x19地址的寄存器中写入0xAA这个数据,数据帧的过程如下:
- 起始条件:SCL高电平期间,SDA从高电平拉低。
- 发送从机地址和读写位(1101000+0)。
- 接收从机应答位。
- 发送寄存器地址(0x19)。
- 接收从机应答位。
- 发送数据值(0xAA)。
- 接收从机应答位。
- 停止条件:SCL高电平期间,SDA从低电平释放至高电平。
通过这些步骤,主机可以可靠地在从机的指定寄存器地址中写入数据。
4.2 当前地址读
对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)
产生起始条件
-
主机在SCL高电平期间拉低SDA,产生起始条件。
寻址和读写操作
-
主机首先发送一个字节,用于从机的寻址和设置读写标志位。
-
在本次通信中,主机发送的目标地址是1101000,读写标志位为1,表示主机接下来要读取数据。
接收从机应答位
-
主机发送完寻址字节后,接收从机的应答位。
-
从机收到第一个字节后,拉低SDA,表示应答,并将SDA的控制权交回主机。
接收数据
-
主机调用接收数据的时序,准备接收从机发送的数据。
-
从机得到允许后,在SCL低电平期间将数据写入SDA。
-
主机在SCL高电平期间读取SDA上的数据。
-
主机在SCL高电平期间依次读取8位数据,从而接收到从机发送的一个字节数据(例如:0000 1111,即0x0F)。
指针自动递增
-
I2C通信中没有指定寄存器地址的环节,默认情况下,从机中的所有寄存器被分配到一个线性区域中。
-
从机内部有一个指针变量,指向某个寄存器。上电时,这个指针通常默认指向0地址。
-
每次写入或读出一个字节后,这个指针会自动递增,指向下一个寄存器位置。
-
主机读取到的数据是当前指针指向的寄存器的值。
4.3 指定地址读
对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)
写入操作
- 指定从机地址和读写标志位:
- 从机地址为1101000,读写标志位为0,表示要进行写操作。
- 从机应答:
- 从机应答后,主机发送第二个字节(0001 1001),用于指定寄存器地址。
- 这个数据写入到从机的地址指针中,从机的寄存器指针指向0x19位置。
重新开始读操作
- 产生新的起始条件:
- 主机再次产生一个起始条件。
- 重新寻址并指定读写标志位:
- 主机重新发送从机地址(1101000)和读写标志位(此时读写标志位为1,表示读操作)。
- 主机接收数据:
- 从机应答后,主机开始接收一个字节的数据。
- 这个字节的数据是从机0x19地址下的内容。
5. I2C外设
硬件资源
-
I2C外设:STM32内部集成的I2C外设,通过通信协议在时序上,驱动根据协议的规范去翻转通信引脚的高低电平。
-
I2C控制器:STM32的I2C外设包括I2C1和I2C2控制器,能够自动进行时钟生成、起始条件生成、应答位发送和接收,减轻了CPU负担。
特性
-
多主机模式:支持多个主机设备,可变多主机模式。
-
地址模式:支持7位和10位地址模式。
-
通信速度:支持不同的通信速率,标准模式最高100kHz,快速模式最高400kHz。
-
DMA支持:支持DMA,在多字节传输时提高传输效率。
-
兼容SMBus协议:SMBus协议用于电源管理系统(System Management Bus)。
10位地址模式
-
标志位:10位地址模式下,起始后的前两个字节都用于寻址,前5位为标志位,表示这是一个10位地址模式。
-
数据格式:
-
第一个字节:前5位标志位为11110,第6位到第8位为高3位地址。
-
第二个字节:包含剩下的7位地址位。
-
-
寻址过程:
-
第一个字节发送特定数据作为10位寻址模式的标志,即11110。
-
如果第二个字节也是寻址,则第一个字节的前5位必须是11110。
-
示例说明
-
I2C地址转换:
-
二进制地址1101000转换为十六进制为0x68。
-
I2C通信时,需要发送7位地址和1位读写位。
-
从机地址0x68左移1位再加上读写位:
-
0x68左移1位为11010000(0xD0),加上读写位为0xD1。
-
-
读写操作:
-
写操作:从机地址为0xD0。
-
读操作:从机地址为0xD1。
-
-
I2C在STM32中的实现
- STM32F103C8T6集成了I2C1和I2C2两个I2C外设,支持多种功能和特性,适用于各种嵌入式应用。
- 通过配置I2C寄存器,可以实现从机地址设置、通信速度调整、DMA传输等功能,满足不同应用需求。
6. I2C框图
数据发送
- 写入数据寄存器:当需要发送数据时,将一个字节数据写入数据寄存器(DR)。
- 移位寄存器:如果移位寄存器(SR)没有数据在移位,数据寄存器中的值会转移到移位寄存器中。
- 连续发送:在移位过程中,可以将下一个数据字节放入数据寄存器,准备发送。一旦前一个数据移位完成,下一个数据就可以无缝衔接继续发送。
- 状态标志:当数据从数据寄存器转移到移位寄存器时,状态标志寄存器的TXE位会置1,表示发送寄存器为空,可以继续写入新的数据。
数据接收
- 接收数据:输入的数据一位一位从引脚移入移位寄存器。
- 移入数据寄存器:当一个字节的数据接收完整后,数据整体从移位寄存器转移到数据寄存器(DR)。
- 状态标志:同时,状态标志寄存器的RXNE位会置1,表示接收寄存器非空,此时可以从数据寄存器读取数据。
7. I2C基本结构
数据发送
-
移位寄存器与DR配合:I2C协议规定数据高位先行,因此移位寄存器的数据是向左移位的。
-
移位过程:
-
在发送时,最高位首先移出,接着是次高位,依次类推。
-
每个SCL时钟周期,移位寄存器移位一次。
-
经过8次移位后,一个字节的数据由高位到低位依次放到SDA线上。
-
数据接收
-
移位过程:
-
接收时,数据通过GPIO口从右边依次移入移位寄存器。
-
经过8次移位后,一个字节的数据接收完成。
-
GPIO配置
-
复用开漏输出模式:
- 使用硬件I2C时,GPIO口需配置为复用开漏输出模式。
- 复用:将GPIO的控制权交给片上硬件外设。
- 开漏输出:I2C协议要求的端口配置,即便是开漏输出模式,GPIO也能进行输入操作。
-
时钟与数据传输:
- 时钟控制器通过GPIO控制时钟线(SCL)。
- 数据通过GPIO输出到SDA端口。
- 接收数据时,数据通过GPIO输入移位寄存器。
8. 主机发送
初始化与起始条件
-
总线空闲状态:在初始化后,总线默认处于空闲状态,STM32默认设置为从模式。
-
产生起始条件:为了开始通信,STM32需要在控制寄存器中写入相应的值以产生起始条件。
-
查看手册中的I2C接口寄存器描述,确定起始条件的写入方法。
-
-
切换到主模式:产生起始条件后,STM32从从模式切换到主模式。在多主机模型下,STM32有数据要发送时会主动跳出来。
控制与检查标志位
-
控制硬件电路:在控制完硬件电路后,需要检查标志位,以确认硬件是否达到了预期状态。
-
发送从机地址:将从机地址写入数据寄存器(DR)。硬件电路会自动将这个字节转移到移位寄存器,并将其放到I2C总线上。
应答与事件处理
-
应答判断:硬件自动接收应答并进行判断。如果没有应答,硬件会置应答失败标志位,并可能触发中断来提醒。
-
事件EV6:寻址完成后,会触发EV6事件。
-
事件EV8_1:TXE标志位=1,表示数据寄存器和移位寄存器均为空,此时需要向数据寄存器写入数据以进行发送。
数据发送
-
写入数据寄存器:将数据写入数据寄存器(DR)。如果移位寄存器为空,数据会立即转移到移位寄存器并开始发送。
-
事件EV8:检测到EV8事件,表示数据寄存器为空,可以写入下一个数据。
数据发送完成
-
事件EV8_2:当移位寄存器和数据寄存器都为空(TXE=1),会触发EV8_2事件。
-
字节发送结束标志位(BTF):EV8_2后,BTF标志位表示字节传输完成。
终止条件
- 产生终止条件:在控制寄存器中写入相应的值以产生终止条件,结束数据传输。
9. 主机接收
10位地址读操作流程
- 起始条件:产生起始条件
- 发送帧头:发送帧头,帧头中的读写位应为写(0),因为后面还需要发送第二个字节的地址。
- 发送第二个字节地址:继续发送第二个字节的8位地址,这样才能完成寻址。
- 重复起始条件:为了转入读的时序,必须再发送一个重复起始条件。
- 再次发送帧头:这次帧头中的读写位应为读(1),发送读的指令后,直接转入接收数据的程序,不再发送第二个字节的地址。
7位地址读操作流程
- 起始条件:在控制寄存器中写入START位,产生起始条件。
- 等待EV5事件:EV5事件表示起始条件已发送。
- 寻址与应答:发送从机地址,接收应答,结束后产生EV6事件,表示寻址完成。
- 数据输入:数据通过移位寄存器输入,产生EV6_1事件,表示数据正在移位。
- 发送应答位:根据配置,硬件自动发送应答位。
- 移入数据寄存器:当移位寄存器成功移入一个字节数据后,这个字节整体转移到数据寄存器,同时置RXNE标志位,表示数据寄存器非空。
- EV7事件:RXNE=1,表示数据寄存器非空,读取数据寄存器(DR)清除EV7事件,表示已收到数据。
- 持续接收数据:当数据1还未读走时,数据2可以直接移入移位寄存器,产生EV7事件,读走数据2后EV7事件消失。按照此流程,继续接收数据。
- 结束接收:
- 当不再需要继续接收数据时,在最后一个时序单元发生时,提前将ACK位置0,并设置终止条件请求,这就是EV7_1事件。
- 在最后一个时序单元完成后,因ACK=0,发送非应答位。
- 设置STOP位,产生终止条件,完成接收一个字节的时序。
10. 软件和硬件波形对比
软件I2C实现
- 波形特点:软件I2C的波形较为不规整,每个时钟周期和空闲时间都不一致。
- 操作特点:软件I2C时的引脚操作会有一定的延时,因此各个时钟周期的间隔和占空比都不均匀。
硬件I2C实现
- 波形特点:硬件I2C的波形更加规整,时钟周期和占空比非常一致。
- 操作特点:每个时钟周期后都有严格的延时,保证每个周期的时间相同。
11. 代码示例
STM32通过I2C软件读写MPU6050
STM32通过I2C硬件读写MPU6050