Servo con teclado 4x4 y pulsador

Hola a todos, estoy realizando el proyecto de utilizar una contraseña para mover un servo (puerta) utilizando también un teclado 4x4 es un proyecto muy conocido el tema es que hay un pulsador que puede abrir y cerrar la puerta (por ejemplo abres la puerta utilizando la contraseña, la puedes cerrar utilizando el pulsador y viceversa) estoy presentando problemas al unir el teclado y el pulsador, el servo se mueve solo con el pulsador, ¿hay alguna secuencia para que estos dos elementos funcionen juntos ?

#include <Servo.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(22, 23, 24, 25, 26, 27);  // crea objeto y asigna pines a los cuales se
// encuentran conectados RS, E, D4, D5, D6, D7
#include <Keypad.h>
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {13, 8, 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

char password[7];
char realpassword[7] = "123456";
byte index = 0;
Servo puerta; // se nombra al servo
const int BOTON = 53;
int val = 0; //val se emplea para almacenar el estado del boton
int state = 0; // 0 LED apagado, mientras que 1 encendido
int old_val = 0; // almacena el antiguo valor de val
boolean abierta = false;
void setup() {
  lcd.begin(16, 2);
  puerta.attach(11);// conecta el servo a un pin
  pinMode(BOTON, INPUT); // y BOTON como señal de entrada
}

void loop() {
  lcd.setCursor(0, 0);
  char key = keypad.getKey();
  val = digitalRead(BOTON); // lee el estado del Boton
  if ((val == HIGH) && (old_val == LOW)) {
    state = 1 - state;
    delay(10);
  }
  old_val = val; // valor del antiguo estado
  if (key != NO_KEY) {
    lcd.println(key);
    password[index] = key;
    index++;
  }
  if (index == 6) {
    byte check = 0;
    for (int i = 0; i < 6; i++) {
      lcd.print(password[i]);
      if (password[i] == realpassword[i]) {
        check++;
      }
    }

    if (check == 6 ) {
      lcd.setCursor(0, 1);
      lcd.println("abierto");
      puerta.write(90); //puerta abierta
      delay(20);
      abierta = true;

    } else {
      lcd.setCursor(0, 1);
      lcd.println("cerrado");
      puerta.write(0); //puera cerrada
      delay(20);
      abierta = false;
    }
    index = 0;
  }

  if ( state == 1) {
    puerta.write(90); //puerta abierta
    delay(20);
    abierta = true;
  } else {
    puerta.write(0);
    abierta = false;
  }


  if ( state != 1) {
    puerta.write(0); //puerta abierta
    delay(20);
    abierta = false;
  } else {
    puerta.write(90);
    abierta = true;
  }

}

el botón debe estar en un estado hasta que se pulsa de nuevo, estoy usando un arduino mega, se que es un problema en la logica me gustaria algunas ideas.
gracias

Ambos bloques

if ( state ...

Hacen lo mismo, quita uno de los dos.

No se que le pasa a mi navegador, tengo problemas para copiar/pegar, no respeta los saltos de línea. :man_facepalming:t2:

A ver si se entiende...

val = ...
if (val... {
  state = ...
  delay(10);
  if (state) {
    // lo que sigue
  }
} else {
  char key = ...
  if (key !=...  {
    // lo que sigue
  }
}
old_val = val;

O sea, lees el pulsador, si se pulsó abres o cierras.
Si no se pulsó lees el teclado y etc.
Al final guardas el estado del pulsador.

Edito: No está bien lo que pensé porque el pulsador tiene prioridad sobre el teclado.
Lo pienso de nuevo a ver que se me ocurre.

gracias, cualquier idea es mas que bienvenida

Bueno, no es la mejor solución pero funciona mejor que tu primer código.
A ver si desde acá lo mejoramos.

Lo tienes en Wokwi para tu simulación

#include <Servo.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(22, 23, 24, 25, 26, 27);  // crea objeto y asigna pines a los cuales se
// encuentran conectados RS, E, D4, D5, D6, D7
#include <Keypad.h>
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {13, 8, 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

char password[7];
char realpassword[7] = "123456";
byte index = 0;
Servo puerta; // se nombra al servo
const int BOTON = 53;
int val = 0; //val se emplea para almacenar el estado del boton
int state = 0; // 0 LED apagado, mientras que 1 encendido
int old_val = 0; // almacena el antiguo valor de val
boolean abierta = false, abrir = false;
boolean abiertaAnt = false;
byte pos=0;
bool hubocambios = false;

void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  puerta.attach(11);// conecta el servo a un pin
  pinMode(BOTON, INPUT_PULLUP); // y BOTON como señal de entrada
  Serial.println("Empezando");
  
}

void loop() {
  byte check;

  char key = keypad.getKey();
  val = digitalRead(BOTON); // lee el estado del Boton
  if ((val == HIGH) && (old_val == LOW)) {
    state = 1 - state;
    delay(100);
    abrir = state;
    hubocambios = true;
  }
  old_val = val; // valor del antiguo estado
  
  if (key != NO_KEY) {
   lcd.setCursor(index, 0);
    lcd.println(key);
    password[index] = key;
    index++;
  }
  if (key == '#') {
    lcd.clear();
    Serial.println("Borrar pantalla.");
  }
  if (index == 6) {
    check = 0;
    for (int i = 0; i < 6; i++) {
      lcd.print(password[i]);
      if (password[i] == realpassword[i]) {
        check++;
      }
    }
    abrir = (check == 6)?true:false;
    hubocambios = true;
    index = 0;
    lcd.clear();
  }
  if (hubocambios) {
      
      if(abrir) {
          lcd.setCursor(0, 1);
          lcd.println("abriendo        ");
          puerta.write(90); //puerta abierta
          delay(1000);
          abierta = true;
          lcd.setCursor(0, 1);
          lcd.println("abierta         ");
          Serial.println("Puerta abierta");
      }
      else {
        lcd.setCursor(0, 1);
          lcd.println("cerrando        ");
          puerta.write(0);
          delay(1000);
          abierta = false;
          lcd.setCursor(0, 1);
          lcd.println("cerrada         ");
          Serial.println("Puerta cerrada");
      }
      hubocambios = false;
  }
}

El truco cuando dos cosas controlan lo mismo no es que poner condicionales que directamente actuén sobre esa salida sino hacer que cada cambio, sea que pulses o que ingreses la clave provoque el cambio de estado. Y luego con dicho estado actúas sobre la salida en este caso el servo.
En tu caso state abre o cierra según su estado pero listo.. ahi termina. Solo cuando lo presionas cambia algo a una nueva variable que será la que decida qué hacer.
Lo mismo con el keypad o teclado. Cuando ingreses la clave y sea correcta abrirás supongo.
Al final la variable abrir acciona solo cuando se produjo algún cambio en las dos anteriores.
Tal vez se pueda mejorar más aún. Hoy estoy medio cerrado para programar.
Mejoraría varias cosas.
Lo primero que no se vea la clave, poner * para cada dígito presionado. Lo segundo menos que menos mostrar la clave a comparar, eso lo haces porque estas en prueba, lo entiendo pero no es buena práctica.
Una tecla para ingresar a la comparación por teclado como # u otra.
Bueno, hasta acá.

1 Like

Hola, la logica es mucho mejor a lo que yo tenia, talves el unico detalle es que luego de abrir la puerta con la contraseña al quererla cerrar con el pulsador se debe presionar 2 veces, es algo que estare revizando, por lo pronto muchas gracias.

Revisa el monitor serie.
Hay que asegurarse que lo haga una sola vez.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.