Usando Um Arduino® Para Controlar Ecrãs OLED Por I2C
Um pequeno projecto de 10 minutos para poder controlar um ecrã OLED por I2C com o Arduino.
Material Necessário:
- Software Arduino IDE (https://www.arduino.cc/en/software).
Hardware + Componentes Electrónicos:
- 1x Um Arduino UNO;
- 1x Ecrã OLED SD1306, I2C, 3,3V ou 5V, (de 0.96 polegadas, 128x64 pixels ou de 0.91 polegadas, 128x32 pixels);
- 1x breadboard;
- Vários fios eléctricos para ligar os componentes.
Esquema/Diagrama de Ligação:
Código/Sketch:
----------------------- OLED-I2C.ino -----------------------
///////////////////////////////////////////////////////////////////////////////
// Project: OLED Display Test
// URL:
// File: OLED-I2C.ino
//
// Description:
// This Sketch controls a small OLED display (0.91" or 0.96") via I2C of the Arduino.
//
// Copyright (C) 2019-2022:
// José Caetano Silva / CaetanoSoft
//
// License:
// This file is part of OLED Display Test.
//
// OLED Display Test is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OLED Display Test is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with OLED Display Test. If not, see <https://www.gnu.org/licenses/>.
///////////////////////////////////////////////////////////////////////////////
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Add comment to the next line to use an OLED Display
// of 0.91" 128x32 pixels, insted of a 0.96" 128x64 pixels
#define OLED_128x64
#ifdef OLED_128x64
// # OLED 0.96" #
// OLED display width, in pixels
#define SCREEN_WIDTH 128
// OLED display height, in pixels
#define SCREEN_HEIGHT 64
#else
// # OLED 0.91" #
// OLED display width, in pixels
#define SCREEN_WIDTH 128
// OLED display height, in pixels
#define SCREEN_HEIGHT 32
#endif
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// Reset pin # (or -1 if sharing Arduino reset pin)
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, & Wire, OLED_RESET);
// Number of snowflakes in the animation example
#define NUMFLAKES 10
// Snowflake sprite height
#define SPRITE_HEIGHT 16
// Snowflake widthsprite
#define SPRITE_WIDTH 16
// Sprite pixels data
static
const unsigned char PROGMEM spriteBitmap[] = {
B00000000,
B11000000,
B00000001,
B11000000,
B00000001,
B11000000,
B00000011,
B11100000,
B11110011,
B11100000,
B11111110,
B11111000,
B01111110,
B11111111,
B00110011,
B10011111,
B00011111,
B11111100,
B00001101,
B01110000,
B00011011,
B10100000,
B00111111,
B11100000,
B00111111,
B11110000,
B01111100,
B11110000,
B01110000,
B01110000,
B00000000,
B00110000
};
/**
* The setup function runs once when you press reset or power the board.
*/
void setup()
{
// Initialization of the console's communication baud rate
Serial.begin(115200);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
{
// Error
Serial.println(F("SSD1306 allocation failed"));
// Don't proceed, loop forever
for (;;);
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display.display();
// Pause for 2 seconds
delay(2000);
// Clear the buffer
display.clearDisplay();
// Draw a single pixel in white
display.drawPixel(10, 10, 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...
// # Draw many lines
TestDrawLine();
// # Draw rectangles (outlines)
TestDrawRect();
// # Draw rectangles (filled)
TestDrawFillRect();
// # Draw circles (outlines)
TestDrawCircle();
// # Draw circles (filled)
TestDrawFillCircle();
// # Draw rounded rectangles (outlines)
TestDrawRoundRect();
// # Draw rounded rectangles (filled)
TestDrawFillRoundRect();
// # Draw triangles (outlines)
TestDrawTriangle();
// # Draw triangles (filled)
TestDrawFillTriangle();
// # Draw characters of the default font
TestDrawChar();
// # Draw 'stylized' characters
TestDrawStylesChar();
// # Draw scrolling text
TestScrollText();
// # Draw a small bitmap image
TestDrawBitmap();
// Invert and restore display, pausing in-between
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
// Animate bitmaps
TestAnimate(spriteBitmap, SPRITE_WIDTH, SPRITE_HEIGHT);
}
/**
* The loop function runs over and over again forever.
*/
void loop()
{
// Do nothing
}
/**
* Draw many lines.
*/
void TestDrawLine()
{
int16_t i;
// Clear the display buffer
display.clearDisplay();
for (i = 0; i < display.width(); i += 4)
{
display.drawLine(0, 0, i, display.height() - 1, WHITE);
// Update screen with each newly-drawn line
display.display();
delay(1);
}
for (i = 0; i < display.height(); i += 4)
{
display.drawLine(0, 0, display.width() - 1, i, 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, WHITE);
display.display();
delay(1);
}
for (i = display.height() - 1; i >= 0; i -= 4)
{
display.drawLine(0, display.height() - 1, display.width() - 1, i, 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, WHITE);
display.display();
delay(1);
}
for (i = display.height() - 1; i >= 0; i -= 4)
{
display.drawLine(display.width() - 1, display.height() - 1, 0, i, 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, WHITE);
display.display();
delay(1);
}
for (i = 0; i < display.width(); i += 4)
{
display.drawLine(display.width() - 1, 0, i, display.height() - 1, WHITE);
display.display();
delay(1);
}
// Pause for 2 seconds
delay(2000);
}
/**
* Draw rectangles (outlines)
*/
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, WHITE);
display.display();
delay(1);
}
delay(2000);
}
/**
* Draw rectangles (filled)
*/
void TestDrawFillRect(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, INVERSE);
display.display();
delay(1);
}
delay(2000);
}
/**
* Draw circles (outlines)
*/
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, WHITE);
display.display();
delay(1);
}
delay(2000);
}
/**
* Draw circles (filled)
*/
void TestDrawFillCircle(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, INVERSE);
display.display();
delay(1);
}
delay(2000);
}
/**
* Draw rounded rectangles (outlines)
*/
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, WHITE);
display.display();
delay(1);
}
delay(2000);
}
/**
* Draw rounded rectangles (filled)
*/
void TestDrawFillRoundRect(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, INVERSE);
display.display();
delay(1);
}
delay(2000);
}
/**
* Draw triangles (outlines)
*/
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, WHITE);
display.display();
delay(1);
}
delay(2000);
}
/**
* Draw triangles (filled)
*/
void TestDrawFillTriangle(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, INVERSE);
display.display();
delay(1);
}
delay(2000);
}
/**
* Draw characters of the default font
*/
void TestDrawChar(void)
{
display.clearDisplay();
// Normal 1:1 pixel scale
display.setTextSize(1);
// Draw white text
display.setTextColor(WHITE);
// Start at top-left corner
display.setCursor(0, 0);
// Use full 256 char 'Code Page 437' font
display.cp437(true);
// 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);
}
/**
* Draw 'stylized' characters
*/
void TestDrawStylesChar(void)
{
display.clearDisplay();
// Normal 1:1 pixel scale
display.setTextSize(1);
// Draw white text
display.setTextColor(WHITE);
// Start at top-left corner
display.setCursor(0, 0);
display.println(F("Hello, world!"));
// Draw 'inverse' text
display.setTextColor(BLACK, WHITE);
display.println(3.141592);
// Draw 2X-scale text
display.setTextSize(2);
display.setTextColor(WHITE);
display.print(F("0x"));
display.println(0xDEADBEEF, HEX);
display.display();
delay(2000);
}
/**
* Draw scrolling text
*/
void TestScrollText(void)
{
display.clearDisplay();
// Draw 2X-scale text
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(10, 0);
display.println(F("scroll"));
// Show initial text
display.display();
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);
}
/**
* Draw a small bitmap image
*/
void TestDrawBitmap(void)
{
display.clearDisplay();
display.drawBitmap(
(display.width() - SPRITE_WIDTH) / 2,
(display.height() - SPRITE_HEIGHT) / 2,
spriteBitmap, SPRITE_WIDTH, SPRITE_HEIGHT, 1);
display.display();
delay(1000);
}
/**
* Draw a small bitmap image
*/
void TestAnimate(const uint8_t * bitmap, uint8_t w, uint8_t h)
{
// Indexes into the 'icons' array in function below
static const int XPOS = 0;
static const int YPOS = 1;
static const int DELTAY = 2;
int8_t f, icons[NUMFLAKES][3];
// Initialize 'snowflake' positions
for (f = 0; f < NUMFLAKES; f++)
{
icons[f][XPOS] = random(1 - SPRITE_WIDTH, display.width());
icons[f][YPOS] = -SPRITE_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);
}
// Loop forever...
for (;;)
{
// Clear the display buffer
display.clearDisplay();
// Draw each snowflake:
for (f = 0; f < NUMFLAKES; f++)
{
display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE);
}
// Show the display buffer on the screen
display.display();
// Pause for 1/10 second
delay(200);
// 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 - SPRITE_WIDTH, display.width());
icons[f][YPOS] = -SPRITE_HEIGHT;
icons[f][DELTAY] = random(1, 6);
}
}
}
}
----------------------- OLED-I2C.ino -----------------------
Instruções de Montagem:
Arduino Uno | OLED SD1306 |
---|---|
SDA (Pin A4) | SDA |
SCL (Pin A5) | SCL |
GND | GND |
5V | VCC |
Faça as conexões entre os componentes como é mostrado na tabela 1 acima e no diagrama de ligação.
Caso ainda não tenha instalado, instale no Arduino IDE, as seguintes bibliotecas, instalando todas as dependências:
* SPI ;
* Wire;
* Adafruit GFX;
* Adafruit SSD1306.
Use o Arduino IDE para colar o sketch "OLED-I2C.ino" e gravar-lo, depois compile-o e envie-o para o dispositivo Arduino Uno.
Funcionamento:
Ao alimentar o seu Arduino com tensão, o ecrã OLED vai demonstrar as capacidades gráficas e de texto.