Problemas con digitalRead en leds utilizando keypad.

Buenas!
Tengo un Arduino uno, soy novato y ando volviéndome loco con digitalRead y el estado de unos leds utilizando keypad.
Comento mi problema para ver si alguien me puede ayudar.Seguramente este haciendo muchas cosas mal, asi que desde ya muchas por cualquier consejo/ayuda y gracias!

Mi idea es poder encender una cantidad n de leds utilizando x boton del keypad. Por ej: si presiono la tecla “1” se encienda el led “a” y “b” y se presiono la tecla “2” se encienda el led “c” , “d” y “f” .

El problema que tengo es que presiono, por ejemplo, el boton “1” y enciende los leds, ya que entiendo, el digital read lee el estado 0 de los leds “a” y “b”, pero cuando vuelvo a precionar, el estado de los leds “a” y “b” me los sigue leyendo como 0.

Primero comento como tengo conectado todo:

  • 8 leds con el catado conectado al GND del arduino, y resistencia de 100 de por medio, el anodo a los pines del 2 al 9.
  • keypad 4x4 conectado conectado en los pines 10,11,12,13,A0,A1,A2 y A3.
  • Arduino alimentado por USB

y el codigo:

#include <Keypad.h>    

const byte ch = 4;     
const byte cv = 4;    
char keys[ch][cv] = {    
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte kh[ch] = {A3,A2,A1,A0}; 
byte kv[cv] = {10,11,12,13}; 

Keypad kpad = Keypad(makeKeymap(keys), kh, kv, ch, cv); 

const int leda = 2;
const int ledb = 3;
const int ledc = 4;
const int ledd = 5;
const int lede = 6;
const int ledf = 7;
const int ledg = 8;
const int ledh = 9;

void setup() {                
  Serial.begin(9600);   
  pinMode(leda, OUTPUT);
  pinMode(ledb, OUTPUT);
  pinMode(ledc, OUTPUT);     
  pinMode(ledd, OUTPUT);
  pinMode(lede, OUTPUT);
  pinMode(ledf, OUTPUT);
  pinMode(ledg, OUTPUT);
  pinMode(ledh, OUTPUT);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);
  pinMode(A3, INPUT_PULLUP);
  pinMode(A2, INPUT_PULLUP);
  pinMode(A1, INPUT_PULLUP);
  pinMode(A0, INPUT_PULLUP);
}


//functions 


void playleds(char leds[]) {
    for (int i = 0; i < sizeof(leds); i++) {
        int stateled = digitalRead(leds[i]);
        Serial.println("Led:"+String(i)+" - State:"+String(stateled));
        digitalWrite(leds[i], !stateled);
    }
}

void loop() {
    char key = kpad.getKey();
    if (key) {
        Serial.println("----");
        Serial.println("tecla: "+String(key));
        switch (key) {
            case '1': {
                char leds[] = {leda, ledb};
                playleds(leds);
                break;
                }
            case '2': {
                char leds[] = {ledc, ledd};
                playleds(leds);
                break;
                }
            case '3': {
                char leds[] = {lede, ledf};
                playleds(leds);
                break;
                }
    }
    Serial.println("----");
  } 
}

Nuevamente muchas gracias a cualquiera que me pueda explicar que estoy haciendo mal o darme cualquier consejo.

Saludos!!!

Hi,
Para ver yo entiendo tiene los leds con al catodo a ground y cuando oprimes el boton los leds prenden. Esto quire decir que usas el boton para energizar los leds ya que el catodo esta a ground. Si la entrada digitar te lee zero es que estas descargando el pin y al posiblemente el pin se queda flotando.Posiblemente tienes que anadirle a los pines un pullup resistor. Creo que lo mejor seria de hacer un dibujo del como tienes alambarado el systema y como estas alimentandolo para evitar dudas.

Hey Tauro, gracias por la respuesta.

Podrias recomendarme algun software para hacer el diagrama ? Preferentemente que sea software libre y corra en linux ?

Gracias!!!

Tienes una versión free de Eagle, tienes Fritzing, y mediante el navegador está EasyEDA.
Personalmente uso Eagle porque lo manejo desde hace muchos años (más de los que quisiera :wink: ).
Fritzing lo he usado, lo tengo instalado pero no me resulta tan cómodo como Eagle aunque es mas amigable para diseños con arduino.
EasyEDA solo lo he probado, parece muy interesante.

Respecto a tu código, he probado hacer la lectura de una salida con un led y me ha funcionado. La verdad nunca se me hubiese ocurrido leer un pin definido como salida (supongo que se accede a la báscula de salida del puerto porque obviamente no se podría leer de otro modo. En otro momento leeré la hoja de datos del ATmega para ver si estoy enfocado...).
Incluso modifiqué Blink para ver si iba bien y "va como piña".

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  byte pp = digitalRead(LED_BUILTIN);   
  digitalWrite(LED_BUILTIN, !pp);
  delay(1000);                      
}

Me sorprende que no te esté funcionando porque debería.

Una solución es que guardes en un array el estado de los led y en lugar del hacer la lectura del puerto los tomes desde el array (que a mi entender sería lo adecuado) aunque sea para probar si el problema es el digitalRead

Hola de nuevo y gracias por el tiempo en las respuestas!

El problema puntual que tengo es que al presionar un boton, prenden los dos leds (a y b), y cuando los vuelvo a presionar la salida de serial me muestra que ambos leds estan en 0 y no tira el LOW para apagarlos (debe tirar nuevamente el HIGH).
Esto no pasa siempre, si pulso muchas veces en algun momento empieza a apagar alguno de los leds y luego volver a prenderlo. Puede ser un tema de tiempos o que no llegue a detectar correctamente el estado del led ?

Adjunto una imagen que representa las conexiones. (las resistencias de los leds son de 100):

Hi,
Segun yo veo tu sketch estas haciendo un output "HIGH" y despues lees el pin con un "or" para que cambie el output pero cuando haces el read no cambias el pin para leerlo. Donde lees el keyboard en el sketch. Seria ideal que bajaras el sketch completo.

Ahora si que me mareaste @tauro0221
¿De que OR hablas?
Cambia el estado con una negación

Y no hace falta cambiar de salida a entrada para leer el estado del pin.
Cuando está en modo OUTPUT una lectura del pin devuelve el estado del buffer de salida (confirmado por la hoja de datos del ATmega) y es una operación totalmente válida, no es un "rebusque" de programación, es algo previsto en el diseño del micro.
La verdad, gracias al código de @ardu2010 me "desayuné" que era una operación válida, nunca se me hubiese ocurrido, hubiese guardado el estado en una variable para luego consultarlo.

Me da la impresión que el código está completo.

Ya sé cual es el problema, getkey() no bloquea el flujo del programa, entonces mientras está la tecla pulsada continuamente está cambiando el estado de los LED.

¿Por qué?
Hace una primera pasada, encuentra una tecla pulsada y enciende los LED correspondientes.
Pega la vuelta al loop, en la nueva pasada todavía no soltaste la tecla, la encuentra pulsada entonces cambia el estado de los LED. ¡Los apaga!

Cuando la sueltas pueden quedar apagados o encendidos, según el estado en que estaban, así que solo si tienes suerte quedan en el estado que esperas (50% de probabilidades de tener suerte :wink: ).

Prueba esto

void loop() {
  char key = kpad.getKey();
  while(keypad.getKey() != NO_KEY){} // espera que sueltes la tecla si estuviese pulsada
  if (key) {

Comenta si te resultó.

Hi,
Pido disculpa a lo que yo referia es que cuando usas !var si la variable es HIGH la cambia a LOW puede ser que me explique mal usando el or creyendo que era al inverso.

@tauro0221 Yo creí que te habías pasado con el vodka. Jeje
Abrazo

Hi,
Jajajaj Gracias gatul pero yo bebo Rum con hielo.

gatul:

void loop() {

char key = kpad.getKey();
 while(keypad.getKey() != NO_KEY){} // espera que sueltes la tecla si estuviese pulsada
 if (key) {

Primero que nada muchas gracias por la ayuda!
Intente agregar esa linea pero la problematica es similar. Si agrego un Serial.println dentro del for que enciende los leds, el digitalread me da siempre 0. En ocasiones toma el valor de 1, pero de manera random y por lo gral de uno de los dos led que intento modificar. Puede esto tener algo que ver con conexiones y/o resistencias?
Por otra parte, puede ser que este afectando la manera en que estoy utilizando las variables que refieren a los pines de los leds ?

dejo mi codigo actualizado hasta el momento.

#include <Keypad.h> 

// keypad
const byte ch = 4;     // n hoz
const byte cv = 4;    // n ver
char keys[ch][cv] = {    // key layout
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte kh[ch] = {A3,A2,A1,A0}; // hor
byte kv[cv] = {10,11,12,13};   // ver

Keypad kpad = Keypad(makeKeymap(keys), kh, kv, ch, cv);  // kpad obj

// leds
#define leda 2
#define ledb 3
#define ledc 4
#define ledd 5 
#define lede 6
#define ledf 7
#define ledg 8
#define ledh 9

void setup() {                
  Serial.begin(9600);   
  // initialize the digital pin as an output.
  pinMode(leda, OUTPUT);
  pinMode(ledb, OUTPUT);
  pinMode(ledc, OUTPUT);     
  pinMode(ledd, OUTPUT);
  pinMode(lede, OUTPUT);
  pinMode(ledf, OUTPUT);
  pinMode(ledg, OUTPUT);
  pinMode(ledh, OUTPUT);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);
  pinMode(A3, INPUT_PULLUP);
  pinMode(A2, INPUT_PULLUP);
  pinMode(A1, INPUT_PULLUP);
  pinMode(A0, INPUT_PULLUP);
}

/*char ledsi[8][2] = {
    {leda,ledb,ledc,ledd,lede,ledf,ledg,ledh},
    {0,0,0,0,0,0,0,0}
};*/

/*void ledsact() {
    for (int i = 0; i < sizeof(leds); i++) {
        Serial.println(leds[i][i]);
    }
}*/

void ledloop(char actled[]) {
    for (int i = 0; i < sizeof(actled); i++) {
        int stateled = digitalRead(actled[i]);
        Serial.println(stateled);
        digitalWrite(actled[i], !stateled);
        }
}

void loop() {
    char key = kpad.getKey();
    while(kpad.getKey() != NO_KEY){} // espera que sueltes la tecla si estuviese pulsada
    if (key) {
        Serial.println("----");
        Serial.println("tecla: "+String(key));
        switch (key) {
            case '1': {
                char actled[] = {leda, ledb};
                ledloop(actled);
                break;
                }
            case '2': {
                char actled[] = {ledc, ledd};
                ledloop(actled);
                break;
                }
            case '9': {
                char actled[] = {lede, ledf};
                ledloop(actled);
                break;
                }
    }
    Serial.println("----");
  }
}

No es el manejo de los LED, como no tengo teclado lo probé con un par de pulsadores y eso funciona bien.

Tengo la sospecha que el problema puede ser que definiste las entradas como INPUT_PULLUP, defínelas como INPUT y luego me comentas a ver si era eso.

Saludos

PD: Bien por darte cuenta que había cometido un error en el while. No fue intencional.

De este modo lo tienes resuelto.
Modifica solo el loop y verás lo que te digo.

void loop() {
    char key = kpad.getKey();
    
    if (key != NO_KEY){
        Serial.println("tecla: "+String(key));
        switch (key) {
            case '1': {
                char actled[] = {leda, ledb};
                ledloop(actled);
                break;
                }
            case '2': {
                char actled[] = {ledc, ledd};
                ledloop(actled);
                break;
                }
            case '9': {
                char actled[] = {lede, ledf};
                ledloop(actled);
                break;
                }
    }
  }
}

Pero así estamos como al principio...

Si el problema es que no les gusta el while al menos hay que hacer esto

void loop() {
    static char oldkey = NO_KEY;

    char key = kpad.getKey();
    
    if (key != oldkey){
        Serial.println("tecla: "+String(key));
        switch (key) {
            case '1': {
                char actled[] = {leda, ledb};
                ledloop(actled);
                break;
                }
            case '2': {
                char actled[] = {ledc, ledd};
                ledloop(actled);
                break;
                }
            case '9': {
                char actled[] = {lede, ledf};
                ledloop(actled);
                break;
                }
       }

     oldkey = key;

    }
}

Sino los led van a oscilar mientras la tecla esté pulsada

Yo hice la simulación en Proteus porque como este código tenía algo raro quería probarlo.
A mi me funciona como el dice

El problema que tengo es que presiono, por ejemplo, el boton "1" y enciende los leds, ya que entiendo, el digital read lee el estado 0 de los leds "a" y "b", pero cuando vuelvo a precionar, el estado de los leds "a" y "b" me los sigue leyendo como 0.

Presiono y los pongo en 1, vuelvo a presionar y los pongo en 0

Yo presioné la tecla 2, 3 veces y esas fueron las respuestas del código.
Lo raro para mi fue esto

 case '1': {
                char actled[] = {leda, ledb};
                ledloop(actled);
                break;
                }

3 veces asigna char actled y no se explicar porque asi funciona y si lo hago como variable local al principio del loop da error y además me pide obviamente asignar el tamaño del vector.

@surbyte Yo te creo que funcione en la simulación.
Yo lo probé en Sofia (simulando botones) y andaba como el traste.

Pero segun Arduino Playground

char getKey()

Returns the key that is pressed, if any. 
This function is non-blocking.

Y si es "non-blocking" mientras esté pulsada una tecla va a entrar al if() tantas veces como se repita el loop y los LED van a cambiar de estado en cada pasada. O sea van a estar parpadeando (aunque para nuestras retinas estén simplemente encendidos).
Y cuando se libere la tecla los LED quedarán en el estado que los dejó el último if(), 50% de probabilidades que queden encendidos, 50% apagados.

¿Me explico?

Por eso, o espera la liberación con un while o compara con el estado anterior (tambien puede usar getState() o keyStateChanged(), por ej., pero ya es otro tema)

Bueno, primero que nada disculpas por la demora en mi respuesta. Los estudios me estuvieron castigando un poco. Ademas de eso, muchas gracias por la ayuda y las respuestas.

Saque los INPUT_PULLUP y probé los últimos dos loops que pasaron y el problema sigue siendo el mismo, pero si es cierto que el resultado suena a lo que comenta @gatul.

Iniciando el arduino algunas veces funciona que prenda los dos leds, otras prende uno y apaga el otro y asi...

La única duda que me queda es que si esta entrando una y otra ves en el loop, no estaría entrando en el case 1, cierto ? porque en teoría debería ir a a la función ledloop y el serial.println repetirse mientras mantenga apretado el boton, y esto no sucede.

Nuevamente muchas gracias!