Leave notes for your family, show a welcome message or display a reminder on your desk. The ESP32 shows a small web page with two text boxes, one for each line of the LCD. Type your message, press Send, and it appears on the screen straight away.
What you need
- ESP32 board, expansion board and USB cable
- 1602 LCD display
- 10 kΩ potentiometer
- 1 resistor, 220 Ω
- Breadboard and jumper wires (all from the ESP32 IoT Starter Kit)
- A 2.4 GHz Wi-Fi network
Good to know
Plug the ESP32 into the expansion board from the kit, or place it next to the breadboard, and connect the pins with jumper wires.
The LCD needs 5V power, from the ESP32's 5V pin. The ESP32 only sends signals to the LCD, so its 3.3 V outputs work fine. If the LCD has no pins, solder 16 pins from the 40-pin male header in the kit.
Wiring

| LCD pin | Connect to |
|---|---|
| VSS | GND |
| VDD | 5V |
| V0 | Middle pin of the potentiometer |
| RS | ESP32 GPIO 13 |
| RW | GND |
| E | ESP32 GPIO 14 |
| D0 to D3 | Not connected |
| D4, D5, D6, D7 | ESP32 GPIO 27, 26, 25, 33 |
| A (backlight +) | 220 Ω resistor, then 5V |
| K (backlight −) | GND |
Connect the potentiometer's outer pins to 5V and GND. Use the breadboard rails for all 5V and GND connections.
Build it step by step
- Place the LCD and the potentiometer on the breadboard.
- Connect the ESP32's 5V and GND to the rails.
- Wire the LCD power, contrast and backlight, then the six signal wires.
- Enter your Wi-Fi details and upload the code. Turn the potentiometer until the text is sharp.
- The LCD shows the address to open. Open it on your phone and send a message.
The code
Replace YOUR_WIFI_NAME and YOUR_WIFI_PASSWORD with your own network details. The ESP32 only connects to 2.4 GHz Wi-Fi. After uploading, open the Serial Monitor at 115200 baud to see the address to open on your phone. The phone must be on the same Wi-Fi network.
#include <WiFi.h>
#include <WebServer.h>
#include <LiquidCrystal.h>
const char* WIFI_NAME = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
// LCD pins: RS, E, D4, D5, D6, D7
LiquidCrystal lcd(13, 14, 27, 26, 25, 33);
WebServer server(80);
String line1 = "Hello!";
String line2 = "";
String cleanText(String text) {
String out = "";
for (unsigned int i = 0; i < text.length() && out.length() < 16; i++) {
char c = text[i];
if (c >= 32 && c <= 126) out += c; // the LCD shows plain letters, numbers and symbols
}
return out;
}
String htmlSafe(String text) {
text.replace("&", "&");
text.replace("<", "<");
text.replace(">", ">");
text.replace("'", "'");
return text;
}
void showMessage() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(line1);
lcd.setCursor(0, 1);
lcd.print(line2);
}
String page() {
String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
html += "<meta name='viewport' content='width=device-width, initial-scale=1'><title>Message board</title></head>";
html += "<body style='font-family:sans-serif;padding:16px;max-width:420px'><h1>Message board</h1>";
html += "<form action='/send'>";
html += "<p><input name='l1' maxlength='16' value='" + htmlSafe(line1) + "' style='font-size:20px;width:100%'></p>";
html += "<p><input name='l2' maxlength='16' value='" + htmlSafe(line2) + "' style='font-size:20px;width:100%'></p>";
html += "<p><button style='font-size:20px'>Send</button></p></form>";
html += "<p style='color:#888'>16 characters per line.</p></body></html>";
return html;
}
void setup() {
Serial.begin(115200);
lcd.begin(16, 2);
lcd.print("Connecting...");
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) delay(500);
lcd.clear();
lcd.print("Open:");
lcd.setCursor(0, 1);
lcd.print(WiFi.localIP()); // the address to open on your phone
Serial.print("Open http://");
Serial.println(WiFi.localIP());
server.on("/", []() { server.send(200, "text/html", page()); });
server.on("/send", []() {
line1 = cleanText(server.arg("l1"));
line2 = cleanText(server.arg("l2"));
showMessage();
server.sendHeader("Location", "/");
server.send(303); // back to the form
});
server.begin();
}
void loop() {
server.handleClient();
}
How it works
When you press Send, your phone opens the /send address with both lines in it. The ESP32 reads them with server.arg(), keeps only characters the LCD can show (up to 16 per line), prints them and sends your phone back to the form. htmlSafe() makes sure text like < or > is shown as text on the web page, not treated as code.
Make it your own
- Make long messages scroll across the screen with
lcd.scrollDisplayLeft(). - Add the DHT11 and show the temperature when no message is set.
- Show the time the message was sent on the web page.
Troubleshooting
- Only blocks or a blank screen: turn the potentiometer slowly from one end to the other.
- Strange characters: check RS, E and D4 to D7.
- Accented letters are missing: the LCD can only show plain English letters, numbers and symbols, so other characters are skipped.
Learn the basics first
New to these parts? These lessons explain them step by step: Set up the ESP32 in the Arduino IDE and Control a relay from your phone over Wi-Fi.
0 comments