
ESP32-S3 board
The brain that runs your uploaded sketch.
TinySkiff ESP32-S3 Lab · Day 25 of 30
Today the project gets a face. You wire the LCD1602's four pins to the board, add one library to the Arduino IDE, and upload a sketch that greets you on the top row while the bottom row counts the seconds — a whole screen carried over two signal wires.
TSK-DAY25-LCD
Hand this to an agent so it can pull the lesson packet and coach you step by step.
01 First, know the pieces
Five things, and only four wires between them. Tap Define on any part you haven't met — the answer opens as a field note you can read and dismiss without losing your place.

The brain that runs your uploaded sketch.

Spreads the pins into rows you can reach and label.

A sixteen-by-two character screen with an I2C backpack on its back.

Female ends slide onto the module's pins; male ends reach the board.

Uploads the sketch to the board.
02 Make the physical circuit
The official Freenove diagram is your chart — schematic on top, the same circuit built on a breadboard below. Click it to enlarge. Four wires today, all from the little backpack board soldered to the back of the screen.
Mind the 5V pin. The module's VCC wants the board's 5V pin — on 3.3V the display runs faint or dark. Unplug USB before you move any wire.
03 One action at a time
This is the main path — you can finish the day without opening a single field note. Tap each step as you go to keep your place.
Seat the ESP32-S3 on the GPIO extension board and keep USB unplugged while you wire.
Turn the LCD module over and find the four labelled pins on its backpack — GND, VCC, SDA, SCL.
Slide female jumper ends onto GND and VCC, then land them on the board's GND and 5V pins.
Wire SDA to GPIO 14 and SCL to GPIO 13.
Compare every wire to the chart before you plug in USB.
In Arduino IDE choose Sketch → Include Library → Add .ZIP Library… and pick LiquidCrystal_I2C-1.1.2.zip from the kit download's C/Libraries folder — you install it once and it stays.
Open Sketch_18.1_Display_the_string_on_LCD1602.ino and upload it. (Wire.h, the I2C library, ships with the board package.)
Watch row 0 greet you and row 1 start counting seconds.
04 Read just enough code
The sketch does its real work in setup — start the I2C bus, find the display's address, wake it, and print the greeting. The loop then rewrites row 1 once a second with the count. Switch to MicroPython if you'd rather see the same idea in Python — the wiring never changes.
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#define SDA 14 //Define SDA pins
#define SCL 13 //Define SCL pins
/*
* note:If lcd1602 uses PCF8574T, IIC's address is 0x27,
* or lcd1602 uses PCF8574AT, IIC's address is 0x3F.
*/
LiquidCrystal_I2C lcd(0x27,16,2);
void setup() {
Wire.begin(SDA, SCL); // attach the IIC pin
if (!i2CAddrTest(0x27)) {
lcd = LiquidCrystal_I2C(0x3F, 16, 2);
}
lcd.init(); // LCD driver initialization
lcd.backlight(); // Open the backlight
lcd.setCursor(0,0); // Move the cursor to row 0, column 0
lcd.print("hello, world!"); // The print content is displayed on the LCD
}
void loop() {
lcd.setCursor(0,1); // Move the cursor to row 1, column 0
lcd.print("Counter:"); // The count is displayed every second
lcd.print(millis() / 1000);
delay(1000);
}
bool i2CAddrTest(uint8_t addr) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
return true;
}
return false;
}
Wire.begin(SDA, SCL)Starts the I2C bus with GPIO 14 as the data line and GPIO 13 as the clock. LiquidCrystal_I2C lcd(0x27,16,2)Names the display by its bus address — 16 columns, 2 rows. If nothing answers at 0x27, i2CAddrTest lets the sketch switch to 0x3F by itself. lcd.setCursor(0,1)Parks the cursor at column 0 of row 1 so the next print lands on the bottom row.lcd.print(millis() / 1000)Prints the seconds since the board booted — the running count you see tick. Optional side path · same circuit
i2c = I2C(scl=Pin(13), sda=Pin(14), freq=400000)
devices = i2c.scan()
lcd = I2cLcd(i2c, device, 2, 16)
lcd.move_to(0, 0)
lcd.putstr("Hello,world!")
count = 0
while True:
lcd.move_to(0, 1)
lcd.putstr("Counter:%d" %(count))
time.sleep_ms(1000)
count += 1
devices = i2c.scan()Asks every address on the bus and uses whichever one answers — the same job the Arduino sketch's address test does.lcd.putstr("Counter:%d" %(count))Rewrites row 1 with the running count once a second.Same pins, same wiring. This path needs two helper modules — I2C_LCD.py and LCD_API.py from the same kit folder — copied onto the board before it runs. Run it in Thonny if MicroPython is set up; otherwise skip it — it should never block the Arduino-first path.
05 Understand, don't memorise
A bare LCD1602 wants over a dozen wires. The backpack soldered to its back shrinks that to two signals, because I2C sends everything as addressed messages down a shared pair.
SDA carries the data while SCL keeps the beat for both ends.
Every device on the bus has a number so the board can call this one by name.
It turns bus messages into the many parallel signals the bare LCD needs.
The sketch parks the cursor at a row and column and writes characters there.
two wires → address → cursor position → characters
The bits travel single file down SDA the way they travel down USB to your Serial Monitor; SCL is the shared clock that tells both ends when each bit counts.
Backpacks built on the PCF8574T chip answer at 0x27 and PCF8574AT boards answer at 0x3F. The sketch tries 0x27 first and switches by itself when nothing replies.
06 Know it worked
Nothing prints to the Serial Monitor today — the proof is written on the glass in front of you.
A glowing backlight with blank rows is normal at first — the contrast dial on the back of the module sets whether characters show, and it often ships turned too far.
07 Make the idea yours
Same working circuit, three edits to the two print lines. It fits inside today's 25 minutes.
Change lcd.print("hello, world!") to your boat's name and upload — row 0 is yours now.
Make row 1 read like a clock — print millis() / 60000 for the minutes, print a colon, then print (millis() / 1000) % 60 for the seconds.
Print a message longer than sixteen characters and watch where the extra letters go. Then trim the message until the whole line fits the glass again.
Logbook
08 Learn it with a hand on the tiller
Every lesson ships with a code and a machine-readable packet, so an agent can guide you with full context.
TSK-DAY25-LCD
How the agent should behave: guide one physical connection at a time, wait for you to confirm, explain terms on request, and always check wiring, board, port, and USB before changing code.