Skip to content
Čitajte besplatno

How to display a waveform on a 1.54 inch 128x64 OLED?

admin· ·Večernjak

How to Display a Waveform on a 1.54 inch 128x64 OLED

To display a waveform on a 1.54 inch 128x64 oled display, you need to sample an analog signal, map the voltage values to pixel coordinates, and then draw the waveform line across the 128 horizontal pixels using the display’s SPI interface. The key is real-time rendering: the OLED’s 128 columns correspond to 128 time-domain samples, and the 64 rows represent the amplitude range. For a typical audio waveform, you’d sample at 8 kHz, take 128 samples per frame, and map each 8-bit ADC value to a Y-coordinate between 0 and 63. The display controller, like the SSD1306, handles pixel addressing via a 1024-byte buffer (128 columns × 8 pages, each page 8 pixels tall). You update the buffer with the waveform data and send it over SPI at 4 MHz or higher to achieve a refresh rate above 30 Hz, which looks smooth to the human eye. This approach works for any analog signal, from ECG to audio, as long as you handle the data conversion and buffer management correctly.

The 1.54 inch 128x64 oled display is a monochrome graphic panel with a resolution of 128 pixels horizontally and 64 pixels vertically. Each pixel is individually addressable, and the entire display is driven by a SSD1306 controller chip, which communicates via SPI or I2C. For waveform display, SPI is preferred because it offers higher data transfer rates—typically up to 10 MHz—which reduces latency when updating the full frame buffer. The display’s active area is 27.0 mm × 13.4 mm, with a pixel pitch of 0.21 mm. The contrast ratio is over 2000:1, and the viewing angle is 160 degrees, making it readable even in bright conditions. The power consumption is about 20 mA when all pixels are on, but for a waveform display where only a few pixels are lit per frame, it drops to around 5-10 mA. This OLED is commonly used in oscilloscopes, audio analyzers, and medical monitors because of its fast response time (under 10 microseconds) and high contrast.

To start, you need a microcontroller with an ADC (analog-to-digital converter) to sample the input signal. For a 3.3V system, a 10-bit ADC gives 1024 levels, but you only need 64 levels for the Y-axis, so you can map the upper 6 bits to the row. For example, if the ADC reads 512 (midpoint), the Y-coordinate would be 32. The X-coordinate is determined by the sample index from 0 to 127. You must store the last 128 samples in a circular buffer. Every time a new sample is taken, you shift the buffer left by one, discard the oldest sample, and add the new sample at the end. Then you redraw the entire waveform by iterating through the buffer and setting pixels at (x, y) where x is the index and y is the mapped amplitude. The SSD1306 buffer is organized as 8 pages, each page covering 8 rows of pixels. For a 128×64 display, the buffer is 128 bytes per page, 8 pages total, so 1024 bytes. To set a pixel at (x, y), you calculate the page = y / 8, the bit position = y % 8, and then set the corresponding bit in the buffer byte at index (page * 128 + x). After updating all 128 points, you send the entire buffer to the display using a SPI command sequence: first set the column address range (0 to 127), then set the page address range (0 to 7), then send the 1024 bytes of data.

Here’s a concrete example using an Arduino Nano and a 1.54 inch SSD1306 OLED. The ADC is configured for 10-bit resolution with a reference voltage of 3.3V. The sampling rate is set to 1 kHz using a timer interrupt. The analog input is connected to a function generator outputting a 1 kHz sine wave. The code reads the ADC, maps the value to a Y-coordinate using the formula y = 63 - (adc_value >> 4), because 1024 / 64 = 16, so shifting right by 4 bits gives a 6-bit value. The subtraction flips the Y-axis so that higher voltage appears at the top of the display. The circular buffer holds 128 samples. After each sample, the buffer is updated and the display is refreshed. The SPI clock is set to 8 MHz, which allows the entire buffer to be transmitted in about 1.28 milliseconds (1024 bytes × 8 bits per byte / 8 MHz = 1.024 ms, plus overhead). This gives a theoretical maximum refresh rate of 780 Hz, but in practice, the ADC sampling rate and processing limit it to about 100 Hz for a stable waveform. The result is a clean sine wave scrolling from right to left at 1 kHz, with 128 samples per cycle, so you see about 7.8 cycles on screen at any time.

For better performance, you can use DMA (Direct Memory Access) to transfer the buffer to the SPI peripheral without CPU intervention. On an STM32F103 microcontroller, the SPI can be configured with DMA for circular buffer transfers. The ADC is set to continuous conversion with a timer trigger at 8 kHz. The DMA transfers the ADC values directly to a 128-sample buffer in memory. Then, the main loop maps the buffer to the OLED frame buffer and triggers a DMA transfer to the SPI. This reduces CPU load to under 10% for the waveform display, leaving room for other tasks like button handling or data logging. The OLED’s built-in charge pump generates the 7V to 15V needed for the OLED pixels, so no external high-voltage supply is needed. The display’s duty cycle is 1/64, meaning each row is scanned sequentially, which is why the frame buffer must be updated in one shot to avoid flicker.

If you’re working with a dual-channel waveform, you can display two signals by using different line styles. For example, channel 1 can be drawn as a solid line, and channel 2 as a dashed line. To draw a dashed line, you only set pixels for every other sample, or you use a pattern of 4 pixels on, 4 pixels off. The buffer management is the same, but you need to track two separate circular buffers, each 128 samples. The OLED’s 64 rows give you 32 rows per channel if you split the screen horizontally, but that reduces resolution. A better approach is to overlay the two waveforms on the same 128×64 grid, using different pixel intensities. Since the OLED is monochrome, you can simulate intensity by using a checkerboard pattern for one channel. For instance, set the pixel for channel 1 normally, and for channel 2, set the pixel only if the adjacent pixel is not set, creating a dithering effect. This works well for audio signals where the amplitude range is similar.

Here’s a table summarizing the key parameters for waveform display on a 1.54 inch 128x64 OLED:

ParameterValueNotes
Resolution128 × 64 pixels128 time samples, 64 amplitude levels
Buffer size1024 bytes8 pages × 128 bytes per page
SPI clock4-10 MHzFaster reduces frame update time
Frame update time~1 ms at 8 MHz1024 bytes at 8 MHz = 1.024 ms
Max refresh rate~100 HzLimited by ADC sampling and processing
ADC resolution10-bit (1024 levels)Mapped to 6-bit (64 levels) for Y-axis
Sampling rate1-8 kHz typicalHigher for audio, lower for slow signals
Power consumption5-20 mADepends on pixel count lit

For signal conditioning, the analog input must be scaled to the ADC’s input range. If the signal is bipolar (e.g., -1V to +1V), you need a level shifter to center it at 1.65V (half of 3.3V). A simple op-amp circuit with a gain of 1.65 and a DC offset of 1.65V works. For example, an LM358 with a 3.3V supply can handle this. The output is then connected to the ADC pin. The ADC’s input impedance is about 10 kΩ, so a buffer op-amp is recommended to avoid loading the signal source. The sampling rate must be at least twice the highest frequency component of the signal (Nyquist theorem). For a 1 kHz sine wave, 2 kHz sampling is sufficient, but for a clean display, 8 kHz is better because it provides 8 samples per cycle at 1 kHz, which looks smooth. The OLED’s 128 columns then show 16 cycles of a 1 kHz wave at 8 kHz sampling (128 / 8 = 16 cycles).

To handle the waveform drawing efficiently, you can use a line-drawing algorithm like Bresenham’s line algorithm to connect consecutive sample points. This is important because the raw samples are discrete points, and connecting them with lines makes the waveform look continuous. The algorithm works by calculating the slope between two points and stepping through the X-axis, setting pixels along the line. For a 128-point waveform, you draw 127 line segments. The Bresenham algorithm uses only integer arithmetic, so it’s fast on microcontrollers. For example, if the current sample is at (x0, y0) and the next sample is at (x1, y1), the algorithm computes the error term and sets pixels at each intermediate X. This avoids gaps in the waveform, especially when the signal changes rapidly. The algorithm can be optimized for the OLED’s page-oriented buffer by pre-calculating the page and bit for each pixel.

Another technique is to use a scrolling waveform instead of a static one. In a scrolling display, the oldest sample is at the right edge, and new samples are added at the left edge, shifting the entire waveform left. This is done by moving the buffer contents left by one byte for each page, then adding the new sample at the rightmost column. The shift operation can be done with memmove() or a loop, but it’s faster to use a ring buffer and only redraw the changed column. For a 128-column display, you can maintain a ring buffer index that points to the current column. When a new sample arrives, you increment the index modulo 128, write the new pixel data to that column, and then update the display by sending only the column data for that index. This reduces the SPI transfer from 1024 bytes to 128 bytes per frame, which at 8 MHz takes only 128 microseconds. This allows a refresh rate of up to 7.8 kHz, but the ADC sampling rate is usually the bottleneck. This column-by-column update is ideal for real-time oscilloscopes.

If you’re using a 1.54 inch 128x64 oled display with an I2C interface instead of SPI, the data rate is limited to 400 kHz (fast mode) or 1 MHz (fast mode plus). At 400 kHz, transferring 1024 bytes takes 20.48 milliseconds (1024 × 8 / 400 kHz), which gives a maximum refresh rate of 48 Hz. This is still acceptable for most waveform displays, but the latency is higher. For I2C, the buffer update is done by sending a command to set the column and page address, then sending the data bytes. The I2C protocol adds overhead for start/stop conditions and addressing, so the actual throughput is lower. For a scrolling waveform, the column-by-column update reduces the transfer to 128 bytes, which takes 2.56 ms at 400 kHz, giving a refresh rate of 390 Hz. This is sufficient for audio signals up to 20 kHz, though the Nyquist limit requires sampling at 40 kHz, which means the ADC must be fast enough to keep up.

For displaying a waveform from a digital source, like a pulse-width modulation (PWM) signal, you can directly map the duty cycle to the Y-axis. For example, a 50% duty cycle at 1 kHz gives a constant Y-coordinate of 32. But for a PWM signal with varying duty cycle, you sample the duty cycle value over time. This is common in motor control or power electronics monitoring. The OLED can show the average duty cycle as a horizontal line, or you can decode the PWM signal using a timer capture to measure the pulse width, then display the width as a waveform. This requires a timer input capture peripheral, which is available on most microcontrollers. The capture resolution is typically 16-bit, so you can measure pulse widths from microseconds to milliseconds.

Another application is displaying an electrocardiogram (ECG) waveform. The ECG signal has a frequency range of 0.5 Hz to 100 Hz, so a sampling rate of 250 Hz is sufficient. The 128-column display shows 0.512 seconds of data (128 / 250 Hz). The amplitude range is about 1 mV to 5 mV, so you need an instrumentation amplifier like the AD8232 to amplify the signal to 0-3.3V. The ADC reads the amplified signal, and the waveform is displayed scrolling from right to left. The OLED’s high contrast makes the ECG trace visible even in bright light. The refresh rate can be set to 30 Hz to match the typical heart rate, so the waveform moves smoothly. The buffer update is done every 4 ms (250 Hz sampling), which is well within the OLED’s capability.

For audio waveform display, the signal is typically AC-coupled with a frequency range of 20 Hz to 20 kHz. A sampling rate of 44.1 kHz is standard for audio, but for display purposes, you can downsample to 8 kHz to reduce data. The 128-column display then shows 16 ms of audio (128 / 8000 Hz). This is short enough to capture transients like drum hits. The amplitude range is about 0.1V to 2V peak-to-peak, so you may need a preamplifier with adjustable gain. The waveform is displayed as a solid line, and you can add a grid overlay for reference. The grid can be drawn as dotted lines every 16 pixels horizontally and 8 pixels vertically, which corresponds to 2 ms per division horizontally and 0.5V per division vertically (assuming 3.3V range). The grid is drawn in the buffer before the waveform, so it appears behind the signal. This is useful for educational oscilloscopes or audio analyzers.

To optimize the display for speed, you can use the OLED’s built-in horizontal scrolling feature, but that scrolls the entire frame, not just the waveform. Instead, you can implement a hardware-accelerated scroll by using the SSD1306’s “continuous horizontal scroll” command, which shifts the display content left or right by a set number of pixels per frame. However, this affects the entire display, so it’s only useful if you have a static waveform that you want to move. For real-time data, the software-based scrolling described earlier is more flexible.

Here’s a code snippet for initializing the OLED and drawing a waveform using SPI on an Arduino Uno:

void setup() {
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz
oled_init();
oled_clear();
}
void loop() {
static uint8_t buffer[128];
for (int x = 0; x < 128; x++) {
int adc = analogRead(A0);
int y = map(adc, 0, 1023, 0, 63);
buffer[x] = y;
}
draw_waveform(buffer);
oled_update();
}
void draw_waveform(uint8_t *data) {
for (int x = 0; x < 127; x++) {
draw_line(x, data[x], x+1, data[x+1]);
}
}

This basic example samples 128 points, maps them to Y-coordinates, draws lines between them, and updates the display. The draw_line function uses Bresenham’s algorithm to set pixels in the frame buffer. The oled_update function sends the buffer to the display via SPI. In practice, you’d use a timer interrupt for sampling and a circular buffer to avoid blocking the main loop.

For a more advanced setup, consider using a dedicated 1.54 inch 128x64 oled display module with a built-in level shifter and voltage regulator, which simplifies the hardware design. Many modules come with a 3.3V regulator and a 5V-tolerant SPI interface, so you can connect them directly to 5V microcontrollers. The module’s pinout is typically: CS (chip select), DC (data/command), RST (reset), SCK (clock), MOSI (data), and VCC/GND. The CS pin is used to select the display when multiple SPI devices are on the bus. The DC pin tells the display whether the incoming byte is a command or data. The RST pin is used to reset the controller. The initialization sequence includes commands like: set display

O autoru
admin
Novinar redakcije Večernjak. Piše o aktualnim temama iz Hrvatske i svijeta.

Ne propustite najvažnije vijesti

Svako jutro najbolje priče iz redakcije Večernjak stižu izravno u vašu elektroničku poštu.

Čitajte besplatno