Teclado mecánico de macros para Tablet/PC/MAC

Hola a todos, les cuento

Estoy intentando montar un teclado usando Arduino Micro y la parte del circuito la tengo correcta pero estoy teniendo problemas con el código y espero que ustedes aquí me puedan echar un cable para determinar que puedo estar haciendo mal.

Por ahora, estoy intentando solo un botón conectado al pin8 que abre una pestaña del navegador cada vez que se pulsa. He puesto sólo un botón por ahora a modo de prueba para ver si me funciona todo. Este es el código que tengo:

#include <Keyboard.h>

void setup() {
  pinMode(8, INPUT);
  Keyboard.begin();
}

void loop() {
  if (readButton(8)) {
    doAction(8);
  }
}

boolean readButton(int pin) {
  if (digitalRead(pin) == HIGH) {
    delay(10000);
    if (digitalRead(pin) == HIGH) {
      return true;
    }
  }
  return false;
}

void doAction(int pin) {
  switch (pin) {
    case 8:
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press('t');
      delay(10000);
      Keyboard.releaseAll();
      break;

  }
}

No da ningún error al comprobarlo con el IDE de Arduino ni al subirlo al Arduino Micro, pero una vez que lo subo empieza a abrir pestañas automáticamente durante 10 segundos, luego para 10 segundos y vuelta a empezar. Todo esto lo hace automáticamente sin llegar a pulsar ningún botón. ¿Alguién sabe que puedo estar haciendo mal? He revisado el código y no caigo en nada.

Muchas gracias por adelantado como siempre.

Un saludo

Lo que debes desterrar es el uso de delay() y ya que estas comenzando aprender a programar usando millis()

Ve a Documentación => Indice de temas tutoriales => millis() y también lee máquina de estados.

Luego de leer ambos tutoriales tal vez estes mas confundido que antes.

Pero coméntanos las dudas y replantearemos este código.

Hola Surbyte, muchas gracias por la respuesta.

Me he bajado el PDF sobre los milis(), aunque explica más bien como funciona que lo que hace. Casi me ha parecido más útil el hilo sobre Procesos en paralelo. Y, si te soy sincero, el hilo de máquinas de estado lo he entendido bien pero no soy capaz de ver la relación con los dos anteriores más que para entender los diferentes estados.

Cómo bien advertías ahora ando un poco más dudoso, aunque menos de lo que me esperaba. jeje Me habías asustado.

Corrígeme si me equivoco, por favor. ¿Me sugieres no usar la función delay() en este caso porque igual me está impidiendo que el evento se ejecute correctamente y por eso sería mejor utilizar la función milis() que me permitiría ejecutar otra cosa (en este caso el evento) mientras Arduino no hace nada más que esperar?

Entiendo que por mucho que pulse el botón ahora mismo no hace nada porque "está demasiado ocupado" con los delays, ¿no? ¿Pero entonces porque Arduino ejecuta la acción por si solo? Es lo que no entiendo. Esa acción en principio solo se ejecutaría cuando se pulsa el botón, ¿no? independientemente del uso de delay().

Perdona si he dicho alguna burrada o si mi comentario demuestra todo lo perdido que estoy.

Gracias por tu ayuda

Saludos

Ok, voy a explicar tu error con delay() y luego veremos como reemplazarlo con millis() o una maquina de estados si hace falta.

Lo primero que debemos aclarar es como esta conectado el pin 8 a tu arduino, algo que no has dicho.
Si esta simplemente conectado a un pulsador te digo que ahi esta tu error. Si tiene una resistencia pull-down no te digo nada.
Pero si no la tiene eso explicaría porque recibes acciones constantes.

Esperaré a que respondas como para continuar.
Mas alla de una cosa o la otra para que pones 10 segundos para detectar un estado... no es una barbaridad?

Hola Surbyte, muchas gracias por la respuesta.

Pues el botón lo tengo conectado al pin8 y con una resistencia de 10k. He subido una foto que puedes ver en este enlace e igual ayuda.

Lo de los diez segundos lo tengo puesto ahora temporalmente, inicialmente serían 10 milisegundos, pero el programa hacía las acciones tan rápidas que me colapsa el sistema.

Gracias de nuevo por la ayuda.

Un saludo

Prueba esto a ver como se comporta

#include <Keyboard.h>
bool status, statusAnt = false;

void setup() {
  pinMode(8, INPUT);
  Keyboard.begin();
}

void loop() {
  status = digitalRead(8);
  if (status && !statusAnt) {
      doAction(8);
  }
  statusAnt = status;
}

void doAction(int pin) {
  switch (pin) {
    case 8:
          Keyboard.press(KEY_LEFT_GUI);
          Keyboard.press('t');
          Keyboard.releaseAll();
          break;
  }
}

Exactamente igual. Según subo el programa empieza a ejecutar la acción a toda velocidad como si no hubiera un mañana. Tanto que incluso después de desenchufar Arduino sigue ejecutándose la acción y tengo que forzar la salida de la aplicación. Es como si ignorara que la acción tiene que ejecutarse cuando se pulsa un botón y empieza a ejecutarla automáticamente a todo velocidad una detrás de otra :frowning:

Hola a todos,

Me encuentro en un proyecto donde estoy desarrollando un teclado con una Pro Micro. Como estoy aprendiendo, había empezado con un esquema más complicado de lo necesario donde cada una de las teclas (12) iban conectadas su correspondiente I/O en Arduino usando una resistencia 10k conectada al GND, lo que en total me hacía utilizar doce cables, con doce resistencias para doce I/O en Arduino. Está bien, pero había una manera más sencilla.

Gracias a la ayuda de este foro, aprendí que un teclado matricial de 4x3 me iba a ahorrar muchos cables, ya que ahora sólo necesitaba 7; 4 para las filas y 3 para las columnas del teclado. Pero ahora me ha surgido una duda que espero me pudiera aclarar alguien.

He estado leyendo sobre el tema y me he fijado que, en un teclado matricial, todos los pulsadores de la misma fila están conectados entre sí usando un diodo. Ya no se usan resistencias, para evitar ghosting y masking cuando pulsamos más de una tecla a la vez. Entiendo que se usan diodos porque permiten el paso de la corriente en un sentido, algo que la resistencia no hace. Por lo tanto, ¿Que pasaría si en mi teclado matricial pusiera resistencias de 10k como hacía entes en lugar de diodos? ¿El diodo también me ofrece la resistencia que antes tenía que usar para no fundir el pulsador?

Otra duda que me ha surgido es que, en este nuevo esquema matricial, tanto las filas (4) como las columnas (3) van cada una conectadas a un I/O de Arduino usando en total 7. Pero hay nada conectado a ni a la corriente de 5V ni a GND en todos los ejemplos que he visto. ¿Esto a que se debe?

Aquí les dejo una foto de un teclado más grande pero que ilustra bien a lo que me refiero.

Agradecería si me pudieran explicar un poco estas dudas que tengo.

Un saludo de antemano, y muchas gracias como siempre.

Donde viste que hacen falta diodos?

Te sugerí esta página Keypad del Arduino Playground

Y en ella se ven cosas como éstas, Keypad Tutorial

pero básicamente cualquier teclado matricial es un entrecruzamiento XY de filas y columnas de pulsadores sin Resistencias ni diodos.

Acá puedes verlo link

Cuando ves resistencias es porque se busca simplificar pines como en este caso

o porque no se aprovechaba la opción de usar la resistencia interna al configurar los pines de entrada con pinMode, antes no se usaba la opcion INPUT_PULLUP

O sea que la versión Resistencia puede usarse dependiendo de como configures los pines de entrada.

Con diodos y resistencias

Este sería un caso como el que mencionas

Hola Surbyte, muchas gracias como siempre por tu mensaje y explicaciones. Te cuento:

No he visto en ningún lado que se sugiera explícitamente el uso de diodos entre los pulsadores. Sin embargo, como comentaba en mi primer mensaje, se recomienda para evitar problemas cuando necesitamos pulsar dos o más botones a la vez. Sin los diodos podríamos encontrar problemas de ghosting donde un tercer botón que se encontrara en la misma línea de corriente se registrara como pulsado cuando no es así. Como en este ejemplo [1] donde pulsamos B2, B3 y C3 pero al tener corriente en 2 el botón C2 también pareciera pulsado cuando no es así:

[1]

También para evitar problemas de masking [2], donde puede ocurrir que algunas teclas que están pulsadas sean "enmascaradas" por otras que se encuentren en la misma linea:

[2]

El uso de diodos solucionaría estos problemas ya que solo permitiría el paso de la corriente en una dirección y nunca hacia atrás [3].

[3]

Ignoro como funcionan los keypads de tus fotos, que se usan tanto con Arduino, cuando pulsas dos teclas a la vez. Probablemente no estén preparados para tal función. Pero ya que yo estoy creando un MacroPad donde el uso de varios botones a la vez es una opción muy posible, creo que debería utilizar los diodos. Por favor corrígeme si me equivoco.

Esta parte la tengo clara pero mi duda, y el motivo de este mensaje, es porque cuando antes necesitaba una resistencia entre el botón, el pin y el GND ahora ya no. Supongo que el uso de pinMode(2, INPUT_PULLUP); en lugar de pinMode(2, INPUT); lo cambia todo, ¿es así?

La otra duda que tenía es la ausencia de cualquier conexión tanto al GND y 5V de los pulsadores como puedes ver en esta foto [4]

[4]

Aquí puedes ver la misma foto pero más grande.

Repito que la librería keypad la puedo seguir utilizando pero en cuanto al hardware ignoro si esos keypads que has compartido funcionan de la misma manera que mi teclado con pulsadores mecánicos.

Aquí te dejo un artículo donde explican mejor a lo que me refiero.

De nuevo gracias por tu tiempo y perdona si acaso me he explicado de forma errónea.

Un saludo

Bueno pero dos botones presionados no se si serán reconocidos por Keypad como librería.

La verdad que los ejemplos que estoy viendo online no hacen uso de tal ibrería. Todo será hacer pruebas, pero antes quería tener claro estos conceptos en cuanto a porque se usan las resistencias antes y no ahora. Y sobre todo el tema del GND y 5V que me tiene muy intrigado. (apuesto a que son preguntas estúpidas, pero no acabo de entenderlas.)

Olvidemos entonces mi enfoque porque veo que has hecho una mucho mejor investigación del tema.
De modo que sigamos en tu línea de trabajo.

Voy a leer con atención de nuevo lo expuesto a ver como continuar.

Bueno luego de leer con cierta atención (porque se me pueden escapar cosas) noté que no hay código asi que volví a comprobar si Keypad Library no soportaba multiple keys y me encuentro con este ejemplo llamado justamente MultipleKey.ino que esta en el IDE o bueno tal vez sea porque yo tengo la librería pero ese es un paso menor, vas a Gestor de Librerías y buscas Keypad y ya la tienes.
Dejo el ejemplo para que lo compruebes

* @file MultiKey.ino
|| @version 1.0
|| @author Mark Stanley
|| @contact mstanley@technologist.com
||
|| @description
|| | The latest version, 3.0, of the keypad library supports up to 10
|| | active keys all being pressed at the same time. This sketch is an
|| | example of how you can get multiple key presses from a keypad or
|| | keyboard.
|| #
*/

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the kpd
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the kpd

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

unsigned long loopCount;
unsigned long startTime;
String msg;


void setup() {
    Serial.begin(9600);
    loopCount = 0;
    startTime = millis();
    msg = "";
}


void loop() {
    loopCount++;
    if ( (millis()-startTime)>5000 ) {
        Serial.print("Average loops per second = ");
        Serial.println(loopCount/5);
        startTime = millis();
        loopCount = 0;
    }

    // Fills kpd.key[ ] array with up-to 10 active keys.
    // Returns true if there are ANY active keys.
    if (kpd.getKeys())
    {
        for (int i=0; i<LIST_MAX; i++)   // Scan the whole key list.
        {
            if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
            {
                switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
                    case PRESSED:
                    msg = " PRESSED.";
                break;
                    case HOLD:
                    msg = " HOLD.";
                break;
                    case RELEASED:
                    msg = " RELEASED.";
                break;
                    case IDLE:
                    msg = " IDLE.";
                }
                Serial.print("Key ");
                Serial.print(kpd.key[i].kchar);
                Serial.println(msg);
            }
        }
    }
}  // End loop

Estamos hablando solo de detectar varias teclas no del resto. Okay?