I2C(内部集成电路)/ TWI(两线接口)是一种广泛使用的串行通信,用于在短距离内连接设备。这是用于连接传感器、EEPROM、RTC、ADC、DAC、显示器、OLED 以及许多其他设备和微控制器的最常见外设之一。
这种串行通信被视为低速总线,多个设备可以连接在同一条双线总线上,每条总线都有一个唯一的 7 位地址(最多 128 个设备)。这两条线称为 SDA (串行数据线) 和 SCL (串行时钟线)。
注意
SDA 和 SCL 线路需要上拉电阻器。有关电阻器值和工作电压的更多详细信息,请参阅器件数据表。
I2C 可以在两种不同的模式下使用:
ESP32 I2C 库基于 Arduino Wire Library 并实现了更多 API,如本文档所述。
以下是用于 master 和 slave 模式的常用函数。
此功能用于使用默认配置启动外围设备。
bool begin();
如果外围设备已正确初始化,则此函数将返回 true。
此功能用于定义 SDA 和 SCL 引脚。
注意
在开始更改默认引脚之前调用此函数。
bool setPins(int sdaPin, int sclPin);
默认引脚可能因板而异。在通用 ESP32 上,默认 I2C 引脚为:
如果外围设备配置正确,则此函数将返回 true。
使用此功能设置总线时钟。如果不使用此函数,将使用默认值。
bool setClock(uint32_t frequency);
如果 clock 配置正确,则此函数将返回 true。
使用此功能获取总线时钟。
uint32_t getClock();
此函数将返回当前频率配置。
设置以毫秒为单位的总线超时。默认值为 50 毫秒。
void setTimeOut(uint16_t timeOutMillis);
获取总线超时(以毫秒为单位)。
uint16_t getTimeOut();
此函数将返回当前的超时配置。
此函数将数据写入缓冲区。
size_t write(uint8_t);
或
size_t write(const uint8_t *, size_t);
返回值将是添加到缓冲区的数据的大小。
此功能将完成通信并释放所有分配的资源。调用 end 后,您需要再次使用 begin 才能再次初始化 I2C 驱动程序。
bool end();
此模式用于启动与从站的通信。
要开始在 Arduino 上使用 I2C 主模式,第一步是将 Wire.h 接头包含在 sketch 中。
#include "Wire.h"
现在,我们可以通过调用 begin 函数来启动外设配置。
Wire.begin();
通过使用不带任何参数的 begin,所有设置都将使用默认值完成。要自行设置值,请参阅函数说明。这个函数描述在这里:i2c begin
调用 begin 后,我们可以通过调用 beginTransmission 并传入 I2C slave 地址来开始传输:
Wire.beginTransmission(I2C_DEV_ADDR);
要将一些字节写入 slave,请使用 write 函数。
Wire.write(x);
您可以使用 write 函数传递不同的数据类型。这个函数描述在这里:i2c 写入
注意
write 函数不直接写入从器件,而是添加到 I2C 缓冲区。为此,您需要使用 endTransmission 函数将缓冲的字节发送到从设备。
Wire.endTransmission(true);
调用 endTransmission 后,存储在 I2C buffer 中的数据将被传输到 slave 设备。
现在您可以从 slave 设备请求读数。requestFrom 将通过提供地址和大小来要求读取所选设备。
Wire.requestFrom(I2C_DEV_ADDR, SIZE);
readBytes 将读取它。
Wire.readBytes(temp, error);
以下是 I2C Master API。这些函数仅用于主模式。
在 master 模式下,可以通过传递 pins 和 bus frequency 来使用 begin 函数。此功能仅用于主模式。
bool begin(int sdaPin, int sclPin, uint32_t frequency)
或者,您可以使用不带任何参数的 begin 函数来使用所有默认值。
如果外围设备已正确初始化,则此函数将返回 true。
此函数用于对与 slave 设备的通信进程进行 star 排序。在将消息写入缓冲区之前,通过传递从地址来调用此函数。
void beginTransmission(uint16_t address)
使用 i2c write 写入缓冲区后,使用函数 endTransmission 将消息发送到 beginTransmission 函数定义的从设备地址。
uint8_t endTransmission(bool sendStop);
在没有 sendStop 的情况下调用 this 函数等效于 sendStop = true。
uint8_t endTransmission(void);
此函数将返回错误代码。
要从从设备读取数据,请使用 requestFrom 函数。
uint8_t requestFrom(uint16_t address, uint8_t size, bool sendStop)
此函数将返回从设备读取的字节数。
以下是如何在 Master 模式下使用 I2C 的示例。
examples/WireMaster/WireMaster.ino
此模式用于接受来自主站的通信。
要开始在 Arduino 上使用 I2C 作为从模式,第一步是将 Wire.h 标头包含在 sketch 中。
#include "Wire.h"
在调用 begin 之前,我们必须创建两个回调函数来处理与主设备的通信。
Wire.onReceive(onReceive);
和
Wire.onRequest(onRequest);
onReceive 将在从设备读取请求时处理来自主设备的请求,而 onRequest 将处理对主设备的应答。
现在,我们可以通过使用设备地址调用 begin 函数来启动外设配置。
Wire.begin((uint8_t)I2C_DEV_ADDR);
通过使用不带任何参数的 begin,所有设置都将使用默认值完成。要自行设置值,请参阅函数说明。这个函数描述在这里:i2c begin
仅适用于 ESP32!
使用函数 slaveWrite 预写入从属响应缓冲区。这仅用于 ESP32,以便在芯片上添加 slave 功能并保持与 Arduino 的兼容性。
Wire.slaveWrite((uint8_t *)message, strlen(message));
以下是 I2C Slave API。这些函数仅用于 slave 模式。
在 slave 模式下,必须通过传递 slave 地址来使用 begin 函数。您还可以定义引脚和总线频率 。
bool Wire.begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency)
如果外围设备已正确初始化,则此函数将返回 true。
onReceive 函数用于定义从 master 接收的数据的回调。
void onReceive( void (*)(int) );
onRequest 函数用于定义要发送到 master 的数据的回调。
void onRequest( void (*)(void) );
slaveWrite 函数在接收响应消息之前写入从属响应缓冲区。此功能仅用于添加 ESP32 的 slave 兼容性。
警告
只有 ESP32 才需要此功能。ESP32-S2 和 ESP32-C3 不需要使用。
size_t slaveWrite(const uint8_t *, size_t);
以下是如何在 Slave 模式下使用 I2C 的示例。
examples/WireSlave/WireSlave.ino