首页 » 科学 » ESP32 I2C通讯原来是这样的讲的具体就这么简单_地址_引脚

ESP32 I2C通讯原来是这样的讲的具体就这么简单_地址_引脚

萌界大人物 2024-12-19 13:33:47 0

扫一扫用手机浏览

文章目录 [+]

在本教程中,我们将先容以下观点:

将I2C设备与ESP32连接利用ESP32扫描I2C地址ESP32利用不同的I2C引脚(变动默认I2C引脚)ESP32利用两个I2C总线接口我们将利用Arduino IDE对ESP32进行编程,因此在连续本教程之前,您该当在Arduino IDE中安装ESP32插件。
具有多个I2C器件的ESP32

1. 相同的总线,不同的地址

ESP32  I2C通讯原来是这样的讲的具体就这么简单_地址_引脚 科学

2. 相同的地址·

ESP32 I2C通讯协议先容

I²C是一个同步,多主,多从通信协议。
您可以连接:

一个主设备有多个从设备:例如,您的ESP32利用I2C从BME280传感器读取数据,并将传感器读数写入I2C OLED显示屏。
多个主设备掌握同一个从设备:例如,两个ESP32板将数据写入同一I2C OLED显示器。

我们在ESP32中多次利用此协议与外部设备(例如传感器和显示器)进行通信。
在这种情形下,ESP32是主芯片,外部设备是从芯片。

ESP32 I2C总线接口

ESP32通过其两个I2C总线接口支持I2C通信,这两个接口可以用作I2C主设备或从设备,详细取决于用户的配置。
根据ESP32数据表,ESP32的I2C接口支持:

标准模式(100 Kbit / s) 快速模式(400 Kbit / s) 高达5 MHz,但受到SDA上拉强度的限定 7位/ 10位寻址模式 双寻址模式。
用户可以对命令寄存器进行编程以掌握I²C接口,从而具有更大的灵巧性将I2C设备与ESP32连接

I2C通信协议利用两条线共享信息。
一个用于时钟旗子暗记(SCL),另一个用于发送和吸收数据(SDA)。

把稳:在许多分支板上,SDA线也可能标记为SDI,SCL线也可能标记为SCK。

SDA和SCL线为低电平有效,因此应利用电阻将其上拉。
对付5V器件,范例值为4.7k Ohm;对付3.3V器件,范例值为2.4k Ohm。

我们在项目中利用的大多数传感器都是已内置电阻的分线板。
因此,常日,当您处理此类电子元件时,您无需为此担心。

将I2C器件连接到ESP32常日很大略,只需将GND连接到GND,将SDA连接到SDA,将SCL连接到SCL并将正电源连接到外围设备常日为3.3V(但这取决于您利用的模块)。

将ESP32与Arduino IDE结合利用时,默认的I2C引脚为GPIO 22(SCL)和GPIO 21(SDA),但您可以将代码配置为利用任何其他引脚。

通过I2C通信,总线上的每个从站都有其自己的地址,此十六进制数许可ESP32与每个设备通信。

I2C地址常日可以在组件的数据表中找到。
但是,如果很难查明,则可能须要运行I2C查找程序以查明I2C地址。

您可以利用以下程序找到设备的I2C地址。

#include <Wire.h>

void setup() {

Wire.begin();

Serial.begin(115200);

Serial.println("\nI2C Scanner");

}

void loop() {

byte error, address;

int nDevices;

Serial.println("Scanning...");

nDevices = 0;

for(address = 1; address < 127; address++ ) {

Wire.beginTransmission(address);

error = Wire.endTransmission();

if (error == 0) {

Serial.print("I2C device found at address 0x");

if (address<16) {

Serial.print("0");

}

Serial.println(address,HEX);

nDevices++;

}

else if (error==4) {

Serial.print("Unknow error at address 0x");

if (address<16) {

Serial.print("0");

}

Serial.println(address,HEX);

}

}

if (nDevices == 0) {

Serial.println("No I2C devices found\n");

}

else {

Serial.println("done\n");

}

delay(5000);

}

您会在串口监视器中看到类似的内容。
此特定示例适用于。

ESP32利用不同的I2C引脚(变动默认I2C引脚)

利用ESP32,您险些可以将任何引脚设置为具有I2C功能,您只须要在代码中进行设置即可。

将ESP32与Arduino IDE合营利用时,请利用Wire.h库与利用I2C的设备进行通信。
利用此库,您可以按以下办法初始化I2C:

Wire.begin(I2C_SDA, I2C_SCL);

因此,您只须要在I2C_SDA和I2C_SCL变量上设置所需的SDA和SCL GPIO 。

但是,如果您利用库与这些传感器进行通信,则这可能无法正常事情,选择其他引脚可能会有些棘手。
发生这种情形是由于,如果在初始化库时不通报自己的Wire实例,这些库可能会覆盖您的引脚。

在这种情形下,您须要仔细查看.cpp库文件,并理解如何通报自己的TwoWire参数。

例如,如果您仔细看一下,您会创造可以将自己的TwoWire通报给begin()方法。

因此,利用其他引脚(例如,GPIO 33作为SDA和GPIO 32作为SCL)从BME280读取示例程序如下。

#include <Wire.h>

#include <Adafruit_Sensor.h>

#include <Adafruit_BME280.h>

#define I2C_SDA 33

#define I2C_SCL 32

#define SEALEVELPRESSURE_HPA (1013.25)

TwoWire I2CBME = TwoWire(0);

Adafruit_BME280 bme;

unsigned long delayTime;

void setup() {

Serial.begin(115200);

Serial.println(F("BME280 test"));

I2CBME.begin(I2C_SDA, I2C_SCL, 100000);

bool status;

status = bme.begin(0x76, &I2CBME);

if (!status) {

Serial.println("Could not find a valid BME280 sensor, check wiring!");

while (1);

}

Serial.println("-- Default Test --");

delayTime = 1000;

Serial.println();

}

void loop() {

printValues();

delay(delayTime);

}

void printValues() {

Serial.print("Temperature = ");

Serial.print(bme.readTemperature());

Serial.println(" C");

Serial.print("Pressure = ");

Serial.print(bme.readPressure() / 100.0F);

Serial.println(" hPa");

Serial.print("Approx. Altitude = ");

Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));

Serial.println(" m");

Serial.print("Humidity = ");

Serial.print(bme.readHumidity());

Serial.println(" %");

Serial.println();

}

让我们看一下利用其他I2C引脚的干系部分。

首先,在I2C_SDA和I2C_SCL变量上定义新的I2C引脚。
在这种情形下,我们利用的是GPIO 33和GPIO 32。

#define I2C_SDA 33

#define I2C_SCL 32

创建一个新的TwoWire实例。
在这种情形下,它称为I2CBME。
这只是创建一个I2C总线。

TwoWire I2CBME = TwoWire(0);

在setup()中,利用您先前定义的引脚初始化I2C通信。
第三个参数是时钟频率。

I2CBME.begin(I2C_SDA, I2C_SCL, 400000);

末了,用您的传感器地址和TwoWire工具初始化一个BME280工具。

status = bme.begin(0x76, &I2CBME);

之后,您可以对bme工具利用常规方法来要求温度,湿度和压力。

把稳:如果您利用的库在其文件中利用诸如wire.begin()之类的语句,则可能须要注释该行,以便可以利用自己的引脚。

具有多个I2C器件的ESP32

如前所述,每个I2C设备都有其自己的地址,因此可能在同一总线上具有多个I2C设备。

多个I2C设备(相同的总线,不同的地址)

当我们有多个具有不同地址的设备时,如何设置它们很大略:

将两个外设都连接到ESP32的SCL和SDA线路;在代码中,通过其地址引用每个外围设备;

看下面的示例,该示例从BME280传感器(通过I2C)获取传感器读数,并将结果显示在I2C OLED显示器上。

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

#include <Adafruit_Sensor.h>

#include <Adafruit_BME280.h>

#define SCREEN_WIDTH 128

#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

Adafruit_BME280 bme;

void setup() {

Serial.begin(115200);

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {

Serial.println(F("SSD1306 allocation failed"));

for(;;);

}

bool status = bme.begin(0x76);

if (!status) {

Serial.println("Could not find a valid BME280 sensor, check wiring!");

while (1);

}

delay(2000);

display.clearDisplay();

display.setTextColor(WHITE);

}

void loop() {

display.clearDisplay();

display.setTextSize(1);

display.setCursor(0,0);

display.print("Temperature: ");

display.setTextSize(2);

display.setCursor(0,10);

display.print(String(bme.readTemperature()));

display.print(" ");

display.setTextSize(1);

display.cp437(true);

display.write(167);

display.setTextSize(2);

display.print("C");

display.setTextSize(1);

display.setCursor(0, 35);

display.print("Humidity: ");

display.setTextSize(2);

display.setCursor(0, 45);

display.print(String(bme.readHumidity()));

display.print(" %");

display.display();

delay(1000);

}

由于OLED和BME280具有不同的地址,因此我们可以利用相同的SDA和SCL线,而不会涌现任何问题。
OLED显示地址为0x3C,BME280地址为0x76。

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {

Serial.println(F("SSD1306 allocation failed"));

for(;;);

}

bool status = bme.begin(0x76);

if (!status) {

Serial.println("Could not find a valid BME280 sensor, check wiring!");

while (1);

}

多个I2C设备(相同地址)

但是,如果您有多个具有相同地址的外设怎么办?例如,多个OLED显示器或多个BME280传感器?有几种办理方案。

变动设备的I2C地址;利用I2C多路复用器。
变动I2C地址

许多分线板都可以选择根据其电路变动I2C地址。
例如,看下面的OLED显示器。

通过将电阻器放在一侧或另一侧,可以选择不同的I2C地址。
其他组件也会发生这种情形。

利用I2C多路复用器

但是,在前面的示例中,这仅许可您在同一总线上具有两个I2C显示器:一个具有0x3C地址,另一个具有0x3D地址。

此外,有时变动I2C地址并非易事。
因此,为了在同一I2C总线中拥有多个具有相同地址的设备,您可以利用I2C多路复用器,如TCA9548A,它许可您与多达8个具有相同地址的设备进行通信。

ESP32利用两个I2C总线接口

要利用ESP32的两个I2C总线接口,您须要创建两个TwoWire实例。

TwoWire I2Cone = TwoWire(0);

TwoWire I2Ctwo = TwoWire(1)

然后,以所需的频率在所需的引脚上初始化I2C通信。

void setup() {

I2Cone.begin(SDA_1, SCL_1, freq1);

I2Ctwo.begin(SDA_2, SCL_2, freq2);

}

然后,您可以利用Wire.h库中的方法与I2C总线接口进行交互。

一个更大略的替代方法是利用预定义的Wire()和Wire1()工具。
Wire()。
begin()利用默认引脚和默认频率在第一条I2C总线上创建I2C通信。
对付Wire1.begin(),您该当通报所需的SDA和SCL引脚以及频率。

setup(){

Wire.begin();

Wire1.begin(SDA_2, SCL_2, freq);

}

这种方法许可您利用两条I2C总线,个中一条利用默认参数。

为了更好地理解其事情事理,我们来看一个大略的示例,该示例从两个BME280传感器读取温度,湿度和压力。

每个传感器都连接到不同的I2C总线。

· I2C总线1:利用GPIO 27(SDA)和GPIO 26(SCL);

· I2C总线2:利用GPIO 33(SDA)和GPIO 32(SCL);

#include <Wire.h>

#include <Adafruit_Sensor.h>

#include <Adafruit_BME280.h>

#define SDA_1 27

#define SCL_1 26

#define SDA_2 33

#define SCL_2 32

TwoWire I2Cone = TwoWire(0);

TwoWire I2Ctwo = TwoWire(1);

Adafruit_BME280 bme1;

Adafruit_BME280 bme2;

void setup() {

Serial.begin(115200);

Serial.println(F("BME280 test"));

I2Cone.begin(SDA_1, SCL_1, 100000);

I2Ctwo.begin(SDA_2, SCL_2, 100000);

bool status1 = bme1.begin(0x76, &I2Cone);

if (!status1) {

Serial.println("Could not find a valid BME280_1 sensor, check wiring!");

while (1);

}

bool status2 = bme2.begin(0x76, &I2Ctwo);

if (!status2) {

Serial.println("Could not find a valid BME280_2 sensor, check wiring!");

while (1);

}

Serial.println();

}

void loop() {

Serial.print("Temperature from BME1= ");

Serial.print(bme1.readTemperature());

Serial.println(" C");

Serial.print("Humidity from BME1 = ");

Serial.print(bme1.readHumidity());

Serial.println(" %");

Serial.print("Pressure from BME1 = ");

Serial.print(bme1.readPressure() / 100.0F);

Serial.println(" hPa");

Serial.println("--------------------");

Serial.print("Temperature from BME2 = ");

Serial.print(bme2.readTemperature());

Serial.println(" C");

Serial.print("Humidity from BME2 = ");

Serial.print(bme2.readHumidity());

Serial.println(" %");

Serial.print("Pressure from BME2 = ");

Serial.print(bme2.readPressure() / 100.0F);

Serial.println(" hPa");

Serial.println("--------------------");

delay(5000);

}

让我们看一下利用两个I2C总线接口的干系部分。

定义要利用的SDA和SCL引脚:

#define SDA_1 27

#define SCL_1 26

#define SDA_2 33

#define SCL_2 32

创建两个TwoWire工具(两个I2C总线接口):

TwoWire I2Cone = TwoWire(0);

TwoWire I2Ctwo = TwoWire(1);

创建Adafruit_BME280库的两个实例以与您的传感器进行交互:bme1和bme2。

Adafruit_BME280 bme1;

Adafruit_BME280 bme2;

在定义的引脚和频率上初始化I2C通信:

I2Cone.begin(SDA_1, SCL_1, 100000);

I2Ctwo.begin(SDA_2, SCL_2, 100000);

然后,应利用精确的地址和I2C总线初始化bme1和bme2工具。
bme1利用I2Cone:

bool status = bme1.begin(0x76, &I2Cone);

而bme2用场I2Ctwo:

bool status1 = bme2.begin(0x76, &I2Ctwo);

现在,您可以在bme1和bme2工具上利用Adafruit_BME280库中的方法来读取温度,湿度和压力。

另一种选择

为了大略起见,可以利用预定义的Wire()和Wire1()工具:

· Wire():在默认引脚GPIO 21(SDA)和GPIO 22(SCL)上创建I2C总线

· Wire1(SDA_2,SCL_2,freq):以所需的频率在定义的SDA_2和SCL_2引脚上创建I2C总线。

这是相同的示例,但是利用此方法。
现在,您的一个传感器利用默认引脚,另一个传感器利用GPIO 32和GPIO 33。

#include <Wire.h>

#include <Adafruit_Sensor.h>

#include <Adafruit_BME280.h>

#define SDA_2 33

#define SCL_2 32

Adafruit_BME280 bme1;

Adafruit_BME280 bme2;

void setup() {

Serial.begin(115200);

Serial.println(F("BME280 test"));

Wire.begin();

Wire1.begin(SDA_2, SCL_2);

bool status1 = bme1.begin(0x76);

if (!status1) {

Serial.println("Could not find a valid BME280_1 sensor, check wiring!");

while (1);

}

bool status2 = bme2.begin(0x76, &Wire1);

if (!status2) {

Serial.println("Could not find a valid BME280_2 sensor, check wiring!");

while (1);

}

Serial.println();

}

void loop() {

Serial.print("Temperature from BME1= ");

Serial.print(bme1.readTemperature());

Serial.println(" C");

Serial.print("Humidity from BME1 = ");

Serial.print(bme1.readHumidity());

Serial.println(" %");

Serial.print("Pressure from BME1 = ");

Serial.print(bme1.readPressure() / 100.0F);

Serial.println(" hPa");

Serial.println("--------------------")

Serial.print("Temperature from BME2 = ");

Serial.print(bme2.readTemperature());

Serial.println(" C");

Serial.print("Humidity from BME2 = ");

Serial.print(bme2.readHumidity());

Serial.println(" %");

Serial.print("Pressure from BME2 = ");

Serial.print(bme2.readPressure() / 100.0F);

Serial.println(" hPa");

Serial.println("--------------------");

delay(5000);

}

您该当在串口监视器上同时得到两个传感器的读数。

在本教程中,您理解了有关ESP32的I2C通信协议的更多信息。
希望对您有帮助。

标签:

相关文章

无线无损音频往后不再是幻想_音质_音频

虽说如今不少厂商都在吹嘘自己的无线耳机利用了多大尺寸的发声单元,利用了哪些专业的解码方案,但我们都清楚,同一价位段的无线蓝牙耳机在...

科学 2024-12-19 阅读0 评论0

关于光模块看这一篇就够啦_模块_暗记

随着光通信的高速发展,现在我们事情和生活中很多场景都已经实现了“光进铜退”。也便是说,以同轴电缆、网线为代表的金属介质通信,逐渐被...

科学 2024-12-19 阅读0 评论0