Bucle hasta pulsar tecla (solucionado)

Buenos dias,

Desde que compre el Arduino, he ido avanzando poco a poco y voy complicando mis proyectos cada vez un poco mas. Este ultimo estoy usando un ldc 20x4 un teclado 3x4 y y sensores de temperatura y humedad.
Lo que intento en este proyecto es lo que me tiene atascado, y es escoger desde el teclado la opcion que quiero ver, temperatura o humedad y mostrar el dato mientras no se pulse #. Esto es lo que no consigo que funcione, hacer un bucle hasta pulsar una tecla. Lo he probado con if, con for, con while.

He de decir que voy leyendo y probando y a base de prueba y error voy sacando conclusiones y creo que for no es una buena opcion para lo que quiero conseguir pero y las otras funciones?

Ayuda por favor

Jopapa
www.jopapa.me

Porque no publicas tu código, así como un esquemático de tu conexión, ya que lo que tu quieres hacer, se puede hacer con una condicional del tipo "if" pero dices que ya lo intentaste y que aun asi no te funciona, debe haber algún fallo por ahí, de otra forma no podríamos ayudarte.

Coincido con mike_117. Difícil intentar ayudarte sin ver el código.

Do, for, while son todas maneras de hacer un bucle, con diferencias menores pero esencialmente lo mismo, mayormente intercambiables.

os pongo aqui el codigo que no funciona, a ver que podeis ver. Comentar que estoy usando puertos analogicos y digitales para el teclado. Esto ultimo lo comento porque he leido por algun sitio que se pueden usar los puertos analogicos como digitales pero que dejan de ser analogicos y como estaba leyendo un lm35 por un puerto analogico he pensado que tal vez fuese esto pero no tampoco funciona porque como veis ahora ya no estoy leyendo puertos

Gracias

void temperatura(){  

char bb = keypad.getKey();
 lcd.clear();
 
 while (bb != '#')
 {      
     temp = millis()/1000; 
     lcd.setCursor(2, 0);
     lcd.print("PRUEBA DE OPCIONES");
     lcd.setCursor(2, 3);
     lcd.print("PULSA # PARA SALIR");
     lcd.setCursor(5, 1);
     lcd.print("TEMPERATURA");
     lcd.setCursor(8, 2);
     lcd.print(temp);
     bb = keypad.getKey();
     delay(6000);
    
   }
}

Hola CorreToN,

Lo mas sencillo que se me ocurre es que uses una interrupcion con temporizador que lea el teclado
y actualice bb cada cierto tiempo (por ejempo cada medio segundo).

Este es el enclace de la libreria de interrupcion con temporizador:
https://code.google.com/p/arduino-timerone/

La implementacion en tu codigo luciria algo como:

#include "TimerOne.h"

char bb = ' ';
char bb1 = ' ';
 
void setup()
{
  Timer1.initialize(500000);         // inicia timer1 y lo ajusta a un periodo de medido segundo
  Timer1.pwm(9, 512);                // Configura pwm en el pin 9, 50% ciclo util
  Timer1.attachInterrupt(leer_teclado);  // interrumpe a la subrutina leer_teclado() cada vez medio segundo 
}
 
void leer_teclado()
{
  // Leer y actualizar teclado cada medio segundo  
  char bb = keypad.getKey();
  if(bb == '#'){
    bb1 = '#';
  }
}
 
void loop()
{

  //.......................................
  if (bb1 == '#') {
  // Aqui va lo que tu codigo tiene que hacer cuando la tecla '#' es pulsada  
  //.......................................
  }

  
}

Puede cambiar el pin de interrupcion en vez de 9 por otro con funcionalidad pwm

Saludos,

p

EDITADO LUEGO: Aun mejor, puedes usa la funcion millis() como en el famoso
ejemplo de blink sin retraso (blink without delay).

p

void temperatura(){  

  char bb = keypad.getKey();
  unsigned long lastTime = 0;
  lcd.clear();
  
  while (bb != '#')
  {
    if(millis() - lastTime >= 6000)
    {      
      temp = millis()/1000; 
      lcd.setCursor(2, 0);
      lcd.print("PRUEBA DE OPCIONES");
      lcd.setCursor(2, 3);
      lcd.print("PULSA # PARA SALIR");
      lcd.setCursor(5, 1);
      lcd.print("TEMPERATURA");
      lcd.setCursor(8, 2);
      lcd.print(temp);
      lastTime = millis();
    }
  bb = keypad.getKey();     
  }
}

comote indicó Pallister, el problema es que usas la función delay() que para lo que quieres hacer no sirve, ya que esta función detiene el loop principal hasta que se cumpla la condición, por lo cual no puedes hacer nada en ese tiempo.
Con la función millis() puedes hace otra cosa mientras la condición no se cumple, en tu caso, puede seguir leyendo que tecla ha sido pulsada.

Prueba con el código que te dejé no lo he probado, pero por lo menos para que entiendas como funciona, si no lo entiendes busca más sobre esa función (millis)

Gracias por vuestras respuestas pero creo que el problema no es cuestión de interrupción ni del delay, este ultimo estaba para ver que hacia el bucle con diferentes opciones.
La cuestión es si bb fuese un entero que en incremento en el bucle funciona sin problema, la cuestión esta en cuando bb es un carácter del leyenda que no consigo que el while la pille y salga del bucle al complirse la condición. Esa es mi duda como comparar un carácter dentro de un bucle

CorreToN me pregunto si has visto otros post? Ves alguno que publique sus códigos como tu o los ves de modo diferente? Bueno. Como ya te habras dado cuenta que te han respondido con códigos que lucen distinto eso se debe al uso del tag. Ve al punto 7 de Normas del Foro y ahi te dice como usar los tags.

Si tu problema es que no sale porque no agregas un simple Serial.print(bb) para saber que estas digitando y que esta comparando el while.
Hay que aprender a valerse por si solo usando los recursos.

Prueba a ver si char bb=keypad.getkey(); devuelve un '#' cuando digitas esa tecla o tienes mal asignada la tecla u otro sea el problema.

Hiciste una prueba tecla a tecla viendo que responde Arduino al presionarlas? Otro paso simple que te asegura que tu tabla de asignación concuerda con filas y columnas.

Surbyte, he visto otros posts, asi que te pido disculpas por haber puesto el codigo de forma diferente a como se debe hacer, ya esta corregido, de nuevo pido disculpas si puede haber molestado este error.

Sobre mi problema, es como digo, que no se el motivo de que cuando salto a esa parte de programa que se llama temperatura, char bb=keypad.getkey(); no coge la tecla que debe, es mas ya coge algo sin pulsar nada, tal vez rebotes. Para ver eso, pues al igual que para ver si con un entero si se salia del bucle, logicamente agregue un lcd.print(bb) y lo que pinta es el cursor no la tecla que se pulsa. Ese es mi problema

El mapeo del keypad, entiendo que debe estar bien hecho puesto que para saltar dentro de temperatura, antes ya he tenido que pulsar esa opcion y funciona.

Y te aseguro surbyte, que intento valerme por mi mismo, usando mis propios recursos, como digo en el primer post, voy aprendiendo leyendo y con prueba y error. Es depues de que ya llevo horas haciendo pruebas que pido ayuda o lo consulto por el foro.
Cierto es que mis unicos posts hasta ahora son para consultar y pedir ayuda, pero espero que con algo mas de tiempo tambien yo pueda ayudar

Pido de nuevo disculpas por las molestias que haya podido causar

Bien. Ante todo te felicito por las correcciones que has hecho a tus post, no molesta, solo ayuda a que todos lo veamos mejor. Como dice Max_saeta "duele a los ojos", jaja me gusta su expresión

Tu dices que antes ya lo has usado y funciona para cargar la temperatura y luego cuando lo necesitas no lo toma. Entonces algo demora tu programa o tienes un delay que esta molestando y te hace perder pulsaciones de teclas.
Veamos que descubro.
Yo sigo sin ver todo tu código y hasta que no lo vea poco puedo aportar.

Agrega tu código completo usando tags por favor.

Te pongo todo el codigo por si ves alguna cosa, el resto de codigo veras que poca cosa hace a parte de pintar el lcd, pero es para ir probando y aprendiendo

gracias!!

p.d. Ahora antes de postear le doy al preview :wink:

#include <LiquidCrystal.h>
#include <Keypad.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int cursorcol;
int tecla;
int mediciontemperatura;
int prueba;
float temp;

const byte filas = 4; //cuatro filas 
const byte columnas = 3; //tres columnas
char keys[filas][columnas] = {
        {'1','2','3'},
        {'4','5','6'},
        {'7','8','9'},
        {'*','0','#'}
        };
byte pinsfilas[filas] = {10, 9, 8, 7}; //PINS ENTRADAS FILAS EN ORDEN F1 F2 F3 F4
byte pinscolumnas[columnas] = {6, 14, 15}; //PINS ENTRADA COLUMNAS EN ORDEN C1 C2 C3
Keypad keypad = Keypad( makeKeymap(keys), pinsfilas, pinscolumnas, filas, columnas );


void setup(){
  lcd.begin(20, 4);

}

void loop(){
 /*
   lcd.clear(); ESTO NO FUNCIONA PARA BORRAR LA PANTALLA PARPADEA DEMASIADO
   delay(100)
  */ 
  lcd.setCursor(1, 0);
  lcd.print("PRUEBA DE OPCIONES");
  lcd.setCursor(1, 1);
  lcd.print("1. TEMPERATURA");
  lcd.setCursor(1, 2);
  lcd.print("2. HUMEDAD");
  lcd.setCursor(1, 3);
  lcd.print("3. ILUMINACION");
  
  
  char key = keypad.getKey();
  
  switch (key){
    
    case '1':
    delay(200);
    temperatura();
  break;
    case '2':
    humedad();
  break;
   case '3':
    iluminacion();
  break;
 
 }  
}

void temperatura(){  

 char bb;
  int bobo;
  lcd.clear();
  while (bb != '#')
  {
  char bb = keypad.getKey();    
      temp = millis()/1000; 
      lcd.setCursor(2, 0);
      lcd.print("PRUEBA DE OPCIONES");
      lcd.setCursor(2, 3);
      lcd.print("PULSA # PARA SALIR");
      lcd.setCursor(5, 1);
      lcd.print("TEMPERATURA");
      lcd.setCursor(8, 2);
      lcd.print(bobo);
      //char bb = keypad.getKey();
      bobo ++;      
   }
 }
 
void humedad(){
    
      lcd.clear();
      lcd.setCursor(2, 0);
      lcd.print("PRUEBA DE OPCIONES");
      lcd.setCursor(2, 3);
      lcd.print("PULSA # PARA SALIR");
      lcd.setCursor(5, 1);
      lcd.print("HUMEDAD");
      lcd.setCursor(8, 2);
      lcd.print("0,0");
      delay(3000);
      lcd.clear();
  }
void iluminacion(){
    
      lcd.clear();
      lcd.setCursor(2, 0);
      lcd.print("PRUEBA DE OPCIONES");
      lcd.setCursor(2, 3);
      lcd.print("PULSA # PARA SALIR");
      lcd.setCursor(5, 1);
      lcd.print("ILUMINACION");
      lcd.setCursor(8, 2);
      lcd.print("0,0");
      delay(3000);
      lcd.clear();
  }

Y donde falla puntualmente?

Mi intención era estar mostrando temperatura hasta pulsar salir, en este caso veras que lo que hace es mostrar milis hasta pulsar # pero se queda dentro del bucle no sale pulses lo que pulses

Correton:

El problema esta en el uso de delay(), hay que cambiarlo por millis().

Acá te paso como me parece que debería ser el código.

Lo hice de ojo porque no tengo la libraría, si no compila por ahí es por algún error menor (jeje).

También cambie “char key = keypad.getKey();” porque no veo sentido en que siga si no se entro ninguna tecla.

Revisalo y contame.

Saludos.

#include <LiquidCrystal.h>
#include <Keypad.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

long timepofinaldisplay = 0;

int cursorcol;
int tecla;
int mediciontemperatura;
int prueba;
float temp;

const byte filas = 4; //cuatro filas 
const byte columnas = 3; //tres columnas
char keys[filas][columnas] = {
        {'1','2','3'},
        {'4','5','6'},
        {'7','8','9'},
        {'*','0','#'}
        };
byte pinsfilas[filas] = {10, 9, 8, 7}; //PINS ENTRADAS FILAS EN ORDEN F1 F2 F3 F4
byte pinscolumnas[columnas] = {6, 14, 15}; //PINS ENTRADA COLUMNAS EN ORDEN C1 C2 C3
Keypad keypad = Keypad( makeKeymap(keys), pinsfilas, pinscolumnas, filas, columnas );


void setup(){
  lcd.begin(20, 4);
}

void loop(){
  while( millis() < timepofinaldisplay ) {
    if( '#' == keypad.getKey() ) break;
  }
  
  lcd.clear();

  lcd.setCursor(1, 0);
  lcd.print("PRUEBA DE OPCIONES");
  lcd.setCursor(1, 1);
  lcd.print("1. TEMPERATURA");
  lcd.setCursor(1, 2);
  lcd.print("2. HUMEDAD");
  lcd.setCursor(1, 3);
  lcd.print("3. ILUMINACION");
  
  while ( (key = keypad.getKey() ) == NO_KEY );
  
  switch (key){    
    case '1':
    temperatura();
  break;
    case '2':
    humedad();
  break;
    case '3':
    iluminacion();
  break;
 
 }  
}

void temperatura(){ 
  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("PRUEBA DE OPCIONES");
  lcd.setCursor(2, 3);
  lcd.print("PULSA # PARA SALIR");
  lcd.setCursor(5, 1);
  lcd.print("TEMPERATURA");
  lcd.setCursor(8, 2);
  lcd.print("0,0");
  
  timepofinaldisplay = millis() + 3000;
 }
 
void humedad(){    
  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("PRUEBA DE OPCIONES");
  lcd.setCursor(2, 3);
  lcd.print("PULSA # PARA SALIR");
  lcd.setCursor(5, 1);
  lcd.print("HUMEDAD");
  lcd.setCursor(8, 2);
  lcd.print("0,0");
  
  timepofinaldisplay = millis() + 3000;
  }
void iluminacion(){    
  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("PRUEBA DE OPCIONES");
  lcd.setCursor(2, 3);
  lcd.print("PULSA # PARA SALIR");
  lcd.setCursor(5, 1);
  lcd.print("ILUMINACION");
  lcd.setCursor(8, 2);
  lcd.print("0,0");
  
  timepofinaldisplay = millis() + 3000;
  }

Perrociego perdona no haber contestado antes, he ido bastante liado estos dias. Decirte que el codigo que has puesto funciona, ahora me queda investigar porque funciona y como. La funcion millis lo hace funcionar pero mi intencion es que una vez entre en temperatura() no salga por si solo si no es mediante la pulsacion de la tecla y con millis sale al cabo de un tiempo, pero gracias ya puedo seguir un poco mas :grin:

Ya esta funcionando y ya se donde estaba el fallo, os pongo el codigo, en si no hace gran cosa, mi intencion era la de probar opciones con el teclado y entrar en bucles que el usuario eligiera. El error estaba en crear una variable char y asignarle a esta variable “keypag.getKey” para compararala dentro del bucle while. Cuando comparas directamente “keypad.getKey” funciona perfecto.
Perrociego he quitado todo el tema de millis, porque me interesaba que una vez estuviera dentro de una de las opciones, se quedara indefinidamente hasta pulsar, con lo de millis acababa saliendo.

gracias!!! ahora a complicarse mas :smiley: me encanta

#include <LiquidCrystal.h>
#include <Keypad.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

long timepofinaldisplay = 0;

int cursorcol;
int tecla;
int mediciontemperatura;
int prueba;
float temp;
char key;
int bobo=0;
int dato;

const byte filas = 4; //cuatro filas 
const byte columnas = 3; //tres columnas
char keys[filas][columnas] = {
        {'1','2','3'},
        {'4','5','6'},
        {'7','8','9'},
        {'*','0','#'}
        };
byte pinsfilas[filas] = {10, 9, 8, 7}; //PINS ENTRADAS FILAS EN ORDEN F1 F2 F3 F4
byte pinscolumnas[columnas] = {6, 14, 15}; //PINS ENTRADA COLUMNAS EN ORDEN C1 C2 C3
Keypad keypad = Keypad( makeKeymap(keys), pinsfilas, pinscolumnas, filas, columnas );


void setup(){
  lcd.begin(20, 4);
}

void loop(){
  

  lcd.setCursor(1, 0);
  lcd.print("PRUEBA DE OPCIONES");
  lcd.setCursor(1, 1);
  lcd.print("1. TEMPERATURA");
  lcd.setCursor(1, 2);
  lcd.print("2. HUMEDAD");
  lcd.setCursor(1, 3);
  lcd.print("3. ILUMINACION");
   
  
  while ( (key = keypad.getKey() ) == NO_KEY );
  
  switch (key){    
    case '1':
    temperatura();
  break;
    case '2':
    humedad();
  break;
    case '3':
    iluminacion();
  break;
 
 }  
}

void temperatura(){ 
 lcd.clear();
  while (keypad.getKey() !='#'){
  mediciontemperatura= analogRead(2);
  
  lcd.setCursor(2, 0);
  lcd.print("PRUEBA DE OPCIONES");
  lcd.setCursor(2, 3);
  lcd.print("PULSA # PARA SALIR");
  lcd.setCursor(5, 1);
  lcd.print("TEMPERATURA");
  lcd.setCursor(8, 2);
  dato=(500*mediciontemperatura)/1023;
  lcd.print(dato);
  }
 }
 
void humedad(){    
  lcd.clear();
  while (keypad.getKey() !='#'){
  lcd.setCursor(2, 0);
  lcd.print("PRUEBA DE OPCIONES");
  lcd.setCursor(2, 3);
  lcd.print("PULSA # PARA SALIR");
  lcd.setCursor(5, 1);
  lcd.print("HUMEDAD");
  lcd.setCursor(8, 2);
  lcd.print("0,0");
  
   }
  }
void iluminacion(){    
  lcd.clear();
  while (keypad.getKey() !='#'){
  lcd.setCursor(2, 0);
  lcd.print("PRUEBA DE OPCIONES");
  lcd.setCursor(2, 3);
  lcd.print("PULSA # PARA SALIR");
  lcd.setCursor(5, 1);
  lcd.print("ILUMINACION");
  lcd.setCursor(8, 2);
  lcd.print("0,0");
  
  }
  }

Hola CorreToN

Me alegro que lo hayas solucionado. Lo que vos querías era mas sencillo que lo que yo entendí y propuse.

En cuanto al código de las funciones temperatura(), humedad(), etc quedaron en un bucle rabioso que no me extrañaría haga parpadear la pantalla. Pondría en cada uno un delay(100) o algún valor pequeño que no se sintiera como que se traba el programa al usarlo.
Mas avanzado, y superior, sería mandar lcd.print(); al inicio, y luego solo cuando cambiara la lectura.

Saludos