Skip to content
Quiero Innovar Quiero Innovar Iberoamérica · 2019 Reservar sesión

How to draw shapes on a 0.96 inch OLED with Arduino?

How to Draw Shapes on a 0.96 Inch OLED with Arduino

To draw shapes on a 0.96 inch OLED display with Arduino, you need to interface the display using either I2C or SPI protocol, then leverage graphics libraries like Adafruit_SSD1306 or U8g2 to render primitives such as lines, rectangles, circles, and triangles. The most common driver chip for these small OLEDs is the SSD1306, which supports a resolution of 128x64 pixels. For a reliable hardware option, consider using a 0.96 inch 128x64 spi i2c oled display that offers both interface choices. The display operates at 3.3V logic level, but many modules include a voltage regulator for 5V Arduino boards. You must connect VCC to 3.3V or 5V depending on your module, GND to ground, SDA to A4 (for I2C on Uno) or a digital pin (for SPI), and SCL to A5 (for I2C) or another digital pin (for SPI). The I2C address is typically 0x3C or 0x3D, and you can scan it with an I2C scanner sketch. For SPI, you need CS, DC, and RESET pins in addition to MOSI and SCK.

Before drawing shapes, you must install the Adafruit SSD1306 library and the Adafruit GFX library via the Arduino Library Manager. The GFX library provides all the drawing functions. After including or and , you create a display object. For I2C, use Adafruit_SSD1306 display(128, 64, &Wire, -1); where -1 disables the reset pin if not used. For SPI, you specify CS, DC, and RESET pins: Adafruit_SSD1306 display(128, 64, &SPI, csPin, dcPin, rstPin);. In setup(), call display.begin(SSD1306_SWITCHCAPVCC, 0x3C); for I2C or display.begin(SSD1306_SWITCHCAPVCC); for SPI. Then clear the buffer with display.clearDisplay();. The OLED uses a frame buffer, so you must call display.display(); after each drawing command to push the buffer to the screen.

Drawing a pixel is the most basic shape. Use display.drawPixel(x, y, WHITE); where x and y range from 0 to 127 and 0 to 63 respectively. The color parameter is WHITE (1) or BLACK (0) for monochrome OLEDs. To draw a line, use display.drawLine(x0, y0, x1, y1, WHITE);. The library uses Bresenham’s line algorithm, which is efficient for embedded systems. For a rectangle, display.drawRect(x, y, width, height, WHITE); draws an outline, while display.fillRect(x, y, width, height, WHITE); draws a filled rectangle. The coordinates specify the top-left corner. For a circle, display.drawCircle(x, y, radius, WHITE); and display.fillCircle(x, y, radius, WHITE); work similarly. The center is at (x, y), and radius is in pixels. For a triangle, display.drawTriangle(x0, y0, x1, y1, x2, y2, WHITE); draws a triangle outline, and display.fillTriangle() fills it. These functions use integer math, so they are fast on the 16 MHz Arduino Uno.

You can also draw rounded rectangles with display.drawRoundRect(x, y, w, h, cornerRadius, WHITE); and display.fillRoundRect(). The corner radius determines the curvature. For complex shapes, you can combine multiple primitives. For example, a house shape can be a rectangle for the body and a triangle for the roof. The GFX library also supports drawing bitmaps, but that’s beyond basic shapes. The display buffer is 1024 bytes (128x64/8), so you can draw up to 1024 pixels at once without flicker. The library automatically handles the page addressing mode of the SSD1306, which organizes memory into 8 pages of 128 bytes each.

Performance matters when drawing shapes. The I2C interface runs at 100 kHz or 400 kHz, limiting the refresh rate to about 15-30 frames per second for complex drawings. SPI runs at up to 10 MHz, achieving 60+ frames per second. For smooth animations, use SPI. The table below compares the two interfaces for drawing 100 random rectangles:

InterfaceClock SpeedTime to Draw 100 Rectangles (ms)Max FPS
I2C (100 kHz)100 kHz~450 ms~22 FPS
I2C (400 kHz)400 kHz~120 ms~83 FPS
SPI (4 MHz)4 MHz~30 ms~333 FPS
SPI (8 MHz)8 MHz~15 ms~667 FPS

These times include the display.display() call. The actual drawing commands are fast, but the buffer transfer is the bottleneck. For static shapes, I2C is fine. For animations, SPI is better. The SSD1306 also supports vertical scrolling, but that doesn’t affect shape drawing.

To draw shapes with variable thickness, you can use loops. For example, to draw a thick line, draw multiple parallel lines offset by one pixel. Or use display.drawFastHLine() and display.drawFastVLine() for horizontal and vertical lines, which are optimized for speed. The GFX library also includes display.drawCircleHelper() for drawing arc segments, which is useful for pie charts. For a filled circle, the library uses a scanline algorithm that fills rows between left and right edges. This is efficient for small circles (radius < 30 pixels). For larger circles, consider using a precomputed bitmap.

Memory usage is critical on Arduino Uno with only 2 KB of SRAM. The display buffer takes 1024 bytes, leaving about 1 KB for variables and stack. If you draw many shapes, use local variables and avoid storing data in arrays. For complex graphics, consider using a board with more RAM, like the Arduino Mega or ESP32. The ESP32 has 520 KB SRAM, so you can draw hundreds of shapes without worry. The 0.96 inch OLED itself has 128x64 pixels, which is 8,192 pixels. Each pixel is either on or off. The buffer is 1,024 bytes because each byte represents 8 vertical pixels in a column. This is called page-column addressing. When you draw a shape, the library updates the relevant bytes in the buffer. For example, drawing a pixel at (10, 20) sets bit 4 in the byte at buffer[10*8 + 20/8].

You can also draw shapes using the U8g2 library, which supports more display controllers and fonts. U8g2 uses a different API. For example, u8g2.drawLine(0, 0, 127, 63);. U8g2 has a firstPage/nextPage loop for buffered drawing. It’s more flexible but uses more flash memory. The Adafruit library is simpler for beginners. Both libraries support the 0.96 inch OLED with SSD1306. The U8g2 library can also use hardware SPI or I2C, and you can select the interface in the constructor. For example, U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); for I2C.

Drawing shapes with anti-aliasing is not possible on the monochrome OLED because each pixel is either on or off. However, you can simulate anti-aliasing by using dithering patterns. For example, a 2x2 checkerboard pattern for a gray tone. But this reduces effective resolution. The 0.96 inch OLED has a pixel pitch of about 0.19 mm, so individual pixels are visible. For smooth lines, use the drawLine() function, which already uses Bresenham’s algorithm to minimize jaggies. For circles, the algorithm uses the midpoint circle algorithm, which produces symmetric circles. The radius can be up to 63 pixels, but a circle larger than 64 pixels will be clipped.

To draw multiple shapes without clearing the screen, use display.clearDisplay() only when needed. You can draw on top of existing shapes, but the monochrome nature means overlapping shapes overwrite previous pixels. If you want to erase a shape, draw it again in BLACK. For example, to animate a moving rectangle, draw it in BLACK at the old position and WHITE at the new position. This is faster than clearing the whole screen. The library’s display.drawRect() with BLACK color effectively erases the rectangle. However, be careful because overlapping shapes can leave artifacts. A better approach is to use a double buffer technique: draw everything to a temporary buffer, then copy to the display buffer. But the Arduino Uno doesn’t have enough RAM for a second buffer. On ESP32, you can allocate a second buffer of 1024 bytes and use memcpy().

The 0.96 inch OLED also supports partial display updates. You can use display.setCursor() and display.setTextSize() to draw text, but that’s not shapes. For shapes, you can combine text and graphics. For example, draw a rectangle and then write text inside it. The font size is 5x7 pixels for size 1, and multiples for larger sizes. The GFX library includes a 5x7 font by default, but you can add custom fonts. The SSD1306 can display up to 21 characters per line (128/6) for size 1, and 8 lines (64/8). But for shapes, you have the full 128x64 pixel area.

Practical example: draw a simple bar chart. First, draw axes with display.drawLine(10, 10, 10, 54, WHITE); and display.drawLine(10, 54, 118, 54, WHITE);. Then draw bars with display.fillRect(20, 54 - value1, 10, value1, WHITE); for each bar. The bar width is 10 pixels, spacing 2 pixels. This uses 8 bars across the screen. You can scale values to the 44-pixel height (54-10). For a pie chart, use display.fillCircle(64, 32, 30, WHITE); for the base, then draw segments with triangles. But drawing arcs requires manual calculation. The GFX library doesn’t have a built-in arc function, but you can use drawCircleHelper() for 90-degree arcs. For a full pie chart, consider using a precomputed bitmap.

Another common shape is a filled polygon. The GFX library doesn’t have a generic polygon fill, but you can use fillTriangle() to build complex polygons by dividing them into triangles. For example, a five-pointed star can be drawn with 5 triangles. The coordinates for a star with center at (64,32) and outer radius 30, inner radius 15 can be calculated using trigonometry. The points are at angles 0, 72, 144, 216, 288 degrees for outer points, and 36, 108, 180, 252, 324 for inner points. Convert to radians and compute x = 64 + radius * cos(angle), y = 32 + radius * sin(angle). Then draw triangles from the center to two adjacent outer points. This creates a star shape.

For drawing shapes with rotation, you need to implement rotation manually. The GFX library doesn’t support rotated rectangles or ellipses. You can rotate a point using matrix multiplication: x' = x*cos(θ) - y*sin(θ), y' = x*sin(θ) + y*cos(θ). Then draw lines between rotated points. For a rotated rectangle, calculate the four corners after rotation, then draw lines between them. This is CPU-intensive on Arduino Uno, but works for a few shapes. The floating point math is slow, so use integer approximations with precomputed sine/cosine tables. For example, a 16-entry table with 0-90 degrees gives 5.625 degree steps. This is sufficient for most animations.

The 0.96 inch OLED’s viewing angle is wide (over 160 degrees), and contrast is high (over 2000:1). The display consumes about 20 mA when all pixels are on, and 10 mA typical. The SSD1306 has a built-in charge pump for the OLED voltage, so no external components are needed. The display is best viewed in dim light; direct sunlight washes it out. For outdoor use, consider a higher brightness OLED or an LCD. The 0.96 inch size is ideal for small projects like wearables, sensors, or control panels. The 128x64 resolution is enough for simple graphics and text.

When drawing shapes, you must consider the coordinate system. The origin (0,0) is the top-left corner. X increases to the right, Y increases downward. This is standard for most displays. The SSD1306 can also be rotated using the setRotation() function. For example, display.setRotation(1); rotates 90 degrees clockwise. This changes the coordinate mapping. The library handles the translation internally. After rotation, the width and height are swapped. So for a 128x64 display, after rotation, you have 64x128. But the physical pixels remain the same; the library just reinterprets the buffer. This is useful for portrait mode applications.

For drawing shapes with gradients or patterns, you can use dithering. The monochrome OLED can only display binary pixels, but you can create the illusion of gray by using patterns. For example, a 2x2 pattern with 1 white pixel and 3 black pixels gives 25% gray. The GFX library doesn’t have built-in dithering, but you can implement it by drawing pixels based on a threshold. For a filled rectangle with a gradient, calculate the intensity based on position, then compare to a random threshold. This is called error diffusion dithering, but it’s slow on Arduino. A simpler approach is to use a precomputed pattern array. For example, a 4x4 Bayer matrix for 16 levels of gray. Each level has a pattern of 16 pixels. This uses 256 bytes of flash for the patterns. Then for each pixel in the rectangle, look up the pattern based on the desired gray level. This is fast enough for static images.

Another advanced technique is drawing shapes with clipping. The GFX library has a setClipRect() function that restricts drawing to a rectangular region. This is useful for creating windows or scrollable areas. For example, you can draw a large shape that extends beyond the screen, but only the part inside the clip rectangle is visible. The clip rectangle is set with display.setClipRect(x, y, w, h); and cleared with display.setClipRect();. This is implemented by checking each pixel against the clip region, so it’s slower but very useful for complex layouts.

For drawing shapes with transparency, the monochrome OLED doesn’t support alpha blending. Overlapping shapes simply overwrite. To create a transparent effect, you can use XOR mode. The GFX library doesn’t have XOR mode, but you can implement it by reading the buffer and toggling bits. For example, to draw a rectangle in XOR mode, read the byte for each pixel, invert the bit for that pixel, and write back. This creates a toggle effect, which is useful for cursors or selection highlights. The SSD1306 supports a XOR mode in hardware via the SSD1306_SETCONTRAST command, but the library doesn’t expose it. You can send raw commands to the display using display.ssd1306_command(0xA8); etc. But this is advanced and not recommended for beginners.

The 0.96 inch OLED’s lifespan is about 20,000 hours for typical use. The organic materials degrade over time, especially with blue pixels. The SSD1306 uses a white or blue OLED, depending on the module. Blue OLEDs have shorter lifespan (about 10,000 hours) than white. For long-term projects, consider a white OLED. The display’s brightness can be adjusted with display.ssd1306_command(SSD1306_SETCONTRAST); followed by a value from 0 to 255. Lower values reduce power consumption and extend lifespan. For shapes, you don’t need full brightness; 50% is often sufficient for indoor use.

For drawing shapes with smooth motion, you need to minimize flicker. The SSD1306 updates the entire screen