цифровая электроника
вычислительная техника
встраиваемые системы

 

ESP32 и интерфейс I2C

Автор: Mike(admin) от 7-10-2019, 11:15

Шина I2C в микроконтроллере ESP32


ESP32 имеет два интерфейса шины I2C, которые позволяют работать ему в качестве главного (Master) или подчиненного (Slave) на шине I2C. В этом руководстве мы рассмотрим протокол связи I2C с ESP32 с использованием Arduino IDE: как выбрать выводы I2C, подключить несколько устройств I2C к одной шине и как использовать два интерфейса шины I2C.


ESP32 и интерфейс I2C

I2C означает Inter Integrated Circuit и представляет собой протокол синхронной связи с несколькими ведущими и несколькими подчиненными устройствами. Вы можете подключить несколько ведомых устройств к одному мастеру: например, ваш ESP32 считывает данные с датчика BME280, используя I2C, и записывает показания датчика на OLED-дисплее I2C. Также вы можете сделать так, что несколько мастеров управляют одним и тем же ведомым устройством: например, две платы ESP32 записывают данные на один и тот же I2C OLED-дисплей.


ESP32 и интерфейс I2C

В соответствии с документацией на ESP32, интерфейсы I2C ESP32 поддерживают:


  • Стандартный режим (100 кбит/с)
  • Быстрый режим (400 Кбит/с)
  • До 5 МГц, но ограничено подтягиванием линии SDA
  • 7-битный / 10-битный режим адресации
  • Режим двойной адресации. Пользователи могут программировать регистры команд для управления интерфейсами I2C, чтобы они были более универсальными

Подключение устройств I2C к ESP32


Протокол обмена данными I2C использует два провода для обмена информацией. Один используется для тактового сигнала (SCL), а другой – для отправки и получения данных (SDA). Примечание: на многих платах линия SDA также может быть помечена как SDI, а линия SCL как SCK.


интерфейс I2C

Линии SDA и SCL имеют низкий активный уровень, поэтому их следует подтягивать резисторами. Типичные значения: 4,7 кОм для устройств с напряжением 5 В и 2,4 кОм для устройств с напряжением 3,3 В. Большинство датчиков, которые радиолюбители используют в своих проектах, представляют собой платы, в которые уже встроены резисторы. Поэтому обычно, когда вы имеете дело с электронными компонентами такого типа, вам не нужно об этом беспокоиться. Подключить устройство I2C к ESP32 обычно так же просто, как подключить GND к GND, SDA к SDA, SCL к SCL и положительный источник питания к линии питания, обычно 3,3 В (но это зависит от используемого вами модуля). При использовании 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);          
}

Вы получите нечто подобное в вашем последовательном мониторе. Этот конкретный пример для ЖК-дисплея I2C.


ESP32 и интерфейс I2C

С ESP32 вы можете установить практически любой вывод для поддержки возможностей I2C, вам просто нужно установить это в своем коде. При использовании ESP32 с Arduino IDE используйте библиотеку Wire.h для связи с устройствами, использующими I2C. С помощью этой библиотеки вы инициализируете I2C следующим образом: Wire.begin(I2C_SDA, I2C_SCL).


Итак, вам просто нужно установить нужные SDIO и SCL GPIO для переменных I2C_SDA и I2C_SCL. Однако, если вы используете библиотеки для связи с этими датчиками, это может не сработать, и может быть немного сложно выбрать другие контакты. Это происходит потому, что эти библиотеки могут перезаписать ваши выводы, если вы не пропустите свой собственный экземпляр Wire при инициализации библиотеки. В этих случаях вам нужно внимательнее взглянуть на файлы библиотеки .cpp и посмотреть, как передать ваши собственные параметры TwoWire. Итак, пример скетча для чтения из BME280 с использованием других выводов, например GPIO 33 в качестве SDA и GPIO 32 в качестве SCL, выглядит следующим образом.



#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();
}

Схема подключения для этого примера следующая.


ESP32 и интерфейс I2C

ESP32 с несколькими устройствами I2C


Как мы уже упоминали ранее, каждое устройство I2C имеет свой собственный адрес, поэтому можно использовать несколько устройств I2C на одной шине. Когда у нас есть несколько устройств с разными адресами, все просто в их настройке: подключите оба периферийных устройства к линиям ESP32 SCL и SDA, в коде обращайтесь к каждому периферийному устройству по его адресу. Посмотрите на следующий пример, который получает показания датчика от датчика BME280 (через I2C) и отображает результаты на OLED-дисплее I2C.



#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);
}

Схема подключения для этого примера следующая.


ESP32 и интерфейс I2C

Поскольку OLED и BME280 имеют разные адреса, мы можем без проблем использовать одни и те же линии SDA и SCL. OLED-дисплей имеет адрес 0x3C, а адрес BME280 - 0x76.


ESP32 и интерфейс I2C

Но что, если у вас есть несколько периферийных устройств с одним и тем же адресом? Например, несколько дисплеев OLED или несколько датчиков BME280? Есть несколько решений: изменить адрес устройства I2C или использовать мультиплексор I2C.


Рассмотрим первый случай. Многие платы имеют возможность изменять адрес I2C в зависимости от его схемы. Например, если посмотреть на следующий OLED-дисплей:


OLED-дисплей с I2C

Поместив резистор на одну или другую сторону, вы можете выбрать разные адреса I2C. Это также происходит с другими компонентами.


Однако в предыдущем примере это позволяет вам иметь только два дисплея I2C на одной шине: один с адресом 0x3C, а другой с адресом 0x3D. Кроме того, иногда сложно выполнить изменение адреса I2C. Таким образом, чтобы иметь несколько устройств с одинаковым адресом на одной шине I2C, вы можете использовать мультиплексор I2C, такой как TCA9548A, который позволяет обмениваться данными с 8 устройствами с одним и тем же адресом.


TCA9548A

ESP32 с использованием двух шинных интерфейсов I2C


Чтобы использовать два интерфейса шины I2C ESP32, необходимо создать два экземпляра TwoWire, например: TwoWire I2Cone = TwoWire(0); TwoWire I2Ctwo = TwoWire(1).


Затем инициализируйте связь I2C на желаемых выводах с определенной частотой: 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, а также частоту. Этот метод позволяет использовать две шины I2C, одна из которых использует параметры по умолчанию. Чтобы лучше понять, как это работает, мы рассмотрим простой пример, который считывает температуру, влажность и давление с двух датчиков BME280.


ESP32 и интерфейс I2C

Каждый датчик подключен к другой шине I2C.


ESP32 и интерфейс I2C

Код программы этого примера следующий.



#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);
}

Для простоты вы можете использовать предопределенные объекты Wire() и Wire1(). Wire() создает шину I2C на выводах по умолчанию GPIO 21 (SDA) и GPIO 22 (SCL), Wire1(SDA_2, SCL_2, freq): создает шину I2C на определенных выводах SDA_2 и SCL_2 с требуемой частотой.


ESP32 и интерфейс 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



© digitrode.ru


Теги: ESP32, I2C



   Благодарим Вас за интерес к информационному проекту digitrode.ru.
   Если Вы хотите, чтобы интересные и полезные материалы выходили чаще, и было меньше рекламы,
   Вы можее поддержать наш проект, пожертвовав любую сумму на его развитие.


Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Комментарии:

Оставить комментарий