Embedded System Journey #5: LCD Display and PWM with Arduino IDE on ESP32

Vincent Franstyo
7 min readMar 15, 2023

--

— Introduction🧠

Hi, back again with me, Vincent. In today’s episode, we’re gonna talk about LCD Display and PWM (Pulse-Width Modulation). This is the my fifth journey with ESP32. If you are new here, I highly recommend you to read my blog since the first episode, which is here. With no further ado, let’s jump right to it!

LCD Display

As what the name suggest, we are gonna display something into our LCD in this project.

— Components🤌🏻

In this project, the required components are:

  • 16x2 soldered with I2C LCD Display
  • ESP32 Board
  • Breadboard
  • Jumper cables (it is recommended to use female-to-female if you have one, but Imma just use male-to-male and female-to-male in this project)
  • USB-A to micro-USB cable

— Schema 👩🏻‍🔧

If you are looking for an official reference, you can see it here.

LCD Display Schema

As what you can see here, the pins are connected:

  • GND — GND
  • VCC — VIN
  • SDA — GPIO 21
  • SCL — GPIO 22

And mine turned out to be this way.

real circuit of LCD

STATIC MESSAGE IN LED DISPLAY

— Codes Overview 💻

Don’t get too excited! We have to download and install a library called LiquidCrystal_I2C in order to make this work. You can get the file here. After downloading the file, you have to move it to the library folder located in the Arduino IDE. Delete the “-master” and re-open your Arduino IDE. You’re good to go!

Firstly, we have to find our I2C Address. Use this code and upload it to your ESP32.

/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/

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

Open the serial monitor and set your baud rate to 115200 baud and see the address printed there. Mine was printed 0x27. If you are using 16x2 LCD, you’ll prolly have the same address.

Next, we get to the real code part. Here’s the code used to display a static message in your LCD Display.

/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/

#include <LiquidCrystal_I2C.h>

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;

// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

void setup(){
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
}

void loop(){
// set cursor to first column, first row
lcd.setCursor(0, 0);
// print message
lcd.print("Hello, World!");
delay(1000);
// clears the display to print new message
lcd.clear();
// set cursor to first column, second row
lcd.setCursor(0,1);
lcd.print("Hello, World!");
delay(1000);
lcd.clear();
}

— Result🏁

Voila! The message shows up. (Yes, it’s the Hello, World! project which everyone should have been familiar with).

Static message in LCD Display

SCROLLING MESSAGE IN LED DISPLAY

— Schema👩🏻‍🔧

The schema is actually the same with the static message display, so I guess I won’t be putting it here again hehe.

— Code Overview 💻

Since we don’t actually have any separate step from the static message display, Imma just jump into the code.

The code itself is actually not quite different though. You can just copy the code down here and upload it to your ESP32.

/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/

#include <LiquidCrystal_I2C.h>

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;

// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

String messageStatic = "Static message";
String messageToScroll = "This is a scrolling message with more than 16 characters";

// Function to scroll text
// The function acepts the following arguments:
// row: row number where the text will be displayed
// message: message to scroll
// delayTime: delay between each character shifting
// lcdColumns: number of columns of your LCD
void scrollText(int row, String message, int delayTime, int lcdColumns) {
for (int i=0; i < lcdColumns; i++) {
message = " " + message;
}
message = message + " ";
for (int pos = 0; pos < message.length(); pos++) {
lcd.setCursor(0, row);
lcd.print(message.substring(pos, pos + lcdColumns));
delay(delayTime);
}
}

void setup(){
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
}

void loop(){
// set cursor to first column, first row
lcd.setCursor(0, 0);
// print static message
lcd.print(messageStatic);
// print scrolling message
scrollText(1, messageToScroll, 250, lcdColumns);
}

— Result🏁

The result should be as shown below. You will see letters going in and out of the display since the message is scrolling.

Scrolling message LCD Display

— Story Time 🤫

I actually made a little message when I tried it the first time. I accidentally connected the VIN to GND and GND to VCC. When I connected the board to the PC, smokes start coming out. I was panicked and pull the cable out quickly. The burnt smells so good that I almost vomit. Luckily, my ESP32 still able to function properly. Since we will be using both sides of the ESP32, I connected only one side of the board to the breadboard. Okay enough story time.
Moral lesson : Drink before attempting to do this project.

PWM

PWM stands for Pulse-Width Modulation. In this project, we’re gonna use PWM to make the LED slowly lights up and slowly dies.

— Components 🤌🏻

All we need is basically the same as doing the digital I/O project since we will just be playing with LEDs. Here are all the components we need.

  • Breadboard
  • ESP32 Board DOIT DEVKIT V1
  • Male-to-male jumper cable
  • LEDs (minimum of 1)
  • 330 Ohm resistor (minimum of 1)
  • micro-USB to USB-A Cable

— Schema 👩🏻‍🔧

Here’s the schema we use in this project. This schema is taken from this reference.

1 LED Schema

And mine turned out to be this way.

1 LED circuit

— Code Overview💻

Here’s the code used to build this project.

// the number of the LED pin
const int ledPin = 16; // 16 corresponds to GPIO16

// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;

void setup(){
// configure LED PWM functionalitites
ledcSetup(ledChannel, freq, resolution);

// attach the channel to the GPIO to be controlled
ledcAttachPin(ledPin, ledChannel);
}

void loop(){
// increase the LED brightness
for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){
// changing the LED brightness with PWM
ledcWrite(ledChannel, dutyCycle);
delay(15);
}

// decrease the LED brightness
for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--){
// changing the LED brightness with PWM
ledcWrite(ledChannel, dutyCycle);
delay(15);
}
}

Compile and upload the code to your ESP32 and you’re done!

— Result🏁

Since using GIF really made the quality downgrade, I’ll just put a Youtube link here to show you the result.

— Personal Experiment 🧪

I tried using 3 LEDs and the additional components are just 2 more LEDs, 2 more 330 Ohm resistor and 2 more Male-to-male jumper cable.

Here’s the schema I use in this experiment.

3 LED Schema

Here’s how my circuit turned out to.

3 LED circuit

The code changed a little bit. Here’s the 3-LED version of the code.

// the number of the LED pin
const int ledPin = 16; // 16 corresponds to GPIO16
const int ledPin2 = 17; // 17 corresponds to GPIO17
const int ledPin3 = 5; // 5 corresponds to GPIO5

// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;

void setup(){
// configure LED PWM functionalitites
ledcSetup(ledChannel, freq, resolution);

// attach the channel to the GPIO to be controlled
ledcAttachPin(ledPin, ledChannel);
ledcAttachPin(ledPin2, ledChannel);
ledcAttachPin(ledPin3, ledChannel);
}

void loop(){
// increase the LED brightness
for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){
// changing the LED brightness with PWM
ledcWrite(ledChannel, dutyCycle);
delay(15);
}

// decrease the LED brightness
for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--){
// changing the LED brightness with PWM
ledcWrite(ledChannel, dutyCycle);
delay(15);
}
}

Compile and upload the code to your ESP32 and you should be done for the day ! 🎊🎊

The result will be as shown in the Youtube video linked below.

3 LED Result

— Thanks! 🙏🏻

Thanks for staying tuned to my fifth journey in doing this embedded system project. Feel free to slide to my DM if something is wrong with the article. 😉

Todalooos! 👋🏻

--

--