No detiene la dosificación en los sg calculados

Buenos días, antes de seguir decir que soy principiante en Arduino hay cosas que aún no las controlo pero hago lo posible por averiguar todo ,estoy haciendo un dosificador con 3 peristalticas,Arduino nano , LCD y ds3231.
Prácticamente me funciona todo pero en esta función la de dosificar cuando dosifica si por ejemplo es a las 12:00 y calcula 10 segundos se activan esos 10 segundos repetidamente durante ese minuto y luego se queda fija activada no encuentro donde está el fallo, si tengo que poner algún trozo más de código o el código completo decirmelo, gracias .

loop())

bool bombaActivada[3] = {false, false, false};
unsigned long tiempoFinActivacion[3] = {0, 0, 0}; // Array para guardar el tiempo de fin de activación de cada bomba

void loop() {
 

  // Lógica para activar las bombas según la hora programada
  now = rtc.now();

  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < timesPerDay[i]; j++) {
      if (now.hour() == dosageHours[i][j] && now.minute() == dosageMinutes[i][j] && !bombaActivada[i]) {
        // Calcular tiempo de activación en segundos
        float tiempoActivacionSegundos = (float(volumeDosage[i][j]) / 100.0) * calibrationTimes[i];

        // Activar la bomba
        activarBomba(i + 1);
        bombaActivada[i] = true;
        tiempoFinActivacion[i] = millis() + tiempoActivacionSegundos * 1000; // Calcular el tiempo de fin de activación
        Serial.print("Bomba ");
        Serial.print(i + 1);
        Serial.print(" activada durante ");
        Serial.print(tiempoActivacionSegundos);
        Serial.println(" segundos.");
      }
    }
  }

  // Desactivar las bombas cuando haya transcurrido el tiempo
  for (int i = 0; i < 3; i++) {
    if (bombaActivada[i] && millis() >= tiempoFinActivacion[i]) {
      apagarBombas();
      bombaActivada[i] = false;
      Serial.print("Bomba ");
      Serial.print(i + 1);
      Serial.println(" desactivada.");
    }
  }

  // Restablecer las banderas de activación al inicio de un nuevo minuto
  if (now.second() == 0) {
    for (int i = 0; i < 3; i++) {
      bombaActivada[i] = false;
      tiempoFinActivacion[i] = 0; // Reiniciar el tiempo de fin de activación
    }
  }

  delay(50);
}

El problema es que si tiempoActivacionSegundos < 60, el sketch baja la bandera de activación de las bombas y restablece la actividad dentro del mismo minuto

Agrega algo así:

int ultimaActivacion[3] = { 0, 0, 0}; // hora+minuto de la ultima activación
...

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < timesPerDay[i]; j++) {
      if (now.hour() == dosageHours[i][j] && now.minute() == dosageMinutes[i][j] && now.hour() * 100 + now.minute() > ultimaActivacion[i]) { // evitar que la bomba se active dos veces en el mismo minuto
...
    ultimaActivacion[i] = now.hour() * 100 + now.minute(); // registra el minuto en que se activó esta bomba

Este cambio permite simplificar tu código, por ejemplo prescindir de bombaActivada

No he probado este cambio, dado que no dispongo del código completo original, pero creo que debe funcionar...

Gracias, lo probaré a ver qué tal

Buenas tardes, he probado lo que me has dicho y a funcionado correctamente, voy a seguir avanzando a ver si lo termino o me encuentro algún error más .
Gracias por la ayuda

buenas, estoy haciendo un proyecto de una dosificadora con peristalticas para el acuario, uso arduino nano, lcd 20X4, ds3231 y 3 bombas, casi lo tengo terminado a falta de algunos ajustes que se como hacerlos pero lo que no consigo es que en la programacion que le tengo puesto para poder hacer varias dosificaciones al dia programando diferentes horas la primera la hace bien pero las siguientes es como si el contador stubiese a 0 y no dosifica o no guarda los datos para hacer la dosificacion nada mas que en la primera, me he perdido un poco en esa parte del codigo , (Soy novatillo). Pongo el codigo completo por si me podeis ayudar y os doy las gracias por adelantado.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <EEPROM.h>

// Configurar LCD 20x4 en la dirección I2C (ajustar si es necesario)
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Inicializar el reloj DS3231
RTC_DS3231 rtc;

// Definir pines de botones
#define BTN_ENTER 2
#define BTN_UP 3
#define BTN_DOWN 4
#define BTN_RIGHT 5
#define BTN_LEFT 6
#define BTN_ESCAPE 7

// Definir direcciones de EEPROM de forma clara y separada
#define EEPROM_CALIBRATION_ADDRESS 10
#define EEPROM_PUMP_DATA_ADDRESS 50 // Empieza en una dirección más adelante

// Función para calcular la dirección de inicio de los datos de una bomba
int getEEPROMAddress(int bomba) {
  return EEPROM_PUMP_DATA_ADDRESS + (bomba * (sizeof(int) * 2 + sizeof(int) * 24 * 3));
}

// Definir pines de las bombas
#define PUMP_1 8
#define PUMP_2 9
#define PUMP_3 10

// Definir estados del menú
enum MenuState { SHOW_TIME, MAIN_MENU, ADJUST_DATETIME, PROGRAM_PUMPS, MANUAL_MODE, CALIBRATION, SELECT_PUMP, SET_TIMES_PER_DAY, SET_INTERVAL_DAYS, SET_VOLUME_DOSAGE, SET_DOSAGE_HOURS, SAVE_PROGRAM_SETTINGS };
MenuState currentMenu = SHOW_TIME;
int menuOption = 0;
int selectedPump = 1;

// Variables para bombas (usar índices 0, 1, 2)
int timesPerDay[3] = {1, 1, 1};
int intervalDays[3] = {0, 0, 0};
int volumeDosage[3][24] = {{0}}; // Inicializar a 0
int dosageHours[3][24] = {{0}};   // Inicializar a 0
int dosageMinutes[3][24] = {{0}}; // Inicializar a 0

void seleccionarBomba(); // Declaración de la función para evitar errores de compilación

// Variables para ajuste de fecha y hora
DateTime now;
int year, month, day, hour, minute;
int cursorPos = 0; // Posición del cursor en ajuste

// Variables para calibración
bool calibrating = false;
unsigned long startTime, elapsedTime;
float calibrationTimes[3] = {0.0}; // Inicializar a 0.0

// Función para detectar si un botón ha sido presionado y liberado (DEBOUNCE)
bool botonPresionado(int pin) {
  static unsigned long lastPressTime[8] = {0}; // Array para cada botón
  const unsigned long debounceDelay = 50; // Reducido para mayor responsividad

  if (digitalRead(pin) == LOW) {
    int buttonIndex = pin - 2; // Índice del botón (0-5)
    if (millis() - lastPressTime[buttonIndex] > debounceDelay) {
      lastPressTime[buttonIndex] = millis();
      while (digitalRead(pin) == LOW); // Espera a que se suelte el botón
      return true;
    }
  }
  return false;
}

void apagarBombas() {
    digitalWrite(PUMP_1, LOW);
    digitalWrite(PUMP_2, LOW);
    digitalWrite(PUMP_3, LOW);
}

void cargarConfiguracionBomba(int bomba) {
  int baseAddress = getEEPROMAddress(bomba);

  EEPROM.get(baseAddress, timesPerDay[bomba]);
  if (timesPerDay[bomba] < 1 || timesPerDay[bomba] > 24) {
    timesPerDay[bomba] = 1; // Valor por defecto
  }

  EEPROM.get(baseAddress + sizeof(int), intervalDays[bomba]);
  if (intervalDays[bomba] < 0 || intervalDays[bomba] > 30) {
    intervalDays[bomba] = 0; // Valor por defecto
  }

  for (int i = 0; i < timesPerDay[bomba]; i++) {
    EEPROM.get(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3, volumeDosage[bomba][i]);
    EEPROM.get(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3 + sizeof(int), dosageHours[bomba][i]);
    EEPROM.get(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3 + sizeof(int) * 2, dosageMinutes[bomba][i]);
  }
}

void cargarCalibracion() {
  for (int i = 0; i < 3; i++) {
    // Leer el float desde la EEPROM
    EEPROM.get(EEPROM_CALIBRATION_ADDRESS + i * sizeof(float), calibrationTimes[i]);

    // Verificar si el valor es válido (puedes ajustar el rango según tus necesidades)
    if (calibrationTimes[i] <= 0.0 || calibrationTimes[i] > 100.0) {
      calibrationTimes[i] = 1.0; // Valor por defecto si no es válido
    }
  }
}

void guardarCalibracion() {
  for (int i = 0; i < 3; i++) {
    // Guardar el float en la EEPROM
    EEPROM.put(EEPROM_CALIBRATION_ADDRESS + i * sizeof(float), calibrationTimes[i]);
  }
}

void mostrarFechaHora() {
  now = rtc.now();

  lcd.setCursor(0, 0);
  lcd.print("Fecha: ");
  lcd.print(now.day());
  lcd.print("/");
  lcd.print(now.month());
  lcd.print("/");
  lcd.print(now.year());

  lcd.setCursor(0, 1);
  lcd.print("Hora: ");

  // Formateo con snprintf para asegurar dos dígitos
  char timeString[9]; // Buffer para guardar la cadena de tiempo formateada
  snprintf(timeString, sizeof(timeString), "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  lcd.print(timeString);
}

void navegarMenuPrincipal() {
    lcd.clear();
    while (currentMenu == MAIN_MENU) {
        lcd.setCursor(0, 0);
        lcd.print(menuOption == 0 ? "> Ajustar Fecha/Hora" : "  Ajustar Fecha/Hora");
        lcd.setCursor(0, 1);
        lcd.print(menuOption == 1 ? "> Programar Bombas " : "  Programar Bombas ");
        
        if (botonPresionado(BTN_UP)) {
            menuOption = (menuOption == 0) ? 1 : 0;
        }
        if (botonPresionado(BTN_DOWN)) {
            menuOption = (menuOption == 1) ? 0 : 1;
        }
        if (botonPresionado(BTN_ENTER)) {
            currentMenu = (menuOption == 0) ? ADJUST_DATETIME : PROGRAM_PUMPS;
        }
        if (botonPresionado(BTN_ESCAPE)) {
            currentMenu = SHOW_TIME;
        }
    }
}

void modoManual() {
    lcd.clear();
    while (currentMenu == MANUAL_MODE) {
        lcd.setCursor(0, 0);
        lcd.print("Modo Manual");
        lcd.setCursor(0, 1);
        lcd.print("Bomba: ");
        lcd.print(selectedPump);
        
        if (botonPresionado(BTN_RIGHT)) {
            selectedPump = (selectedPump == 3) ? 1 : selectedPump + 1;
        }
        if (botonPresionado(BTN_LEFT)) {
            selectedPump = (selectedPump == 1) ? 3 : selectedPump - 1;
        }
        if (digitalRead(BTN_ENTER) == LOW) {
            activarBomba(selectedPump);
        } else {
            apagarBombas();
        }
        if (botonPresionado(BTN_ESCAPE)) {
            apagarBombas();
            lcd.clear();
            currentMenu = SHOW_TIME;
        }
    }
}

void activarBomba(int bomba) {
    apagarBombas();
    digitalWrite(PUMP_1, bomba == 1 ? HIGH : LOW);
    digitalWrite(PUMP_2, bomba == 2 ? HIGH : LOW);
    digitalWrite(PUMP_3, bomba == 3 ? HIGH : LOW);
}


void ajustarFechaHora() {
    now = rtc.now();
    year = now.year();
    month = now.month();
    day = now.day();
    hour = now.hour();
    minute = now.minute();
    cursorPos = 0;
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Editar Fecha/Hora");
    
    while (currentMenu == ADJUST_DATETIME) {
        lcd.setCursor(1, 1);
        lcd.print(day);
        lcd.print("/");
        lcd.print(month);
        lcd.print("/");
        lcd.print(year);
        
        lcd.setCursor(1, 2);
        lcd.print(hour);
        lcd.print(":");
        lcd.print(minute);
        
        if (botonPresionado(BTN_RIGHT)) {
            cursorPos = (cursorPos + 1) % 5;
        }
        if (botonPresionado(BTN_LEFT)) {
            cursorPos = (cursorPos == 0) ? 4 : cursorPos - 1;
        }
        if (botonPresionado(BTN_UP)) {
            incrementarValor();
        }
        if (botonPresionado(BTN_DOWN)) {
            decrementarValor();
        }
        if (botonPresionado(BTN_ENTER)) {
            rtc.adjust(DateTime(year, month, day, hour, minute, 0));
            lcd.clear();
            currentMenu = SHOW_TIME;
        }
        if (botonPresionado(BTN_ESCAPE)) {
            lcd.clear();
            currentMenu = SHOW_TIME;
        }
    }
}

void incrementarValor() {
  switch (cursorPos) {
    case 0:
      if (day < 31) day++;
      break;
    case 1:
      if (month < 12) month++;
      break;
    case 2:
      if (year < 2099) year++;
      break;
    case 3:
      if (hour < 23) hour++;
      break;
    case 4:
      if (minute < 59) minute++;
      break;
  }
}


void decrementarValor() {
  switch (cursorPos) {
    case 0:
      if (day > 1) day--;
      break;
    case 1:
      if (month > 1) month--;
      break;
    case 2:
      if (year > 2000) year--;
      break;
    case 3:
      if (hour > 0) hour--;
      break;
    case 4:
      if (minute > 0) minute--;
      break;
  }
}

void calibrarBomba() {
  lcd.clear();
  while (currentMenu == CALIBRATION) {
    lcd.setCursor(0, 0);
    lcd.print("Calibrar bomba");
    lcd.setCursor(0, 1);
    lcd.print("Bomba: ");
    lcd.print(selectedPump);
    lcd.setCursor(0, 2);
    lcd.print("100ml = ");
    // Usar selectedPump - 1 para acceder al array
    lcd.print(calibrationTimes[selectedPump - 1]); 
    lcd.print(" s   "); // Espacios para limpiar residuos

    if (botonPresionado(BTN_RIGHT)) {
      selectedPump = (selectedPump == 3) ? 1 : selectedPump + 1;
    }
    if (botonPresionado(BTN_LEFT)) {
      selectedPump = (selectedPump == 1) ? 3 : selectedPump - 1;
    }
    if (botonPresionado(BTN_ENTER)) {
      iniciarCalibracion();
    }
    if (botonPresionado(BTN_ESCAPE)) {
      lcd.clear();
      currentMenu = SHOW_TIME;
    }
  }
}

void iniciarCalibracion() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Fluido correcto");
  elapsedTime = 0;
  calibrating = false;

  unsigned long calibrationStartTime = 0;

  while (currentMenu == CALIBRATION) {
    if (calibrating) {
      elapsedTime = (millis() - calibrationStartTime) / 1000;
    }

    lcd.setCursor(0, 1);
    lcd.print("100ml =     "); // Limpiar espacio para mostrar el tiempo
    lcd.setCursor(9, 1);
    lcd.print(elapsedTime);  // Mostrar el tiempo en segundos
    lcd.print(" s   "); // Espacios para limpiar residuos

    if (botonPresionado(BTN_UP)) {
      if (!calibrating) {
        calibrating = true;
        calibrationStartTime = millis();
        activarBomba(selectedPump);
      } else {
        calibrating = false;
        elapsedTime = (millis() - calibrationStartTime) / 1000;
        apagarBombas();
      }
    }

    if (botonPresionado(BTN_ENTER)) {
      // Usar selectedPump - 1 para acceder al array y guardar
      calibrationTimes[selectedPump - 1] = elapsedTime;
      guardarCalibracion();
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Datos guardados");
      delay(1000);
      lcd.clear();
      currentMenu = SHOW_TIME;
    }

    if (botonPresionado(BTN_ESCAPE)) {
      apagarBombas();
      lcd.clear();
      currentMenu = SHOW_TIME;
    }
  }
}

void establecerIntervaloDias() {
    lcd.clear();
    while (currentMenu == SET_INTERVAL_DAYS) {
        lcd.setCursor(0, 0);
        lcd.print("Intervalo dias");
        lcd.setCursor(0, 1);
        lcd.print(intervalDays[selectedPump - 1]); // CORREGIDO: selectedPump - 1

        lcd.print("    ");
        
        if (botonPresionado(BTN_UP)) {
            if (intervalDays[selectedPump - 1] < 30) intervalDays[selectedPump - 1]++; // CORREGIDO: selectedPump - 1

        }
        if (botonPresionado(BTN_DOWN)) {
            if (intervalDays[selectedPump - 1] > 0) intervalDays[selectedPump - 1]--; // CORREGIDO: selectedPump - 1

        }
        if (botonPresionado(BTN_ENTER)) {
            lcd.clear();
            currentMenu = SET_VOLUME_DOSAGE;
            break; // Salir del bucle while (AÑADIDO)
        }
        if (botonPresionado(BTN_ESCAPE)) {
            lcd.clear();
            currentMenu = SHOW_TIME;
        }
    }
}
void establecerVecesPorDia() {
    lcd.clear();
    while (currentMenu == SET_TIMES_PER_DAY) {
        lcd.setCursor(0, 0);
        lcd.print("Veces por dia");
        lcd.setCursor(0, 1);
        lcd.print(timesPerDay[selectedPump - 1]); // CORREGIDO: selectedPump - 1

        lcd.print("    ");
        
        if (botonPresionado(BTN_UP)) {
            if (timesPerDay[selectedPump - 1] < 24) timesPerDay[selectedPump - 1]++; // CORREGIDO: selectedPump - 1

        }
        if (botonPresionado(BTN_DOWN)) {
            if (timesPerDay[selectedPump - 1] > 1) timesPerDay[selectedPump - 1]--; // CORREGIDO: selectedPump - 1

        }
        if (botonPresionado(BTN_ENTER)) {
            lcd.clear();
            currentMenu = SET_INTERVAL_DAYS;
        }
        if (botonPresionado(BTN_ESCAPE)) {
            lcd.clear();
            currentMenu = SHOW_TIME;
        }
    }
}

void establecerVolumenDosificar() {
    lcd.clear(); // Limpiar la pantalla al entrar en la función
    lcd.setCursor(0, 0);
    lcd.print("Volumen dosificar");

    while (currentMenu == SET_VOLUME_DOSAGE) { // Mantener el bucle mientras estemos en este menú
        lcd.setCursor(0, 1);
        lcd.print(volumeDosage[selectedPump - 1][0]);
        lcd.print(" ml");

        if (botonPresionado(BTN_UP)) {
            volumeDosage[selectedPump - 1][0]++;
            delay(100); // Pequeña pausa para evitar múltiples incrementos
        }
        if (botonPresionado(BTN_DOWN)) {
            if (volumeDosage[selectedPump - 1][0] > 0) {
                volumeDosage[selectedPump - 1][0]--;
                delay(100); // Pequeña pausa para evitar múltiples decrementos
            }
        }
        if (botonPresionado(BTN_ENTER)) {
            currentMenu = SET_DOSAGE_HOURS;
            delay(100); // Pequeña pausa para evitar que se interprete como siguiente ENTER
            break; // Salir del bucle while
        }

        if (botonPresionado(BTN_ESCAPE)) {
            currentMenu = SELECT_PUMP; // Volver al menú anterior
            delay(100); // Pequeña pausa para evitar que se interprete como siguiente ENTER
            break; // Salir del bucle while
        }
    }
}


void establecerHoraDosificacion() {
    lcd.clear(); // Limpiar la pantalla al entrar en la función
    lcd.setCursor(0, 0);
    lcd.print("Hora dosificacion");

    int indiceHora = 0; // Reiniciar el índice aquí, dentro de la función
    bool editandoHora = true; // Variable para saber si se está editando la hora o los minutos

    while (currentMenu == SET_DOSAGE_HOURS) { // Bucle principal del menú
        lcd.setCursor(0, 1);

        // Mostrar la hora y minutos en el formato adecuado
        if (editandoHora) {
            lcd.print(dosageHours[selectedPump - 1][indiceHora]);
        } else {
            lcd.print(dosageMinutes[selectedPump - 1][indiceHora]);
        }

        lcd.print(":");
        if (editandoHora) {
            lcd.print(dosageMinutes[selectedPump - 1][indiceHora]); // Mostrar los minutos cuando se edita la hora
        } else {
            lcd.print(dosageHours[selectedPump - 1][indiceHora]); // Mostrar la hora cuando se edita los minutos
        }

        // Incrementar valor
        if (botonPresionado(BTN_UP)) {
            if (editandoHora) {
                // Aumentar la hora, con un límite de 23
                if (dosageHours[selectedPump - 1][indiceHora] < 23) {
                    dosageHours[selectedPump - 1][indiceHora]++;
                }
            } else {
                // Aumentar los minutos, con un límite de 59
                if (dosageMinutes[selectedPump - 1][indiceHora] < 59) {
                    dosageMinutes[selectedPump - 1][indiceHora]++;
                }
            }
            delay(100);
        }
        
        // Decrementar valor
        if (botonPresionado(BTN_DOWN)) {
            if (editandoHora) {
                // Disminuir la hora, con un límite de 0
                if (dosageHours[selectedPump - 1][indiceHora] > 0) {
                    dosageHours[selectedPump - 1][indiceHora]--;
                }
            } else {
                // Disminuir los minutos, con un límite de 0
                if (dosageMinutes[selectedPump - 1][indiceHora] > 0) {
                    dosageMinutes[selectedPump - 1][indiceHora]--;
                }
            }
            delay(100);
        }

        // Moverse a la izquierda o derecha
        if (botonPresionado(BTN_LEFT)) {
            editandoHora = true; // Volver a editar la hora
            delay(100); // Pausa para evitar que se interprete como varias pulsaciones
        }

        if (botonPresionado(BTN_RIGHT)) {
            editandoHora = false; // Cambiar a la edición de minutos
            delay(100); // Pausa para evitar que se interprete como varias pulsaciones
        }

        // Avanzar al siguiente conjunto de hora/minuto
        if (botonPresionado(BTN_ENTER)) {
            indiceHora++; // Avanzar a la siguiente hora

            if (indiceHora >= timesPerDay[selectedPump - 1]) {
                currentMenu = SAVE_PROGRAM_SETTINGS;
                break; // Salir del bucle while
            }
            delay(100); // Pausa para evitar múltiples entradas rápidas
        }

        if (botonPresionado(BTN_ESCAPE)) {
            currentMenu = SET_VOLUME_DOSAGE; // Volver al menú anterior
            delay(100); // Pausa para evitar que se interprete como siguiente ENTER
            break; // Salir del bucle while
        }
    }
}


void guardarConfiguracionBombas() {
  int pumpIndex = selectedPump - 1;
  int baseAddress = getEEPROMAddress(pumpIndex);

  EEPROM.put(baseAddress, timesPerDay[pumpIndex]);
  EEPROM.put(baseAddress + sizeof(int), intervalDays[pumpIndex]);

  for (int i = 0; i < timesPerDay[pumpIndex]; i++) {
    EEPROM.put(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3, volumeDosage[pumpIndex][i]);
    EEPROM.put(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3 + sizeof(int), dosageHours[pumpIndex][i]);
    EEPROM.put(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3 + sizeof(int) * 2, dosageMinutes[pumpIndex][i]);
  }

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Configuracion");
    lcd.setCursor(0, 1);
    lcd.print("Guardada");
    delay(1000);
    lcd.clear();

    // Esperar a que el usuario suelte cualquier botón antes de continuar
    while (botonPresionado(BTN_ENTER) || botonPresionado(BTN_ESCAPE)) {
        delay(50);
    }

    currentMenu = SELECT_PUMP;
    
}
void setup() {
  Serial.begin(9600);
    Wire.begin();
    lcd.init();
    lcd.backlight();
    
    if (!rtc.begin()) {
        lcd.setCursor(0, 0);
        lcd.print("No se detecta RTC");
        while (1);
    }
    cargarCalibracion(); // Cargar calibración al inicio
  for(int i = 0; i < 3; i++){
    cargarConfiguracionBomba(i); // Cargar configuración de bombas
  }
    pinMode(BTN_ENTER, INPUT_PULLUP);
    pinMode(BTN_UP, INPUT_PULLUP);
    pinMode(BTN_DOWN, INPUT_PULLUP);
    pinMode(BTN_RIGHT, INPUT_PULLUP);
    pinMode(BTN_LEFT, INPUT_PULLUP);
    pinMode(BTN_ESCAPE, INPUT_PULLUP);
    
    pinMode(PUMP_1, OUTPUT);
    pinMode(PUMP_2, OUTPUT);
    pinMode(PUMP_3, OUTPUT);
    apagarBombas();

    
}

bool bombaActivada[3] = {false, false, false};
unsigned long tiempoFinActivacion[3] = {0, 0, 0};
unsigned long ultimaActivacion[3] = {0, 0, 0}; // Array para guardar el tiempo de la última activación de cada bomba

void loop() {
  
    switch (currentMenu) {
        case SHOW_TIME:
            mostrarFechaHora();
            if (botonPresionado(BTN_ENTER)) {
                currentMenu = MAIN_MENU;
            }
            
            if (botonPresionado(BTN_RIGHT) || botonPresionado(BTN_LEFT)) {
                currentMenu = MANUAL_MODE;
            }
            if (botonPresionado(BTN_UP) || botonPresionado(BTN_DOWN)) {
                currentMenu = CALIBRATION;
            }
            break;
        case MAIN_MENU:
            navegarMenuPrincipal();
            break;
        case ADJUST_DATETIME:
            ajustarFechaHora();
            break;
        case PROGRAM_PUMPS:
            lcd.clear();
            currentMenu = SELECT_PUMP;
            break;
        case MANUAL_MODE:
            modoManual();
            break;
        case CALIBRATION:
            calibrarBomba();
            break;
        case SELECT_PUMP:
            seleccionarBomba();
            break;
        case SET_TIMES_PER_DAY:
            establecerVecesPorDia();
            break;
        case SET_INTERVAL_DAYS:
            establecerIntervaloDias();
            break;
        case SET_VOLUME_DOSAGE:
            establecerVolumenDosificar();
            break;
        case SET_DOSAGE_HOURS:
            establecerHoraDosificacion();
            break;
        case SAVE_PROGRAM_SETTINGS:
            guardarConfiguracionBombas();
            break;
    }

   // Lógica para activar las bombas según la hora programada
  now = rtc.now();

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < timesPerDay[i]; j++) {
            if (now.hour() == dosageHours[i][j] && now.minute() == dosageMinutes[i][j] && now.hour() * 100 + now.minute() > ultimaActivacion[i]) {
                // Calcular tiempo de activación en segundos
                float tiempoActivacionSegundos = (float(volumeDosage[i][j]) / 100.0) * calibrationTimes[i];

                // Activar la bomba
                activarBomba(i + 1);
                bombaActivada[i] = true;
                tiempoFinActivacion[i] = millis() + tiempoActivacionSegundos * 1000; // Calcular el tiempo de fin de activación
                ultimaActivacion[i] = now.hour() * 100 + now.minute(); // Registra el minuto en que se activó esta bomba

                Serial.print("Bomba ");
                Serial.print(i + 1);
                Serial.print(" activada durante ");
                Serial.print(tiempoActivacionSegundos);
                Serial.println(" segundos.");
            }
        }
    }

    // Desactivar las bombas cuando haya transcurrido el tiempo
    for (int i = 0; i < 3; i++) {
        if (bombaActivada[i] && millis() >= tiempoFinActivacion[i]) {
            apagarBombas();
            bombaActivada[i] = false;
            Serial.print("Bomba ");
            Serial.print(i + 1);
            Serial.println(" desactivada.");
        }
    }

    // Restablecer las banderas de activación al inicio de un nuevo minuto
    if (now.second() == 0) {
        for (int i = 0; i < 3; i++) {
            bombaActivada[i] = false;
            tiempoFinActivacion[i] = 0; // Reiniciar el tiempo de fin de activación
            ultimaActivacion[i] = 0; // Reiniciar el tiempo de la última activación
        }
    }

    delay(50);
}

void seleccionarBomba() {
    lcd.clear();
    while (currentMenu == SELECT_PUMP) {
        lcd.setCursor(0, 0);
        lcd.print("Seleccionar bomba");
        lcd.setCursor(0, 1);
        lcd.print("Bomba: ");
        lcd.print(selectedPump);
        
        if (botonPresionado(BTN_RIGHT)) {
            selectedPump = (selectedPump == 3) ? 1 : selectedPump + 1;
        }
        if (botonPresionado(BTN_LEFT)) {
            selectedPump = (selectedPump == 1) ? 3 : selectedPump - 1;
        }
        if (botonPresionado(BTN_ENTER)) {
            EEPROM.put(20, selectedPump);
            lcd.clear();
            currentMenu = SET_TIMES_PER_DAY;
        }
        if (botonPresionado(BTN_ESCAPE)) {
            lcd.clear();
            currentMenu = SHOW_TIME;
            
        }
    }
}

Buenas, ya tengo practicamente el codigo para las bombas peristalticas, lo unico que no se como hacer es que me guarde los datos en la eeprom para todas las dosis diarias solo me guarda 2, pongo el codigo completo por si podeis ayudarme. Gracias

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <EEPROM.h>


// Configurar LCD 20x4 en la dirección I2C (ajustar si es necesario)
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Inicializar el reloj DS3231
RTC_DS3231 rtc;

// Definir pines de botones
#define BTN_ENTER 2
#define BTN_UP 3
#define BTN_DOWN 4
#define BTN_RIGHT 5
#define BTN_LEFT 6
#define BTN_ESCAPE 7

// Definir direcciones de EEPROM de forma clara y separada
#define EEPROM_CALIBRATION_ADDRESS 10
#define EEPROM_PUMP_DATA_ADDRESS 50 // Empieza en una dirección más adelante

// Función para calcular la dirección de inicio de los datos de una bomba
int getEEPROMAddress(int bomba) {
  return EEPROM_PUMP_DATA_ADDRESS + (bomba * (sizeof(int) * 2 + sizeof(int) * 24 * 3));
}

// Definir pines de las bombas
#define PUMP_1 8
#define PUMP_2 9
#define PUMP_3 10

// Definir estados del menú
enum MenuState { SHOW_TIME, MAIN_MENU, ADJUST_DATETIME, PROGRAM_PUMPS, MANUAL_MODE, CALIBRATION, SELECT_PUMP, SET_TIMES_PER_DAY, SET_INTERVAL_DAYS, SET_VOLUME_DOSAGE, SET_DOSAGE_HOURS, SAVE_PROGRAM_SETTINGS };
MenuState currentMenu = SHOW_TIME;
int menuOption = 0;
int selectedPump = 1;

// Variables para bombas (usar índices 0, 1, 2)
int timesPerDay[3] = {1, 1, 1};
int intervalDays[3] = {0, 0, 0};
int volumeDosage[3][24] = {{0}};
int dosageHours[3][24] = {{0}};
int dosageMinutes[3][24] = {{0}};


void seleccionarBomba(); // Declaración de la función para evitar errores de compilación


// Variables para ajuste de fecha y hora
DateTime now;
int year, month, day, hour, minute;
int cursorPos = 0; // Posición del cursor en ajuste

// Variables para el control de la dosificación
bool bombaActivada[3] = {false, false, false};
unsigned long tiempoFinActivacion[3] = {0, 0, 0};
unsigned long ultimaActivacion[3][24] = {{0}}; // Array bidimensional para cada bomba y hora de dosificación

// Variables para calibración
bool calibrating = false;
unsigned long startTime, elapsedTime;
float calibrationTimes[3] = {0.0}; // Inicializar a 0.0


// Función para detectar si un botón ha sido presionado y liberado (DEBOUNCE)
bool botonPresionado(int pin) {
  static unsigned long lastPressTime[8] = {0}; // Array para cada botón
  const unsigned long debounceDelay = 50; // Reducido para mayor responsividad

  if (digitalRead(pin) == LOW) {
    int buttonIndex = pin - 2; // Índice del botón (0-5)
    if (millis() - lastPressTime[buttonIndex] > debounceDelay) {
      lastPressTime[buttonIndex] = millis();
      while (digitalRead(pin) == LOW); // Espera a que se suelte el botón
      return true;
    }
  }
  return false;
}

void apagarBombas() {
    digitalWrite(PUMP_1, LOW);
    digitalWrite(PUMP_2, LOW);
    digitalWrite(PUMP_3, LOW);
}

void cargarConfiguracionBomba(int bomba) {
  int baseAddress = getEEPROMAddress(bomba);

  EEPROM.get(baseAddress, timesPerDay[bomba]);
  if (timesPerDay[bomba] < 1 || timesPerDay[bomba] > 24) {
    timesPerDay[bomba] = 1; // Valor por defecto
  }

  EEPROM.get(baseAddress + sizeof(int), intervalDays[bomba]);
  if (intervalDays[bomba] < 0 || intervalDays[bomba] > 30) {
    intervalDays[bomba] = 0; // Valor por defecto
  }

  for (int i = 0; i < timesPerDay[bomba]; i++) {
    EEPROM.get(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3, volumeDosage[bomba][i]);
    EEPROM.get(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3 + sizeof(int), dosageHours[bomba][i]);
    EEPROM.get(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3 + sizeof(int) * 2, dosageMinutes[bomba][i]);
  }
}

void cargarCalibracion() {
  for (int i = 0; i < 3; i++) {
    // Leer el float desde la EEPROM
    EEPROM.get(EEPROM_CALIBRATION_ADDRESS + i * sizeof(float), calibrationTimes[i]);

    // Verificar si el valor es válido (puedes ajustar el rango según tus necesidades)
    if (calibrationTimes[i] <= 0.0 || calibrationTimes[i] > 100.0) {
      calibrationTimes[i] = 1.0; // Valor por defecto si no es válido
    }
  }
}

void guardarCalibracion() {
  for (int i = 0; i < 3; i++) {
    // Guardar el float en la EEPROM
    EEPROM.put(EEPROM_CALIBRATION_ADDRESS + i * sizeof(float), calibrationTimes[i]);
  }
}


void mostrarFechaHora() {
  now = rtc.now();

  lcd.setCursor(0, 0);
  lcd.print("Fecha: ");
  lcd.print(now.day());
  lcd.print("/");
  lcd.print(now.month());
  lcd.print("/");
  lcd.print(now.year());

  lcd.setCursor(0, 1);
  lcd.print("Hora: ");

  // Formateo con snprintf para asegurar dos dígitos
  char timeString[9]; // Buffer para guardar la cadena de tiempo formateada
  snprintf(timeString, sizeof(timeString), "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  lcd.print(timeString);
}

void navegarMenuPrincipal() {
    lcd.clear();
    while (currentMenu == MAIN_MENU) {
        lcd.setCursor(0, 0);
        lcd.print(menuOption == 0 ? "> Ajustar Fecha/Hora" : "  Ajustar Fecha/Hora");
        lcd.setCursor(0, 1);
        lcd.print(menuOption == 1 ? "> Programar Bombas " : "  Programar Bombas ");
        
        if (botonPresionado(BTN_UP)) {
            menuOption = (menuOption == 0) ? 1 : 0;
        }
        if (botonPresionado(BTN_DOWN)) {
            menuOption = (menuOption == 1) ? 0 : 1;
        }
        if (botonPresionado(BTN_ENTER)) {
            currentMenu = (menuOption == 0) ? ADJUST_DATETIME : PROGRAM_PUMPS;
        }
        if (botonPresionado(BTN_ESCAPE)) {
            currentMenu = SHOW_TIME;
        }
    }
}

void modoManual() {
    lcd.clear();
    while (currentMenu == MANUAL_MODE) {
        lcd.setCursor(0, 0);
        lcd.print("Modo Manual");
        lcd.setCursor(0, 1);
        lcd.print("Bomba: ");
        lcd.print(selectedPump);
        
        if (botonPresionado(BTN_RIGHT)) {
            selectedPump = (selectedPump == 3) ? 1 : selectedPump + 1;
        }
        if (botonPresionado(BTN_LEFT)) {
            selectedPump = (selectedPump == 1) ? 3 : selectedPump - 1;
        }
        if (digitalRead(BTN_ENTER) == LOW) {
            activarBomba(selectedPump);
        } else {
            apagarBombas();
        }
        if (botonPresionado(BTN_ESCAPE)) {
            apagarBombas();
            lcd.clear();
            currentMenu = SHOW_TIME;
        }
    }
}

void activarBomba(int bomba) {
    apagarBombas();
    digitalWrite(PUMP_1, bomba == 1 ? HIGH : LOW);
    digitalWrite(PUMP_2, bomba == 2 ? HIGH : LOW);
    digitalWrite(PUMP_3, bomba == 3 ? HIGH : LOW);
}



void ajustarFechaHora() {
    now = rtc.now();
    year = now.year();
    month = now.month();
    day = now.day();
    hour = now.hour();
    minute = now.minute();
    cursorPos = 0;
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Editar Fecha/Hora");
    
    while (currentMenu == ADJUST_DATETIME) {
        lcd.setCursor(1, 1);
        lcd.print(day);
        lcd.print("/");
        lcd.print(month);
        lcd.print("/");
        lcd.print(year);
        
        lcd.setCursor(1, 2);
        lcd.print(hour);
        lcd.print(":");
        lcd.print(minute);
        
        if (botonPresionado(BTN_RIGHT)) {
            cursorPos = (cursorPos + 1) % 5;
        }
        if (botonPresionado(BTN_LEFT)) {
            cursorPos = (cursorPos == 0) ? 4 : cursorPos - 1;
        }
        if (botonPresionado(BTN_UP)) {
            incrementarValor();
        }
        if (botonPresionado(BTN_DOWN)) {
            decrementarValor();
        }
        if (botonPresionado(BTN_ENTER)) {
            rtc.adjust(DateTime(year, month, day, hour, minute, 0));
            lcd.clear();
            currentMenu = SHOW_TIME;
        }
        if (botonPresionado(BTN_ESCAPE)) {
            lcd.clear();
            currentMenu = SHOW_TIME;
        }
    }
}


void incrementarValor() {
  switch (cursorPos) {
    case 0:
      if (day < 31) day++;
      break;
    case 1:
      if (month < 12) month++;
      break;
    case 2:
      if (year < 2099) year++;
      break;
    case 3:
      if (hour < 23) hour++;
      break;
    case 4:
      if (minute < 59) minute++;
      break;
  }
}



void decrementarValor() {
  switch (cursorPos) {
    case 0:
      if (day > 1) day--;
      break;
    case 1:
      if (month > 1) month--;
      break;
    case 2:
      if (year > 2000) year--;
      break;
    case 3:
      if (hour > 0) hour--;
      break;
    case 4:
      if (minute > 0) minute--;
      break;
  }
}

void calibrarBomba() {
  lcd.clear();
  while (currentMenu == CALIBRATION) {
    lcd.setCursor(0, 0);
    lcd.print("Calibrar bomba");
    lcd.setCursor(0, 1);
    lcd.print("Bomba: ");
    lcd.print(selectedPump);
    lcd.setCursor(0, 2);
    lcd.print("100ml = ");
    // Usar selectedPump - 1 para acceder al array
    lcd.print(calibrationTimes[selectedPump - 1]); 
    lcd.print(" s   "); // Espacios para limpiar residuos

    if (botonPresionado(BTN_RIGHT)) {
      selectedPump = (selectedPump == 3) ? 1 : selectedPump + 1;
    }
    if (botonPresionado(BTN_LEFT)) {
      selectedPump = (selectedPump == 1) ? 3 : selectedPump - 1;
    }
    if (botonPresionado(BTN_ENTER)) {
      iniciarCalibracion();
    }
    if (botonPresionado(BTN_ESCAPE)) {
      lcd.clear();
      currentMenu = SHOW_TIME;
    }
  }
}

void iniciarCalibracion() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Fluido correcto");
  elapsedTime = 0;
  calibrating = false;

  unsigned long calibrationStartTime = 0;

  while (currentMenu == CALIBRATION) {
    if (calibrating) {
      elapsedTime = (millis() - calibrationStartTime) / 1000;
    }

    lcd.setCursor(0, 1);
    lcd.print("100ml =     "); // Limpiar espacio para mostrar el tiempo
    lcd.setCursor(9, 1);
    lcd.print(elapsedTime);  // Mostrar el tiempo en segundos
    lcd.print(" s   "); // Espacios para limpiar residuos

    if (botonPresionado(BTN_UP)) {
      if (!calibrating) {
        calibrating = true;
        calibrationStartTime = millis();
        activarBomba(selectedPump);
      } else {
        calibrating = false;
        elapsedTime = (millis() - calibrationStartTime) / 1000;
        apagarBombas();
      }
    }

    if (botonPresionado(BTN_ENTER)) {
      // Usar selectedPump - 1 para acceder al array y guardar
      calibrationTimes[selectedPump - 1] = elapsedTime;
      guardarCalibracion();
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Datos guardados");
      delay(1000);
      lcd.clear();
      currentMenu = SHOW_TIME;
    }

    if (botonPresionado(BTN_ESCAPE)) {
      apagarBombas();
      lcd.clear();
      currentMenu = SHOW_TIME;
    }
  }
}

void establecerIntervaloDias() {
    lcd.clear();
    while (currentMenu == SET_INTERVAL_DAYS) {
        lcd.setCursor(0, 0);
        lcd.print("Intervalo dias");
        lcd.setCursor(0, 1);
        lcd.print(intervalDays[selectedPump - 1]); // CORREGIDO: selectedPump - 1

        lcd.print("    ");
        
        if (botonPresionado(BTN_UP)) {
            if (intervalDays[selectedPump - 1] < 30) intervalDays[selectedPump - 1]++; // CORREGIDO: selectedPump - 1

        }
        if (botonPresionado(BTN_DOWN)) {
            if (intervalDays[selectedPump - 1] > 0) intervalDays[selectedPump - 1]--; // CORREGIDO: selectedPump - 1

        }
        if (botonPresionado(BTN_ENTER)) {
            lcd.clear();
            currentMenu = SET_VOLUME_DOSAGE;
            break; // Salir del bucle while (AÑADIDO)
        }
        if (botonPresionado(BTN_ESCAPE)) {
            lcd.clear();
            currentMenu = SHOW_TIME;
        }
    }
}
void establecerVecesPorDia() {
    lcd.clear();
    while (currentMenu == SET_TIMES_PER_DAY) {
        lcd.setCursor(0, 0);
        lcd.print("Veces por dia");
        lcd.setCursor(0, 1);
        lcd.print(timesPerDay[selectedPump - 1]); // CORREGIDO: selectedPump - 1

        lcd.print("    ");
        
        if (botonPresionado(BTN_UP)) {
            if (timesPerDay[selectedPump - 1] < 24) timesPerDay[selectedPump - 1]++; // CORREGIDO: selectedPump - 1

        }
        if (botonPresionado(BTN_DOWN)) {
            if (timesPerDay[selectedPump - 1] > 1) timesPerDay[selectedPump - 1]--; // CORREGIDO: selectedPump - 1

        }
        if (botonPresionado(BTN_ENTER)) {
            lcd.clear();
            currentMenu = SET_INTERVAL_DAYS;
        }
        if (botonPresionado(BTN_ESCAPE)) {
            lcd.clear();
            currentMenu = SHOW_TIME;
        }
    }
}

void establecerVolumenDosificar() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Volumen dosificar");

    int indiceHora = 0; // Índice para la hora actual que se está configurando

    while (currentMenu == SET_VOLUME_DOSAGE) {
        lcd.setCursor(0, 1);
        lcd.print("Hora: "); lcd.print(indiceHora); lcd.print(" - "); // Indica la hora actual
        lcd.print(volumeDosage[selectedPump - 1][indiceHora]); // Muestra el volumen para la hora actual
        lcd.print(" ml");

        if (botonPresionado(BTN_UP)) {
            volumeDosage[selectedPump - 1][indiceHora]++;
            delay(100);
        }
        if (botonPresionado(BTN_DOWN)) {
            if (volumeDosage[selectedPump - 1][indiceHora] > 0) {
                volumeDosage[selectedPump - 1][indiceHora]--;
                delay(100);
            }
        }

        if (botonPresionado(BTN_RIGHT)) { // Cambiar a la siguiente hora
            indiceHora = (indiceHora + 1) % timesPerDay[selectedPump-1]; // Circular a través de las horas
            delay(100);
        }

        if (botonPresionado(BTN_LEFT)) { // Cambiar a la hora anterior
            indiceHora = (indiceHora == 0) ? timesPerDay[selectedPump-1] - 1 : indiceHora - 1; // Circular a través de las horas
            delay(100);
        }


        if (botonPresionado(BTN_ENTER)) {
            currentMenu = SET_DOSAGE_HOURS;
            delay(100);
            break;
        }

        if (botonPresionado(BTN_ESCAPE)) {
            currentMenu = SELECT_PUMP;
            delay(100);
            break;
        }
    }
}



void establecerHoraDosificacion() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Hora dosificacion");

    int indiceHora = 0;
    bool editandoHora = true;

    while (currentMenu == SET_DOSAGE_HOURS) {
        lcd.setCursor(0, 1);

        // ***MODIFICACIÓN IMPORTANTE***: Mostrar el número de hora (índice)
        lcd.print("Dosis "); lcd.print(indiceHora + 1); lcd.print(": "); // +1 para mostrar 1, 2, 3... en lugar de 0, 1, 2...

        // Mostrar la hora y minutos en el formato adecuado
        if (editandoHora) {
            lcd.print(dosageHours[selectedPump - 1][indiceHora]);
        } else {
            lcd.print(dosageMinutes[selectedPump - 1][indiceHora]);
        }

        lcd.print(":");
        if (editandoHora) {
            lcd.print(dosageMinutes[selectedPump - 1][indiceHora]);
        } else {
            lcd.print(dosageHours[selectedPump - 1][indiceHora]);
        }

        // Incrementar valor
        if (botonPresionado(BTN_UP)) {
            if (editandoHora) {
                // Aumentar la hora, con un límite de 23
                if (dosageHours[selectedPump - 1][indiceHora] < 23) {
                    dosageHours[selectedPump - 1][indiceHora]++;
                }
            } else {
                // Aumentar los minutos, con un límite de 59
                if (dosageMinutes[selectedPump - 1][indiceHora] < 59) {
                    dosageMinutes[selectedPump - 1][indiceHora]++;
                }
            }
            delay(100);
        }
        
        // Decrementar valor
        if (botonPresionado(BTN_DOWN)) {
            if (editandoHora) {
                // Disminuir la hora, con un límite de 0
                if (dosageHours[selectedPump - 1][indiceHora] > 0) {
                    dosageHours[selectedPump - 1][indiceHora]--;
                }
            } else {
                // Disminuir los minutos, con un límite de 0
                if (dosageMinutes[selectedPump - 1][indiceHora] > 0) {
                    dosageMinutes[selectedPump - 1][indiceHora]--;
                }
            }
            delay(100);
        }

        // Moverse a la izquierda o derecha
        if (botonPresionado(BTN_LEFT)) {
            editandoHora = true; // Volver a editar la hora
            delay(100); // Pausa para evitar que se interprete como varias pulsaciones
        }

        if (botonPresionado(BTN_RIGHT)) {
            editandoHora = false; // Cambiar a la edición de minutos
            delay(100); // Pausa para evitar que se interprete como varias pulsaciones
        }

        // Avanzar al siguiente conjunto de hora/minuto
        if (botonPresionado(BTN_ENTER)) {
            indiceHora++; // Avanzar a la siguiente hora

            if (indiceHora >= timesPerDay[selectedPump - 1]) {
                currentMenu = SAVE_PROGRAM_SETTINGS;
                break; // Salir del bucle while
            }
            delay(100); // Pausa para evitar múltiples entradas rápidas
        }

        if (botonPresionado(BTN_ESCAPE)) {
            currentMenu = SET_VOLUME_DOSAGE; // Volver al menú anterior
            delay(100); // Pausa para evitar que se interprete como siguiente ENTER
            break; // Salir del bucle while
        }
    }
}



void guardarConfiguracionBombas() {
    int pumpIndex = selectedPump - 1;
    int baseAddress = getEEPROMAddress(pumpIndex);

    Serial.print("Guardando bomba: "); Serial.println(selectedPump);
    Serial.print("Direccion base: "); Serial.println(baseAddress);

    for (int i = 0; i < timesPerDay[pumpIndex]; i++) {
        Serial.print("Volumen a guardar (bomba "); Serial.print(selectedPump);
        Serial.print(", hora "); Serial.print(i); Serial.print("): ");
        Serial.println(volumeDosage[pumpIndex][i]);

        EEPROM.put(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3, volumeDosage[pumpIndex][i]);
    }

    Serial.println("Verificando datos guardados:");
    for (int i = 0; i < timesPerDay[pumpIndex]; i++) {
        int volumenLeido;
        EEPROM.get(baseAddress + sizeof(int) * 2 + i * sizeof(int) * 3, volumenLeido);
        Serial.print("Volumen leido (bomba "); Serial.print(selectedPump);
        Serial.print(", hora "); Serial.print(i); Serial.print("): ");
        Serial.println(volumenLeido);
    }

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Configuracion");
    lcd.setCursor(0, 1);
    lcd.print("Guardada");
    delay(1000);
    lcd.clear();

    while (botonPresionado(BTN_ENTER) || botonPresionado(BTN_ESCAPE)) {
        delay(50);
    }

    currentMenu = SELECT_PUMP;
}
void setup() {
  Serial.begin(9600);
    Wire.begin();
    lcd.init();
    lcd.backlight();
    
    if (!rtc.begin()) {
        lcd.setCursor(0, 0);
        lcd.print("No se detecta RTC");
        while (1);
    }

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 24; j++) {
            ultimaActivacion[i][j] = 0;
        }
    }

    cargarCalibracion(); // Cargar calibración al inicio
  for(int i = 0; i < 3; i++){
    cargarConfiguracionBomba(i); // Cargar configuración de bombas
  }
    pinMode(BTN_ENTER, INPUT_PULLUP);
    pinMode(BTN_UP, INPUT_PULLUP);
    pinMode(BTN_DOWN, INPUT_PULLUP);
    pinMode(BTN_RIGHT, INPUT_PULLUP);
    pinMode(BTN_LEFT, INPUT_PULLUP);
    pinMode(BTN_ESCAPE, INPUT_PULLUP);
    
    pinMode(PUMP_1, OUTPUT);
    pinMode(PUMP_2, OUTPUT);
    pinMode(PUMP_3, OUTPUT);
    apagarBombas();

    
}




void loop() {
  
    switch (currentMenu) {
        case SHOW_TIME:
            mostrarFechaHora();
            if (botonPresionado(BTN_ENTER)) {
                currentMenu = MAIN_MENU;
            }
            
            if (botonPresionado(BTN_RIGHT) || botonPresionado(BTN_LEFT)) {
                currentMenu = MANUAL_MODE;
            }
            if (botonPresionado(BTN_UP) || botonPresionado(BTN_DOWN)) {
                currentMenu = CALIBRATION;
            }
            break;
        case MAIN_MENU:
            navegarMenuPrincipal();
            break;
        case ADJUST_DATETIME:
            ajustarFechaHora();
            break;
        case PROGRAM_PUMPS:
            lcd.clear();
            currentMenu = SELECT_PUMP;
            break;
        case MANUAL_MODE:
            modoManual();
            break;
        case CALIBRATION:
            calibrarBomba();
            break;
        case SELECT_PUMP:
            seleccionarBomba();
            break;
        case SET_TIMES_PER_DAY:
            establecerVecesPorDia();
            break;
        case SET_INTERVAL_DAYS:
            establecerIntervaloDias();
            break;
        case SET_VOLUME_DOSAGE:
            establecerVolumenDosificar();
            break;
        case SET_DOSAGE_HOURS:
            establecerHoraDosificacion();
            break;
        case SAVE_PROGRAM_SETTINGS:
            guardarConfiguracionBombas();
            break;
    }

   // Lógica para activar las bombas según la hora programada
  now = rtc.now();

    for (int i = 0; i < 3; i++) { // Para cada bomba
        for (int j = 0; j < timesPerDay[i]; j++) { // Para cada hora de dosificación
            if (now.hour() == dosageHours[i][j] && now.minute() == dosageMinutes[i][j] && now.second() == 0 && now.hour() * 60 + now.minute() > ultimaActivacion[i][j]) {

                // ***CORRECCIÓN IMPORTANTE***
                // Usar 'j' para la hora de dosificación, pero un índice SEPARADO
                // para acceder al volumen correcto en volumeDosage.  Inicializamos este
                // índice 'k' a 'j' y lo usamos para acceder al volumen.
                int k = j;  // Índice para el volumen, empieza igual que la hora.

Serial.print("Bomba ");
Serial.print(i + 1);
Serial.print(", hora: ");
Serial.print(j);
Serial.print(", volumen: ");
Serial.print(volumeDosage[i][j]); // Imprime el volumen *antes* de usarlo
Serial.print(", ultimaActivacion: ");
Serial.print(ultimaActivacion[i][j]);
Serial.print(", tiempo actual (minutos): ");
Serial.print(now.hour() * 60 + now.minute());
Serial.println();

                // Calcular tiempo de activación en segundos
                float tiempoActivacionSegundos = (float(volumeDosage[i][k]) / 100.0) * calibrationTimes[i];

                // Activar la bomba
                activarBomba(i + 1);
                bombaActivada[i] = true;
                tiempoFinActivacion[i] = millis() + tiempoActivacionSegundos * 1000;
                ultimaActivacion[i][j] = now.hour() * 60 + now.minute(); // Guarda la marca de tiempo para esta bomba y hora

                
            }
        }
    }

    // Desactivar las bombas cuando haya transcurrido el tiempo
    for (int i = 0; i < 3; i++) {
        if (bombaActivada[i] && millis() >= tiempoFinActivacion[i]) {
            apagarBombas();
            bombaActivada[i] = false;
            Serial.print("Bomba ");
            Serial.print(i + 1);
            Serial.println(" desactivada.");
        }
    }

    delay(50);
}


void seleccionarBomba() {
    lcd.clear();
    while (currentMenu == SELECT_PUMP) {
        lcd.setCursor(0, 0);
        lcd.print("Seleccionar bomba");
        lcd.setCursor(0, 1);
        lcd.print("Bomba: ");
        lcd.print(selectedPump);
        
        if (botonPresionado(BTN_RIGHT)) {
            selectedPump = (selectedPump == 3) ? 1 : selectedPump + 1;
        }
        if (botonPresionado(BTN_LEFT)) {
            selectedPump = (selectedPump == 1) ? 3 : selectedPump - 1;
        }
        if (botonPresionado(BTN_ENTER)) {
            EEPROM.put(20, selectedPump);
            lcd.clear();
            currentMenu = SET_TIMES_PER_DAY;
        }
        if (botonPresionado(BTN_ESCAPE)) {
            lcd.clear();
            currentMenu = SHOW_TIME;
            
        }
    }
}

















Moderador:
Deja de abrir hilos sin pedilre (pedirme) que cierre los anteriores, si no se consideran posteos cruzados.
Moveré este al anterior ya abierto y agota el tema de la peristática por favor.
Movido a

hasta que termine el tema en cuestión con todas las variantes que se te presenten.

Perdona pensaba que al ser una pregunta diferente se hacía en otro tema pero no te preocupes si agota el tema ya lo puedes quitar ya me buscaré la vida por otro lado . Un saludo

Buenas, ya puedes cerrarlo ya lo he solucionado, Gracias a RMancera por su ayuda inicial. un saludo

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