Mudar tela com um botão ou menu simples. (One push button change lcd screen)

Olá pessoal, bom dia! há um longo tempo sem programar, venho solicitar que refresquem minha memória. Estou com uma serie de sensores acoplados ao arduino uno r3. tenho um LCD com interface I2c ou IIC e todas as informações estão sendo mostradas corretamente contudo estou tendo uma enorme dificuldade em fazer com que ao apertar um botão a tela mude para mostrar outros grupos de sensores. Bem, desenferrujando meu limitado e antigo conhecimento de programação eu cheguei a uma ideia básica de registrar e contar a ação do botão, armazenar numa variável essa contagem e de acordo com ela usando a função switch eu mudo a tela. Mas …

Para que eu leia a ação do botão (CLICK) eu preciso definir um delay de 50 “daley(50);” e isso causa um refresh de tela incomodo, se eu aumento o delay fica uma tremenda briga para registrar o click.

E o código:

// Programa : Display LCD 16x2 e modulo I2C
// Autor : André Abreu - MAR2016
// Exercicio #0034

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

// Inicializa o display no endereco 0x27
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

const int botaoPino = 3;
int Tela = 0;

int bconta_push = 0;
int bstatus_anterior = 0;
int bstatus_atual = 0;


int RefreshTela = 80;
 
void setup()
{
  lcd.begin (16,2);  
  lcd.clear();
  pinMode(botaoPino, INPUT);
  digitalWrite(botaoPino, LOW);
  lcd.setBacklight(HIGH);  
}

void loop()
{ 

  bstatus_atual = digitalRead(botaoPino);

  if (bstatus_atual != bstatus_anterior){
    if (bstatus_atual == HIGH){
      delay (250);
      bconta_push++;
      Tela = bconta_push;
    } else {
      Serial.println("off");
    }
    if (bconta_push > 4){
      bconta_push = 0;  
    }
  }
  bstatus_anterior = bstatus_atual;

  switch (Tela) {
      
     default: {
        lcd.clear();        
        lcd.setCursor(0, 0);
        lcd.print("DEFAULT");
        lcd.setCursor(0,1);
        lcd.print(bconta_push);

        delay(RefreshTela);
        break;
      } 
      
      case 1: {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("TELA #1");
        lcd.setCursor(0,1);
        lcd.print(bconta_push);

        delay(RefreshTela);
        break;
      }
       
      case 2: {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("TELA #2");
        lcd.setCursor(0,1);
        lcd.print(bconta_push);

        delay(RefreshTela);
        break;
      }
        
      case 3: {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("TELA #3");
        lcd.setCursor(0,1);
        lcd.print(bconta_push);

        delay(RefreshTela);
        break;
      }

      case 4: {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("TELA #4");
        lcd.setCursor(0,1);
        lcd.print(bconta_push);

        delay(RefreshTela);
        break;
      }
  }
  
 //delay(2000);
}

Agradeço qualquer ajuda! Obrigado.

Não percebi porque é que diz:

andreabreu:
(…)
Para que eu leia a ação do botão (CLICK) eu preciso definir um delay de 50 “daley(50);”
(…)

Caso eu aumente o tempo de delay o loop demora a registrar o pressionar do botão.

luisilva: Não percebi porque é que diz:

Não foi isso que eu perguntei. Não há nenhum "delay(50);" no seu código e não estou a ver a utilidade do que está a ser utilizado (pode ser debouncing, mas se for isso não está muito bem executado).

Daley(50) foi um exemplo ... no código está a variável "RefreshTela" de fato o deboucing ou interrupt me auxiliaria mas como sou novo nessa linguagem ainda não entendi muito bem como estas funções se aplicam no meu caso.

Em outra linguagem me parece simples, na verdade eu preciso de uma multitarefa ... um função com loop curto para ouvir o botão e outra não tão curta para ouvir os sensores.

luisilva: Não foi isso que eu perguntei. Não há nenhum "delay(50);" no seu código e não estou a ver a utilidade do que está a ser utilizado (pode ser debouncing, mas se for isso não está muito bem executado).

Se a ideia é passar de ecrã quando se prime o botão, não estou a perceber para que serve o “delay(RefreshTela);”. O que acontece se essas linha forem retiradas do programa? Já agora, como disse antes, o “delay(250);” também me parece que não está a fazer nada, por isso, faço a mesma pergunta para este caso: o que acontece se essas linha forem retiradas do programa?
Depois de ver o vídeo, ainda reparo noutra coisa que não está correcta no seu programa. Se vir com atenção, o display “pisca”. É muito rápido, mas pode ver-se. Isso quer dizer que existe um refresh muito grande. Com um ecrã deste género, pode alterar apenas aquilo que muda de um ecrã para o outro e só fazer refresh quando for realmente necessário (isto é, quando uma tecla for premida ou quando o valor das variáveis que irá mostrar se altere). Outra coisa que eu não acho que esteja correcta no seu código é a repetição das mesmas linhas dentro do switch/case. Se está sempre a fazer a mesma coisa, é porque não precisa do switch. Qualquer coisa como a seguinte, retira estes elementos do programa:

// Programa : Display LCD 16x2 e modulo I2C
// Autor : André Abreu - MAR2016
// Exercicio #0034

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

// Inicializa o display no endereco 0x27
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

const int botaoPino = 3;
int Tela = 0;

int bconta_push = 0;
int bstatus_anterior = 0;
int bstatus_atual = 0;


int RefreshTela = 80;

int refresh = 1;

char tela_linha1[21];
char tela_linha2[21];

 
void setup()
{
  lcd.begin (16,2); 
  lcd.clear();
  pinMode(botaoPino, INPUT);
  digitalWrite(botaoPino, LOW);
  lcd.setBacklight(HIGH); 
}

void loop()
{

  bstatus_atual = digitalRead(botaoPino);

  if (bstatus_atual != bstatus_anterior){
    if (bstatus_atual == HIGH){
      bconta_push++;
      Tela = bconta_push;
      refresh = 1;
    } 
    else {
      Serial.println("off");
    }

    if (bconta_push > 4){
      bconta_push = 0; 
    }
  }
  bstatus_anterior = bstatus_atual;


  if (refresh == 1) {
     refresh = 0;
     switch (Tela) {
     
        default:
           strcpy(tela_linha1, "DEFAULT");
           sprintf(tela_linha2, "%d", bconta_push);
           break;
     
         case 1:
           strcpy(tela_linha1, "TELA #1");
           sprintf(tela_linha2, "%d", bconta_push);
           break;
     
         case 2:
           strcpy(tela_linha1, "TELA #2");
           sprintf(tela_linha2, "%d", bconta_push);
           break;
       
         case 3:
           strcpy(tela_linha1, "TELA #3");
           sprintf(tela_linha2, "%d", bconta_push);
           break;

         case 4:
           strcpy(tela_linha1, "TELA #4");
           sprintf(tela_linha2, "%d", bconta_push);
           break;
     }

     lcd.clear();
     lcd.setCursor(0, 0);
     lcd.print(tela_linha1);
     lcd.setCursor(0,1);
     lcd.print(tela_linha2);
  }
}

PS: Esqueci-me de comentar o post anterior.

andreabreu:
(…) eu preciso de uma multitarefa … um função com loop curto para ouvir o botão e outra não tão curta para ouvir os sensores.

Não, não é isso que precisa. Apenas precisa de um loop curto. Um loop “não tão curto” é um loop curto em que durante várias execuções desse loop não é feito nada. (como a parte dos sensores não está implementada, não sei exactamente do que estamos a falar, mas à primeira vista, eu diria que também não precisa de ser muito mais comprido do que o do botão).

andreabreu:
(…) no código está a variável “RefreshTela” de fato (…)

Por isso é que eu não a vi! Estava de fato e não a conheci. :slight_smile:

Caramba, obrigado! Vim aqui postar um código cheio de linhas e várias variáveis com o millis justamente para resolver o "piscar" de tela e você me dá essa aula mostrando o quanto estou enferrujado!

Agradeço sua paciencia e esforço.

Vou ali estudar as funções que utilizou!