Problemas com menu de configuração

Olá
Tenho um projeto para controlar um aquecedor com um arduino uno, um relé e os botões do LCD (16x2).
O aquecedor pode-se controlar de duas formas:
-Pela temperatura (O utilizador escolhe a temperatura desejada e o aquecedor irá manter-se aceso ate o sensor marcar essa temperatura);
-Pelos dias da semana (O utilizador pode escolher quantos dias é que o aquecedor vai estar aceso).
A minha duvida é: Como posso fazer um menu para que em qualquer momento o utilizador consiga alterar esses valores, sem ter de reiniciar o programa?
Ou seja, eu quero fazer um menu de configurações que possa ser acessado não só no inicio do programar, mas sim em qualquer momento da sua execução.

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

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

Procuraste sequer ao menos?

Passei uma semana a procurar e não consegui encontrar o que quero.
O que encontrei foram menus iniciais, mas o que eu quero é um menu que possa ser acessado em qualquer momento da execução do programa

E em vez de criticar, viste os links que coloquei e se são o que pretendes?

Eu não critiquei nada, e os links não me deram a informação que eu precisava.
Peço desculpa se se sentiu ofendido
Acho que não expliquei bem o que pretendo.
A minha duvida não é como fazer o menu, porque já o tenho feito, mas o meu problema é que preciso de, por exemplo, clicar no botão e apareça o menu para alterar o valor das variaveis que controlam o aquecedor.
Se me pudesse ajudar seria otimo :slight_smile:

Dois dos links que coloquei tem exemplos para fazer exactamente o que pretendes.

LCD Countdown Timer with Menu System

The source code for an Arduino countdown timer with multiple profiles can be downloaded from the link below:

LCD count down timer

The Select button on the LCD shield starts/stops a timer, with a long press resetting the timer. A long press of Up enters the menu. Up/Down/Right buttons are for navigating the menu, and Select for choosing a menu item. When an item is selected, Up/Down are used for changing values. When the Reset menu item is displayed, a long press of Select loads default configuration values. Digital pin 2 is used for activating a beeper for the alarm. Examining the source should give you good insight for using the menu system in your own projects. If you find this Arduino menu library guide useful, please share it.

Eu já indiquei exemplos com código que podes utilizar... tu ainda nem sequer mostraste o código que já tens com os teus menús. Logo para ajudar mais só fazendo o projecto por ti...

lcd.setCursor(14, 0);
  botao = analogRead (0);  //Leitura do valor da porta analógica A0 é guardada na variavel botao

  if (botao < 100) { //verifica qual botao foi clicado ("RIGHT")
  }

  else if (botao < 200) { //botao "UP": diminui a temperatura desejada
    delay(300);
    lcd.print (cont = cont + 1);
  }

  else if (botao < 400) { //botao "DOWN": diminui a temperatura desejada
    delay(300);
    lcd.print (cont = cont - 1);
  }

  else if (botao < 600) { //botao "LEFT": nada faz, por agora
    alterar();
  }

  else if (botao < 800) { //botao "SELECT": inicia o programa

    do {

      if (menu == 1) {

        File logFile = SD.open("LOG5.csv", FILE_WRITE);
        DateTime now = rtc.now(); //mostra a data e hora no LCD

        horas = now.hour();
        minutos = now.minute();

        botao = analogRead (0); //Leitura do valor da porta analógica A0 é guardada na variavel botao
        Serial.println(botao);

        delay(2000);
        float h = dht.readHumidity(); // Leitura da Humidade
        float t = dht.readTemperature(); // Leitura da temperatura (Celsius)
        lcd.clear();
        lcd.createChar(0, grau); // Cria o caracter com o simbolo do grau
        lcd.setCursor(0, 0);
        lcd.print("Temp  : ");
        lcd.setCursor(13, 0);
        lcd.print(t);
        lcd.write(byte(0)); // Mostra o simbolo do grau
        lcd.print("C");
        lcd.setCursor(0, 1);
        lcd.print("Humid : ");
        lcd.setCursor(14, 1);
        lcd.print(h);
        lcd.print("%");
        lcd.print(" ");

        if (t > cont) { //se t for maior que cont quer dizer a temperatura desejada foi atingida

          
          digitalWrite(rele, LOW); //o rele passa a estar inativo
          lcd.clear();
          lcd.print("Temperatura");
          lcd.setCursor(0, 1);
          lcd.print("atingida: ");
          lcd.print(cont);
          lcd.write(byte(0));
          lcd.print("C");
          delay(2000);
          lcd.clear();
          lcd.print("Temperatura ");
          lcd.setCursor(0, 1);
          lcd.print("Atual: ");
          lcd.print(t);
          lcd.write(byte(0));
          lcd.print("C");
          delay(2000);

          logFile.print(daysOfTheWeek[now.dayOfTheWeek()]);
          logFile.print(" ");
          logFile.print(now.day(), DEC);
          logFile.print("/");
          logFile.print(now.month(), DEC);
          logFile.print("/");
          logFile.print(now.year(), DEC);
          logFile.print(" ");
          logFile.print(now.hour(), DEC);
          logFile.print(':');
          logFile.print(now.minute(), DEC);
          logFile.println();
          Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
          Serial.print(" ");
          Serial.print(now.day(), DEC);
          Serial.print("/");
          Serial.print(now.month(), DEC);
          Serial.print("/");
          Serial.print(now.year(), DEC);
          Serial.print(" ");
          Serial.print(now.hour(), DEC);
          Serial.print(':');
          Serial.println(now.minute(), DEC);

          logFile.print("Temperatura atingida: ");
          logFile.print(cont);
          logFile.println(" *C");
          logFile.print("Temperatura atual: ");
          logFile.print(t);
          logFile.println(" *C");
          logFile.println();
          Serial.print("Temperatura atingida: ");
          Serial.print(cont);
          Serial.println(" *C");
          Serial.print("Temperatura atual: ");
          Serial.print(t);
          Serial.println(" *C");
          Serial.println();

        } else { //se t nao for maior que cont quer dizer que a temperatura desejada ainda nao foi atingida
          digitalWrite(rele, HIGH); //o rele passa a estar ativo
          lcd.clear();
          lcd.begin(16, 2);
          lcd.clear();

          lcd.createChar(0, grau); // Cria o caracter com o simbolo do grau
          lcd.setCursor(0, 0);
          lcd.print("Temp  : ");
          lcd.setCursor(13, 0);
          lcd.write(byte(0));  // Mostra o simbolo do grau
          lcd.print("C");
          lcd.setCursor(0, 1);
          lcd.print("Humid : ");
          lcd.setCursor(14, 1);
          lcd.print("%");

          lcd.setCursor(8, 0);
          lcd.print(t); //apresenta a temperatura no LCD
          lcd.write(byte(0));
          lcd.setCursor(8, 1);
          lcd.print(h); //apresenta a humidade no LCD

          delay(3000);
          lcd.clear();
          lcd.setCursor(0, 1);
          lcd.print(now.day(), DEC);
          lcd.print('/');
          lcd.print(now.month(), DEC);
          lcd.print('/');
          lcd.print(now.year(), DEC);
          lcd.print("  ");
          lcd.setCursor(0, 0);
          lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
          lcd.setCursor(11, 0);
          lcd.print(now.hour(), DEC);
          lcd.print(':');
          lcd.print(now.minute(), DEC);

          logFile.print(daysOfTheWeek[now.dayOfTheWeek()]);
          logFile.print(" ");
          logFile.print(now.day(), DEC);
          logFile.print("/");
          logFile.print(now.month(), DEC);
          logFile.print("/");
          logFile.print(now.year(), DEC);
          logFile.print(" ");
          logFile.print(now.hour(), DEC);
          logFile.print(':');
          logFile.print(now.minute(), DEC);
          logFile.println();
          Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
          Serial.print(" ");
          Serial.print(now.day(), DEC);
          Serial.print("/");
          Serial.print(now.month(), DEC);
          Serial.print("/");
          Serial.print(now.year(), DEC);
          Serial.print(" ");
          Serial.print(now.hour(), DEC);
          Serial.print(':');
          Serial.println(now.minute(), DEC);

          logFile.print("Temperatura: ");
          logFile.print(t);
          logFile.println(" *C");
          Serial.print("Temperatura: ");
          Serial.print(t);
          Serial.print(" *C  ");

          logFile.print("Humidade: ");
          logFile.print(h);
          logFile.println(" %");
          logFile.println();
          logFile.close();
          Serial.print("Humidade: ");
          Serial.print(h);
          Serial.println(" %");
          Serial.println();

        } //fim do else
            
      } //fim do if (menu)
      
    } while (botao == 741 || botao == 742 || botao == 1023 || botao == 1022); //o codigo repete-se enquanto o botao selecionado for o "SELECT"

  } //fim do else if

} //fim do loop

O problema do menu está resolvido, consegui por a funcionar só que agora para entrar no menu tem de ser precisamente quando ele entre no "if" que testa se esse botão foi clicado.
Eu pesquisei sobre o "attachInterrupt()" mas não o posso usar porque os botões estão todos associados ao mesmo pino que é o A0. Está aqui o link para ver se me consegue ajudar. [url=https://www.arduino.cc/reference/pt/language/functions/external-interrupts/attachinterrupt/[/url]
:slight_smile:

O teu problema é utilizado pela utilização de delay()... Quando fazes um delay(), o programa fica ali sem responder, daí que tu notes que tens de carregar no botão no preciso momento para funcionar.

Tira os delay() do teu código e vais notar que o problema desaparece.

Como eu mostro duas telas diferentes que é a parte da temperatura e a parte das horas se tirar os delay(), o ecrã fica sempre a piscar. A parte de ir ao menu esta resolvida sem os delay() mas preciso deles para mostrar as informações na tela, pois sem eles a informação nem se consegue ler.
Espero que possa ter alguma solução para isto e obrigado por tudo.

Claro que há uma solução.

Um dos exemplos do Arduino chama-se blink without delay. Esse exemplo simples mostra como podes realizar temporizações sem usares delay(). Eu aconselho a veres o exemplo e tentares entender como funciona antes de avançares.

Eu aconselharia também a separares um pouco mais o teu código para se tornar mais fácil de entender. Porque não uma função que lê e processa os dados dos sensores. Outra para lidar com o LCD, outra com o cartão SD, etc...

Dessa forma, torna-se mais simples de fazeres alterações numa funcionalidade específica sem afectares as outras.

Já estive a pesquisar bastante sobre exmeplos do blink without delay, já percebi a utilidade dele e é a unica solução para o meu problema. Em todos os exemplos que encontrei na net percebi o que ele faz.
A minha duvida é como meter o blink no meu programa, eu não sei como fazer isso porque no meu caso eu não quero acender um led ou algo do genero, eu quero clicar num botão sem ter que ser no momento em que ele entra no if().
Fico a espera de uma resposta sua a ver se conseguiria acabar isto hoje. Muito obrigado

bubulindo:
Eu aconselharia também a separares um pouco mais o teu código para se tornar mais fácil de entender. Porque não uma função que lê e processa os dados dos sensores. Outra para lidar com o LCD, outra com o cartão SD, etc...

Há dias eu disse isto aqui em cima. O motivo pelo qual o disse era precisamente para ser mais fácil de incorporares o millis() na funcionalidade do teu programa. Em vez de ligar ou desligar um LED, o teu programa iria fazer update dos dados que estão a ser mostrados no LCD.

Já meti tudo o que tinha a meter em funções, o programa agora esta menos confuso.
Eu vou lhe mandar o meu codigo e espero que me posso ajudar a incorporar a função millis().

#include <SD.h> //Biblioteca cartão SD
#include <DHT.h> //Biblioteca do sensor DHT
#include <LiquidCrystal.h> //Biblioteca do LCD
#include <Wire.h> //Envia e recebe dados através de uma rede de dispositivos ou sensores
#include <Arduino.h> //Biblioteca usada para algumas funções da temperatura
#include "RTClib.h" //Biblioteca do RTC

LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //Declara os pinos do LCD

int rele = 3; //Declara uma variavel para tratar o pino do rele

#if defined(ARDUINO_ARCH_SAMD)
#define Serial SerialUSB
#endif

RTC_Millis rtc; //Declara o RTC

#define DHTPIN 2 //Define o pino do sensor 

#define DHTTYPE DHT22 //Define o tipo do sensor

DHT dht(DHTPIN, DHTTYPE); //Declara variaveis para tratar o pino e o tipo do DHT

int botao;  //Declara uma variavel onde se vai armazenar o valor do botao que foi clicado

int menu = 1;

char daysOfTheWeek[7][12] = {"Domingo", "Segunda", "Terca", "Quarta", "Quinta", "Sexta", "Sabado"}; //Declara os dias da semana

#define CS_pin  10 //Declara o pino do CS


byte grau[8] = { B00001100,
                 B00010010,
                 B00010010,
                 B00001100,
                 B00000000,
                 B00000000,
                 B00000000,
                 B00000000,
               }; //Cria o simbolo do grau


int cont = 15; //Esta variavel guarda a temperatura desejada

int tempo = 1; //Esta variavel guarda o tempo desejado que o aquecedor vai permanecer ligado

int hora_atual = 0; //Esta variavel guarda a temperatura atual




//--------------------------------------------------------void setup--------------------------------------------------------------//

void setup() {
  
  pinMode(rele, OUTPUT); //Define o pino do rele
  
  rtc.begin(DateTime(F(__DATE__), F(__TIME__)));
  
  Serial.begin(9600); // Iniclaiza o COM
  dht.begin(); // Iniclaiza o sensor DHT
  lcd.begin(16, 4); //Inicializa o LCD

  lcd.setCursor(0, 0);
  lcd.print("Inserir temp:");
  
  cartaoSD();

  DateTime now = rtc.now(); //Mostra a data e hora no LCD
  hora_atual = now.hour(); //Esta a ser dado um valor a variavel que é a hora
  
} //fim do setup




//---------------------------------------------------------void loop--------------------------------------------------------------//

void loop() {
  
  lcd.setCursor(14, 0);
  botao = analogRead (0); //Leitura do valor da porta analógica A0 é guardada na variavel botao

  if (botao < 100) { //Verifica qual botao foi clicado ("RIGHT")
  }

  else if (botao < 200) { //Botao "UP": diminui a temperatura desejada
    delay(300);
    if (menu == 1) {
      lcd.print (cont = cont + 1);
    } else if (menu == 2) {
      lcd.print (tempo = tempo + 1);
      if (tempo == 23) {
        tempo = 0;
        lcd.clear();
        horas_alterar();

      } //Fim do if

    } //Fim do else if

  } //Fim do else if

  else if (botao < 400) { //Botao "DOWN": diminui a temperatura desejada
    delay(300);
    if (menu == 1) {
      lcd.print (cont = cont - 1);
    } else if (menu == 2) {
      lcd.print (tempo = tempo - 1);
      if (tempo == 0) {
        tempo = 24;
        lcd.clear();
        horas_alterar();

      } //Fim do if

    } //Fim do else if

  } //Fim do else if

  else if (botao < 600) { //Botao "LEFT": é aberto o menu
    alterar();
  }

  else if (botao < 800) { //Botao "SELECT": inicia o programa
    do{
    temperatura();
    }while (botao == 741 || botao == 742 || botao == 1023 || botao == 1022); //O codigo repete-se enquanto o botao selecionado for o "SELECT"
  }
  
} //fim do loop

Aqui esta o resto do programa, se me poder ajudar agradecia.

//---------------------------------------------------------void temperatura-----------------------------------------------------------//

void temperatura(){
  
  File logFile = SD.open("LOG5.csv", FILE_WRITE);
      DateTime now = rtc.now(); //Mostra a data e hora no LCD
      botao = analogRead (0); //Leitura do valor da porta analógica A0 é guardada na variavel botao

      delay(2000);
      float h = dht.readHumidity(); // Cria a variavel que vai ler a Humidade
      float t = dht.readTemperature(); // Cria a variavel que vai ler a Temperatura
      lcd.clear();
      lcd.createChar(0, grau); // Cria o caracter com o simbolo do grau
      lcd.setCursor(0, 0);
      lcd.print("Temp  : ");
      lcd.setCursor(13, 0);
      lcd.print(t);
      lcd.write(byte(0)); // Mostra o simbolo do grau
      lcd.print("C");
      lcd.setCursor(0, 1);
      lcd.print("Humid : ");
      lcd.setCursor(14, 1);
      lcd.print(h);
      lcd.print("%");
      lcd.print(" ");

      if (t > cont || (hora_atual + tempo) == now.hour()) { //Se "t" for maior que cont quer dizer a temperatura desejada foi atingida

        digitalWrite(rele, LOW); //O rele passa a estar inativo
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Aquecedor");
        lcd.setCursor(0, 1);
        lcd.print("Desligado "); //Mensagem que aparece no LCD quando a temperatura ou as horas forem atingidas

        logFile.print(daysOfTheWeek[now.dayOfTheWeek()]);
        logFile.print(" ");
        logFile.print(now.day(), DEC);
        logFile.print("/");
        logFile.print(now.month(), DEC);
        logFile.print("/");
        logFile.print(now.year(), DEC);
        logFile.print(" ");
        logFile.print(now.hour(), DEC);
        logFile.print(':');
        logFile.print(now.minute(), DEC);
        logFile.println();
        Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
        Serial.print(" ");
        Serial.print(now.day(), DEC);
        Serial.print("/");
        Serial.print(now.month(), DEC);
        Serial.print("/");
        Serial.print(now.year(), DEC);
        Serial.print(" ");
        Serial.print(now.hour(), DEC);
        Serial.print(':');
        Serial.println(now.minute(), DEC);

        logFile.print("Aquecedor Desligado ");
        Serial.print("Aquecedor Desligado ");

      } else { //Se "t" nao for maior que cont quer dizer que a temperatura desejada ainda nao foi atingida

        digitalWrite(rele, HIGH); //O rele passa a estar ativo
        lcd.clear();
        lcd.begin(16, 2);
        lcd.clear();

        lcd.createChar(0, grau); // Cria o caracter com o simbolo do grau
        lcd.setCursor(0, 0);
        lcd.print("Temp  : ");
        lcd.setCursor(13, 0);
        lcd.write(byte(0));  // Mostra o simbolo do grau
        lcd.print("C");
        lcd.setCursor(0, 1);
        lcd.print("Humid : ");
        lcd.setCursor(14, 1);
        lcd.print("%");

        lcd.setCursor(8, 0);
        lcd.print(t); //Apresenta a temperatura no LCD
        lcd.write(byte(0));
        lcd.setCursor(8, 1);
        lcd.print(h); //Apresenta a humidade no LCD

        delay(3000);
        lcd.clear();
        lcd.setCursor(0, 1);
        lcd.print(now.day(), DEC);
        lcd.print('/');
        lcd.print(now.month(), DEC);
        lcd.print('/');
        lcd.print(now.year(), DEC);
        lcd.print("  ");
        lcd.setCursor(0, 0);
        lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
        lcd.setCursor(11, 0);
        lcd.print(now.hour(), DEC);
        lcd.print(':');
        lcd.print(now.minute(), DEC);

        logFile.print(daysOfTheWeek[now.dayOfTheWeek()]);
        logFile.print(" ");
        logFile.print(now.day(), DEC);
        logFile.print("/");
        logFile.print(now.month(), DEC);
        logFile.print("/");
        logFile.print(now.year(), DEC);
        logFile.print(" ");
        logFile.print(now.hour(), DEC);
        logFile.print(':');
        logFile.print(now.minute(), DEC);
        logFile.println();
        Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
        Serial.print(" ");
        Serial.print(now.day(), DEC);
        Serial.print("/");
        Serial.print(now.month(), DEC);
        Serial.print("/");
        Serial.print(now.year(), DEC);
        Serial.print(" ");
        Serial.print(now.hour(), DEC);
        Serial.print(':');
        Serial.println(now.minute(), DEC);

        logFile.print("Temperatura: ");
        logFile.print(t);
        logFile.println(" *C");
        Serial.print("Temperatura: ");
        Serial.print(t);
        Serial.print(" *C  ");

        logFile.print("Humidade: ");
        logFile.print(h);
        logFile.println(" %");
        logFile.println();
        logFile.close();
        Serial.print("Humidade: ");
        Serial.print(h);
        Serial.println(" %");
        Serial.println();

      } //Fim do else
      
} //fim do temperatura




//---------------------------------------------------------void alterar-----------------------------------------------------------//

void alterar() {

  lcd.clear();
  lcd.print("Temperatura");
  lcd.setCursor(0, 1);
  lcd.print("Horas func");

  do {

    botao = analogRead(0); //Leitura do valor da porta analógica A0 é guardada na variavel botao

    if (botao < 100) { //Verifica qual botao foi clicado ("RIGHT")
    }

    else if (botao < 200) { //Botao "UP": diminui a temperatura desejada
      delay(300);
      menu--;
      lcd.clear();
      lcd.print(">Temperatura");
      lcd.setCursor(0, 1);
      lcd.print(" Horas func");
      delay(100);
      if (menu == 0 || menu == 3)
        menu = 1;
    }

    else if (botao < 400) { //Botao "DOWN": diminui a temperatura desejada
      delay(300);
      menu++;
      delay(100);
      lcd.clear();
      lcd.print(" Temperatura");
      lcd.setCursor(0, 1);
      lcd.print(">Horas func");
      if (menu == 0 || menu == 3)
        menu = 1;
    }

    else if (botao < 600) { //Botao "LEFT": neste caso não faz nada
    }

    else if (botao < 800) { //Botao "SELECT": inicia o menu
      if (menu == 1) {
        temp_alterar();
      } else if (menu == 2) {
        horas_alterar();
      }
      return;
    }

  } while (botao != 800);

} //Fim do alterar




//---------------------------------------------------------void cartaoSD-----------------------------------------------------------//

void cartaoSD(){
  
  Serial.begin(9600); //Inicia comunicação serial com 9600 de baud rate
  Serial.println("Iniciando SD Card"); //Apresenta a frase no COM

  pinMode(CS_pin, OUTPUT); //Configura o pino CS como saída

  if (!SD.begin(CS_pin)) //Verifica se cartão SD está pronto
  {
    Serial.println("Falha ao abrir cartao SD");
    return;
  }

  Serial.println("Cartao SD iniciado com sucesso!");

  File logFile = SD.open("LOG5.csv", FILE_WRITE); //Cria e escreve num arquivo CSV
  if (logFile)
  {
    Serial.println("O arquivo foi aberto");
    Serial.println("\n");
  }
  else
  {
    Serial.println("Erro ao abrir arquivo");
  }
  
} //fim do CartaoSD




//-----------------------------------------------------void temp_alterar----------------------------------------------------------//

void temp_alterar() {

  lcd.clear();
  lcd.print("Inserir temp:"); //Função que vai ser chamada para o menu
  delay(300);

} //Fim do temp_alterar




//----------------------------------------------------void horas_alterar----------------------------------------------------------//

void horas_alterar() {

  lcd.clear();
  lcd.print("Inserir horas:"); //Função que vai ser chamada para o menu
  delay(300);

} //Fim do horas_alterar

Obrigado pela ajuda toda, consegui concluir o projeto.
Precisei apenas de mais um pouco de informação sobre a função millis() e consegui finalizar.
Muito obrigado outra vez.