Crear menú, con 3 o cuatro botones

Hola, soy nuevo en esto pero con ayuda de otros colegas pude realizar este código de control de humedad, temperatura, intervalo tiempo-marcha/parada de una heladera, calentar y enfriar (es un proyecto de secadero para salame).
El programa se compone de dos fases o ciclos; el primero son dos días con temperatura y humedad máxima, el segundo ciclo continúa del primero unos 15 días más, con temperaturas y humedades máximas diferentes.
Tengo algunos inconvenientes con el modulo DS3231, no se si tengo un problema en el código o el modulo, pero se atrasa más de diez minutos al día, y también aparecen 2 o 3 cifras en los segundos (por lo que yo entiendo serían mili segundos, se detalla en la imagen) . Mas tarde intentaré cambiar el modulo. Tampoco me cuenta la cantidad de días, seguramente hay un error en el código.

Pero lo más importante que quiero hacer es el MENÚ:
Quiero hacer el menú y no logro resolverlo, busqué varias librerías y códigos en internet; pero muchos tienen sus errores, o hay conflictos con las bibliotecas, o no son tan detallados en su explicación, y no logro entenderlos.

Necesito hacer un menú con 3 o 4 botones y poder cambiar la temperatura max, temperatura min, humedad max, humedad min; también cambiar la cantidad de días de cada una de las fases.

Sé que que es mucho pedir, pero cualquier ayuda será bienvenida...


#include <Wire.h>
#include <RTClib.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#define DHTPIN 8 //sensor pin
#define DHTTYPE DHT22

#include <pt.h>                   //protothreads
struct pt hilo1;                  //protothreads
unsigned long marchavapor = 3000;    //protothreads
unsigned long paradavapor = 3000;     //protothreads

struct pt hilo2;                  //protothreads
unsigned long marchacalentar = 3000;    //protothreads
unsigned long paradacalentar = 3000; //protothreads

struct pt hilo3;                  //protothreads
unsigned long marchaenfriar = 3000;    //protothreads
unsigned long paradaenfriar = 3000; //protothreads

struct pt hilo4;                  //protothreads
unsigned long marchahela = 3000;    //protothreads  300000
unsigned long paradahela = 1200; //protothreads   1200000


LiquidCrystal_I2C lcd(0x27, 20, 4);
RTC_DS3231 rtc;
DHT dht(DHTPIN, DHTTYPE);

int btn_inicio = 2;
int enfriar = 12;
int vapor = 10;
int calentar = 11;
int hela = 9;   //heladera

long tiempo = 0;
long tiempoUltimaLectura = 0;
long fechayhora = 0;
float hum = 0, tem = 0;
int dia_inicio = 0;
int hora_inicio = 0;
int dia_actual = 0;
int hora_actual = 0;
int temperatura_min = 0;
int temperatura_max = 0;
int humedad_min = 0;
int humedad_max = 0;
int dia_mem  = 0;

void setup () {
  Wire.begin();
  Serial.begin(9600);
  rtc.begin();
  dht.begin();
  lcd.init ();
  lcd.backlight();
  lcd.clear();

  PT_INIT(&hilo1);     //protothreads vapor
  PT_INIT(&hilo2);     //protothreads calentador
  PT_INIT(&hilo3);     //protothreads enfriador
  PT_INIT(&hilo4);     //protothreads intervalo heladera

  //pinMode(btn_inicio, INPUT_PULLUP);
  pinMode(calentar, OUTPUT);
  pinMode(vapor, OUTPUT);
  pinMode(heladera, OUTPUT);

  //Solo una vez para establecer la hora
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  //temperatura_min = 17;
  // temperatura_max = 19;
  //humedad_min = 90;
  // humedad_max = 95;

  lcd.setCursor(5, 0);
  lcd.print("CAL=");
  lcd.setCursor(13, 0);
  lcd.print("ENF=");
  lcd.setCursor(5, 1);
  lcd.print("VAP=");
  lcd.setCursor(13, 1);
  lcd.setCursor(0, 0);
  lcd.print("F=");
  lcd.setCursor(0, 1);
  lcd.print("D=");
  lcd.setCursor(13, 1);
  lcd.print("HEL=");
 
}

void loop () {
//if ( digitalRead ( btn_inicio ) == 0 ){
  DateTime now = rtc.now();

 
 //if ( digitalRead ( btn_inicio ) == 0 ){
    if (millis() - tiempo > 1000) {

      dia_inicio = now.day() + now.month() + now.year();
      hora_inicio = now.hour() + now.minute() + now.second();
      //delay(10);
      tiempo = millis();
    }
 
    dia_actual = now.day() + now.month() + now.year();
    hora_actual = now.hour() + now.minute() + now.second();
 
    lcd.setCursor(11, 2);
    lcd.print(" ");
    lcd.print(now.hour(), DEC);
    lcd.print(":");
    lcd.print(now.minute(), DEC);
    lcd.print(":");
    lcd.print(now.second(), DEC);
    lcd.setCursor(0, 2);
    lcd.print(now.day(), DEC);
    lcd.print("/");
    lcd.print(now.month(), DEC);
    lcd.print("/");
    lcd.print(now.year(), DEC);
 
    if (millis() - tiempoUltimaLectura > 2000)
    {
      hum = dht.readHumidity();
      tem = dht.readTemperature();

      lcd.setCursor(0, 3); //COLOCAR EN POSICION
      lcd.print("T=" + String(tem, 1) + "C  ");
      lcd.setCursor(8, 3); //COLOCAR EN POSICION
      lcd.print("H=" + String(hum, 1) + "% ");

      tiempoUltimaLectura = millis();
    }

    int dias_transcurridos = dia_actual - dia_inicio;

    temperatura_min = 21;
    temperatura_max = 23;
    humedad_min = 90;
    humedad_max = 95;

    if (dias_transcurridos >= 0) {   //cantidad de dias que van pasando
      lcd.setCursor(2, 1);
      lcd.print(dias_transcurridos);
    }

    if (dias_transcurridos <= 2) {      // fase 1

      lcd.setCursor(2, 0);
      lcd.print("1");
    }
    if (dias_transcurridos > 2) {      // fase 2

      lcd.setCursor(2, 0);
      lcd.print("2");

    }

    //cantidad de días fase 2
    if (dias_transcurridos > 2 && dias_transcurridos <= 15) {

      temperatura_min = 17;
      temperatura_max = 19;
      humedad_min = 75;
      humedad_max = 80;
    }

    if (tem < temperatura_min) {

      calentador(&hilo2);     //protothreads

      //digitalWrite(calentar, HIGH);
      lcd.setCursor(9, 0);
      lcd.print("ON");
    }
    else {
      lcd.setCursor(9, 0);
      lcd.print("OFF");
      digitalWrite(calentar, LOW);
    }
    if (tem > temperatura_max) {

      enfriador(&hilo3);

      //digitalWrite(enfriar, LOW);
      lcd.setCursor(17, 0);
      lcd.print("ON ");
    }
    else {
      lcd.setCursor(17, 0);
      lcd.print("OFF");
    }

    if (hum < humedad_min) {

      vaporizador(&hilo1);     //protothreads

      //digitalWrite(vapor, HIGH);
      lcd.setCursor(9, 1);
      lcd.print("ON ");
    }
    else {

      lcd.setCursor(9, 1);
      lcd.print("OFF");
      digitalWrite(vapor, LOW);
    }

 
    heladera(&hilo4);

}
//}
void vaporizador(struct pt *pt) {         //protothreads
  PT_BEGIN(pt);                           //protothreads
  //void setup(){
  static long t = 0;                       //protothreads
  pinMode(vapor, OUTPUT);                   //protothreads

  do {                                      //protothreads
    digitalWrite(vapor, HIGH);                 //protothreads
    t = millis();                              //protothreads
    PT_WAIT_WHILE(pt, (millis() - t) < marchavapor); //protothreads

    digitalWrite(vapor, LOW);                       //protothreads
    t = millis();                                //protothreads
    PT_WAIT_UNTIL(pt, (millis() - t) >= paradavapor); //protothreads

  } while (true);                                //protothreads
  PT_END(pt);                                   //protothreads
}                                               //protothreads

void calentador(struct pt *pt) {         //protothreads
  PT_BEGIN(pt);                           //protothreads
  //void setup(){
  static long t = 0;                       //protothreads
  pinMode(calentar, OUTPUT);                   //protothreads

  do {                                      //protothreads
    digitalWrite(calentar, HIGH);                 //protothreads
    t = millis();                              //protothreads
    PT_WAIT_WHILE(pt, (millis() - t) < marchacalentar); //protothreads

    digitalWrite(calentar, LOW);                       //protothreads
    t = millis();                                //protothreads
    PT_WAIT_UNTIL(pt, (millis() - t) >= paradacalentar); //protothreads

  } while (true);                                //protothreads
  PT_END(pt);
}

void enfriador(struct pt *pt) {         //protothreads
  PT_BEGIN(pt);                           //protothreads
  //void setup(){
  static long t = 0;                       //protothreads
  pinMode(enfriar, OUTPUT);                   //protothreads

  do {                                      //protothreads
    digitalWrite(enfriar, HIGH);                 //protothreads
    t = millis();                              //protothreads
    PT_WAIT_WHILE(pt, (millis() - t) < marchaenfriar); //protothreads

    digitalWrite(enfriar, LOW);                       //protothreads
    t = millis();                                //protothreads
    PT_WAIT_UNTIL(pt, (millis() - t) >= paradaenfriar); //protothreads

  } while (true);                                //protothreads
  PT_END(pt);                                   //protothreads
}                                                //protothreads

void heladera(struct pt *pt) {         //protothreads
  PT_BEGIN(pt);                           //protothreads
  //void setup(){
  static long t = 0;                       //protothreads
  pinMode(hela, OUTPUT);                   //protothreads

  do {                                      //protothreads
    digitalWrite(hela, HIGH);                 //protothreads
    t = millis();                              //protothreads
    PT_WAIT_WHILE(pt, (millis() - t) < marchahela); //protothreads
    lcd.setCursor(17, 1);
    lcd.print("OFF");

    digitalWrite(hela, LOW);                       //protothreads
    t = millis();                                //protothreads
    PT_WAIT_UNTIL(pt, (millis() - t) >= paradahela); //protothreads
    lcd.setCursor(17, 1);
    lcd.print("ON ");

  } while (true);                                //protothreads
  PT_END(pt);                                   //protothreads

}                                               //protothreads

Usa esto

Mira los ejemplos, sirven para todo tipo de entradas, 3, 4, o 6 pulsadores. Tambien otras opciones.

Lo voy a estudiar, espero que llegue a algo...

Tienes ejemplos y funciona al 100% porque yo los he usado.

Estoy en eso... jugando un poco con los botones, por lo visto funciona
Te da 7 ejemplos, borré los demás, estoy con el ejemplo 2 (los botones)

Ahora tengo que estudiarlo, para ver si lo puedo adaptar al código...esto me va a ser traspirar bastante...ja ja ja

Intenta entender como se crean los menú, y submenús.
Y como se incremetan variables para lograr configuraciones.

Sin duda... y aparte tengo que solucionar un problema en el código con el módulo rtc3231ds que se me atrasa como 10 minutos en el día, me cansé de probar con otros códigos, modifiqué el programa con otras librerías pero me hace lo mismo. Voy a comprar otro módulo a ver si se va el problema...

Ojo con ésta línea

rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

que ajusta el reloj a la hora en que se hizo la compilación.
Si reinicias el arduino, va a volver a ajustar el RTC a esa hora por lo que va a parecer que atrasa cuando en realidad se le a recargado una hora que ya está atrasada.
Lo que debes hacer es compilar y cargar el código, dejar que se ejecute una vez.
Luego comentas la línea

// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

para que ya no se compile, vuelves a subir el código y listo.

Saludos

Ya probé con eso, pero me hace lo mismo

Ahora miro más a fondo el código por lo que cuentas de las 3 cifras en los segundos, seguro tienes un error al posicionar el cursor porque la librería no devuelve más de 2 cifras.

Por otro lado, no niego que pudo vernir fallado el RTC pero es llamativo tanto error, por ejemplo, estoy usando uno en este momento y apenas atrasó 4 segundos en 1 mes, justamente lo sincronicé hace 2 días por eso lo digo con seguridad.

Bueno, miro el código a ver que encuentro.

Saludos y feliz año!

PD: Acabo de mirar la foto y no solo hay problemas con los segundos, el año es un desastre. Eso no es por el RTC.

Sin duda hay un problema en el código, hay algo de configuración o acomodarlo de otra forma; el error aparece después de un tiempo y se va atrasando, pero es mucho tiempo el q se atrasa.

Felicidades para vos también y tu flia, y muchas gracias por la ayuda...

Bueno, lo primero que veo

    lcd.setCursor(11, 2);
    lcd.print(" ");
    lcd.print(now.hour(), DEC);
    lcd.print(":");
    lcd.print(now.minute(), DEC);
    lcd.print(":");
    lcd.print(now.second(), DEC);
    lcd.setCursor(0, 2);
    lcd.print(now.day(), DEC);
    lcd.print("/");
    lcd.print(now.month(), DEC);
    lcd.print("/");
    lcd.print(now.year(), DEC);

Si imprimes de esa manera, mira como quedan por ejemplo la hora

0:8:59
//  1 segundo después deberías ver
0:9:0
// pero en el display obtienes
0:9:09

0:8:59 tiene 6 caracteres
0:9:0 tiene 5 caracteres
¿quien se encarga de borrar el 6to. caracter, el 9 del 59?
Tienes que darle formato a los números.
Puedes hacerlo imprimiendo un cero cuando el numero es menor que 10

if(minutos < 10) lcd.print('0');
lcd.print(minutos);

O usando spritf(), algo así

char strBuff[17];
DateTime actualTime = rtc.now();

sprintf(strBuff,"%02d:%02d:%02d",actualTime.hour(),actualTime.minute(),actualTime.second());
lcd.setCursor(0,0);
lcd.print(strBuff);

Sigo revisando...

No te cuenta los días que han pasado porque

DateTime now = rtc.now();

 
 //if ( digitalRead ( btn_inicio ) == 0 ){
    if (millis() - tiempo > 1000) {

      dia_inicio = now.day() + now.month() + now.year();
      hora_inicio = now.hour() + now.minute() + now.second();
      //delay(10);
      tiempo = millis();
    }

actualiza el valor de dia_inicio y hora_inicio a la hora actual una vez cada segundo.
Entonces esta resta

int dias_transcurridos = dia_actual - dia_inicio;

siempre va a dar 0.
Excepcionalmente puede llegar a dar 1 en el paso de 23:59:59 a 0:00:00 pero al siguiente segundo, y por el resto del día, vuelve a dar 0.

Saludos

Ahora desapareció el error del maldito 9, agregándole una parte al final:
por lo menos ahora no se atrasa.

    lcd.setCursor(11, 2);
    lcd.print(" ");
    lcd.print(now.hour(), DEC);
    lcd.print(":");
    lcd.print(now.minute(), DEC);
    lcd.print(":");
    lcd.print(now.second(), DEC);
    lcd.setCursor(0, 2);
    lcd.print(now.day(), DEC);
    lcd.print("/");
    lcd.print(now.month(), DEC);
    lcd.print("/");
    lcd.print(now.year(), DEC);
    delay(1000);
    
    lcd.setCursor(12, 2);              //la parte agregada
    lcd.print(           "        ");         //la parte agregada

Ademas esta cuenta

 dia_inicio = now.day() + now.month() + now.year();

es cualquier cosa..
Si lo quieres llevar como un entero entonces debes convertir todo a dias.
y esto

 hora_inicio = now.hour() + now.minute() + now.second();

a segundos
De otro modo comparas cualquier cosa.
Imagina hora 23 min 30 y seg 10 y tu sumas todo, 23+30+10 = 63 cuando debió ser
233600+3060+10= 84610
Y lo mismo con dias, meses años
Lo mejor es hacer como hace @PeterKanTropus que siempre recomienda usar el tiempo en formato unix y entonces puedes comparar absolutamente todo como fecha y hora únicas.

UnixTime