Skip to content

Mediazione Creditizia — OAM 2014-A

How to display a scatter plot on a 1.54 inch 128x64 OLED?

How to Display a Scatter Plot on a 1.54 Inch 128x64 OLED

To display a scatter plot on a 1.54 inch 128x64 oled display, you need to map your data points to pixel coordinates within the 128x64 grid, then write those pixels to the display buffer using a microcontroller like an Arduino or ESP32. The display’s 128 columns and 64 rows give you a resolution of 8,192 pixels, which is enough for around 100 to 200 distinct scatter points without overlapping too much, depending on your data distribution. The key is to use the SPI interface for fast data transfer, typically at 4 MHz to 8 MHz, to update the screen smoothly. Start by initializing the display with a library like Adafruit_SSD1306 or u8g2, which support the SH1106 or SSD1306 driver chips common in these 1.54-inch OLEDs. For example, the SH1106 driver has a 132x64 internal RAM but only 128x64 is visible, so you’ll need to set the column offset to 2 in your initialization code. The actual scatter plot rendering involves converting your data values to pixel positions: for x-axis, map your data range to 0 to 127, and for y-axis, map to 0 to 63, remembering that pixel y=0 is the top of the screen. If your data has negative values, you’ll need to shift the origin to a visible area, like setting the bottom-left corner at pixel (0, 63) for standard Cartesian plots. Use the drawPixel() function to place each point, and for better visibility, consider drawing 2x2 or 3x3 pixel blocks, which reduces the maximum number of points to about 50 or 25 respectively. The SPI wiring is straightforward: connect SCK to pin 13, MOSI to pin 11, DC to pin 9, CS to pin 10, and RST to pin 8 on an Arduino Uno, but you can change these pins in your code. The display consumes about 20 mA to 30 mA during operation, so it’s fine for battery-powered projects if you use sleep modes. Below is a table summarizing the key parameters for implementing a scatter plot on this display:

ParameterValueNotes
Display resolution128 x 64 pixelsTotal 8,192 pixels
Driver chipSH1106 or SSD1306SH1106 has 132x64 RAM, offset 2
InterfaceSPI (4-wire)Up to 8 MHz clock
Max scatter points (1x1 pixel)~200With 50% overlap tolerance
Max scatter points (2x2 pixel)~50Better visibility
Operating current20-30 mAIdle ~0.1 mA in sleep
Typical libraryAdafruit_SSD1306Version 2.5.0+
Data mapping rangeX: 0-127, Y: 0-63Y inverted from Cartesian

For a concrete example, say you have 50 data points from a sensor measuring temperature vs. humidity. You’d normalize the temperature range (e.g., 20°C to 30°C) to 0-127 for x-axis, and humidity (30% to 80%) to 0-63 for y-axis. In code, you’d loop through each point, compute the pixel coordinates using map() function, and call display.drawPixel(x, y, WHITE). After all points are drawn, call display.display() to send the buffer to the OLED. The buffer size is 128 * 64 / 8 = 1,024 bytes, so it fits easily in the microcontroller’s RAM. If you’re using an ESP32, you can even update the plot in real-time at 10 to 30 frames per second, depending on how many points you redraw. One common mistake is forgetting to clear the buffer before drawing a new plot, which causes ghosting. Use display.clearDisplay() at the start of each frame. Also, the OLED’s contrast can be adjusted via display.setContrast() with values from 0 to 255, but 128 is typical for indoor use. For outdoor readability, you might need to increase it to 200, but that raises power consumption slightly. The viewing angle is around 160 degrees, so it’s fine for most applications. If you want to add axes and labels, you’ll need to draw lines using drawLine() and text using setCursor() with a font like FreeSans9pt. However, the 128x64 resolution limits text to about 10 characters per line at 6x8 pixel font, so keep labels short. For example, you can label the x-axis as “Temp” and y-axis as “Hum” at the bottom-left and top-left corners. The scatter plot itself should be placed in the center 120x56 area, leaving 4 pixels on each side for margins. This gives you a usable plotting area of 120x56 pixels, which is 6,720 pixels for data. If you’re plotting time-series data, you can scroll the plot by shifting the buffer left by 1 pixel each update, which requires a display.ssd1306_command(SSD1306_SCROLL_LEFT) or manual buffer manipulation. But for static scatter plots, no scrolling is needed. The SPI bus speed is critical for smooth updates: at 4 MHz, sending 1,024 bytes takes about 2 milliseconds, plus the drawing time of your points. With 50 points, total frame time is under 10 ms, achieving 100+ fps theoretically, but the OLED’s internal refresh rate is around 60 Hz, so you’re limited to that. Practically, you’ll see smooth updates at 30 fps. Another detail: the 1.54-inch OLED has a pixel pitch of about 0.29 mm, so each point is clearly visible from 30 cm away. For dense scatter plots, consider using anti-aliasing or dithering to represent overlapping points, but that’s complex on a monochrome display. Instead, you can use different pixel sizes for different data densities: small dots for sparse areas, larger blocks for clusters. This is done by conditionally drawing 2x2 blocks when points are within 3 pixels of each other. The code would check the Euclidean distance between each new point and existing points, and if it’s less than 3, draw a 2x2 block instead of a single pixel. This technique works well for up to 100 points. For the SPI wiring, use 10 kΩ pull-up resistors on the CS and DC lines if you’re using long wires (over 20 cm), to prevent signal degradation. The display’s operating voltage is 3.3V, but it’s 5V tolerant on the logic pins, so you can connect directly to an Arduino Uno’s 5V pins with a current-limiting resistor (e.g., 100 Ω) on the data lines to avoid overvoltage. However, it’s safer to use a level shifter or run the Arduino at 3.3V. The OLED’s lifespan is about 50,000 hours of continuous use, so it’s durable for long-term projects. If you’re using the u8g2 library, the initialization code is U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, CS, DC, RST), which sets up the hardware SPI. For scatter plots, u8g2’s drawPixel() is slower than Adafruit’s because it uses a page buffer, but you can switch to full buffer mode with U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI for faster updates. The difference is about 20% slower in practice, but it’s still fine for 50 points. To handle multiple datasets, you can use different pixel patterns: for example, dataset A uses solid pixels, dataset B uses hollow circles drawn with drawCircle() of radius 1. This requires 4 pixels per circle, so you can fit about 30 such points. The code for a hollow circle is: for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i*i + j*j == 1) display.drawPixel(x+i, y+j, WHITE); } }. This creates a cross pattern, which is visually distinct. For axis labels, use a 5x7 pixel font to fit 25 characters per line, but you’ll only have 2 lines for labels due to the 64-pixel height. Place the x-axis label at the bottom (y=60) and y-axis label at the top (y=2). The actual plot area then becomes 128x56 if you use 4 pixels for top and bottom margins. This is fine for most scatter plots. If you need to display a legend, you can use the bottom-right corner with a 2x2 pixel block and a short text like “A” and “B”. The legend text should be no more than 4 characters to fit in the 128-pixel width. For real-time data, you can use a circular buffer of 128 points for x-axis and update the plot by shifting the buffer. This is common in oscilloscope-like applications. The buffer stores the last 128 y-values, and you draw them as a line or scatter plot. For scatter, you draw each point individually, which is slower but more accurate for noisy data. The update rate is limited by the ADC sampling rate of your microcontroller, but the OLED can handle up to 1000 updates per second theoretically. In practice, you’ll be limited by the sensor read rate. For example, a typical temperature sensor like the DS18B20 takes 750 ms per reading, so you can only update the plot every 0.75 seconds, which is fine. The display’s persistence of vision is about 30 ms, so you won’t see flicker. If you’re using a battery, the OLED’s power consumption is 20 mA, which means a 2000 mAh battery lasts about 100 hours. You can reduce this by turning off the display between updates with display.ssd1306_command(SSD1306_DISPLAYOFF) and waking it with SSD1306_DISPLAYON. This is useful for low-power projects. The scatter plot’s accuracy depends on the mapping function: use map(value, fromLow, fromHigh, 0, 127) for x and map(value, fromLow, fromHigh, 63, 0) for y to invert the y-axis. If your data has outliers, clamp the values to the display range to avoid drawing outside the buffer, which can cause memory corruption. The Adafruit library handles this by ignoring out-of-bounds pixels, but it’s better to clamp manually. For example, x = constrain(x, 0, 127). This ensures the plot is always within bounds. The 1.54-inch OLED’s SPI interface also supports 3-wire mode (without DC pin), but that’s slower and not recommended for scatter plots because you lose the ability to differentiate commands from data. Stick with 4-wire SPI for best performance. The display’s initialization sequence includes setting the multiplex ratio to 63, display start line to 0, and segment remap to 1 for correct orientation. Most libraries handle this automatically, but if you’re writing your own driver, you need to send these commands: 0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00, 0x40, 0x8D, 0x14, 0x20, 0x00, 0xA1, 0xC8, 0xDA, 0x12, 0x81, 0xCF, 0xD9, 0xF1, 0xDB, 0x40, 0xA4, 0xA6, 0xAF. This sequence is standard for SH1106. For scatter plots, you don’t need to change the display orientation unless you’re mounting the screen upside down. The U8G2_R0 parameter in u8g2 sets the rotation to 0 degrees. If you need to rotate, use U8G2_R2 for 180 degrees. This is useful if the OLED is mounted in a different orientation. The pixel density of 128x64 on a 1.54-inch diagonal gives a PPI of about 95, which is lower than modern smartphones but perfectly readable for data visualization. The contrast ratio is typically 2000:1, so white pixels are very bright against the black background. This makes scatter plots highly visible even in dim light. For direct sunlight, the OLED is less readable than reflective LCDs, but you can increase contrast to 255 to compensate. The display’s response time is under 10 microseconds, so there’s no motion blur for fast-moving scatter points. If you’re plotting data from a gyroscope or accelerometer at 100 Hz, you can update the plot at 100 fps, but the human eye can’t perceive changes faster than 30 fps, so it’s overkill. Instead, update at 30 fps and average the data to reduce noise. The scatter plot’s axes can be drawn with drawLine(0, 63, 127, 63) for x-axis and drawLine(0, 0, 0, 63) for y-axis. Add tick marks every 10 pixels using drawLine(x, 63, x, 61) for x-axis and drawLine(0, y, 2, y) for y-axis. This gives a professional look. For the tick labels, use the smallest font (5x7) to fit numbers like “10”, “20”, etc. The font height is 7 pixels, so you can fit 9 rows of text, but with axes, you have only 56 pixels for the plot area, so you can fit 8 tick marks on the y-axis (every 7 pixels) and 18 on the x-axis (every 7 pixels). This is adequate for most scatter plots. The actual data points should be drawn after the axes to avoid being overwritten. The order in your code should be: clear display, draw axes, draw tick marks, draw labels, then draw scatter points. This ensures the points are on top. If you have multiple datasets, draw them in order of importance, with the most important dataset last. The 1.54-inch OLED’s memory is page-addressed, meaning the buffer is organized in 8 pages of 128 bytes each. This affects how you draw pixels: the Adafruit library uses a linear buffer, so it’s straightforward. The u8g2 library uses a page buffer by default, which requires calling u8g2.firstPage() and u8g2.nextPage() in a loop. This is slower but uses less RAM. For scatter plots, the full buffer mode is faster because you can draw all points at once. The choice depends on your microcontroller’s RAM: an Arduino Uno has 2 KB, so 1 KB for the buffer is fine. An ESP32 has 520 KB, so no issue. The scatter plot’s performance is also affected by the font rendering. If you use a proportional font, it takes longer to compute character widths. Stick with fixed-width fonts like 5x7 for speed. The total code size for a scatter plot with axes and labels is about 10 KB on an Arduino, which fits in the 32 KB flash. For the ESP32, it’s negligible. The display’s SPI clock speed can be increased to 8 MHz if your wiring is short (under 10 cm). Longer wires cause signal reflections, so use shielded cables or reduce speed to 4 MHz. The OLED’s internal oscillator is about 400 kHz, so the SPI speed doesn’t affect the display’s internal timing, only the data transfer rate. The scatter plot’s visual quality can be improved by using anti-aliased lines for the axes, but that’s not necessary for most applications. The monochrome display only supports on/off pixels, so no gray levels. However, you can simulate gray by using dithering patterns, like a 2x2 checkerboard for a 50% gray effect. This is useful for highlighting different regions in the scatter plot, like a background grid. The grid can be drawn with dotted lines using drawLine() with a pattern of 1 pixel on, 1 pixel off. This creates a subtle grid that doesn’t interfere with the data points. The grid spacing should be every 10 pixels, matching the tick marks. The code for a dotted line is: for (int x = 0; x < 128; x+=2) { display.drawPixel(x, y, WHITE); }. This creates a horizontal dotted line. For vertical lines, use for (int y = 0; y < 64; y+=2) { display.drawPixel(x, y, WHITE); }. This adds a professional touch to the scatter plot. The 1.54-inch OLED’s viewing angle is 160 degrees, so the plot is readable from

Redazione CTM Italia

admin

Consulente del credito e analista del team editoriale di CTM Italia. Si occupa di normativa bancaria, mutui e tutela del consumatore creditizio.

Approfondimento
Mutui e Prestiti
Approfondimento
Credito alle Imprese
Approfondimento
La nostra Rete
Parliamone
Contatti

Pronto a confrontare la tua rata?

Oltre 1.200.000 preventivi erogati dal 2007. Compila il modulo e un consulente OAM ti ricontatterà entro 24 ore lavorative.

Richiedi un preventivo gratuito