Das Cheap Yellow Display (ESP32-2432S028) besitzt auf der Vorderseite ein kleines, oft übersehenes Bauteil: einen Fotowiderstand – kurz LDR (Light Dependent Resistor).
Ein LDR verändert seinen Widerstand abhängig von der Umgebungshelligkeit. Je heller es ist, desto geringer wird sein Widerstand – in dunkler Umgebung steigt er entsprechend an. Über einen analogen Eingang des ESP32 lässt sich diese Änderung als Messwert erfassen.
In der Praxis kann man dieses Feature sinnvoll nutzen, um das Display automatisch an die Umgebungshelligkeit anzupassen. So bleibt der Bildschirminhalt bei direkter Sonneneinstrahlung gut ablesbar, während das Display in dunkler Umgebung gedimmt werden kann – ideal für Dashboard- oder Smart-Home-Projekte.
In diesem Beitrag zeige ich dir Schritt für Schritt, wie du den LDR auf dem Cheap Yellow Display ausliest und in deinem Projekt verwendest.


Hinweis:
Der LDR ist fest mit GPIO34 verbunden. GPIO34 und GPIO35 gehören beim ESP32 zu den reinen ADC-Eingängen und unterstützen keine OUTPUT-Funktionalität.
Was ist ein LDR überhaupt?
Ein LDR (Light Dependent Resistor) ist ein lichtabhängiger Widerstand.
Er verändert seinen elektrischen Widerstand abhängig von der Helligkeit der Umgebung.
Das Prinzip ist einfach:
- Viel Licht → niedriger Widerstand
- Wenig Licht → hoher Widerstand
Der LDR selbst erzeugt kein Signal. Er ist lediglich ein variabler Widerstand.
Damit der ESP32 diesen Helligkeitswert erfassen kann, wird der LDR auf dem Board in einer Spannungsteiler-Schaltung betrieben.
Beim Cheap Yellow Display ist der LDR bereits fest mit GPIO34 (ADC1) verbunden. Eine zusätzliche Verdrahtung ist also nicht notwendig.
LDR am Cheap Yellow Display auslesen
Der LDR auf dem Cheap Yellow Display (ESP32-2432S028) ist fest mit GPIO34 (ADC1) verbunden.
Wir lesen den Helligkeitswert über den integrierten Analog-Digital-Wandler des ESP32 aus.
Der folgende Sketch gibt den Messwert nur dann aus, wenn sich dieser merklich ändert. Dadurch vermeiden wir unnötige serielle Ausgaben.
#define ldrPin 34 // LDR am GPIO34
// letzter gelesener Wert vom LDR
int lastLDRValue = 0;
// Zeitpunkt (in ms) des letzten Lesevorgangs
unsigned long lastRead = 0;
// Pause zwischen zwei Lesezyklen (in Millisekunden)
const int PAUSE = 50;
void setup() {
// Start der seriellen Kommunikation mit 9600 Baud
Serial.begin(9600);
// ADC-Dämpfung setzen
// siehe: https://docs.espressif.com/projects/arduino-esp32/en/latest/api/adc.html#analogsetattenuation
analogSetAttenuation(ADC_0db);
}
void loop() {
// aktuelle Millisekunden seit Start/Reset des Mikrocontrollers ermitteln
unsigned long currentMillis = millis();
// prüfen, ob die definierte Pause abgelaufen ist
if (currentMillis > (lastRead + PAUSE)) {
// Zeitpunkt des letzten Lesevorgangs aktualisieren
lastRead = currentMillis;
// analogen Wert vom LDR (GPIO34) einlesen
int currentLDRValue = analogRead(ldrPin);
// nur reagieren, wenn sich der Wert deutlich verändert hat (>= 5)
if (abs(currentLDRValue - lastLDRValue) >= 5) {
// Ausgabe des Messwertes über die serielle Schnittstelle
// kann z.B. im seriellen Plotter als Liniendiagramm dargestellt werden
Serial.println(currentLDRValue);
// neuen Wert als Referenz speichern
lastLDRValue = currentLDRValue;
}
}
}
Die gelesenen Werte können wir nun im seriellen Monitor der Arduino IDE auslesen oder auch im seriellen Plotter in einem Liniendiagram visualisieren lassen.


Anzeigen des Wertes vom LDR auf dem Display des ESP32-2432S028 (CYD)
Nachdem wir den LDR über analogRead() auslesen können, soll der Messwert nun direkt auf dem Display des Cheap Yellow Display angezeigt werden.


Hierfür verwende ich LVGL in Kombination mit der TFT_eSPI-Bibliothek.
Der aktuelle Helligkeitswert wird dabei:
- als numerischer Wert angezeigt
- zusätzlich visuell über einen Kreis dargestellt, dessen Helligkeit sich abhängig vom LDR-Wert verändert
#include <lvgl.h>
#include <TFT_eSPI.h>
#define TFT_HOR_RES 240
#define TFT_VER_RES 320
#define TFT_ROTATION LV_DISPLAY_ROTATION_270
#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
#define COLOR_BG lv_color_hex(0x000000) // Hintergrund: Schwarz
#define COLOR_WHITE lv_color_hex(0xFFFFFF) // Weiß
#define COLOR_YELLOW lv_color_hex(0xFDD835) // Gelb
#define ldrPin 34
lv_obj_t *ldrValueLabel;
int lastLDRValue = 0;
unsigned long lastRead = 0;
const int PAUSE = 250;
lv_obj_t *ldrCircle;
void setup() {
Serial.begin(9600);
analogSetAttenuation(ADC_0db);
lv_init();
lv_display_t *disp = lv_tft_espi_create(
TFT_HOR_RES,
TFT_VER_RES,
draw_buf,
sizeof(draw_buf));
lv_display_set_rotation(disp, TFT_ROTATION);
lv_obj_t *scr = lv_screen_active();
lv_obj_set_style_bg_color(scr, COLOR_BG, 0);
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, 0);
lv_obj_set_style_pad_all(scr, 12, 0);
lv_obj_set_scrollbar_mode(scr, LV_SCROLLBAR_MODE_OFF);
lv_obj_t *ldrDescLabel = lv_label_create(scr);
lv_label_set_text(ldrDescLabel, "LDR");
lv_obj_set_style_text_color(ldrDescLabel, COLOR_YELLOW, 0);
lv_obj_set_style_text_font(ldrDescLabel, &lv_font_montserrat_28, 0);
lv_obj_align(ldrDescLabel, LV_ALIGN_TOP_MID, 0, 0);
ldrValueLabel = lv_label_create(scr);
lv_label_set_text(ldrValueLabel, "0");
lv_obj_set_style_text_color(ldrValueLabel, COLOR_WHITE, 0);
lv_obj_set_style_text_font(ldrValueLabel, &lv_font_montserrat_28, 0);
lv_obj_align(ldrValueLabel, LV_ALIGN_TOP_MID, 0, 50);
ldrCircle = lv_obj_create(scr);
lv_obj_set_size(ldrCircle, 80, 80);
lv_obj_set_style_radius(ldrCircle, LV_RADIUS_CIRCLE, 0);
lv_obj_set_style_bg_color(ldrCircle, COLOR_YELLOW, 0);
lv_obj_set_style_border_width(ldrCircle, 0, 0);
lv_obj_set_style_bg_opa(ldrCircle, LV_OPA_0, 0);
lv_obj_align(ldrCircle, LV_ALIGN_CENTER, 0, 40);
setOpacity(0);
}
void setOpacity(int currentLDRValue) {
int opa = map(currentLDRValue, 0, 1023, 255, 0);
opa = constrain(opa, 0, 255);
lv_obj_set_style_bg_opa(ldrCircle, (lv_opa_t)opa, 0);
}
void loop() {
lv_tick_inc(5);
lv_timer_handler();
unsigned long currentMillis = millis();
if (currentMillis > (lastRead + PAUSE)) {
lastRead = currentMillis;
int currentLDRValue = analogRead(ldrPin);
if (abs(currentLDRValue - lastLDRValue) >= 5) {
lastLDRValue = currentLDRValue;
Serial.println(currentLDRValue);
String s = String(currentLDRValue, DEC);
lv_label_set_text(ldrValueLabel, s.c_str());
setOpacity(currentLDRValue);
}
}
delay(5);
}
Hinweis zur Programmierung mit LVGL
Die grundlegende Einrichtung des Cheap Yellow Display (ESP32-2432S028) in Kombination mit der LVGL-Bibliothek habe ich bereits ausführlich anhand eines kleinen Dashboards erklärt.
Dort zeige ich unter anderem:
- Einrichtung von LVGL
- Einbindung der TFT_eSPI-Bibliothek
- Display-Rotation und Buffer-Konfiguration
- Erstellen von Labels und grafischen Elementen
- Grundlegende Struktur mit
lv_timer_handler()undlv_tick_inc()
Falls du neu mit LVGL auf dem CYD arbeitest, empfehle ich dir zunächst einen Blick in meine YouTube-Playlist zu diesem Thema: ESP32 CYD Display mit LVGL programmieren – Komplettkurs
In diesem Beitrag konzentrieren wir uns ausschließlich auf das Auslesen und Visualisieren des LDR-Wertes.
Dashboard-Helligkeit automatisch mit dem LDR regulieren
Nachdem wir den LDR-Wert auslesen und visualisieren können, lässt sich dieser nun verwenden, um die Helligkeit eines Dashboards automatisch anzupassen.


In diesem Beispiel simulieren wir ein kleines Dashboard mit:
- Temperaturwert
- Statusanzeige
- Hintergrundfläche
Je nach Umgebungshelligkeit wird dabei die gesamte Display-Helligkeit bzw. die Hintergrund-Deckkraft angepasst.
#include <lvgl.h>
#include <TFT_eSPI.h>
#define TFT_HOR_RES 240
#define TFT_VER_RES 320
#define TFT_ROTATION LV_DISPLAY_ROTATION_270
#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
#define COLOR_BG lv_color_hex(0x000000)
#define COLOR_WHITE lv_color_hex(0xFFFFFF)
#define COLOR_GREEN lv_color_hex(0x4CAF50)
#define COLOR_RED lv_color_hex(0xE53935)
// 3 Helligkeitsstufen
enum BrightnessLevel {
BRIGHT,
MEDIUM,
DARK
};
// Farben-Array: [Helligkeit][Farbtyp]
lv_color_t colorSet[3][3] = {
// BRIGHT
{
lv_color_hex(0xFFFFFF), // Weiß
lv_color_hex(0xFF0000), // Rot
lv_color_hex(0x00FF00) // Grün
},
// MEDIUM
{
lv_color_hex(0xAAAAAA), // Grau
lv_color_hex(0xCC4444), // Mittel-Rot
lv_color_hex(0x44CC44) // Mittel-Grün
},
// DARK
{
lv_color_hex(0x555555), // Dunkelgrau
lv_color_hex(0x662222), // Dunkelrot
lv_color_hex(0x226622) // Dunkelgrün
}
};
#define ldrPin 34
lv_obj_t *titleLabel;
lv_obj_t *tempLabel;
lv_obj_t *statusLabel;
unsigned long lastUpdate = 0;
const int UPDATE_INTERVAL = 1000;
BrightnessLevel getBrightnessLevel(int ldrValue) {
if (ldrValue < 10) {
return BRIGHT;
} else if (ldrValue < 50) {
return MEDIUM;
} else {
return DARK;
}
}
void applyColorTheme(int ldrValue, bool statusWarning) {
BrightnessLevel level = getBrightnessLevel(ldrValue);
// Textfarbe Temperatur (Weiß/Grau)
lv_obj_set_style_text_color(titleLabel, colorSet[level][0], 0);
lv_obj_set_style_text_color(tempLabel, colorSet[level][0], 0);
// Statusfarbe (Rot oder Grün)
if (statusWarning) {
lv_obj_set_style_text_color(statusLabel, colorSet[level][1], 0);
} else {
lv_obj_set_style_text_color(statusLabel, colorSet[level][2], 0);
}
}
// ----------- Setup -----------
void setup() {
Serial.begin(115200);
analogSetAttenuation(ADC_0db);
lv_init();
lv_display_t *disp = lv_tft_espi_create(
TFT_HOR_RES,
TFT_VER_RES,
draw_buf,
sizeof(draw_buf));
lv_display_set_rotation(disp, TFT_ROTATION);
lv_obj_t *scr = lv_screen_active();
lv_obj_set_style_bg_color(scr, COLOR_BG, 0);
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, 0);
// Titel
titleLabel = lv_label_create(scr);
lv_label_set_text(titleLabel, "DASHBOARD");
lv_obj_set_style_text_color(titleLabel, COLOR_WHITE, 0);
lv_obj_set_style_text_font(titleLabel, &lv_font_montserrat_28, 0);
lv_obj_align(titleLabel, LV_ALIGN_TOP_MID, 0, 10);
// Temperatur
tempLabel = lv_label_create(scr);
lv_label_set_text(tempLabel, "-- °C");
lv_obj_set_style_text_color(tempLabel, COLOR_WHITE, 0);
lv_obj_set_style_text_font(tempLabel, &lv_font_montserrat_28, 0);
lv_obj_align(tempLabel, LV_ALIGN_CENTER, 0, -20);
// Status
statusLabel = lv_label_create(scr);
lv_label_set_text(statusLabel, "--");
lv_obj_set_style_text_font(statusLabel, &lv_font_montserrat_28, 0);
lv_obj_align(statusLabel, LV_ALIGN_CENTER, 0, 30);
}
// ----------- Loop -----------
void loop() {
lv_tick_inc(5);
lv_timer_handler();
// Dashboard-Werte aktualisieren
if (millis() - lastUpdate > UPDATE_INTERVAL) {
lastUpdate = millis();
int ldrValue = analogRead(ldrPin);
int temperature = random(20, 35);
bool warn = temperature > 30;
String tempText = String(temperature) + " °C";
lv_label_set_text(tempLabel, tempText.c_str());
lv_label_set_text(statusLabel, warn ? "WARN" : "OK");
applyColorTheme(ldrValue, warn);
}
delay(5);
}
Fazit
Das Auslesen eines LDR – oder generell anderer analoger Sensoren, die über einen Spannungsteiler betrieben werden (z. B. ein NTC-Widerstand) – ist mit dem ESP32 denkbar einfach. Im Grunde benötigt es nur wenige Zeilen Code, um einen stabilen Messwert über den ADC einzulesen und weiterzuverarbeiten.
Der integrierte LDR auf dem Cheap Yellow Display ist daher ein kleines, aber praktisches Feature, das sich ohne zusätzliche Hardware direkt nutzen lässt. Besonders für Projekte mit automatischer Helligkeitsanpassung oder einfachen Umgebungslicht-Erkennungen bietet sich dieser Sensor an.
Deutlich umfangreicher wird der Code erst dann, wenn der Messwert grafisch auf dem Display visualisiert wird. Durch den Einsatz von LVGL wächst das Projekt spürbar an – was jedoch der Flexibilität und den Gestaltungsmöglichkeiten geschuldet ist. Mit einem einfachen OLED-Display über I2C ließe sich die reine Anzeige des Messwertes deutlich schlanker umsetzen.
Das Cheap Yellow Display bietet hier jedoch den Vorteil, dass sich Sensorwerte nicht nur anzeigen, sondern auch ansprechend visualisieren lassen – etwa durch grafische Elemente wie Balken, Kreise oder dynamische Oberflächen.
Letzte Aktualisierung am: 20. Februar 2026