Skip to content

How to use a 2.4 inch resistive TFT display with a vibration sensor?

admin Villas Saint-Jean
To get a 2.4 inch resistive TFT display working with a vibration sensor, you need to wire the sensor’s analog output to a microcontroller’s ADC pin, then read the voltage changes and map them to screen updates—like drawing a real-time waveform or triggering a visual alert. The display itself, typically a 240x320 pixel ST7789V-based module with a resistive touch layer, runs on SPI or parallel interface, while the vibration sensor (often a piezoelectric or MEMS type) outputs a varying voltage proportional to mechanical vibration intensity. I’ll walk you through the hardware connections, communication protocols, power requirements, and code examples, all grounded in real-world specs and datasheet numbers. Expect dense details on timing, voltage thresholds, and touch calibration, because this isn’t a generic tutorial—it’s a practical, data-driven guide.

Hardware Wiring and Interface Specifications

The 2.4 inch resistive tft display (model DM-TFT24-312, based on ST7789V controller) uses a 4-wire SPI interface by default, but some variants support 8-bit parallel. For this setup, I’ll assume SPI mode because it’s common with Arduino or ESP32. The display runs at 3.3V logic, though the backlight LED can take 5V through a resistor (typically 10-20 ohms for 20mA current). The resistive touch layer is separate—it uses 4 analog pins (X+, X-, Y+, Y-) that connect to ADC inputs on the microcontroller. The vibration sensor, say a 2.4 inch resistive tft display compatible SW-420 or a piezoelectric disc, outputs an analog voltage from 0V to 3.3V (or 5V if you use a voltage divider). For a MEMS accelerometer like ADXL335, the vibration signal is filtered through a 0.1uF capacitor to remove DC offset, giving a 0-3.3V AC-coupled signal.

Here’s a typical wiring table for an ESP32 (3.3V logic) with the display and a piezoelectric vibration sensor:

Component Pin ESP32 Pin Notes
Display (ST7789V) VCC 3.3V Max 50mA draw; backlight via 5V with 10-ohm resistor
GND GND Common ground with sensor
SCL (SCK) GPIO 18 SPI clock up to 40MHz; ST7789V max is 62.5MHz
SDA (MOSI) GPIO 23 Data out from MCU to display
RES GPIO 4 Reset pin, active low; 10k pull-up to 3.3V
DC GPIO 2 Data/command select; 0 = command, 1 = data
CS GPIO 5 Chip select, active low
Touch Layer X+ GPIO 34 (ADC) Analog input for X position
Y+ GPIO 35 (ADC) Analog input for Y position
X- GPIO 32 Digital output to drive X- low
Y- GPIO 33 Digital output to drive Y- low
Vibration Sensor Vout GPIO 36 (ADC) Analog input; 0-3.3V range
VCC 3.3V Piezoelectric sensor needs no power; MEMS needs 3.3V
GND GND Common ground

For a piezoelectric disc (like the one used in knock sensors), the output voltage can spike to 10V or more if you hit it hard, so you must add a voltage divider (two resistors: 10k and 3.3k) to bring it down to 3.3V safe level. The ST7789V datasheet specifies a 1.8V to 3.3V logic supply, but the I/O pins are 3.3V tolerant. If you’re using a 5V Arduino Uno, you’ll need a level shifter for the SPI lines—don’t skip this, because the display’s absolute maximum input voltage is 4.0V, and 5V will fry it. The resistive touch layer operates at 2.8V to 3.3V, and its analog outputs are ratiometric: when you press the screen, the X+ and Y+ pins give voltages proportional to the touch position, with a typical resistance of 200-900 ohms across the layer.

Communication Protocol and Timing Details

The ST7789V controller uses a 16-bit command/data structure over SPI. To initialize the display, you send a sequence of commands like SWRESET (0x01), SLPOUT (0x11), and DISPON (0x29), each followed by a 5ms delay. The datasheet specifies that after SWRESET, you must wait 120ms before sending any other commands. The SPI clock frequency can go up to 62.5MHz in theory, but with long wires (over 10cm), you’ll see signal degradation above 20MHz. I run it at 10MHz for reliability. The display’s pixel format is 16-bit RGB565, so each pixel takes 2 bytes. For a full 240x320 screen refresh, that’s 240 * 320 * 2 = 153,600 bytes. At 10MHz SPI, that’s about 15.36ms for a full frame, but you’ll also need to send the column and page address commands. Real-world frame rate with partial updates (like a 50x50 pixel waveform) is around 60fps.

The resistive touch controller (built into the display module’s touch layer) uses a 4-wire analog interface. To read a touch position, you set X- to GND, X+ to VCC (3.3V), then read the voltage on Y+ (which gives X position). Then swap: set Y- to GND, Y+ to VCC, read X+ for Y position. The ADC reading is 12-bit (0-4095) on ESP32, but the touch layer’s resolution is limited by its physical construction—typical accuracy is ±1.5% of the full scale, which means about ±3.6 pixels in X and ±4.8 pixels in Y. You’ll need to calibrate this by mapping the ADC values to pixel coordinates: for example, if the left edge reads 200 and the right edge reads 3800, then X_pixel = (ADC_value - 200) * 240 / 3600. The touch layer also has a pressure measurement: by reading the voltage across X+ and X- while touching, you can detect the force. But for vibration sensing, we’ll use the sensor’s analog output directly.

Vibration Sensor Data Acquisition and Processing

Let’s focus on a piezoelectric vibration sensor because it’s cheap and gives a wide dynamic range. The sensor outputs an AC voltage that’s proportional to the acceleration of the vibration. For a typical 27mm piezoelectric disc, the sensitivity is about 10mV/g at 100Hz, but it can go up to 100mV/g at resonance (around 4-5kHz). The output impedance is high (10M ohms), so you must buffer it with an op-amp like LM358 or use a voltage follower. Without a buffer, the ADC’s input impedance (around 1M ohm on ESP32) will load the sensor and attenuate the signal by 50% or more. A better approach: use a simple RC filter with a 100k resistor and 0.1uF capacitor to ground, giving a cutoff frequency of 16Hz, which removes DC drift and high-frequency noise above 16kHz.

On the ESP32, the ADC has 12-bit resolution (0-4095) and a reference voltage of 3.3V. So the smallest detectable voltage change is 3.3V / 4095 = 0.806mV. With a 10mV/g sensitivity, you can detect vibrations as low as 0.08g. But the ADC’s effective resolution is lower due to noise—about 9-10 bits in practice, so you’ll see about 3.2mV steps. To improve this, you can oversample: take 64 samples and average them, which gives you 2 extra bits of resolution (12-bit to 14-bit effective). The sampling rate on ESP32 is configurable via the ADC clock divider; at 6MHz ADC clock, you get about 100,000 samples per second. For vibration analysis, you typically need 1kHz to 10kHz sampling, so this is plenty.

Here’s how you process the data: read the ADC value, subtract a baseline (the average of 100 samples when no vibration is present), then take the absolute value. This gives you a vibration amplitude. You can then threshold it: if the amplitude exceeds 100 ADC counts (about 80mV, or 8g), you trigger a screen event. For a real-time waveform display, you store the last 320 samples (one per pixel column) and draw them as a line graph. The display’s drawing speed is the bottleneck—drawing a line between two points takes about 50 microseconds using the Adafruit GFX library, so for 320 points, that’s 16ms per frame, which gives you 62fps. But if you also need to handle touch input, the total frame time might double.

Touch and Vibration Interaction: Practical Use Cases

You can combine the resistive touch with vibration sensing to create a user interface. For example, touch the screen to start recording vibration data, then draw a histogram of vibration intensity over time. The touch layer’s response time is about 10ms (due to the analog settling time and ADC conversion), so you can poll it at 100Hz. The vibration sensor’s analog output changes faster—up to 5kHz for mechanical vibrations—so you need to sample the sensor at a higher rate (say 2kHz) and only update the display at 30fps to avoid flicker. One trick: use the touch to set a threshold for vibration alerts. When the sensor’s amplitude exceeds that threshold, the display flashes red and draws a bar graph. The ST7789V can handle this with a simple fill rectangle command (0x2C for memory write), which takes about 2ms for a 50x50 pixel area.

For power consumption, the display draws 20mA with backlight on (at 3.3V), the ESP32 draws 80mA during active mode, and the vibration sensor draws negligible current (piezoelectric generates its own voltage). Total: 100mA at 3.3V, or 0.33W. If you’re battery-powered, you can use the display’s sleep mode (SLEEPIN command 0x10) to drop current to 0.1mA, and wake it up with a touch interrupt. The resistive touch layer can be used as a wake-up trigger: connect the X+ pin to a GPIO interrupt (rising edge) when the screen is pressed. But note that the resistive touch layer consumes about 1mA when idle due to the voltage divider on the analog lines—you can turn that off by setting the touch pins to high-impedance when not in use.

Code Structure and Optimization Tips

Here’s a stripped-down code skeleton in Arduino C++ for ESP32, focusing on the data flow:

Initialize the display with TFT_eSPI library (which handles the ST7789V specifics). Set the SPI pins in the User_Setup.h file: TFT_CS=5, TFT_DC=2, TFT_RST=4, TFT_MOSI=23, TFT_SCLK=18. For the touch, use the XPT2046 library if your display has that controller (some 2.4-inch modules use XPT2046 for resistive touch, but the DM-TFT24-312 uses a raw 4-wire interface, so you’ll need to read the analog pins directly). For the vibration sensor, read ADC1_CH0 (GPIO 36) using analogRead() with 12-bit resolution. To get consistent timing, use the ESP32’s hardware timer to trigger ADC reads at 2kHz. Store the last 320 samples in a circular buffer, then every 33ms (30fps), draw the waveform using tft.drawLine() from the previous point to the current point.

For the touch calibration, you need to map the raw ADC values to pixel coordinates. Here’s a typical calibration routine: read the touch layer’s X and Y values when you press the four corners of the screen. For example, top-left corner gives X=300, Y=300; top-right gives X=3800, Y=300; bottom-left gives X=300, Y=3800; bottom-right gives X=3800, Y=3800. Then the mapping is: X_pixel = (X_raw - 300) * 240 / (3800 - 300), Y_pixel = (Y_raw - 300) * 320 / (3800 - 300). You’ll need to invert the Y axis because the touch layer’s Y+ pin corresponds to the screen’s vertical direction. Store these calibration constants in EEPROM so you don’t recalibrate every boot.

One common issue: the resistive touch layer is prone to noise when the vibration sensor is active, because the vibration can cause micro-movements of your finger on the screen. To filter this, apply a low-pass filter to the touch ADC readings: new_touch_X = 0.9 * old_touch_X + 0.1 * raw_X. This gives a cutoff frequency of about 15Hz at 100Hz polling rate, which smooths out jitter from vibration. For the vibration data itself, you might want a high-pass filter to remove DC offset: new_vibration = 0.9 * old_vibration + 0.1 * (raw_vibration - old_vibration). This passes frequencies above 30Hz, which is where most mechanical vibrations occur.

— Villas Saint-Jean, Villefranche-sur-Mer