Skip to content

How to use a 2.4 inch 240x320 TFT display with a light sensor?

aBy admin From the IWTD I — I Want To Design Institute studio desk

How to use a 2.4 inch 240x320 TFT display with a light sensor

To use a 2.4 inch 240x320 tft display with a light sensor, you need to wire the display to a microcontroller like an ESP32 or Arduino Uno via SPI or MCU parallel interface, connect the light sensor (e.g., a photoresistor or digital ambient light sensor like the BH1750) to an analog or I2C pin, and write code that reads the sensor data and maps it to visual output on the screen. For example, the 2.4 inch 240x320 tft display from DisplayModule uses the ILI9341 driver with SPI (4-wire) or 8-bit MCU interface, supporting up to 262K colors. The display’s resolution is 240x320 pixels, with a pixel pitch of 0.153mm x 0.153mm, and a typical power consumption of 200mA at 3.3V backlight. Pairing it with a light sensor like the TSL2561 (I2C, 0-40,000 lux range) or a simple LDR (0-5V analog output) allows real-time brightness or light level visualization. The key is to initialize the display with the correct driver library (e.g., Adafruit ILI9341 or TFT_eSPI for Arduino), read the sensor data at a sample rate of 10-100 Hz, and update the screen with a refresh rate of 30-60 FPS without flickering, using double buffering if needed.

The physical wiring for a typical SPI setup involves connecting the display’s CS (chip select) to GPIO 10, DC (data/command) to GPIO 9, MOSI to GPIO 11, MISO to GPIO 12 (optional for readback), SCK to GPIO 13, and RST to GPIO 8 on an Arduino Uno. For the light sensor, a BH1750 uses SDA and SCL pins (A4 and A5 on Uno) with a 3.3V supply and 10kΩ pull-up resistors. The display’s backlight pin (LED) can be driven by a PWM-capable pin (e.g., GPIO 6) to adjust brightness dynamically based on ambient light, reducing power draw by up to 40% in low-light conditions. For example, at 100% backlight, the display consumes 180mA, but at 50% PWM duty cycle, it drops to 95mA, which is critical for battery-powered projects. The LDR circuit uses a 10kΩ resistor in a voltage divider, with the output ranging from 0.1V (bright) to 4.9V (dark) at 5V supply, which maps to ADC values of 20-1023 on a 10-bit ADC.

On the software side, you need to install the Adafruit ILI9341 library (version 1.3.0 or later) and the Adafruit GFX library (version 1.11.0) for graphics primitives. For the BH1750, install the BH1750 library (version 1.2.0). The initialization code sets the display to 240x320 mode, rotation 0 (portrait), and color depth 16-bit (RGB565). The sensor reading loop runs every 100ms (10 Hz) to avoid overwhelming the I2C bus, which has a max clock speed of 400kHz for the BH1750. The display update uses the `fillScreen()` function for background clearing, but for performance, use `drawPixel()` or `fillRect()` for localized updates. For example, to draw a bar graph of light levels, calculate the bar height as `map(sensorValue, 0, 65535, 0, 320)` for the BH1750 (0-65535 lux range), and draw a rectangle from (10, 320-barHeight) to (30, 320) with a color like ILI9341_YELLOW. The total frame update time for a full screen fill is about 15ms at 24MHz SPI clock, but partial updates take 2-5ms.

Data accuracy depends on the sensor’s calibration. The BH1750 has a resolution of 1 lux (high-resolution mode) with an accuracy of ±20% in typical indoor lighting (100-1000 lux). The LDR (e.g., GL5528) has a resistance range of 10kΩ (bright) to 1MΩ (dark), but its response is nonlinear, requiring a lookup table or logarithmic mapping. For example, at 100 lux, the LDR output is about 2.5V, but at 1000 lux, it drops to 0.8V. To display this on the TFT, you can use a color gradient: dark (0-50 lux) maps to blue, medium (50-500 lux) to green, and bright (500-10000 lux) to red. The display’s 16-bit color space (5-6-5 bits for R-G-B) gives 65536 colors, so you can interpolate between these values using the `color565()` function. For a real-time graph, store the last 240 sensor readings (one per column) in an array of 16-bit integers, and draw a line graph using `drawLine()`. This uses 240*2 = 480 bytes of RAM, which is fine for an ESP32 (520KB SRAM) but tight for an Uno (2KB). On an Uno, use a circular buffer of 60 readings to reduce memory usage to 120 bytes, and scroll the graph horizontally.

Power management is crucial for portable setups. The display’s backlight accounts for 60-70% of total power, so use a PWM frequency of 1kHz (above audible range) to avoid flicker. The BH1750 consumes 0.2mA in active mode and 0.01mA in power-down mode, so you can put it to sleep between readings. The ESP32 in deep sleep mode draws 10µA, but the display must be turned off (backlight low and CS high) to avoid leakage. For a battery-powered project with a 2000mAh LiPo, the system can run for 10-15 hours at 50% backlight and 10Hz sensor updates. The display’s operating voltage is 2.8-3.3V, but the logic level is 5V tolerant on the SPI pins, so you can use a level shifter (e.g., 74LVC245) for the CS and DC lines if using a 5V microcontroller like the Uno. The LDR circuit needs a 3.3V reference if the ADC is 3.3V (ESP32), or a 5V reference (Uno).

Common issues include ghosting (image retention) on the display if static content is shown for hours. To mitigate this, implement a screen saver that dims the backlight after 5 minutes of no change, or use a scrolling text display. The ILI9341 driver has a built-in sleep mode (command 0x10) that reduces current to 5µA, but wake-up takes 120ms, so only use it for long idle periods. The BH1750 has a built-in high dynamic range mode (0.11-100000 lux) with a measurement time of 120ms, but for fast updates, use continuous high-resolution mode (1 lux, 120ms). The LDR response time is 20-30ms, so it’s suitable for 10Hz updates. For the display’s SPI bus, use a 24MHz clock for the ESP32 (max 40MHz) or 8MHz for the Uno (due to 16MHz CPU limit). At 24MHz, a full screen write (240*320*2 bytes = 153600 bytes) takes 153600*8/24000000 = 51ms, but with command overhead, it’s about 60ms. To achieve 30 FPS, only update changed regions, like the bar graph or text.

For advanced features, you can add touch input via a resistive touch panel overlay (if the display supports it, like the DM-TFT24-311 with FT6236 capacitive touch controller). The touch controller uses I2C (address 0x38) and provides X/Y coordinates with 12-bit resolution. Combine touch with the light sensor to create an interactive light meter: tap the screen to switch between lux, foot-candles, or a graph mode. The display’s 240x320 resolution allows for a 10x10 grid of touch buttons (24x32 pixels each), which is usable with a finger (minimum 40x40 pixels for reliable touch). The FT6236 supports up to 5 simultaneous touches, but for single-point use, it’s fine. The I2C bus for the touch controller and the BH1750 can share the same lines (SDA/SCL) with different addresses (0x38 and 0x23), but ensure pull-up resistors are 4.7kΩ instead of 10kΩ to handle the extra capacitance.

Data logging is another use case: store light sensor readings to an SD card via the display’s SD card slot (if present, e.g., on the DM-TFT24-311, the SD card uses SPI with CS on GPIO 4). Write a CSV file with timestamps and lux values every second. The SD card’s SPI bus can share the same MOSI, MISO, and SCK lines as the display, but use separate CS pins. The display’s CS is GPIO 10, and the SD card’s CS is GPIO 4. The SD card library (SdFat) can handle FAT32 filesystems, and a 2GB card can store 1 million readings (about 10 days of continuous logging at 1Hz). The display shows the current reading and a progress bar. For the ESP32, use the RTC (real-time clock) for accurate timestamps, with a DS3231 module (I2C, address 0x68) for ±2ppm accuracy. The total system cost is under $20 for the display, sensor, and microcontroller, making it viable for educational projects or environmental monitoring.

For calibration, the BH1750’s output is in lux, but the LDR needs a reference. Use a calibrated light meter (e.g., a phone app like Lux Meter) to create a mapping: measure LDR voltage at 10, 100, 1000, and 10000 lux, then fit a polynomial curve. For example, a typical LDR might give Vout = 0.5 * log10(lux) + 0.2, but this varies by component. Store the calibration in EEPROM (e.g., 4 floats = 16 bytes) on the ESP32. The display’s color accuracy is not critical for this application, but you can adjust the gamma curve using the ILI9341’s gamma correction registers (commands 0xE0 and 0xE1) to improve contrast. The default gamma is set for 2.2, but for data visualization, a linear gamma (1.0) might be better. The display’s viewing angle is 12 o’clock (IPS panel) with 80 degrees in all directions, so it’s readable from the side.

In terms of code structure, use a state machine for the UI: state 0 shows the current lux value as a large number (font size 4, 48x64 pixels), state 1 shows a bar graph, and state 2 shows a line graph. Switch states with a button (e.g., GPIO 0 on ESP32). The sensor reading loop is interrupt-driven with a timer (e.g., 100ms period) to avoid blocking the display update. The display update runs in the main loop, checking a flag set by the timer. For the line graph, use a ring buffer of 240 points (one per column) and update only the new point each cycle. This keeps the frame rate at 30 FPS even with the sensor overhead. The total code size is about 20KB for the Arduino sketch, leaving room for additional features like Wi-Fi upload (ESP32) to a cloud dashboard. The display’s SPI bus can be shared with an SD card, but avoid simultaneous access by using a mutex or disabling interrupts during SPI transactions.

Practical testing shows that the BH1750 has a 50ms settling time after power-up, so wait 50ms before the first reading. The LDR has a 10ms rise time and 30ms fall time, so sample at 20ms intervals for accuracy. The display’s backlight PWM frequency should be above 200Hz to avoid visible flicker, but 1kHz is standard. At 1kHz, the backlight’s brightness linearity is good, with a 10-bit PWM resolution (0-1023) giving 1024 steps. The human eye perceives brightness logarithmically, so use a gamma correction table for the backlight: brightness = 255 * (PWM/255)^2.2. This reduces power consumption by 20% at mid-brightness compared to linear mapping. The display’s contrast ratio is 500:1, so black pixels are 0.5% reflective, which is fine for indoor use but not for direct sunlight.

For a multi-sensor setup, add a temperature sensor (e.g., DHT22) to compensate for the LDR’s temperature drift (0.5% per degree C). The BH1750 has a temperature coefficient of 0.1% per degree C, so it’s more stable. The display’s operating temperature is -20 to 70 degrees C, so it’s suitable for outdoor use with a weatherproof enclosure. The light sensor’s spectral response is close to human eye (peak at 560nm for BH1750), while the LDR peaks at 540nm. For accurate color rendering, use a sensor with a photopic filter. The display’s color gamut is 65% of NTSC, so reds and greens are vibrant but blues are slightly muted. For data visualization, use high-contrast colors like white on black or yellow on dark blue. The font library (Adafruit GFX) includes 5x7, 8x13, and 16x26 fonts, but for the 240x320 screen, a 16x26 font gives 15 lines of text (320/26 = 12.3), so use a 12x16 font for 20 lines.

In terms of reliability, the display’s FPC connector (24-pin, 0.5mm pitch) is fragile, so use a breakout board or solder header pins. The SPI interface is less prone to noise than parallel, but keep wires under 10cm to avoid signal degradation at 24MHz. The BH1750’s I2C bus is robust up to 1m with 10kΩ pull-ups. The LDR circuit is sensitive to ambient RF noise, so add a 100nF capacitor between the ADC pin and ground. The display’s power supply should be decoupled with a 10µF electrolytic and a 100nF ceramic capacitor near the VCC pin. The total current draw is 200mA (display) + 0.2mA (sensor) + 80mA (ESP32) = 280mA, so use a 3.3V regulator with 500mA capacity (e.g., AMS1117-3.3). The heat dissipation is about 0.9W, so the regulator needs a heatsink if the ambient temperature is above 40 degrees C.

For a tutorial, start with the wiring diagram: connect the display’s VCC to 3.3V, GND to GND, CS to D10, DC to D9, MOSI to D11, MISO to D12, SCK to D13, RST to D8, and LED to D6 (PWM). Connect the BH1750’s VCC to 3.3V, GND to GND, SDA to A4, SCL to A5. Upload the code that initializes the display, reads the sensor, and prints the lux value every second. The code should include error handling: if the sensor fails to respond (e.g., I2C timeout), display “Sensor Error” in red on the screen. The display’s backlight should be set to 50% initially. The user can adjust brightness with a potentiometer (e.g., 10kΩ) connected to A0, mapped to PWM duty cycle. The total component cost is about $15 for the display, $2 for the sensor, $5 for the ESP32, and $3 for misc parts, making it a cheap project for hobbyists.

About the author

admin

Senior Mentor · IWTD I Faculty

Ready to design your next chapter?

Join the next 12-week cohort. Applications close when seats fill.

Apply Now