Voltar a tela inicial LCD + Menu

Bom Dia a todos!

Estou com uma duvida no meu sketch, meu projeto é de uma estufa automática(para acelerar o desenvolvimento das plantas), na tela "IDLE" ficará apresentando

-------ESTUFA-------
HH:MM DD/MM
TEMP INT TEMP EXT
SOLO: Umido

ao entrar no menu será apresentado as seguintes opções:

ILUMUNACAO
TEMPERATURA
UMIDADE
AJUSTE RELOGIO

Os sub-menus desse menu será o tempo que a iluminação ficará acesa ex: >ILUMINAÇÃO > 24h / 12-12 / 18-6 / 14-10.... vários foto períodos pré-defindos.

A TEMPERATURA / UMIDADE será exibido uma tela com mais detalhes que a "IDLE"

A AJUSTE RELÓGIO entra no menu de ajuste.. :wink:

Eu consegui fazer o processo de entrar nos menus mas nao consigo sair e voltar a tela "IDLE", quando consegui ficou a escrita do menu de ILUMINAÇÃO na frente.

:fearful: Postei metade do cogido pois ele inteiro estava dando "maximum carateres"

Segue o codigo:

/ --- Bibliotecas Auxiliares ---
#include <LiquidCrystal.h>                              //Biblioteca para o display LCD

// --- Mapeamento de Hardware ---
#define butUp        12                                     //Botão para selecionar tela acima no digital 12
#define butDown      11                                     //Botão para selecionar tela abaixo no digital 11
#define butEsquerda  10                                     //Botão de ajuste mais no digital 10
#define butDireita   9                                     //Botão de ajuste menos no digital 9
#define select       8                                     //Botão de seleção no digital 8

// --- Protótipo das Funções Auxiliares ---
void changeMenu();                                      //Função para modificar o menu atual
void dispMenu();                                        //Função para mostrar o menu atual
void data_hora();                                       //Função do menu1, data e hora
void temperatura();//Função do menu2, temperatura
void dispIdle();

void readSelect(char option);                           //Função de Leitura do botão select para seleção de subMenus
void subMenu4_1();                                      //Função para subMenu4_1
void subMenu4_2();                                      //Função para subMenu4_2
void subMenu4_3();
void subMenu4_4();              //Função para subMenu4_3


// --- Variáveis Globais ---
char menu = 0x01;                                       //Variável para selecionar o menu
char subMenu4 = 0x01;                                   //Variável para selecionar subMenu no menu4
char set1 = 0x00, set2 = 0x00;                          //Controle das lâmpadas
boolean t_butUp, t_butDown, t_butEsquerda, t_butDireita, t_select;   //Flags para armazenar o estado dos botões

// --- Hardware do LCD ---
LiquidCrystal disp(7,  //RS no digital 7
                   6,  //EN no digital 6
                   5,  //D4 no digital 5
                   4,  //D5 no digital 4
                   3,  //D6 no digital 3
                   2); //D7 no digital 2

// --- Configurações Iniciais ---
void setup()
{
  disp.begin(20,4);                                      //Inicializa LCD 20 x 4
  
  for(char i=8; i<13; i++) pinMode(i, INPUT_PULLUP);     //Entrada para os botões (digitais 8 a 12) com pull-ups internos
  
  t_butUp   = 0x00;                                      //limpa flag do botão Up
  t_butDown = 0x00;                                      //limpa flag do botão Down
  t_butEsquerda    = 0x00;                                      //limpa flag do botão P
  t_butDireita    = 0x00;                                      //limpa flag do botão M
  t_select  = 0x00;                                      //limpa flag do botão select


} //end setup


// --- Loop Infinito ---
void loop()
  {
   dispIdle();
    


} //Final do loop

// --- Desenvolvimento das Funções Auxiliares ---
void dispIdle()
  {
    disp.setCursor(0,0);
    disp.print("------Plantario-----");
    disp.setCursor(0,1);
    disp.print("HH:MM          DD/MM");
    disp.setCursor(0,2);
    disp.print("Temp EXT:  Temp INT:");
    disp.setCursor(0,3);
    disp.print("Umidade Solo: Umido ");  
       
    if(!digitalRead(select))   t_select   = 0x01;          //Botão Up pressionado? Seta flag
    if(digitalRead(select) && t_select)                    //Botão Up solto e flag setada?
      {                                                    //Sim...
      t_select = 0x00;                                   //Limpa flag
      disp.clear();
      while(1)
      {
      changeMenu();
      dispMenu();
      }
      }
  }


void changeMenu()                                       //Modifica o menu atual
{
   if(!digitalRead(butUp))   t_butUp   = 0x01;          //Botão Up pressionado? Seta flag
   if(digitalRead(butUp) && t_butUp)                    //Botão Up solto e flag setada?
   {                                                    //Sim...
      t_butUp = 0x00;                                   //Limpa flag
      
      disp.clear();                                     //Limpa display
      menu--;                                           //Decrementa menu
      
      if(menu < 0x01) menu = 0x04;                      //Se menu maior que 1, volta a ser 4
   
   } //end butUp

   if(!digitalRead(butDown)) t_butDown = 0x01;          //Botão Down pressionado? Seta flag
   if(digitalRead(butDown) && t_butDown)                //Botão Down solto e flag setada?
   {                                                    //Sim...
      t_butDown = 0x00;                                 //Limpa flag
      
      disp.clear();                                     //Limpa display
      menu++;                                           //Incrementa menu
      
      if(menu > 0x04) menu = 0x01;                      //Se menu menor que 4, volta a ser 1
   
   } //end butDown   

} //end changeMenu

void readSelect(char option)                            //Leitura do botão select para seleção de subMenus
{
    
   if(!digitalRead(select))     t_select    = 0x01;      //Botão select pressionado? Seta flag
   
   
   if(digitalRead(select) && t_select)                  //Botão select solto e flag setada?
   {                                                    //Sim...
        t_select = 0x00;                                //Limpa flag
        disp.clear();
        
        switch(option)
        {
           case 0x01: subMenu4_1(); break;
           
           case 0x02: subMenu4_2(); break;
           
           case 0x03: subMenu4_3(); break;

           case 0x04: subMenu4_4(); break;
        
        } //end switch option
   
   } //end if
}

void dispMenu()                                         //Mostra o menu atual
{
    switch(menu)                                        //Controle da variável menu
    {
       case 0x01:                                       //Caso 1
             disp.setCursor(1,0);                       //Posiciona cursor na coluna 2, linha 2   
             disp.print(">ILUMINACAO");
             disp.setCursor(1,1);                       //Posiciona cursor na coluna 2, linha 2   
             disp.print(" TEMPERATURA");
             disp.setCursor(1,2);                       //Posiciona cursor na coluna 2, linha 2   
             disp.print(" UMIDADE");
             disp.setCursor(1,3);                       //Posiciona cursor na coluna 2, linha 2   
             disp.print(" AJUSTE RELOGIO");  
             readSelect(1);                             //Lê botão select com parâmetro 1
                      
             break;                                     //break

    } //end switch menu

} //end dispMenu




void subMenu4_1()
{ 
  while(1)
  {
   disp.setCursor(0,0);                                 //Posiciona cursor na coluna 1, linha 1
   disp.print("ILUMINACAO");                              //Imprime mensagem
   disp.setCursor(0,1);                                 //Posiciona cursor na coluna 1, linha 2   
   disp.print("< 24 HORAS >");                      //Mostrador (apenas ilustrativo......)   
  
   if(!digitalRead(butEsquerda))   t_butEsquerda   = 0x01;          //Botão Up pressionado? Seta flag
   if(digitalRead(butEsquerda) && t_butEsquerda)                    //Botão Up solto e flag setada?
   {                                                    //Sim...
      t_butEsquerda = 0x00;//Limpa flag
      disp.clear();
      disp.setCursor(0,3);
      disp.print("botao");
      
         
   } //end butEsquerda*/
 }
} //end subMenu4_1

Normalmente em menús ou tens a possibilidade de voltar para trás (criar um menu principal) ou após passar alguns segundos sem input do utilizador, a tela volta ao menú inicial.

A navegação nos menús é normalmente feita com uma tecla de enter e escape... podes criar uma tecla que volta atrás nos menús.

Sim!
Como escrevi no codigo:

void subMenu4_1()
{ 
  while(1)
  {
   disp.setCursor(0,0);                                 //Posiciona cursor na coluna 1, linha 1
   disp.print("ILUMINACAO");                              //Imprime mensagem
   disp.setCursor(0,1);                                 //Posiciona cursor na coluna 1, linha 2   
   disp.print("< 24 HORAS >");                      //Mostrador (apenas ilustrativo......)   
  
   if(!digitalRead(butEsquerda))   t_butEsquerda   = 0x01;          //Botão Up pressionado? Seta flag
   if(digitalRead(butEsquerda) && t_butEsquerda)                    //Botão Up solto e flag setada?
   {                                                    //Sim...
      t_butEsquerda = 0x00;//Limpa flag
      disp.clear();
      disp.setCursor(0,3);
      disp.print("Voltar");
      dispIdle();
      
         
   } //end butEsquerda*/
 }
} //end subMenu4_1

Quando aperto Botão da esquerda (butEsquerda) ele entende como verdadeiro entra na função dipsIdle() mas o LCD fica bagunçado. fica ainda mostrando as msgs de "ILUMINACAO" ("< 24 HORAS >") e trava , nao consigo fazer mais nada, como entrar no menu select

Sem ver o código todo é difícil entender exactamente o que se passa, mas a impressão que me dá é que estás a fazer isto da maneira mais complicada possível.

Por exemplo, a quantidade de "while(1)" que tens no teu código é demais. Tu depois encadeias while(1) dentro de while(1) que inevitavelmente traz problemas com a memória interna do CPU.

Há dias havia aqui alguém a querer fazer algo semelhante e eu indiquei estes links:

https://forum.arduino.cc/index.php?topic=529299.0

https://eeenthusiast.com/arduino-lcd-tutorial-display-menu-system-scrolling-menu-changeable-variables-projects/

Dá uma vista de olhos neles e possivelmente utiliza a biblioteca que eles utilizam para atingir o que queres.

Caso queiras fazer isto por ti, o método que eu sempre achei melhor é ter uma variável por cada nível de menú que guarda o menú a mostrar.

Depois de segundo a segundo chamas uma função que mostra a tela que pretendes mostrar dependendo do valor dessa variável.
Antes de chamares a função que mostra a tela, chamas uma função que lê os botões do teclado e actua sobre as variáveis que referi em cima. Assim não precisas de andar a saltar de função para função com vários while(1).

Boas Amigo @bubulindo consegui fazer a tela do programa e com os menus e as telas, retirei todos os while(1), substitui por switch case,muito melhor!

Para voltar a tela do menu principal ( nao sei se fiz certo) ao apertar o "esc" eu gravo 1 na flag menu e consequentemente ela volta a primeira tela, achei o modo mais facil de fazer isso

Mas como nem tudo são rosas, eu cai em um "probleminha" da função milis():

void leitura_temp()
   {
   if ( (millis() - delayIntervalo) > intervalo ) {     //LEITURA DOS DADOS ==INTERVALO = A 2000
        unsigned long start = micros();
        int chk = DHT.read11(DHT11_PIN);       
        unsigned long stop = micros();
        delayIntervalo = millis();
    };
}

Ao final de 48~49 dias a contagem do millis volta a zero(0) e esta parte do meu programa vai travar pois nao fiz nada para "dar a volta" (e não faço ideia como fazer)

Como estou usando um RTC externo como poderia usar para substituir o millis? Tenho mas 4 contagens de tempo no codigo usando Millis() uma de 24hras para a leitura de umidade do solo.

Poderia me dar mais uma força ?

O teu código não parece ter problema nenhum e não tem desde que a variável "delayIntervalo" seja unsigned long.

Podes ver a matemática das contas do millis onde explica o que eu disse.

https://www.gammon.com.au/millis