Problemas al iniciar pantalla Oled 128x64

Hola a todos,
estoy empezando con esto del Arduino, no conocía el lenguaje, aunque fui programador hace años.
Hardware que utilizo
Arduino UNO
pantalla oled 128x64
encoder KY-040
Estoy intentando hacer un menú que por medio del encoder pueda mostrar las opciones y una vez en pantalla la deseada, pulsar el encoder para seleccionarla.
El código que os paso es sencillo, si lo ejecuto tal y como esta, la pantalla se inicializa, pero si descomento el 'if del 'loop' o las sentencias 'pantalla.' de menuPrincipal, da error de iniciar pantalla y no funciona. No entiendo, o no sé que puede pasar, agradecería vuestra ayuda para comprenderlo. Me ha pasado en todos los programas en los que utilizo esta pantalla.
hay bastante código anulado como comentario, porque he ido eliminado para dar con las sentencias que provocaban que la pantalla no se iniciara

//*****************************
//** DEFINICION Y CONEXION   **
//**
//*****************************
//****     LIBRERIAS       ****
//*****************************
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RotaryEncoder.h>
//*****************************
//** definicion              **
//** DE HARDWARE             **
//*****************************
// Definición de la pantalla OLED
#define ANCHO_PANTALLA 128
#define ALTO_PANTALLA 64
#define RESET_PANTALLA -1
#define DIRECCION_I2C_OLED 0x3C
#define PIN_SDA A4
#define PIN_SCL A5

Adafruit_SSD1306 pantalla(ANCHO_PANTALLA, ALTO_PANTALLA, &Wire, RESET_PANTALLA);

//------------------------------------------------------------------------------
// Definicion del encoder
#define PIN_ENCODER_CLK 2
#define PIN_ENCODER_DT 3
#define PIN_ENCODER_PULSADOR 4
#define PIN_LED_VERDE 5
#define PIN_LED_ROJO 6
//------------------------------------------------------------------------------
// definicion de funciones

//--------------------------------------------------------------------------------
// variables para el manejo del encoder
bool primeraVez = true;
int ANTERIOR = 0;                  // almacena valor anterior de la variable movimientoEncoder
int ultimoPulsadorEncoder = 0;     // valor encoder del pulsador
volatile int pulsadorEncoder = 0;  // valor encoder del pulsador
bool estadoPulsador = 0;
volatile int movimientoEncoder = 1;           // variable movimientoEncoder con valor inicial de 50 y definida
volatile int limiteMaxEncoder = 0;            // valor maximo del encoder
volatile int limiteMinEncoder = 0;            //valor minimo del encoder
volatile int limite = 1;                      // limite = 1 (Min 1, Max 2)
static unsigned long ultimaInterrupcion = 0;  // variable static con ultimo valor de
                                              // tiempo de interrupcion
//-------------------------------------------------------------------------------
// variables para el manejo del menu
// Variables para controlar el menú
volatile int opcionMenu = 0;                                               // opcion seleccionada
                                                                           // 1 - CONFIGURACION
                                                                           // 2 - CAMBIO DE AGUA
bool inSubMenu = false;                                                    // submenu
//char *opciones[] = { "    ", "CONFIGURACION ", "CAMBIO DE AGUA " };  // Arreglo del Menu PRINCIPAL
char opciones[3][14]; // 5 elementos, cada uno con un tamaño máximo de 10 caracteres
  // Asignación de valores a las variables del conjunto
  // strcpy(opciones[0], "CONFIGURACION ");
  // strcpy(opciones[1], "CAMBIO DE AGUA");
  // strcpy(opciones[2], "Variable 3");
  
//-------------------------------------------------------------------------------
//*******************************************************
//****    funciones que nos devuelven datos          ****
//*******************************************************
int encoder(volatile int limite) {
  //static unsigned long ultimaInterrupcion = 0;  // variable static con ultimo valor de
  // tiempo de interrupcion
  unsigned long tiempoInterrupcion = millis();  // variable almacena valor de func. millis

  if (tiempoInterrupcion - ultimaInterrupcion > 5) {  // rutina antirebote desestima
                                                      // pulsos menores a 5 mseg.
    if (digitalRead(PIN_ENCODER_DT) == HIGH)          // si PIN_ENCODER_DT es HIGH, sentido horario
    {
      movimientoEncoder++;  // incrementa movimientoEncoder en 1
    } else {                // si PIN_ENCODER_DT es LOW, senti anti horario
      movimientoEncoder--;  // decrementa movimientoEncoder en 1
    }
  }

  if (limite == 1) {
    limiteMinEncoder = 1;
    limiteMaxEncoder = 2;
  }
  movimientoEncoder = min(limiteMaxEncoder, max(limiteMinEncoder, movimientoEncoder));  // establece limite inferior  y
  // superior  para movimientoEncoder segun que tengamos que leer
  ultimaInterrupcion = tiempoInterrupcion;  // guarda valor actualizado del tiempo de la interrupcion en variable static
  return movimientoEncoder;
}
// //------------------------------------------------------------------------------------------------
// int lecturaPulsadorEncoder() {
//   static unsigned long ultimaInterrupcion = 0;  // variable static con ultimo valor de
//                                                 // tiempo de interrupcion
//   unsigned long tiempoInterrupcion = millis();  // variable almacena valor de func. millis

//   if (tiempoInterrupcion - ultimaInterrupcion > 5) {  // rutina antirebote desestima
//                                                       // pulsos menores a 5 mseg.

//     //Leer el estado del pin del pulsador del encoder
//     boolean estadoPulsador = digitalRead(PIN_ENCODER_PULSADOR);
//     Serial.println("lectua pin pulsador = ");
//     Serial.println(estadoPulsador);
//     if (estadoPulsador == LOW) {  // suponemos que al estar en PULLUP, un LOW es que se ha pulsado
//     //if (pulsador == LOW) {  // suponemos que al estar en PULLUP, un LOW es que se ha pulsado
//       pulsadorEncoder = 1;
//     } else {
//       (pulsadorEncoder = 0);
//     }
//     // al pulsar damos por terminada la captura de la posicion del encoder y fin de programa
//   }
//   Serial.print("lectura del pulsador = ");
//   Serial.println(pulsadorEncoder);
//   ultimaInterrupcion = tiempoInterrupcion;  // guarda valor actualizado del tiempo

//   return pulsadorEncoder;
// }
//*******************************************************

void setup() {
  // Asignación de valores a las variables del conjunto
  // strcpy(opciones[1], "CONFIGURACION ");
  // strcpy(opciones[2], "CAMBIO DE AGUA");
  // strcpy(opciones[0], "              ");
  // Inicializar el puerto serial con una velocidad de 9600 baudios
  Serial.begin(9600);
  Serial.println(" ");
  Serial.println("entro den Setup");
  Wire.begin();
  Serial.println("voy a inicioOled");
  inicioOled();
  movimientoEncoder = 1;
  // Asigna funcion de entrada a los PIN del encoder derecha izquierda y pulsador
  pinMode(PIN_ENCODER_CLK, INPUT);                                        // pin 2
  pinMode(PIN_ENCODER_DT, INPUT);                                         // pin 3
  pinMode(PIN_ENCODER_PULSADOR, INPUT_PULLUP);                            // pin 4
  attachInterrupt(digitalPinToInterrupt(PIN_ENCODER_CLK), encoder, LOW);  // interrupcion sobre pin A con funcion ISR encoder y modo LOW
  // attachInterrupt(digitalPinToInterrupt(PIN_ENCODER_PULSADOR), lecturaPulsadorEncoder, CHANGE);  // interrupcion sobre pin A con funcion ISR encoder y modo LOW
}

void loop() {
  //Serial.println("entramos en loop");
  // Serial.println("voy a menu principal");
  // Lectura del encoder y actualización del menú
  Serial.print("movimiento encoder = ");
  Serial.println(movimientoEncoder);

  delay(1000);
  int opcionMenu = movimientoEncoder;
  Serial.print("Opcion Menu     = ");
  Serial.println(opcionMenu);
  menuPrincipal(opcionMenu);
    // Si se pulsa el botón del encoder
  //   if (pulsadorEncoder == 1) {
  //     if (opcionMenu == 1) {
  //       configurar(); // Llamar al programa 'configurar.ino'
  //     }
  //     else if (opcionMenu == 2) {
  //       cambiarAgua(); // Llamar al programa 'cambiarAgua.ino'
  //     }
  // }
}
// //=============================================================================
void inicioOled() {
  Serial.println("entro en inicioOled");
  // Inicializar la pantalla OLED
  pantalla.begin(SSD1306_SWITCHCAPVCC, DIRECCION_I2C_OLED);
  Serial.println("intento iniciar pantalla");
  if (!pantalla.begin(SSD1306_SWITCHCAPVCC, DIRECCION_I2C_OLED)) {
    Serial.println("Error: No se pudo iniciar la pantalla OLED");
    while (1)
      ;  // Detener la ejecución en caso de error
  }
  pantalla.clearDisplay();
  pantalla.setTextColor(WHITE);  // Color del texto (blanco)
  pantalla.setTextSize(1);       // Tamaño de las letras (6x8 pixels)
  pantalla.setCursor(0, 0);
  pantalla.println("termino setup");
  pantalla.setCursor(0, 32);
  pantalla.println("VOY A MENU");
  pantalla.display();
  Serial.println("mira si ha funcionado la pantalla");
  delay(50);
}
//===================================================================================
// FUNCION PRESENTACION DEL MENU PRINCIPAL
//
void menuPrincipal(int opcionMenu) {
  Serial.println("estoy en MENU PRINCIPAL");
  if (primeraVez == true) {
    primeraVez = false;
    movimientoEncoder = 1;
    // acotamos los valoes del movimiento encoder a las opcinoes del menu principal
    limite = 1;
  }
  // Serial.print("limite              = ");
  // Serial.println(limite);
  // pantalla.clearDisplay();
  // pantalla.setCursor(19, 24);
  // pantalla.println(opciones[opcionMenu]);
  // pantalla.println("CONFIGURACION");
  // pantalla.display();
  // MONITOR SERIAL
  Serial.println(" ");
  Serial.println("entro en MENU PRINCIPAL");
  Serial.print("movimientoEncoder = ");
  Serial.println(movimientoEncoder);
  Serial.print("pulsadorEncoder   = ");
  Serial.println(pulsadorEncoder);
  //
}
//===================================================================================

Hola a todos,
He seguido probando cosas y veo que hay un momento que la pantalla se inicia correctamente, pero si añado alguna función que utiliza la pantalla ya no se inicia.
¿Podría ser un problema de memoria de la placa?, Por que si le quitó mensajes por pantalla o salidas por el monitor serial, vuelve a iniciar correctamente.

Puede ser que esté muy justo de memoria.
Prueba usando la macro F() para las cadenas "fijas", por ej.

Serial.println(F("estoy en MENU PRINCIPAL"));
//...
Serial.print(F("movimiento encoder = "));

aunque solo las uses durante las pruebas.
Mira la diferencia de memoria dinámica, sin usar la macro F()

El Sketch usa 15600 bytes (48%) del espacio de almacenamiento de programa. El máximo es 32256 bytes.
Las variables Globales usan 855 bytes (41%) de la memoria dinámica, dejando 1193 bytes para las variables locales. El máximo es 2048 bytes.

Usando la macro F()

El Sketch usa 15674 bytes (48%) del espacio de almacenamiento de programa. El máximo es 32256 bytes.
Las variables Globales usan 543 bytes (26%) de la memoria dinámica, dejando 1505 bytes para las variables locales. El máximo es 2048 bytes.

En este código se ganan 312 bytes de preciada RAM. :wink:

Muchas gracias, ya intuía que el problema era de memoria. El proyecto aún debe de crecer mucho, por lo que no sé cómo abordar el problema, es mi primer programa en arduino. He empezado también a poner las cadenas fijas en 'char'.
He estado mirando un poco y veo que el mega tiene más, 256Kb en vez de 32Kb. A lo mejor me tendré que pasar a esa placa. ¿O hay alguna otra solución?
Muchas gracias por contestar.
Un saludo.

Probablemente lo mejor sea apuntar a una placa más "potente".
La Mega puede ser una buena opción pero también tienes otras más económicas y mucho más potentes como Pi Pico, Blue Pill, o alguna de las variantes que portan ESP32.

Me lo tendré que mirar, soy totalmente nuevo en esto, ya te digo que es la primera vez que lo utilizo, llevaba por casa años desde que lo uso mi hijo cuando estudiaba.
Gracias, un saludo.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.