G039 Los displays OLED de 128×64 I2C

 
Descripción 
Lo que sorprende de estos displays OLED, es su tamaño. Son pequeños. Vamos a ver como se conecta y configura la pantalla.

¿Para qué  se usa un display pequeño y de tecnología OLED?
Porque el consumo que presenta este display es ridículo: unos 16 mA, aún menos que un LED y eso con una resolución de 128×64 pixels.

Tiene un contraste magnifico y no necesita backlit para poder ver el display, ya que la tecnología OLED genera la luz de por sí.

Lo de OLED viene de Organic Light Emitting Diode, o sea que son diodos LED con otra tecnología.
 
Suelen tener un color azul o blanco y resulta muy agradable de leer, tanto a plena luz, como en la oscuridad completa.

Permite la representación tanto de caracteres como de matrices graficas e imágenes en una cierta resolución, 128×64 pixels, lo que hace que tenga muchas ventajas, entre ellas que supuestamente funciona igual a 5V que a 3.3V, tanto para la alimentación como para las señales de datos.

Materiales
Placa de Arduino
1 Display OLED I2C 128X64
Protoboard, cables para conexiones y un cable USB para conectar Arduino al PC y sirve además como alimentación

Esquema


 
Hay variantes de estos displays en I2C y en versión SPI. 
La conexión resulta trivial.
OLED ARDUINO
GND GND
VDD 5V
SCK A5
SDA A4

Como es habitual, podemos aprovecharnos de la facilidad de usar una protoboard para conectar los pines del display OLED directamente a los pines de Arduino, para programarlos directamente.

Montaje


Código
Este primer código es para comprobar que la pantalla funciona

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  Serial.begin(9600);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("Fallo pantalla");
    while (true);
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("OK funciona");
  display.display();
}

void loop() {}


El siguiente código es para ver como imprimir en pantalla texto dinámico, texto animado e información del sistema.

Librería para comunicación I2C (SDA/SCL)
No tiene parámetros modificables aquí
#include <Wire.h>

Librería gráfica base (textos, líneas, formas)
#include <Adafruit_GFX.h>

Driver específico para pantallas OLED SSD1306
#include <Adafruit_SSD1306.h>

// Ancho de pantalla en píxeles (normal: 128, algunos módulos 128 o 64 de altura)
#define SCREEN_WIDTH 128

Alto de pantalla en píxeles (puede ser 32 o 64 según modelo)
#define SCREEN_HEIGHT 64


Crea el objeto pantalla.
Parámetros:
- SCREEN_WIDTH → ancho en píxeles
- SCREEN_HEIGHT → alto en píxeles
- &Wire → bus I2C (puede ser Wire o Wire1 en otras placas)
- -1 → pin RESET (si la pantalla no tiene pin RESET físico)
Valores posibles:
- Wire / Wire1 / TwoWire custom
- reset pin: número de pin o -1 si no existe
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

Índice del menú actual (0,1,2)
int menuIndex = 0;

Guarda el tiempo del último cambio de menú (millis)
unsigned long lastChange = 0;

Posición horizontal de la animación (pixel X)
int animX = 0;

Dirección de movimiento de la animación (+1 derecha, -1 izquierda)
int dir = 1;

Función que establece los valores necesario al encender el arduino
void setup() {

Inicia puerto serie.
Parámetro:
- 115200 → velocidad en baudios
Valores comunes: 9600, 115200
Serial.begin(115200);

Inicializa la pantalla.
Parámetros:
- SSD1306_SWITCHCAPVCC → modo de alimentación interno del driver
- 0x3C → dirección I2C (puede ser 0x3C o 0x3D)
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
   
Si falla devuelve false e imprime el pantalla "Fallo OLED"
Serial.println("Fallo OLED");

Bloquea el programa si no detecta pantalla
while (true);

Limpia buffer interno de pantalla (no se ve aún)
display.clearDisplay();

Tamaño del texto.
Valores posibles:
1 → tamaño normal (6x8 px por carácter)
2 → doble
3+ → más grande (ocupa mucha pantalla)
display.setTextSize(1);

Color del texto.
Posibles valores:
- SSD1306_WHITE (blanco / encendido)
- SSD1306_BLACK (apagado sobre fondo invertido)
display.setTextColor(SSD1306_WHITE);

Función personalizada llamada drawMenu
void drawMenu() {

Limpia pantalla antes de dibujar menú
display.clearDisplay();

Posición del texto.
Parámetros:
- X → columna (0 a 127)
- Y → fila (0 a 63)
No hay valores fijos, pero:
- Y en pasos de ~8 funciona bien con texto tamaño 1
display.setCursor(0, 0);

Escribe texto con salto de línea automático
display.println("MENU TEST OLED");

Posición del texto.
Parámetros:
- X → columna (0 a 127)
- Y → fila (0 a 63)
No hay valores fijos, pero:
- Y en pasos de ~8 funciona bien con texto tamaño 1  display.setCursor(0, 20);
 
Imprime las opcioens de menu
display.print(menuIndex == 0 ? "> " : "  ");

operador ternario:
- si menuIndex == 0 → muestra "> "
- si no → espacios
Sirve para marcar opción seleccionada
display.println("Texto dinamico");


Establece el cursosr en la posición 0,30 
  display.setCursor(0, 30);

Imprime en pantalla la opción 1
  display.print(menuIndex == 1 ? "> " : "  ");
 
Imprime en pantalla "Animacion"
display.println("Animacion");
 
Establece el cursosr en la posición 0, 40
display.setCursor(0, 40);
 
Imprime en pantalla la opción 2
display.print(menuIndex == 2 ? "> " : "  ");
 
Imprime en pantalla "Info sistema"
display.println("Info sistema");


Envía buffer a pantalla física.
display.display();
}

IMPORTANTE:
Sin esto NO se ve nada.
*/
}

Función repetitiva de arduinoa
void loop() {

Cambia  automáticamente cada 3 segundos
millis():
- devuelve tiempo desde inicio en ms

Condición:
- cambia menú cada 3000 ms (3 segundos)
*/
// Cambia menú automáticamente cada 3s
  if (millis() - lastChange > 3000) {

Cambia entre 0,1,2%3 → reinicia a 0 cuando llega a 3
menuIndex = (menuIndex + 1) % 3;

actualiza tiempo de referencia
}lastChange = millis();
  }


// ===== MENU 0 =====
muestra tiempo en ms desde encendido
// ===== MENU 0: texto dinámico =====
  if (menuIndex == 0) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("Texto dinamico:");

    display.setCursor(0, 20);
    display.print("Millis: ");
    display.println(millis());


convierte ms a segundos
display.setCursor(0, 40);
    display.print("Seg: ");
    display.println(millis() / 1000);

    display.display();
  }


// ===== MENU 1 =====
mueve posición horizontal
  // ===== MENU 1: animacion =====
  else if (menuIndex == 1) {
    display.clearDisplay();

    display.setCursor(animX, 20);
    display.println("OLED");

    animX += dir;
   
rebote:
- si llega a borde cambia dirección
if (animX <= 0 || animX >= 100) dir = -dir;

controla velocidad de animación
(menor = más rápido)
*/
    display.display();
    delay(20);
  }

// ===== MENU 2 =====
  // ===== MENU 2: info sistema =====
  else if (menuIndex == 2) {
    display.clearDisplay();

    display.setCursor(0, 0);
    display.println("INFO SISTEMA");

    display.setCursor(0, 20);
    display.println("Arduino UNO");

    display.setCursor(0, 35);
    display.println("OLED 128x64");

    display.setCursor(0, 50);
    display.print("I2C: 0x3C");

    display.display();
  }

Aquí tienes el código completo
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

int menuIndex = 0;
unsigned long lastChange = 0;
int animX = 0;
int dir = 1;

void setup() {
  Serial.begin(9600);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("Fallo OLED");
    while (true);
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
}

void drawMenu() {
  display.clearDisplay();

  display.setCursor(0, 0);
  display.println("MENU TEST OLED");

  display.setCursor(0, 20);
  display.print(menuIndex == 0 ? "> " : "  ");
  display.println("Texto dinamico");

  display.setCursor(0, 30);
  display.print(menuIndex == 1 ? "> " : "  ");
  display.println("Animacion");

  display.setCursor(0, 40);
  display.print(menuIndex == 2 ? "> " : "  ");
  display.println("Info sistema");

  display.display();
}

void loop() {

  // Cambia menú automáticamente cada 3s
  if (millis() - lastChange > 3000) {
    menuIndex = (menuIndex + 1) % 3;
    lastChange = millis();
  }

  // ===== MENU 0: texto dinámico =====
  if (menuIndex == 0) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("Texto dinamico:");

    display.setCursor(0, 20);
    display.print("Millis: ");
    display.println(millis());

    display.setCursor(0, 40);
    display.print("Seg: ");
    display.println(millis() / 1000);

    display.display();
  }

  // ===== MENU 1: animacion =====
  else if (menuIndex == 1) {
    display.clearDisplay();

    display.setCursor(animX, 20);
    display.println("OLED");

    animX += dir;
    if (animX <= 0 || animX >= 100) dir = -dir;

    display.display();
    delay(20);
  }

  // ===== MENU 2: info sistema =====
  else if (menuIndex == 2) {
    display.clearDisplay();

    display.setCursor(0, 0);
    display.println("INFO SISTEMA");

    display.setCursor(0, 20);
    display.println("Arduino UNO");

    display.setCursor(0, 35);
    display.println("OLED 128x64");

    display.setCursor(0, 50);
    display.print("I2C: 0x3C");

    display.display();
  }
}

El siguiente código me permite mostrar una barra que indican el nivcl del sonido
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1   // I2C normalmente no usa reset

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int ancho = 16;
byte data[6];

void setup() {
  Wire.begin();

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // dirección típica I2C
    while (true); // si falla, se queda aquí
  }

  display.clearDisplay();
}

void loop() {
  for (int i = 0; i < 6; i++) {
    data[i] = map(analogRead(i), 0, 1023, 0, 64);
  }

  barChart();
  delay(150);
}

void barChart() {
  display.clearDisplay();

  for (int j = 0; j < 6; j++) {
    int X0 = ancho * j;
    int H = data[j];

    display.fillRect(X0, 64 - H, ancho - 2, H, SSD1306_WHITE);
  }

  display.drawLine(0, 63, 127, 63, SSD1306_WHITE);
  display.display();
}
 
El siguiente código es lo mismo pero con una señal de ondas
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
  Wire.begin();

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    while (true); // fallo de pantalla
  }

  display.clearDisplay();
}

void loop() {
  display.clearDisplay();

  for (int x = 0; x < 128; x++) {
    int y = map(analogRead(A0), 0, 1023, 63, 0); // invertido eje Y
    display.drawPixel(x, y, SSD1306_WHITE);
  }

  display.display();
  delay(500);
}

El siguiente código es un osciloscópio tremendamente básico. La entrada de señal está en A0
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int buffer[128];

void setup() {
  Wire.begin();

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    while (true);
  }

  display.clearDisplay();
}

void loop() {

  // 1. Captura de señal
  for (int i = 0; i < 128; i++) {
    buffer[i] = analogRead(A0);
    delayMicroseconds(200); // ajusta velocidad de muestreo
  }

  // 2. Dibujar señal
  display.clearDisplay();

  for (int x = 0; x < 127; x++) {
    int y1 = map(buffer[x], 0, 1023, 63, 0);
    int y2 = map(buffer[x + 1], 0, 1023, 63, 0);

    display.drawLine(x, y1, x + 1, y2, SSD1306_WHITE);
  }

  display.display();
}



















No hay comentarios:

Publicar un comentario