STM32软件I2C通信详解

目录

18.[江协]I2C通信详解

I2C通信介绍

软件I2C和硬件I2C的区别

I2C硬件电路规定

I2C软件设计(时序基本单元)

起始条件与终止条件

主机发送一个字节 的时序单元

主机接收一个字节 的时序单元

主机/从机 应答 基本单元

I2C完整时序(拼接基本单元)

从机设备的地址

指定地址写

当前地址读

指定地址读


I2C通信介绍

I2C总线 的英文全称是:Inter IC BUS

他有两根通信线:SCL (Serial Clock)、SDA(Serial Data) 串行时钟线和串行数据线 支持总线挂载多设备。可以是一主多从和多主多从

  1. 一主多从的意思是单片机作为主机主导I2C总线的运行,其他挂载在I2C总线上的都是从机。从机只有被主机点名之后,才能控制I2C总线。就像老师点了你的名字之后你才能说话。
  2. 而多主多从模式是:每个模块都可以突然站出来,说接下来我是主机,你们听我的。 这时候如果有其他人说我也要当主机, I2C也会有一个仲裁器来仲裁, 优先级高的胜利。失败的自动变为从机。

I2C通信属于 半双工 同步 多设备 带数据应答的 通信

而USART是 全双工 异步 点对点的通信

  • 半双工 是可以双向传输,但每次只能有一个传输方向
  • 全双工 是既可以双向传输,它又可以同时有两个传输方向。
  • 异步的好处是省下一根时钟线,节省资源。缺点是对时间要求严格,对硬件电路依赖严格。
  • 同步时钟的好处是。对时间要求不严格,对硬件电路不依赖。稳定性也比异步的好,容易使用软件来模拟时序,缺点是多一根时钟线。
  • 多设备则是在一根数据线上挂载很多的设备。在访问其中某个设备时。其他的设备对通信没有影响。

I2C通信可以理解外,通过一根时钟线和一根数据线。 来链接单片机外的外设。 并且可以读写其中指定的寄存器。实现这个外挂模块的完全控制

比如MPU6050模块,可以进行姿态测量。 它就使用了I2C通信协议 或者OLED模块,可以显示字符、图片等信息。也使用了I2C通信协议 以及AT24C02存储器模块。也是I2C的通信协议

或者DS3231 实时时钟模块。也是使用I2C通信。

因为使用通用的协议。对于开发者来说是很方便的

软件I2C和硬件I2C的区别

  • 硬件电路件I2C的波形更加规整,时钟周期和占空比非常一致。

    每个时钟周期后都有严格的延时,保证每个周期的时间相同。

    硬件电路需要专门的某些GPIO口才能实现

  • 软件I2C的波形较为不规整,每个时钟周期和空闲时间都不一致。

    软件I2C时的引脚操作会有一定的延时,因此各个时钟周期的间隔和占空比都不均匀。

    但是软件实现I2C更加的方便,随便那个GPIO口都可以实现。

I2C硬件电路规定

  1. 所有的I2C设备的SCL 均要连接在一起,SDA连接在一起
  2. 所有设备的SCL和SDA均要配置成开漏输出模式
  3. SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右

为什么呢?

因为只有一根数据线,所以采用的是半双工的协议。

在一主多从的模式下,主机的SCL线可以是推挽输出状态。来拥有对SCL的绝对控制权。 (但是仍然采用的是开漏输出+上拉电阻的模式。因为在多主机模式下会用到这个特性) 所有从机的SCL线都配置为 浮空输入 或者 上拉输入 数据的流向为 主机发送,所有的从机只能被动接收, 这样是没问题的

**但SDA就不能这样了。**因为数据线是只有一条。 主机在接收的时候是输入,在发送的时候是输出。 同样,从机的SDA也会在输入和输出之间反复切换。 如果这时使用的是推挽输出模式下。 在总线没协调好两个设备的时序的情况下。就会出现两个设备都是输出的状态。如果此时一个输出高电平。另一个输出低电平。**就会出现电源对地短路的情况。**如图:

这是应该极力避免的。

所以,在I2C这里的解决办法是,禁止所有设备为强制上拉的高电平 采用了外置弱上拉电阻 加 开漏输出的电路结构。如图:

在开漏输出模式下,每个引脚的内部结构如图:

可以看到。不管是SCL 还是SDA
在输入时 都可以随便输入。对电路不会有影响

在输出高电平时 只需要打开自己所控制的mos管,外部的上拉电阻会拉为高电平。

在输出低电平时 只需要闭合自己所控制的mos管,外部的高电平会被强制拉低接地。

所以,开漏输出不同于推挽输出的强上拉强下拉。

开漏输出 配合 上拉电阻 是弱上拉、强下拉

所以,这个模式会有一个 “线与” 的现象。即只要有任意一个或多个设备输出了低电平,总线就处于低电平。只有所有的设备都输出高电平。总线才输出高电平

所以,挂载在I2C总线上的 所有设备。 所有的GPIO 引脚 都要设置为 开漏输出的模式。 并且在SCL和 SDA两条线 添加上拉电阻

I2C软件设计(时序基本单元)

起始条件与终止条件

起始和终止,都是由主机产生的,从机不允许产生起始和终止

在I2C总线处于空闲状态时。SCL和SDA都被上拉为高电平。

当主机需要进行数据收发时,就会产生一个起始条件。 起始条件就是,时钟线不动,拉低SDA数据线。 当从机捕获到SCL时钟线为高电平。SDA数据线产生了下降沿信号时,就会进行自身的复位,等待主机点名。 然后主机会拉下SCL时钟线的电平。准备开始下一步动作。

终止条件是,主机先对SCL时钟线放手,让上拉电阻把SCL拉高为高电平,再对SDA数据线放手,产生一个上升沿。这个上升沿就会触发终止条件

此时就会恢复到最初的两个高电平的平静状态

  • 起始条件:SCL高电平期间SDA从高电平切换到低电平
  • 终止条件:SCL高电平期间SDA从低电平切换到高电平

主机发送一个字节 的时序单元

时钟线SCL低电平期间,主机将数据位依次放到SDA数据线线上**(高位先行**),然后释放SCL, 从机将在SCL高电平期间读取数据位 所以SCL高电平期间SDA不允许有数据变化, 依次循环上述过程8次即可发送一个字节

因为SCL同步时钟是主机在控制。从机并不知道什么时候时钟会消失。所以从机要尽快在SCL高电平期间读取主机所发送的电平信号(一般在主机松手的一刹那,上升沿来临时就已经读取了)。

主机也应该在SCL时钟线下降沿上尽快把数据放到SDA数据线上。 但是主机有对时钟线的主导权。即使中途有什么事情打断了主机放数据的操作。主机也可以一直拉低时钟SCL。等到把数据放到SDA上之后再松开SCL 使他恢复高电平(这也是同步时序的好处)。

在主机的主导的SCL时钟下。 SCL低电平,主机发送; 高电平,从机接收; 如此循环8次 就发送了8位数据,也就是一个字节

在发送一个字节的时序中,主机完全掌控SCL和SDA,从机只能被动的读取。

主机接收一个字节 的时序单元

与发送一个字节同理。这里实线是主机控制,虚线是从机控制。 时钟线SCL低电平期间,从机将数据位依次放到SDA数据线线上**(高位先行**),然后释放SCL, 主机将在SCL高电平期间读取数据位 所以SCL高电平期间SDA不允许有数据变化, 依次循环上述过程8次即可读取一个字节

主机在接收之前,必须释放SDA(因为总线是线与的特征)

如图:

可以看到。主机在接收前,释放了SDA数据线。 这时数据线的主导权到了某个从机的手中。 但是SCL时钟线的主导权还是在主机这里。从机只能等待时钟为下降沿时被动发送。所以也是要尽快的发送,否则错过低电平的时期就不好啦(一般在下降沿来临后就已经发送了。贴着下降沿)。 主机则是在高电平任意时刻读取就行,反正主机能控制SCL时钟线

主机/从机 应答 基本单元

  • 发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答在下一个时钟接收一位数
  • 接收应答:主机在发送完一个字节之后,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

可以看出,接收方必须在接收到一个字节之后,在下一个时钟拉低SDA数据线,如果没有拉低,那么发送方就会认为 这次发送失败,没有人接收到。

如图:接收应答时,当主机释放SDA时,从机就应该立刻把SDA拉下来。在SCL高电平期间,主机读取应答位,如果应答位为0,就代表接收到。为1 代表没有接收到

同理,主机在接受到一个字节的时候,也要发送应答。拉低电平,然后使SCL为高电平,等待从机读取。在高电平期间,从机如果收到了主机的应答,他就可以继续执行操作。如果主机没有应答,那么 从机就会乖乖释放SDA的主导权,防止干扰主机之后的工作

I2C完整时序(拼接基本单元)

I2C的完整时序主要有3种

  • 指定地址写
  • 当前地址读
  • 指定地址读

从机设备的地址

主机可以访问总线上的任何一个设备,要把每个从机都确定一个唯一的设备地址 从机设备地址,在I2C协议里分为:7位地址和 10位地址 (这里主要是讲7位地址) 在每一个I2C设备出厂时,厂商就会给他分配一个I2C 7 位地址(可以在芯片手册中查看)

比如MPU6050的7位地址是1101 000 AT24C02的7位地址是1010 000 一般不同芯片的地址是不一样的。 相同芯片的地址是一样的。

为了应对总线上挂载相同芯片的情况:一般器件地址的最后几位,是可以在电路中通过地址改变引脚的高低电平来改变的。(比如MPU6050的AD0引脚就可以决定地址。 低电平为1101 000 接高电平为 1101 001 ;AT24C02地址的最后三位,都可以由板子的A0 A1 A2来确定)

指定地址写

  • 对于指定设备(Slave Address)在指定地址(Reg Address)**下写入指定数据(**Data)

对于指定设备(从机地址),在指定地址(寄存器地址)下写入数据。

空闲状态

  • 两条总线(SCL和SDA)都是高电平。

产生起始条件

  1. 主机在SCL高电平期间拉低SDA,产生起始条件。
  2. 在起始条件之后,主机发送一个字节,该字节内容为从机地址和读写位(从机地址是7位,读写位是1位,总共8位)。

发送从机地址和读写位

  1. 发送从机地址:确定通信的对象。
  2. 发送读写位:确认接下来是写入还是读出(0表示写入,1表示读出)。
  3. 接收应答位
  4. 主机发送从机地址和读写位后,释放SDA。
  5. 从机响应后会拉低SDA,产生应答位。
  6. 应答位产生后,从机释放SDA的控制权。

发送数据

  1. 主机再次发送第二个字节,通常为寄存器地址或控制字。
  2. 接着发送第三个字节,表示要写入寄存器地址中的数据值。

产生停止条件

  1. 主机拉低SDA,为后续的上升沿做准备。
  2. 然后依次释放SCL和SDA,产生SC**L高电平期间的SDA上升沿,**表示停止条件。

示例

对于从机地址为1101000的设备,在其内部0x19地址的寄存器中写入0xAA这个数据,数据帧的过程如下:

  1. 起始条件:SCL高电平期间,SDA从高电平拉低。
  2. 发送从机地址和读写位(1101000+0)。
  3. 接收从机应答位。
  4. 发送寄存器地址(0x19)。
  5. 接收从机应答位。
  6. 发送数据值(0xAA)。
  7. 接收从机应答位。
  8. 停止条件:SCL高电平期间,SDA从低电平释放至高电平。

通过这些步骤,主机可以可靠地在从机的指定寄存器地址中写入数据

当前地址读

对于指定设备(Slave Address),在**当前地址指针指示的地址下,**读取从机数据(Data)

产生起始条件

  • 主机在SCL高电平期间拉低SDA,产生起始条件。

寻址和读写操作

  1. 主机首先发送一个字节,用于从机的寻址和设置读写标志位。
  2. 在本次通信中,主机发送的目标地址是1101000,读写标志位为1,表示主机接下来要读取数据。

接收从机应答位

  1. 主机发送完寻址字节后,接收从机的应答位。
  2. 从机收到第一个字节后,拉低SDA,表示应答,并将SDA的控制权交回主机。

接收数据

  1. 主机调用接收数据的时序,准备接收从机发送的数据。
  2. 从机得到允许后,在SCL低电平期间将数据写入SDA。
  3. 主机在SCL高电平期间读取SDA上的数据。
  4. 主机在SCL高电平期间依次读取8位数据,从而接收到从机发送的一个字节数据(例如:0000 1111,即0x0F)。

指针自动递增

  1. I2C通信中没有指定寄存器地址的环节,默认情况下,从机中的所有寄存器被分配到一个线性区域中。
  2. 从机内部有一个指针变量,指向某个寄存器。上电时,这个指针通常默认指向0地址。
  3. 每次 写入 或 读出 一个字节后,这个指针会自动递增,指向下一个寄存器位置。
  4. 主机读取到的数据是当前指针指向的寄存器的值。

所以一般这个时序用的不是很多

指定地址读

对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)

对弈指定地址读,其实是先告诉设备我要写,当寄存器指向这个地址之后,我又不写了。我要读。

写入操作

  1. 指定从机地址和读写标志位: 从机地址为1101000,读写标志位为0,表示要进行写操作。
  2. 从机应答: 从机应答后,主机发送第二个字节(0001 1001),用于指定寄存器地址。 这个数据写入到从机的地址指针中,从机的寄存器指针指向0x19位置。

重复起始 开始读操作

  1. 产生一个新的起始条件: 主机再次产生一个起始条件。
  2. 重新寻址并指定读写标志位: 主机重新发送从机地址(1101000)和读写标志位(此时读写标志位为1,表示读操作)。
  3. 主机接收数据: 从机应答后,主机开始接收一个字节的数据。 这个字节的数据是从机0x19地址下的内容。

读写操作也不一定只能一次一个字节。 在主机读或写的时候,只要主机应答,从机就不会停。直到主机给非应答,从机才会停止,然后把SDA主导权交给主机。

  • 22
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值