Integrating microcontrollers with OLED displays is a key requirement in many embedded systems projects. This guide provides a comprehensive overview of how to connect a 0.96-inch SSD1306 I2C OLED display to an STM32 microcontroller ( NUCLEO-F303RE STM32 Development Board ) using Arduino IDE. By the end of this tutorial, you’ll be equipped with the knowledge to create interactive projects leveraging this setup.
What is an OLED Display, and Why Use It?
OLED (Organic Light Emitting Diode) display is a flat, thin display technology that emits light when an electric current flows through organic materials. Unlike LCDs, OLEDs don’t require backlighting, resulting in sharper contrasts, faster refresh rates, and better energy efficiency.
Advantages of OLED Displays:
- High contrast ratio.
- Wide viewing angles.
- Thin and lightweight design.
- Energy-efficient for displaying black pixels.
Disadvantages of OLED Displays:
- Potential for burn-in over time.
- Shorter lifespan compared to traditional LEDs.
- Higher cost for larger screen sizes.
Features of the 0.96 Inch I2C 4-Pin OLED Display Module
The 0.96-inch OLED display is a monochrome screen that features a resolution of 128×64 pixels. It utilizes the SSD1306 driver IC and communicates via the I2C protocol, making it easy to connect to microcontrollers like the STM32.
Key features include:
- Size: 0.96 inches
- Resolution: 128×64 pixels
- Interface: I2C (also known as IIC)
- Operating Voltage: 3.3V to 5V
- Display Color: White
Installing Drivers in Arduino IDE
Before programming, ensure that your Arduino IDE is set up correctly with the necessary libraries for the SSD1306 OLED display: To control the OLED display with your STM32, you need to install two libraries in the Arduino IDE:
- Adafruit SSD1306 Library
- Adafruit GFX Library
Follow these steps to install them:
- Open Arduino IDE.
- Navigate to Sketch > Include Library > Manage Libraries.
- Search for “SSD1306” and install the Adafruit SSD1306 library.
- Search for “GFX” and install the Adafruit GFX library.
Overview of the NUCLEO-F303RE STM32 Development Board
The Nucleo-F303RE board is based on the ARM Cortex-M4 microcontroller from STMicroelectronics. It supports various interfaces including I2C, making it suitable for connecting to the OLED display.
Key specifications include:
- Microcontroller: STM32F303RET6
- Clock Speed: Up to 72 MHz
- Flash Memory: 512 KB
- SRAM: 64 KB + 16 KB
- I/O Pins: Compatible with Arduino Uno V3 connectors
Connection Diagram Using NUCLEO-F303RE with OLED
Connecting the OLED display to the Nucleo-F303RE involves linking four pins:
OLED Pin | Function | Nucleo Pin |
---|---|---|
VCC | Power | 3.3V |
GND | Ground | GND |
SCL | Clock | PB8 |
SDA | Data | PB9 |
Ensure that these connections are secure to avoid communication errors.
Programming STM32 using Arduino IDE
Once connected, you can program the OLED display using Arduino IDE. Below is a sample code snippet that initializes the display and shows functions :
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library.
// On an arduino UNO: A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO: 2(SDA), 3(SCL), ...
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define NUMFLAKES 10 // Number of snowflakes in the animation example
#define LOGO_HEIGHT 16
#define LOGO_WIDTH 16
static const unsigned char PROGMEM logo_bmp[] =
{ 0b00000000, 0b11000000,
0b00000001, 0b11000000,
0b00000001, 0b11000000,
0b00000011, 0b11100000,
0b11110011, 0b11100000,
0b11111110, 0b11111000,
0b01111110, 0b11111111,
0b00110011, 0b10011111,
0b00011111, 0b11111100,
0b00001101, 0b01110000,
0b00011011, 0b10100000,
0b00111111, 0b11100000,
0b00111111, 0b11110000,
0b01111100, 0b11110000,
0b01110000, 0b01110000,
0b00000000, 0b00110000 };
void setup() {
Wire.setSDA(PB9);
Wire.setSCL(PB8);
Serial.begin(115200);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display.display();
delay(2000); // Pause for 2 seconds
// Clear the buffer
display.clearDisplay();
// Draw a single pixel in white
display.drawPixel(10, 10, SSD1306_WHITE);
// Show the display buffer on the screen. You MUST call display() after
// drawing commands to make them visible on screen!
display.display();
delay(2000);
// display.display() is NOT necessary after every single drawing command,
// unless that's what you want...rather, you can batch up a bunch of
// drawing operations and then update the screen all at once by calling
// display.display(). These examples demonstrate both approaches...
testdrawline(); // Draw many lines
testdrawrect(); // Draw rectangles (outlines)
testfillrect(); // Draw rectangles (filled)
testdrawcircle(); // Draw circles (outlines)
testfillcircle(); // Draw circles (filled)
testdrawroundrect(); // Draw rounded rectangles (outlines)
testfillroundrect(); // Draw rounded rectangles (filled)
testdrawtriangle(); // Draw triangles (outlines)
testfilltriangle(); // Draw triangles (filled)
testdrawchar(); // Draw characters of the default font
testdrawstyles(); // Draw 'stylized' characters
testscrolltext(); // Draw scrolling text
testdrawbitmap(); // Draw a small bitmap image
// Invert and restore display, pausing in-between
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
}
void loop() {
}
void testdrawline() {
int16_t i;
display.clearDisplay(); // Clear display buffer
for(i=0; i<display.width(); i+=4) {
display.drawLine(0, 0, i, display.height()-1, SSD1306_WHITE);
display.display(); // Update screen with each newly-drawn line
delay(1);
}
for(i=0; i<display.height(); i+=4) {
display.drawLine(0, 0, display.width()-1, i, SSD1306_WHITE);
display.display();
delay(1);
}
delay(250);
display.clearDisplay();
for(i=0; i<display.width(); i+=4) {
display.drawLine(0, display.height()-1, i, 0, SSD1306_WHITE);
display.display();
delay(1);
}
for(i=display.height()-1; i>=0; i-=4) {
display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE);
display.display();
delay(1);
}
delay(250);
display.clearDisplay();
for(i=display.width()-1; i>=0; i-=4) {
display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE);
display.display();
delay(1);
}
for(i=display.height()-1; i>=0; i-=4) {
display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE);
display.display();
delay(1);
}
delay(250);
display.clearDisplay();
for(i=0; i<display.height(); i+=4) {
display.drawLine(display.width()-1, 0, 0, i, SSD1306_WHITE);
display.display();
delay(1);
}
for(i=0; i<display.width(); i+=4) {
display.drawLine(display.width()-1, 0, i, display.height()-1, SSD1306_WHITE);
display.display();
delay(1);
}
delay(2000); // Pause for 2 seconds
}
void testdrawrect(void) {
display.clearDisplay();
for(int16_t i=0; i<display.height()/2; i+=2) {
display.drawRect(i, i, display.width()-2*i, display.height()-2*i, SSD1306_WHITE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
}
delay(2000);
}
void testfillrect(void) {
display.clearDisplay();
for(int16_t i=0; i<display.height()/2; i+=3) {
// The INVERSE color is used so rectangles alternate white/black
display.fillRect(i, i, display.width()-i*2, display.height()-i*2, SSD1306_INVERSE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
}
delay(2000);
}
void testdrawcircle(void) {
display.clearDisplay();
for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
display.drawCircle(display.width()/2, display.height()/2, i, SSD1306_WHITE);
display.display();
delay(1);
}
delay(2000);
}
void testfillcircle(void) {
display.clearDisplay();
for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
// The INVERSE color is used so circles alternate white/black
display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE);
display.display(); // Update screen with each newly-drawn circle
delay(1);
}
delay(2000);
}
void testdrawroundrect(void) {
display.clearDisplay();
for(int16_t i=0; i<display.height()/2-2; i+=2) {
display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
display.height()/4, SSD1306_WHITE);
display.display();
delay(1);
}
delay(2000);
}
void testfillroundrect(void) {
display.clearDisplay();
for(int16_t i=0; i<display.height()/2-2; i+=2) {
// The INVERSE color is used so round-rects alternate white/black
display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
display.height()/4, SSD1306_INVERSE);
display.display();
delay(1);
}
delay(2000);
}
void testdrawtriangle(void) {
display.clearDisplay();
for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
display.drawTriangle(
display.width()/2 , display.height()/2-i,
display.width()/2-i, display.height()/2+i,
display.width()/2+i, display.height()/2+i, SSD1306_WHITE);
display.display();
delay(1);
}
delay(2000);
}
void testfilltriangle(void) {
display.clearDisplay();
for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
// The INVERSE color is used so triangles alternate white/black
display.fillTriangle(
display.width()/2 , display.height()/2-i,
display.width()/2-i, display.height()/2+i,
display.width()/2+i, display.height()/2+i, SSD1306_INVERSE);
display.display();
delay(1);
}
delay(2000);
}
void testdrawchar(void) {
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
// Not all the characters will fit on the display. This is normal.
// Library will draw what it can and the rest will be clipped.
for(int16_t i=0; i<256; i++) {
if(i == '\n') display.write(' ');
else display.write(i);
}
display.display();
delay(2000);
}
void testdrawstyles(void) {
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0,0); // Start at top-left corner
display.println(F("Hello, world!"));
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
display.println(3.141592);
display.setTextSize(2); // Draw 2X-scale text
display.setTextColor(SSD1306_WHITE);
display.print(F("0x")); display.println(0xDEADBEEF, HEX);
display.display();
delay(2000);
}
void testscrolltext(void) {
display.clearDisplay();
display.setTextSize(2); // Draw 2X-scale text
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 0);
display.println(F("scroll"));
display.display(); // Show initial text
delay(100);
// Scroll in various directions, pausing in-between:
display.startscrollright(0x00, 0x0F);
delay(2000);
display.stopscroll();
delay(1000);
display.startscrollleft(0x00, 0x0F);
delay(2000);
display.stopscroll();
delay(1000);
display.startscrolldiagright(0x00, 0x07);
delay(2000);
display.startscrolldiagleft(0x00, 0x07);
delay(2000);
display.stopscroll();
delay(1000);
}
void testdrawbitmap(void) {
display.clearDisplay();
display.drawBitmap(
(display.width() - LOGO_WIDTH ) / 2,
(display.height() - LOGO_HEIGHT) / 2,
logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
display.display();
delay(1000);
}
#define XPOS 0 // Indexes into the 'icons' array in function below
#define YPOS 1
#define DELTAY 2
void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
int8_t f, icons[NUMFLAKES][3];
// Initialize 'snowflake' positions
for(f=0; f< NUMFLAKES; f++) {
icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width());
icons[f][YPOS] = -LOGO_HEIGHT;
icons[f][DELTAY] = random(1, 6);
Serial.print(F("x: "));
Serial.print(icons[f][XPOS], DEC);
Serial.print(F(" y: "));
Serial.print(icons[f][YPOS], DEC);
Serial.print(F(" dy: "));
Serial.println(icons[f][DELTAY], DEC);
}
for(;;) { // Loop forever...
display.clearDisplay(); // Clear the display buffer
// Draw each snowflake:
for(f=0; f< NUMFLAKES; f++) {
display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
}
display.display(); // Show the display buffer on the screen
delay(200); // Pause for 1/10 second
// Then update coordinates of each flake...
for(f=0; f< NUMFLAKES; f++) {
icons[f][YPOS] += icons[f][DELTAY];
// If snowflake is off the bottom of the screen...
if (icons[f][YPOS] >= display.height()) {
// Reinitialize to a random position, just off the top
icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width());
icons[f][YPOS] = -LOGO_HEIGHT;
icons[f][DELTAY] = random(1, 6);
}
}
}
}
Detailed Explanation of the Code
Library Inclusions
The code begins by including necessary libraries such as Wire
, Adafruit_GFX
, and Adafruit_SSD1306
. These libraries handle communication and graphics rendering on the OLED.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Defining Display Parameters
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
- Screen Dimensions: This OLED display has a resolution of 128×64 pixels, where
SCREEN_WIDTH
is the width andSCREEN_HEIGHT
is the height. - Reset Pin: The
OLED_RESET
value is set to-1
to indicate that the OLED shares the Arduino’s reset line. - I²C Address: The default address is
0x3C
. If your display has a different address (e.g.,0x3D
), you’ll need to modify this value. - Adafruit SSD1306 Object: An instance of
Adafruit_SSD1306
is created to interact with the display.
Setting Up the OLED Display
void setup() {
Wire.setSDA(PB9);
Wire.setSCL(PB8);
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.display(); // Show Adafruit splash screen
delay(2000);
display.clearDisplay(); // Clear display buffer
}
- I²C Pins:
Wire.setSDA
andWire.setSCL
specify the I²C pins (SDA and SCL). This is necessary for microcontrollers like STM32 where custom pin assignment is required. - Initialization: The
display.begin
method initializes the display. The parameterSSD1306_SWITCHCAPVCC
generates the required display voltage from 3.3V. If initialization fails, the code enters an infinite loop. - Splash Screen: After initialization, the library automatically displays a default Adafruit splash screen.
- Clearing Buffer:
display.clearDisplay()
clears the display’s buffer to prepare for new graphics.
Drawing a Single Pixel
display.drawPixel(10, 10, SSD1306_WHITE);
display.display();
delay(2000);
- Pixel Drawing: The function
drawPixel(x, y, color)
draws a single pixel at coordinates(10, 10)
with the colorSSD1306_WHITE
(white). - Update Screen:
display.display()
updates the OLED with the new drawing.
Drawing Graphics
The following methods demonstrate how to draw shapes and patterns on the OLED. Each operation updates the display buffer, which is then rendered using display.display()
.
//Drawing Lines
void testdrawline() {
display.clearDisplay();
for(int16_t i = 0; i < display.width(); i += 4) {
display.drawLine(0, 0, i, display.height() - 1, SSD1306_WHITE);
display.display();
}
}
- Purpose: Draws lines originating from the top-left corner (
0, 0
) and extending to various points along the display’s edges. - Loop: Iterates through the display’s width, drawing a line every 4 pixels
//Drawing Rectangles
void testdrawrect() {
display.clearDisplay();
for(int16_t i = 0; i < display.height() / 2; i += 2) {
display.drawRect(i, i, display.width() - 2 * i, display.height() - 2 * i, SSD1306_WHITE);
display.display();
}
}
- Drawing Rectangles: The
drawRect
function draws rectangles with top-left corner(x, y)
and dimensionswidth
andheight
. - Loop: Reduces the size of successive rectangles, creating a nested rectangle effect.
//Drawing Circles
void testdrawcircle() {
display.clearDisplay();
for(int16_t i = 0; i < max(display.width(), display.height()) / 2; i += 2) {
display.drawCircle(display.width() / 2, display.height() / 2, i, SSD1306_WHITE);
display.display();
}
}
- Purpose: Draws concentric circles centered on the display.
- Dynamic Radius: The radius increases in increments of 2 pixels.
void testscrolltext() {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 0);
display.println(F("scroll"));
display.display();
display.startscrollright(0x00, 0x0F);
delay(2000);
display.stopscroll();
}
- Text Rendering: The text “scroll” is displayed with size
2
and colorSSD1306_WHITE
. - Scrolling: The text scrolls to the right using
startscrollright(startPage, endPage)
. Scrolling is stopped usingstopscroll()
.
void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
for(int8_t f = 0; f < NUMFLAKES; f++) {
icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width());
icons[f][YPOS] = -LOGO_HEIGHT;
icons[f][DELTAY] = random(1, 6);
}
for(;;) {
display.clearDisplay();
for(int8_t f = 0; f < NUMFLAKES; f++) {
display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
icons[f][YPOS] += icons[f][DELTAY];
if(icons[f][YPOS] >= display.height()) {
icons[f][YPOS] = -LOGO_HEIGHT;
}
}
display.display();
delay(200);
}
}
- Purpose: Animates snowflakes falling across the screen.Bitmap: Each snowflake is represented using the
logo_bmp
bitmap.Random Motion: Snowflakes have random positions and speeds, creating a natural falling effect.
This setup allows you to easily modify text and graphics displayed on your OLED screen by changing parameters in your code.
By following this guide, you can successfully connect and program a 0.96-inch SSD1306 OLED display with an STM32 microcontroller using Arduino IDE. This setup is ideal for a wide range of projects, including data loggers, interactive interfaces, and compact displays.
For further exploration, dive deeper into the Adafruit GFX library to create complex graphics or display custom animations.
Почивка на Гран Канария: райски отдих, най-добрите места за почивка.
Гид за плажовете на Гран Канария: изберете идеалното място за слънчева баня.
Кулинарно пътешествие до Гран Канария: насладете се на вкуса на местната кухня.
Почивка на Гран Канария: екскурзии за истински пътешественици.
Спа хотели на Гран Канария: релаксирайте и се наслаждавайте на почивката.
Семейна почивка на Гран Канария: отличен избор за цялото семейство.
Семейна почивка в Гран Канария bohemia.bg .