Arduino UNO, OLED y Serial - No responde

Estimados, buenos días! Es mi primer posteo, espero no estar cometiendo muchos errores.
Tengo un código que es de un proyecto en desarrollo, para una bomba de infusión a jeringa con un Arduino UNO, una pantalla OLED 0,96", y un driver para motor stepper A4988. Por ahora estoy haciendo el menú, el cual imprimo en el panel OLED, y tengo 4 pulsadores para moverme (arriba, abajo, atrás, adelante), un pulsador para OK, y otro para Cancelar. En este menú quiero modificar la cantidad de ml/h a infundir, y para ello quiero imprimir un número en pantalla como "000,00" en el que pueda desplazarme por dígito de adelante a atrás, y poder cambiar cada dígito por separado, del 0 al 9.
Cada submenú tiene un "case", y cada botón tiene un switch case con acciones para ese menú.
Tengo dos problemas:
Para mostrar el número "000,00" intento imprimir cada dígito con un vector "dosis[editPosición]", pero cuando intento imprimir en la pantalla OLED todos los valores en un bucle for() y cargo el código, el arduino se bloquea.

for (int j=0 ; j<5; j++){
oled.print(dosis[j]);
}

Carga el código sin errores de compilación, pero la pantalla se congela. Arduino no se resetea y no reacciona.
Si en lugar de esto, hago lo siguiente, Arduino UNO carga el código y funciona perfecto.

for (int j = 0; j < editPos + 1; j++) {
        char dosisStr[2];
        snprintf(dosisStr, sizeof(dosisStr), "%02d", dosis[j]);
        oled.print(dosisStr);
      }

Alguien podría explicarme por qué?

Además, quise iniciar "Serial.begin(9600)" para poder imprimir en serial algunas variables que me ayuden a entender qué sucede, pero en este caso también Arduino se bloquea luego de cargar el código, y tampoco entiendo por qué.
Dejo el código para ver si me pueden ayudar a entender qué sucede. Muchas gracias por sus aportes!

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

// Define pantalla OLED
#define ANCHO 128
#define ALTO 64
#define OLED_RESET 4

Adafruit_SSD1306 oled(ANCHO, ALTO, &Wire, OLED_RESET);

//// Define pulsadores
#define BTN_ATRAS_PIN 7
#define BTN_ADELANTE_PIN 6
#define BTN_ARRIBA_PIN 9
#define BTN_ABAJO_PIN 8
#define BTN_OK_PIN 10 // Nuevo pulsador "OK"
#define BTN_CANCEL_PIN 11 // Nuevo pulsador "Cancel"
//
//// Define botones para librería Button, para hacer debouncing
Button btnAtras(BTN_ATRAS_PIN);
Button btnAdelante(BTN_ADELANTE_PIN);
Button btnArriba(BTN_ARRIBA_PIN);
Button btnAbajo(BTN_ABAJO_PIN);
Button btnOk(BTN_OK_PIN); // Nuevo botón "OK"
Button btnCancel(BTN_CANCEL_PIN); // Nuevo botón "Cancel"
//
#define MAX_JERINGAS 7  // Define el tamaño máximo de la matriz

struct Jeringas {
  int numero;
  char nombre[20];
  float diametro;
  float largo;
};

Jeringas matriz[MAX_JERINGAS];
int numJeringas = 0;  // Variable para llevar el control del número de elementos en la matriz
int cuentaFilas = 0;  // Variable para contar filas llenas de la matriz
int indiceMatriz = 0; // Indice para selección de jeringa
int dosis[5]= {1,2,3,4,5};// Valor inicial de la dosis


int editPos = 0;   // Posición de edición: 0 para el primer dígito, 1 para el segundo, 2 para el tercero, 3 para el primer decimal y 4 para el segundo
//char dosisStr[8]; // Muestra el valor de la dosis formateado en la pantalla

enum MenuState { // Enumera opciones de menú
  MENU_PRINCIPAL,
  CONTINUAR_DOSIS,
  CONFIRM_DOSIS,
  NUEVA_DOSIS, // Empieza mostrando "Seleccionar jeringa"
  SET_DOSIS,
  OPTION_1,
  OPTION_2,
  NUEVA_JERINGA,
  SET_JERINGA
};

MenuState currentMenuState = MENU_PRINCIPAL;
int opMenuPpal = 1; // Opción seleccionada en el menú principal
int opMenuJeringas = 1; // Opción seleccionada en menú jeringas

void setup() {
//Serial.begin(9600); 
  
  matriz[0].numero = 1;
  strcpy(matriz[0].nombre, "B-D 5ml");
  matriz[0].diametro = 11.99;
  matriz[0].largo = 46.5;

  matriz[1].numero = 2;
  strcpy(matriz[1].nombre, "B-D 10ml");
  matriz[1].diametro = 14.43;
  matriz[1].largo = 69;

  matriz[2].numero = 3;
  strcpy(matriz[2].nombre, "B-D 20ml");
  matriz[2].diametro = 19.05;
  matriz[2].largo = 76;

  matriz[3].numero = 4;
  strcpy(matriz[3].nombre, "B-D 30ml");
  matriz[3].diametro = 21.59;
  matriz[3].largo = 87;

  matriz[4].numero = 5;
  strcpy(matriz[4].nombre, "B-D 60ml");
  matriz[4].diametro = 26.59;
  matriz[4].largo = 98;

  for (int cuentaFilas = 0; cuentaFilas < MAX_JERINGAS; cuentaFilas++) {
  // Verificar si la primera columna de la fila tiene datos válidos (por ejemplo, no es cero)
  if (matriz[cuentaFilas].numero != 0) {
    numJeringas++;
    }
  }
  int nuevaFila = numJeringas; //Guarda el número de la última fila de matriz ocupada

  matriz[nuevaFila].numero = numJeringas + 1;  // Número único para "Nueva jeringa"
  strcpy(matriz[nuevaFila].nombre, "Nueva jeringa");
  matriz[nuevaFila].diametro = 0.0;  
  matriz[nuevaFila].largo = 0.0;

  // Llamar a la función agregarJeringa() para añadir un nuevo elemento
  //agregarJeringa(4, "Nombre4", 3.2, 12.1);

  pinMode(BTN_ATRAS_PIN, INPUT_PULLUP);
  pinMode(BTN_ADELANTE_PIN, INPUT_PULLUP);
  pinMode(BTN_ARRIBA_PIN, INPUT_PULLUP);
  pinMode(BTN_ABAJO_PIN, INPUT_PULLUP);
  pinMode(BTN_OK_PIN, INPUT_PULLUP);
  pinMode(BTN_CANCEL_PIN, INPUT_PULLUP);

  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.clearDisplay();
  oled.setTextSize(1);
  oled.setTextColor(WHITE);
  oled.setCursor(0, 0);
  oled.println("Menu Principal");
  oled.display();
  //delay(2000);
}

void showMenu(MenuState state) {
  oled.clearDisplay();
  oled.setCursor(0, 0);
  oled.setTextSize(1);

  switch (state) {
    case MENU_PRINCIPAL:
      oled.print(opMenuPpal == 1 ? "> " : "  ");
      oled.println("1 Continuar dosis");
      oled.print(opMenuPpal == 2 ? "> " : "  ");
      oled.println("2 Nueva dosis");
      
      break;

    case CONTINUAR_DOSIS:
      oled.println("1.1 Confirmar?");
      break;

    case CONFIRM_DOSIS:
      oled.println("Confirmada!");
      break;

    case NUEVA_DOSIS:
        oled.println("Seleccionar jeringa");
      for (int i = 0; i <= numJeringas; i++) {
        oled.print(opMenuJeringas == (i + 1) ? "> " : "  ");
        oled.println(matriz[i].nombre);
        
      }
      break;
  
    case SET_DOSIS:
      oled.setCursor(0, 0);
      oled.setTextSize(1);
      oled.print(matriz[indiceMatriz].nombre);
      oled.println(" seleccionada");
      oled.println("Set dosis: ");
      oled.setTextSize(2);
      oled.setTextColor(WHITE);
      oled.setCursor(10, 25);

      
      for (int j = 0; j < editPos + 1; j++) {
      //for (int j=0 ; j<5; j++){
      //oled.print(dosis[j]);
        char dosisStr[2];
        snprintf(dosisStr, sizeof(dosisStr), "%02d", dosis[j]);

        oled.print(dosisStr);
      }
      oled.println();
      //oled.display();
      break;

    case NUEVA_JERINGA:
      oled.println("Ingrese nueva jeringa");
      break;

    case SET_JERINGA:
      oled.println("Diametro interno: ");
      break;
  }

  oled.display();
}

void handleInput() {
  if (btnArriba.pressed()) {
    switch (currentMenuState) {
      case MENU_PRINCIPAL:
        opMenuPpal = opMenuPpal == 1 ? 2 : 1;
        break;

      case CONTINUAR_DOSIS:
        break;  // No action

      case CONFIRM_DOSIS:
        break;  // No action

      case NUEVA_DOSIS:
        if(opMenuJeringas > 1){
          opMenuJeringas --;
        } else { opMenuJeringas = numJeringas+1;
        };
        break;

      case SET_DOSIS:
        dosis[editPos] = (dosis[editPos] + 1) % 10;
        break;  
    }
  }

  if (btnAbajo.pressed()) {
    switch (currentMenuState) {
      case MENU_PRINCIPAL:
        opMenuPpal = opMenuPpal == 2 ? 1 : 2;
        break;

      case CONTINUAR_DOSIS:
        break;  // No action

      case NUEVA_DOSIS:
        if(opMenuJeringas < numJeringas+1){
          opMenuJeringas ++;
          } else { 
          opMenuJeringas = 1;
        }
        break;

      case SET_DOSIS:
        dosis[editPos] = (dosis[editPos] - 1 + 10) % 10;
        break;  // No action
    }
  }

  if (btnOk.pressed()) { // Nuevo botón "OK"
    switch (currentMenuState) {
      case MENU_PRINCIPAL:
      if (opMenuPpal == 1)
        currentMenuState = CONTINUAR_DOSIS;
      else if (opMenuPpal == 2)
        currentMenuState = NUEVA_DOSIS;
      break;
    // ...

      case CONTINUAR_DOSIS:
        currentMenuState = CONFIRM_DOSIS;
        break;

      case CONFIRM_DOSIS:
        currentMenuState = MENU_PRINCIPAL;
        break;

      case NUEVA_DOSIS:
        if (opMenuJeringas < numJeringas+1) {
          indiceMatriz = opMenuJeringas-1;
          currentMenuState = SET_DOSIS;
        } else {
          currentMenuState = SET_JERINGA;
        }
        break;

      case SET_DOSIS:
        break;  // No action

      case SET_JERINGA:
        break;  // No action
    }
  }

  if (btnCancel.pressed()) { // Nuevo botón "Cancel"
    switch (currentMenuState) {
     case CONTINUAR_DOSIS:
        currentMenuState = MENU_PRINCIPAL;
        break;

      case CONFIRM_DOSIS:
        currentMenuState = CONTINUAR_DOSIS;
        break;

      case NUEVA_DOSIS:
        currentMenuState = MENU_PRINCIPAL;
        break;

      case SET_DOSIS:
        currentMenuState = NUEVA_DOSIS;
//        Serial.println(dosisStr);
        break;

      case OPTION_1:
        currentMenuState = NUEVA_DOSIS;
        break;

      case OPTION_2:
        currentMenuState = NUEVA_DOSIS;
        break;

      case SET_JERINGA:
        currentMenuState = NUEVA_DOSIS;
        break;
   }
  }

  if (btnAdelante.pressed()) {
    switch (currentMenuState) {
       case SET_DOSIS:
      // Cambiar la posición de edición entre dígitos y decimales
      editPos = (editPos + 1) % 5;
      break;
    }
  }

  if (btnAtras.pressed()) {
    switch (currentMenuState) {
       case SET_DOSIS:
      // Cambiar la posición de edición entre dígitos y decimales
      editPos = (editPos + 4) % 5;
      break;
    } 
  } 
}

void loop() {
    handleInput();
    showMenu(currentMenuState);
//Serial.println(dosisStr);
}

Para almacenar una cadena de dos caracteres, la longitud de la matriz de dosisStr[] debe ser de tres elementos.

1 Like

Gracias por tu respuesta! Aún sigo intentando imprimir con "for" cada valor de la matriz, pero Arduino se bloquea y no entiendo por qué. Tampoco puedo imprimir con Serial. Ojalá puedan ayudarme. Gracias de nuevo!

He trasladado su tema de una categoría de idioma inglés del foro a la categoría International > Español @lukmmar.

En adelante por favor usar la categoría apropiada a la lengua en que queráis publicar. Esto es importante para el uso responsable del foro, y esta explicado aquí la guía "How to get the best out of this forum".
Este guía contiene mucha información útil. Por favor leer.

De antemano, muchas gracias por cooperar.

1 Like

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