Text Displays
Wiring character LCDs and small OLEDs to an ESP32 over I²C, and dividing a screen into Text Fields for radio frequencies, transponder codes and other cockpit readouts.
When a value needs more than digits — "COM1 118.750", "XPDR 7000 ALT", a page of a radio stack — a character LCD or a small OLED does the job. Both sit on the ESP32's I²C bus , so they cost no extra pins beyond SDA and SCL, and both are treated as a grid of character cells.
| Display | Grid | I²C address | Supply |
|---|---|---|---|
| HD44780 LCD + PCF8574 backpack | 8–40 columns × 1–4 rows (16×2, 20×4) | 0x20–0x27 (PCF8574), 0x38–0x3F (PCF8574A) — usually 0x27 or 0x3F | 5 V |
| SSD1306 / SH1106 OLED, 128×64 | 21×8 at text size 1, 10×4 at size 2 | 0x3C or 0x3D | 3.3 V |
| SSD1306 / SH1106 OLED, 128×32 | 21×4 at text size 1, 10×2 at size 2 | 0x3C or 0x3D | 3.3 V |
A bare HD44780 needs six or more pins. Buy it with a PCF8574 I²C backpack soldered on (or solder one yourself) and it needs only the two bus wires plus power. The backpack carries a contrast trimmer — if the screen powers up showing nothing or a row of solid blocks, turn it until the characters appear — and a jumper that switches the backlight .
| Backpack pin | Connect to | Colour |
|---|---|---|
| SDA | I²C SDA (e.g. GPIO 21) | Orange |
| SCL | I²C SCL (e.g. GPIO 22) | Yellow |
| VCC | 5 V (VIN / USB 5 V) | Red |
| GND | GND | Black |
Arduino code
// 20×4 character LCD on a PCF8574 backpack (LiquidCrystal_I2C library)
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // address, columns, rows
void setup() {
Wire.begin(21, 22); // SDA, SCL
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0); // column 0, row 0
lcd.print("COM1 118.750");
lcd.setCursor(0, 1);
lcd.print("STBY 121.500");
}
void loop() {}The common 0.96" and 1.3" OLED modules are 128 pixels wide and 64 or 32 high, driven by an SSD1306 or an SH1106 (most 1.3" modules). The two chips need different drivers, so check which one your module has. They run on 3.3 V and wire straight to the bus. The address is 0x3C , or 0x3D with the address jumper on the back moved.
| Setting | Values | Notes |
|---|---|---|
| Text size | 1 or 2 | A fixed 6×8 font: 21×8 cells at size 1, 10×4 at size 2 on a 128×64 panel |
| Contrast | 0–255 | Dims the whole panel; 207 if you leave it out |
| Flipped | on / off | For a panel mounted upside down behind the bezel |
Arduino code
// 128×64 SSD1306 OLED (Adafruit_SSD1306 library)
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
void setup() {
Wire.begin(21, 22);
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
oled.clearDisplay();
oled.setTextSize(1); // 6×8 cells: 21 columns × 8 rows
oled.setTextColor(SSD1306_WHITE);
oled.setCursor(0, 0);
oled.print("XPDR 7000 ALT");
oled.display();
}
void loop() {}One screen almost always shows several independent values — a radio's active and standby frequency on one 20×4 LCD, for example. So rather than binding the whole screen, you divide it into Text Fields : a run of character cells on one row, given by its row , starting column and width . Each field shows one value.
| Field | Row | Column | Width | Shows |
|---|---|---|---|---|
| COM1 active | 0 | 5 | 7 | 118.750 |
| COM1 standby | 1 | 5 | 7 | 121.500 |
| Transponder code | 2 | 5 | 4 | 7000 |
The text a field receives is final: it is drawn left-aligned, cut to the field's width, and the rest of the field is blanked. Characters outside printable ASCII show as blanks. Two fields on the same row must not overlap.
// Write one field: left-aligned, cut to its width, rest blanked
void writeField(uint8_t row, uint8_t column, uint8_t width, const char* text) {
lcd.setCursor(column, row);
for (uint8_t i = 0; i < width; i++) {
char c = text[i];
if (c == '\0') {
break;
}
lcd.write(c >= 32 && c <= 126 ? c : ' ');
}
for (uint8_t i = strlen(text); i < width; i++) {
lcd.write(' ');
}
}
// Two independent values on one screen
writeField(0, 5, 7, "118.750"); // COM1 active
writeField(1, 5, 7, "121.500"); // COM1 standby On a CockpitConnect controller you don't write this: add the LCD or OLED to the controller in the Flow Builder, place a Text Field node per value, and bind it to a dataref. Right alignment, padding, decimals and units come from the Mapping's format or lookup , so the screen shows exactly what the Flow sent.
| Application | Display | Notes |
|---|---|---|
| COM / NAV radio | 16×2 LCD | Active on row 0, standby on row 1 — two Text Fields |
| Radio stack summary | 20×4 LCD | COM1, COM2, NAV1, NAV2 on one screen, one field each |
| Transponder | 128×32 OLED, text size 2 | Large code plus mode ("7000 ALT") |
| Autopilot mode annunciation | 128×64 OLED | Lateral and vertical modes on separate rows, blanked by a Gate when unpowered |
| FMC scratchpad | 20×4 LCD | Combine with a key matrix keypad for a compact CDU |