USB HID reading only one pin at a time.

Hello, First post I am sorry for anything that may not be up to spec.

I am trying to build a USB HID modular switch board for someone with mobility issues. My code is getting hung up somewhere causing my computer to recognize only one key press at a time.

I have each individual switch working in the way that I want them to, thanks to other posts and info on this forum, however I cannot read from more than one pin at a time. I am under the understanding that USB HID should support six simultaneous presses at the same time, but I can only get one to show up. So for example, if I am using WASD motion, I can either go straight OR right, not forward towards the right.

I know that it must be something with the code getting hung up on the the pin that is connected, but I don't know enough about how to keep it from getting hung up. So may of the things I have tried over the past couple days just bug out my code. And, so many of the HID tutorials either deal with getting a single button working or jump into keyboard matrices which I am not using.

Any advice would be amazing. Thank you.

  • Bud

Teensy LC - Arduino 1.6.8

void setup() {
  // make pin x an input and turn on the 
  // pullup resistor so it goes low unless
  // connected to ground:
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  Keyboard.begin();
}

void loop() {
  
//When Pin 0 is connected to Ground
 while (digitalRead(0) == LOW) 
  {
  Keyboard.press(KEY_1);
  delay (100);  // debounce
  while (digitalRead(0) == LOW)
    { } // Wait for Release
  Keyboard.release(KEY_1);  // Release Key
  }  // Pin 0 No Longer connected to Ground

//When Pin 1 is connected to Ground
 while (digitalRead(1) == LOW) 
  {
  Keyboard.press(KEY_3);
  delay (100);  // debounce
  while (digitalRead(1) == LOW)
    { } // Wait for Release
  Keyboard.release(KEY_3);  // Release Key
  }  // Pin 1 No Longer connected to Ground
  
//When Pin 2 is connected to Ground
 while (digitalRead(2) == LOW) 
  {
  Keyboard.press(char(0x20));
  delay (100);  // debounce
  while (digitalRead(2) == LOW)
    { } // Wait for Release
  Keyboard.release(char(0x20));  // Release Key
  }  // Pin 2 No Longer connected to Ground

//When Pin 3 is connected to Ground
 while (digitalRead(3) == LOW) 
  {
  Keyboard.press(char(10));
  delay (100);  // debounce
  while (digitalRead(3) == LOW)
    { } // Wait for Release
  Keyboard.release(char(10));  // Release Key
  }  // Pin 3 No Longer connected to Ground
 
 //When Pin 4 is connected to Ground
 while (digitalRead(4) == LOW) 
  {
  Keyboard.press(KEY_W);
  delay (100);  // debounce
  while (digitalRead(4) == LOW)
    { } // Wait for Release
  Keyboard.release(KEY_W);  // Release Key
  }  // Pin 4 No Longer connected to Ground
  
 //When Pin 5 is connected to Ground
 while (digitalRead(5) == LOW) 
  {
  Keyboard.press(KEY_S);
  delay (100);  // debounce
  while (digitalRead(5) == LOW)
    { } // Wait for Release
  Keyboard.release(KEY_S);  // Release Key
  }  // Pin 5 No Longer connected to Ground

//When Pin 6 is connected to Ground
 while (digitalRead(6) == LOW) 
  {
  Keyboard.press(KEY_A);
  delay (100);  // debounce
  while (digitalRead(6) == LOW)
    { } // Wait for Release
  Keyboard.release(KEY_A);  // Release Key
  }  // Pin 6 No Longer connected to Ground
  
//When Pin 7 is connected to Ground
 while (digitalRead(7) == LOW) 
  {
  Keyboard.press(KEY_D);
  delay (100);  // debounce
  while (digitalRead(7) == LOW)
    { } // Wait for Release
  Keyboard.release(KEY_D);  // Release Key
  }  // Pin 7 No Longer connected to Ground

//When Pin 8 is connected to Ground
 while (digitalRead(8) == LOW) 
  {
  Keyboard.press(KEY_UP_ARROW);
  delay (100);  // debounce
  while (digitalRead(8) == LOW)
    { } // Wait for Release
  Keyboard.release(KEY_UP_ARROW);  // Release Key
  }  // Pin 8 No Longer connected to Ground

//When Pin 9 is connected to Ground
 while (digitalRead(9) == LOW) 
  {
  Keyboard.press(KEY_DOWN_ARROW);
  delay (100);  // debounce
  while (digitalRead(9) == LOW)
    { } // Wait for Release
  Keyboard.release(KEY_DOWN_ARROW);  // Release Key
  }  // Pin 9 No Longer connected to Ground
  
//When Pin 10 is connected to Ground
 if (digitalRead(10) == LOW) 
  {
  Keyboard.press(KEY_LEFT_ARROW);
  delay (100);  // debounce
  while (digitalRead(10) == LOW)
    { } // Wait for Release
  Keyboard.release(KEY_LEFT_ARROW);  // Release Key
  }  // Pin 10 No Longer connected to Ground

//When Pin 11 is connected to Ground
 while (digitalRead(11) == LOW) 
  {
  Keyboard.press(KEY_RIGHT_ARROW);
  delay (100);  // debounce
  while (digitalRead(11) == LOW)
    { } // Wait for Release
  Keyboard.release(KEY_RIGHT_ARROW);  // Release Key
  }  // Pin 11 No Longer connected to Ground
  
//When Pin 12 is connected to Ground
 while (digitalRead(12) == LOW) 
  {
  Keyboard.press(char(0x1B));
  delay (100);  // debounce
  while (digitalRead(12) == LOW)
    { } // Wait for Release
  Keyboard.release(char(0x1B));  // Release Key
  }  // Pin 12 No Longer connected to Ground
   
}

Screen Shot 2016-05-27 at 12.15.32 PM.png

On most of the Arduinos, pins 0 and 1 are connected to the Serial instance. Is that not the case for the Teensys?

100 milliseconds is a very long time for a switch to bounce.

The state change detection example shows a more reasonable way of performing an action when a switch becomes pressed or becomes released.

Using arrays would considerable reduce the amount of duplicate code that you have.

The way that you read the keys - waiting for the switch to become released once you have detected that a switch is pressed - means that you can only read one switch at a time, so there is no way that the current code can determine that multiple switches are pressed.

PaulS:
100 milliseconds is a very long time for a switch to bounce.

Anything less than that and I am getting multiple instances of the button being pressed before it is seen as being held down, even at 100 it occasionally happens.

PaulS:
The way that you read the keys - waiting for the switch to become released once you have detected that a switch is pressed - means that you can only read one switch at a time, so there is no way that the current code can determine that multiple switches are pressed.

I am realizing that. It's just tough because all of the tutorials for USB Keyboard interfaces have been setting them up that way, and I am just starting to get my head around that limitation. I am not a coder, obviously. I can't use arrays because of how it will be wired up. I will look into state change detection, if there is anything you can point me towards, let me know. - Bud

I can't use arrays because of how it will be wired up.

So, you can't use an array because the switches will be connected to pins 5, 2, 8, 14, and 3?

byte pins[] = { 5, 2, 8, 14, 3 };

Here is an example of how you would write your sketch with arrays:

const int PIN_COUNT = 13;
const byte Pins[PIN_COUNT] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
const byte Keycode[PIN_COUNT] = {KEY_1, KEY_3, 0x20, 10,
                                 KEY_W, KEY_S, KEY_A, KEY_D,
                                 KEY_UP_ARROW, KEY_ARROW_DOWN,
                                 KEY_ARROW_LEFT, KEY_ARROW_RIGHT,
                                 0x1B
                                };

void setup() {
  // make pin x an input and turn on the
  // pullup resistor so it goes low unless
  // connected to ground:
  for (int pin = 0; pin < PIN_COUNT; pin++) {
    pinMode(Pins[pin], INPUT_PULLUP);
  }

  Keyboard.begin();
}

void loop() {

  for (int pin = 0; pin < PIN_COUNT; pin++) {

    // When Pin is connected to Ground
    if (digitalRead(Pins[pin]) == LOW) {
      Keyboard.press(Keycode[pin]);
      delay (100);  // debounce
      while (digitalRead(Pins[pin]) == LOW)
      { } // Wait for Release
      Keyboard.release(Keycode[pin]);  // Release Key
    }
  }
}

Sir, You are amazing. I have been learning from many posts that you have made on this forum before I signed up, thank you so much for the help.

I there is one last thing that I am trying to figure out on this project. I am trying to get my keystrokes to mimic the keys on the number pad of a full sized keyboard, so instead of sending this information:

Key Down
Characters: 8
Unicode: 56 / 0x38
Keys: 8
Key Code: 28 / 0x1c
Modifiers: 256 / 0x100 ⓘ

I am trying to send this:

Key Down
Characters: 8
Unicode: 56 / 0x38
Keys: #8
Key Code: 91 / 0x5b
Modifiers: 2097408 / 0x200100 ⓘ

I think I need to send the key code directly, and I have not been able to figure out how to do it.

I am building an interface to help people with disabilities be able to control their mouse through a button interface. So I need to use the buttons for mouse interfaces through Windows and OSX, in case you were wondering why I need this seemingly strange request.

  • Bud

I don't know about the Teensy. With the Leonardo or Micro you can send raw scan codes by adding 136 (0x88) to the scan code value. This will work for codes 0 through 119 (0x77).

You can find the USB scan codes in the USB specification:
http://www.usb.org/developers/hidpage/Hut1_12v2.pdf
The table starts on page 53.