Serial Communications: All about the I2C protocols and connecting multiple devices!

Kinanti Wening Asih
7 min readMar 19, 2023

--

Serial Communications!

Hey guys! :D Today we’ll be delving into the world of I2C communication with the ESP32. As you may already know, the ESP32 is a powerful microcontroller that has two I2C bus interfaces that can function as either an I2C master or slave. In our embedded systems class, we’ve been learning about various communication protocols and their implementation in microcontrollers. I2C, or Inter-Integrated Circuit, is a communication protocol that allows multiple devices to communicate with each other using only two wires: a clock line (SCL) and a data line (SDA). Our class was tasked with implementing I2C communication with the ESP32 using the Arduino IDE. We learned about the importance of choosing the right I2C pins for our project and how to connect multiple I2C devices to the same bus. It was fascinating to learn about the different techniques for avoiding signal distortion when multiple devices are connected to the same bus. One of the most interesting things we learned was how to use the two I2C bus interfaces on the ESP32. This allows us to connect even more I2C devices to our project, expanding its capabilities and functionality.

For my personal project, I decided to experiment with the BME280 sensor and an OLED display to demonstrate I2C communication with the ESP32. The BME280 sensor is a popular sensor for measuring temperature, pressure, and humidity. I connected it to the ESP32 via the I2C bus and was able to read its data on the OLED display.

But I didn’t stop there! I wanted to add a personal touch to my project and decided to incorporate an LED light that would turn on when the temperature exceeded a certain threshold. I wrote some code to read the BME280 sensor data and used it to control the LED light. It was a great way to see the practical application of I2C communication in my embedded systems project.

To put to perspective, here is an example schema, with ESP32 being the Master and the other sensors/displays being the Slaves

Source: randomnerdtutorials.com

In this project, since we are using the OLED and BME280 which use the I2C communication, we’ll tackle those! Let’s get started right away!

The Materials

Materials for Serial Communication project
  1. Our friend, the ESP32, and the breadboard!
  2. The OLED display
  3. The BME280 sensor
  4. (A lot of) male-to-male jumper cables
  5. USB Cable

The Assembly

Circuit Assembly!

Initially, I found it quite hard to think about assembly. You had to connect two devices to the same bus (in this case, GPIO 21 and 22 of the ESP32). Then, I tried to simplify my flow of thoughts:

  1. First, I connected the 3V3 port on the ESP32 to the positive side of the breadboard. Then, I connected the GND port to the negative side.
  2. On the OLED and the BME280, I connected the VCC/VDD to the positive side and the GND to the negative side. We have set up a loop! :D
  3. I connected the SCK and SDA on the OLED to their respective pins on the ESP32.
  4. To bring the BME280 into the equation, I connected the SCK and SDA pins on the BME280 parallel to the SCK and SDA pins of the OLED. This allows for both SCKs and SDAs to be connected to the buses in ESP32 :D

The Code

Here is the code I used for this scheme. I followed a tutorial posted on https://microcontrollerslab.com/bme280-esp32-display-values-oled-arduino-ide/:

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme;

Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire);
unsigned long delayTime;

void setup() {
Serial.begin(9600);
Serial.println(F("BME280 test"));

display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
delay(100);
display.clearDisplay();
display.display();
display.setTextSize(1.2);
display.setTextColor(WHITE);

bool status;
status = bme.begin(0x76);
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() {

display.setCursor(0,0);
display.clearDisplay();

Serial.print("Temperature = "); Serial.print(bme.readTemperature()); Serial.println(" *C");
display.print("Temperature: "); display.print(bme.readTemperature()); display.println(" *C");

Serial.print("Pressure = "); Serial.print(bme.readPressure() / 100.0F); Serial.println(" hPa");
display.print("Pressure: "); display.print(bme.readPressure() / 100.0F); display.println(" hPa");

Serial.print("Humidity = "); Serial.print(bme.readHumidity()); Serial.println(" %");
display.print("Humidity: "); display.print(bme.readHumidity()); display.println(" %");

Serial.println();
display.display();
delay(1000);
}

First, we include all the needed libraries as stated down below:

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Then, we define the Sea Level Pressure and set up the BME and OLED by setting them on the default I2C GPIO pins.

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme;

Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire);
unsigned long delayTime;

The next part initiates the serial communication at a baud rate of 115200 by using the begin() function and prints out “BME280 test”

void setup() {
Serial.begin(9600);
Serial.println(F("BME280 test"));

The next bit of code initializes the OLED display and checks for errors:

display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
delay(100);
display.clearDisplay();
display.display();
display.setTextSize(1.2);
display.setTextColor(WHITE);

bool status;
status = bme.begin(0x76);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}

Serial.println("-- Default Test --");
delayTime = 1000;

Serial.println();

We are now going to the loop! To put simply, it displays on the screen whatever readings the BME280 gets:

void loop() { 

display.setCursor(0,0);
display.clearDisplay();

Serial.print("Temperature = "); Serial.print(bme.readTemperature()); Serial.println(" *C");
display.print("Temperature: "); display.print(bme.readTemperature()); display.println(" *C");

Serial.print("Pressure = "); Serial.print(bme.readPressure() / 100.0F); Serial.println(" hPa");
display.print("Pressure: "); display.print(bme.readPressure() / 100.0F); display.println(" hPa");

Serial.print("Humidity = "); Serial.print(bme.readHumidity()); Serial.println(" %");
display.print("Humidity: "); display.print(bme.readHumidity()); display.println(" %");

Serial.println();
display.display();
delay(1000);
}

Voila! The code is done :D

The Tests

Let’s see if our code and assembly is correct. We’ll upload the code and pray all goes well!

IT WORKS! :D

First try! Successfully displayed the readings. Very grateful :) Now let’s test it by putting my finger over the sensor. The temperature and humidity should increase.

Before I cover with my finger:

Display before sensor covered by finger

After I cover it:

Display after sensor covered by finger

You could see a 3 degree change on the temperature and a 13% increase in humidity!

Personal Experiment

For my personal experiment I will be adding a 330 ohm resistor and an LED light. The LED will light up when the humidity is above 80%!

The Assembly

Circuit + LED and resistor!

The assembly is similar to the previous one, except for the fact that there is an additional LED, connected to the GND and the D5 GPIO.

The Code

For the code, we will be adding the settings for the LED:

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SEALEVELPRESSURE_HPA (1013.25)
const int ledPin = 5;

Adafruit_BME280 bme; // I2C
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire);
unsigned long delayTime;

void setup() {
Serial.begin(9600);
Serial.println(F("BME280 test"));

pinMode (ledPin, OUTPUT);

display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
delay(100);
display.clearDisplay();
display.display();
display.setTextSize(1.2);
display.setTextColor(WHITE);

bool status;
status = bme.begin(0x76);
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() {

display.setCursor(0,0);
display.clearDisplay();

Serial.print("Temperature = "); Serial.print(bme.readTemperature()); Serial.println(" *C");
display.print("Temperature: "); display.print(bme.readTemperature()); display.println(" *C");

Serial.print("Pressure = "); Serial.print(bme.readPressure() / 100.0F); Serial.println(" hPa");
display.print("Pressure: "); display.print(bme.readPressure() / 100.0F); display.println(" hPa");

Serial.print("Humidity = "); Serial.print(bme.readHumidity()); Serial.println(" %");
display.print("Humidity: "); display.print(bme.readHumidity()); display.println(" %");
if (bme.readHumidity()>80) {
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}

Serial.println();
display.display();
delay(1000);
}

The Test

For the test, we will blow onto the sensor! The LED should light up. This is what it looks like directly after I blew onto the sensor, and a couple of seconds after.

LED lights up when humidity > 80

Initially when the humidity is 80>, the LED is on. Then after it slowly drops and reaches 78%, the LED turns off!

Conclusion

No words but congrats to everyone who made it through this week! With tubes deadlines, tasks, quizzes, etc., you guys deserve a good rest. Arrivederci!

Good Luck!

--

--

Kinanti Wening Asih

STEMinist || figure skating enthusiast passionate about computer science, discrete maths, english, and philosophy