Arduino - 内部集成电路

内部集成电路 (I2C) 是新一代微控制器和专用集成电路之间进行串行数据交换的系统。当它们之间的距离较短时使用(接收器和发射器通常在同一印刷电路板上)。通过两根导线建立连接。一根用于数据传输,另一根用于同步(时钟信号)。

如下图所示,一个设备始终是主设备。它在通信开始之前对一个从属芯片进行寻址。这样,一个微控制器可以与 112 个不同的设备通信。波特率通常为 100 Kb/秒(标准模式)或 10 Kb/秒(慢速波特率模式)。最近出现了波特率为 3.4 Mb/秒的系统。通过 I2C 总线进行通信的设备之间的距离限制为几米。

I2C

电路板 I2C 引脚

I2C 总线由两个信号组成 − SCL 和 SDA。SCL 是时钟信号,SDA 是数据信号。当前总线主设备始终生成时钟信号。某些从设备可能会强制时钟有时处于低位,以延迟主设备发送更多数据(或在主设备尝试将其输出之前需要更多时间来准备数据)。这被称为"时钟拉伸"。

以下是不同 Arduino 板的引脚 −

  • Uno、Pro Mini A4 (SDA)、A5 (SCL)
  • Mega、Due 20 (SDA)、21 (SCL)
  • Leonardo、Yun 2 (SDA)、3 (SCL)

Arduino I2C

我们有两种模式 - 主代码和从代码 - 使用 I2C 连接两个 Arduino 板。它们是 −

  • 主发送器/从接收器
  • 主接收器/从接收器

主发送器/从接收器

现在让我们看看什么是主发送器和从接收器。

主发送器

以下函数用于初始化 Wire 库并作为主设备或从设备加入 I2C 总线。这通常只调用一次。

  • Wire.begin(address) − 在我们的例子中,Address 是 7 位从设备地址,因为未指定主设备,它将作为主设备加入总线。

  • Wire.beginTransmission(address) −开始向具有给定地址的 I2C 从属设备传输数据。

  • Wire.write(value) − 将字节排队以从主设备传输到从属设备(在调用 beginTransmission() 和 endTransmission() 之间)。

  • Wire.endTransmission() − 结束由 beginTransmission() 开始的向从属设备的传输,并传输由 wire.write() 排队的字节。

示例

#include <Wire.h> //包含 wire 库

void setup() //这将仅运行一次 {
Wire.begin(); // 作为主设备加入 i2c 总线
}

short age = 0;

void loop() {
    Wire.beginTransmission(2);
    // 传输到设备 #2
    Wire.write("age is = ");
    Wire.write(age); // 发送一个字节
    Wire.endTransmission(); // 停止传输
    delay(1000);
}

从属接收器

使用以下函数 −

  • Wire.begin(address) − Address 是 7 位从属地址。

  • Wire.onReceive(received data handler) − 当从属设备从主设备接收数据时调用的函数。

  • Wire.available() − 返回可使用 Wire.read() 检索的字节数。这应该在 Wire.onReceive() 处理程序中调用。

示例

#include <Wire.h> //include wire 库

void setup() { //这将仅运行一次
    Wire.begin(2); // 使用地址 #2 加入 i2c 总线
    Wire.onReceive(receiveEvent); // 当主机发送任何内容时调用接收事件
    Serial.begin(9600); // 启动串行输出以打印我们收到的内容
}

void loop() {
    delay(250);
}

//-----只要从主机接收到数据,此函数就会执行-----//

void acceptEvent(int howMany) {
    while (Wire.available()>1) // 循环遍历除最后一个之外的所有内容 
    {
    char c = Wire.read(); // 将字节作为字符接收
    Serial.print(c); // 打印字符
	}
}

主接收器/从属发送器

现在让我们看看什么是主接收器和从属发送器。

主接收器

主设备被编程为请求,然后读取从具有唯一地址的从属 Arduino 发送的数据字节。

使用以下函数 −

Wire.requestFrom(address,number of bytes) − 主设备使用它来从从属设备请求字节。然后可以使用 wire.available() 和 wire.read() 函数检索字节。

示例

#include <Wire.h> //include wire library 
void setup() {
    Wire.begin(); // 加入 i2c 总线(主机地址可选)
    Serial.begin(9600); // 启动串行输出
}

void loop() {
    Wire.requestFrom(2, 1); // 从从设备 #2 请求 1 个字节
    while (Wire.available()) // 从设备可能发送少于请求的字节 
    {
        char c = Wire.read(); // 接收一个字节作为字符
        Serial.print(c); // 打印字符
    }
    delay(500);
}

从设备发送器

使用以下函数。

Wire.onRequest(handler) − 当主机从此从设备请求数据时,将调用该函数。

示例

#include <Wire.h>

void setup() {
    Wire.begin(2); // 使用地址 #2 加入 i2c 总线
    Wire.onRequest(requestEvent); // 注册事件
}

Byte x = 0;

void loop() {
    delay(100);
}

// 主机请求数据时执行的函数
// 此函数注册为事件,请参阅 setup()

void requestEvent() {
    Wire.write(x); // 根据主机的预期,以 1 字节的消息进行响应
    x++;
}