【IIC】通过Arduino的SoftI2C库学习IIC通信

【IIC】通过Arduino的SoftI2C库学习IIC通信

SoftIC库

SoftI2C库是Arduino的一个第三方库,可以通过软件模拟IIC时序与其他设备进行通信。可以实现与Wire库一样的功能。

SoftI2C库的官方链接:https://www.arduino.cc/reference/en/libraries/softi2c/

相关的API函数如下所示:

IIC基本知识

物理层

IIC通信是通过两条线进行,分别是SDASCL,为IIC总线。

在物理接连层面,IIC总线都是通过上拉电阻(一般为4.7k)上拉至高电平,所以在空闲期间,IIC总线SDA和SCL的空闲电平为高电平。IIC主从设备通过将自身的接口连接至总线上进行通信。

IIC物理连接

协议层

在协议层,IIC总线的SDA和SCL通过形成不同的时序进行数据传输。

通过一张图来介绍一下IIC的时序:

协议

1 起始信号
数据发送开始时,由主设备发送起始信号,表示通信开始。起始信号是SCL高电平期间,SDA由高变低(下降沿)。

2 数据信号
在SCL低电平期间,SDA信号允许进行翻转变化,在SCL高电平期间,SDA信号必须保持不变。因为在SCL高电平期间,会对SDA进行采样,进而传输1bit数据。
如上图所示,在传输单byte数据时,高位数据会先传输,低位数据后传输。一共传输8bit。

3 应答信号ACK
在主设备传输了一个字节数据后,主设备将SDA拉高,放弃SDA线的控制权,对应的从设备会在SDA上产生应答信号ACK,即将SDA拉低。当主设备在第九个SCL高电平期间采样到SDA低电平,表示与从设备通信成功;如果未检测到ACK信号,则表示数据传输失败。

4 非应答信号NACK
与应答信号相反的,就是非应答信号NACK,即在第九个SCL高电平期间采样到SDA为高电平,表示设备没有应答。

5 结束信号
结束信号代表通信的结束。对应的时序是在SCL高电平期间,SDA由低变高(上升沿)。

IIC的通信过程都是由上面这5中信号组成的。

记忆小技巧:
在SCL低电平期间,SDA信号可以随意发生变化,并不会影响通信过程;在SCL高电平期间,SDA信号不发生变化,则为传输数据信号;如果发生了变化,就会形成起始信号(SDA由高变低)和结束信号(SDA由低变高)。


以IIC芯片AS5600的数据手册为例,了解一下IIC的写数据读数据的通信规则:

AS5600数据手册:获取链接

AS5600具体的通信时序如下图所示:
具体时序

挂载在IIC总线上的从设备都会有一个独立的器件地址(slave address),是一个7位的二进制数,例如AS5600的器件地址固定为0x36

在通信过程中紧接着起始信号的就是器件地址和1bit的R/W读写标识位(write=0,read=1),组成了一字节的数据,表示向对应的从设备写数据或读数据。

AS5600写数据时序:
写数据

  1. 首先是起始信号S,然后紧接着是器件地址0x36和写标志位0,等待从设备应答。
  2. 从设备应答后,再发送将要写的寄存器地址(Word address),等待从设备应答。
  3. 从设备应答后,继续发送要写的数据data。
  4. 最后发送停止信号P结束通信。

需要注意的是,AS5600支持多数据的写入,多个数据的写入会将寄存器地址递增依次写入。

AS5600读数据时序:
读数据

  1. 首先是起始信号S,然后紧接着是器件地址0x36和写标志位0,等待从设备应答。
  2. 从设备应答后,再发送将要读的寄存器地址(Word address),从设备应答。
  3. 主设备重新发送起始信号S,器件地址0x36和读标志位1。从设备应答后,从设备会将指定寄存器地址中的数据返回给主设备。(这个时候主设备每接收一个字节后,会向从设备发送应答信号,直到主设备发送非应答信号NACK,表示不需要再发送数据了,然后主设备发送停止信号P结束通信。)

需要注意的是,AS5600支持多数据的读取,多个数据的读取会将寄存器地址递增依次读取。

使用Arduino SoftI2C库进行IIC通信

#include "SoftI2C.h"

myiic = SoftI2C(0,1);   //定义iic对象,sda=0,scl=1

myiic.begin();          //初始化

/****写数据****/
myiic.beginTransmission(0x36);  //1 向器件地址为0x36的从设备通信
myiic.write(0x10);              //2 向寄存器地址0x10写入数据
myiic.write(0x3f);              //3 写如数据0x3f
myiic.endTransmission();        //4 结束通信,发送停止信号

/****读数据****/
myiic.beginTransmission(0x36);  //1 向器件地址为0x36的从设备通信
myiic.write(0x10);              //2 从寄存器地址0x10读数据
my.iic.requestFrom(0x36,1);     //3 请求一个字节的数据,并且停止通信

posted @ 2023-12-23 12:13  HAOstudio  阅读(1303)  评论(0编辑  收藏  举报