Buttons gleichzeitig drücken mit der Keypad Library für ein PS4 Buttonbox

Hallo zusammen,

ich bin Anfänger und baue mir den Sketch nach dem Try&Error Prinzip auf.

Was ist das Ziel: Eine Buttonbox für die PS4 zu bauen, um per Knopfdruck/Ausgabe einer Keyboard-Taste auf dem Arduino Leonardo eine Funktion in einem Rennspiel auszulösen (bspw. wenn "4" gedruckt wird, schaltet sich die Rundenanzeige um, bei "5" gehen die Scheibenwischer ein/aus etc.). Wenn man sich das Bild in dem zweiten Link ansieht, wird es ersichtlicher :).

Mein Problem: Ich möchte gerne für die ABS-Funktion, aber auch für andere Funktionen, Kippschalter und keine Taster verwenden. Vorstellung: Kippschalter nach oben schaltet die Funktion ein/aus (HOLD) und eine LED geht an, Kippschalter in Mittelstellung (wäre ein Release) macht nichts (um die Einstellung mit dem Spiel zu synchronisieren zu können, da PS4 keine Daten ausgibt), Kippschalter nach unten (Hold) schaltet die Funktion ein/aus und die LED aus. Wenn ich hierfür Kippschalter nutze, kann ich aber mit meinem Sketch keine weitere Taste drücken und eine Ausgabe einer Keyboard-Taste erzeugen. Im Serial Monitor wird die Ausgabe wie folgt angezeigt, wenn ich 1 gedrückt halte und dann 2 drücke und dann 1 loslasse. Die drei x 2 wird erst angezeigt, wenn ich 1 loslasse. Ich benötige die 2 aber währenddessen und die 2 auch nur einmal bei Pressed und nicht bei Release und Idle und eben auch als Keyboard-Ausgabe und nicht nur im Serial Monitor. Wenn z.B. ABS mit Kippschalter eingeschaltet ist, Schalter steht auf Pressed oder Hold, dann muss ich ja auch weitere Buttons/Funktionen nutzen können. Das gelingt mir jetzt nur, wenn ich Taster nutze und diese nach dem Einschalten wieder in der Neutralstellung verharren.

Evtl. hat ja jemand das Verständnis für mein Problem und sieht direkt wo der Fehler ist. Würde mich über verständliche Hilfen freuen und bedanke mich im Voraus!

Markus

Serial Monitor:

Key 1 PRESSED. Key 2 PRESSED. Key 2 RELEASED. Key 2 IDLE. Key 1 HOLD. Key 1 RELEASED. Key 1 IDLE.

"Keyboard" Ausgabe: 1222

Code:

https://drive.google.com/file/d/0B3tO95cofeQCaUYyeG9xQTBjODA/view?usp=sharing

The ButtonBox: https://drive.google.com/file/d/1mD_tfjWiF8ucE7uA_takpV89g47T0kOL6A/view?usp=sharing

Wenn du den Code in Code-Tags (Schaltfläche </>) hier reinstellst, dann ist es für uns einfacher den zu lesen.

Gerne :slight_smile:

//ARDUINO LEONARDO ButtonBox -> Example: MAP THE KEYBOARD-BUTTON "1" FOR INGAME-FUNCTION "WIPER ON/OFF" ETC.

#include <Keypad.h>

const byte ROWS = 4; // Four rows
const byte COLS = 5; // Three columns
// Define the Keymap
char hexaKeys[ROWS][COLS] = {
  {'1','2','3','4','5'},
  {'6','7','8','9','A'},
  {'B','C','D','E','F'},
  {'G','H','I','J','K'}
  
};
// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte rowPins[ROWS] = { 0, 1, 2, 3 };
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[COLS] = { 4, 5, 6, 7, 8 }; 

// Create the Keypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS );

#define ledpin11 11
#define ledpin12 12
#define ledpin13 13


boolean blink = false;

boolean ledpin11_state;
boolean ledpin12_state;
boolean ledpin13_state;

unsigned long loopCount;
unsigned long startTime;
String msg; 

void setup()
{
  pinMode(ledpin11,OUTPUT);
  pinMode(ledpin12,OUTPUT);
  pinMode(ledpin13,OUTPUT);
  //JUST A FUNNY LED TEST
  digitalWrite(ledpin11, HIGH);   
  delay(75);
  digitalWrite(ledpin11, LOW);
  delay(75);
  digitalWrite(ledpin12, HIGH);
  delay(75);
  digitalWrite(ledpin12, LOW);
  delay(75);
  digitalWrite(ledpin13, HIGH);
  delay(75);
  digitalWrite(ledpin13, LOW); 
  delay(75);
  digitalWrite(ledpin12, HIGH);
  delay(75);
  digitalWrite(ledpin12, LOW);
  delay(75);
  digitalWrite(ledpin11, HIGH);
  delay(75);
  digitalWrite(ledpin11, LOW);
  
  Serial.begin(9600);

    loopCount = 0;
    startTime = millis();
    msg = "";
    ledpin11_state = digitalRead(ledpin11);
    ledpin12_state = digitalRead(ledpin12);
    ledpin13_state = digitalRead(ledpin13);
    customKeypad.addEventListener(keypadEvent);
    customKeypad.setHoldTime(500);
  
  
}

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 (customKeypad.getKeys())
    {
        for (int i=0; i<LIST_MAX; i++)   // Scan the whole key list.
        {
            if ( customKeypad.key[i].stateChanged )   // Only find keys that have changed state.
            {
                switch (customKeypad.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(customKeypad.key[i].kchar);
                Serial.println(msg);
            }
        }
  
 
  }

   if (blink){                                  //Headlights -> Flashlight blink
        Keyboard.press(0x39);
        digitalWrite(ledpin12,!digitalRead(ledpin12));    // Change the ledPin from Hi2Lo or Lo2Hi.
        delay(100);
        Keyboard.release(0x39);
        delay(100);
        
    }

}
void keypadEvent(KeypadEvent key){
    switch (customKeypad.getState()){

    
    case PRESSED:  
        
        if (key == '9') {                                   //Headlights On/Off (cant use toggle switch)
            digitalWrite(ledpin12,!digitalRead(ledpin12));
            ledpin12_state = digitalRead(ledpin12);        // Remember LED state, lit or unlit.
          //  digitalWrite(ledpin12, HIGH);
            Keyboard.press(0x39);
            delay(50);
            Keyboard.release(0x39);
            
        }
         if (key == '6') {                                   //ABS On (cant use toggle switch)
           // digitalWrite(ledpin11,!digitalRead(ledpin11));
           // ledpin11_state = digitalRead(ledpin11);        // Remember LED state, lit or unlit.
            digitalWrite(ledpin11, HIGH);
            Keyboard.press(0x36);
            delay(50);
            Keyboard.release(0x36);
        }
          if (key == '7') {                                   //ESP On (cant use toggle switch)
           // digitalWrite(ledpin12,!digitalRead(ledpin12));
           // ledpin12_state = digitalRead(ledpin12);        // Remember LED state, lit or unlit.
            digitalWrite(ledpin12, HIGH);
            Keyboard.press(0x37);
            delay(50);
            Keyboard.release(0x37);
        }
          if (key == '8') {                                   //TCS On (cant use toggle switch)
            //digitalWrite(ledpin13,!digitalRead(ledpin13));
            //ledpin13_state = digitalRead(ledpin13);        // Remember LED state, lit or unlit.
            digitalWrite(ledpin13, HIGH);
            Keyboard.press(0x38);
            delay(50);
            Keyboard.release(0x38);
        }
         if (key == 'B') {                                   //ABS Off (cant use toggle switch)
           // digitalWrite(ledpin11,!digitalRead(ledpin11));
           // ledpin11_state = digitalRead(ledpin11);        // Remember LED state, lit or unlit.
            digitalWrite(ledpin11, LOW);
            Keyboard.press(0x36);
            delay(50);
            Keyboard.release(0x36);
        }
          if (key == 'C') {                                   //ESP Off (cant use toggle switch)
           // digitalWrite(ledpin12,!digitalRead(ledpin12));
           // ledpin12_state = digitalRead(ledpin12);        // Remember LED state, lit or unlit.
            digitalWrite(ledpin12, LOW);
            Keyboard.press(0x37);
            delay(50);
            Keyboard.release(0x37);
        }
          if (key == 'D') {                                   //TCS Off (cant use toggle switch)
           // digitalWrite(ledpin13,!digitalRead(ledpin13));
           // ledpin13_state = digitalRead(ledpin13);        // Remember LED state, lit or unlit.
            digitalWrite(ledpin13, LOW);
            Keyboard.press(0x38);
            delay(50);
            Keyboard.release(0x38);
        }
       
         if (key == '1') {                                   //Switch MoTec
            Keyboard.press(0x31);
            delay(50);
            Keyboard.release(0x31);
        }
         if (key == '2') {                                   //Reset
            Keyboard.press(0x32);
            delay(50);
            Keyboard.release(0x32);
        }
         if (key == '3') {                                   //Switch HUD
            Keyboard.press(0x33);
            delay(50);
            Keyboard.release(0x33);
        }
         if (key == '4') {                                   //Switch Lap Info
            Keyboard.press(0x34);
            delay(50);
            Keyboard.release(0x34);
        }
         if (key == '5') {                                  //Wiper On/Off and Test on ledpin13
            digitalWrite(ledpin13,!digitalRead(ledpin13));
            ledpin13_state = digitalRead(ledpin13);        // Remember LED state, lit or unlit.
            Keyboard.press(0x35);
            delay(50);
            Keyboard.release(0x35);
        }
        break;
        
        case HOLD:
           if (key == 'A') {                                  //Headligh -> Flashlight blink (cant use toggle switch)
            blink = true;    // Blink the LED when holding the A key.
        } 
       
        break;
         case RELEASED:
        if (key == 'A') {                                  //Headligh -> Flashlight Off
         //   //digitalWrite(ledpin12,ledpin12_state);    // Restore LED state from before it started blinking.
           // digitalWrite(ledpin12, LOW);
            blink = false;
            digitalWrite(ledpin12, LOW);
        }
       
         
        break;
     }
     }

Ok, so ist es prima.

Leider mit der Library nicht. ;) Die ist so gebaut, dass immer nur eine Taste/Schalter zur Zeit ausgewertet werden kann.

Deine Vorstellung kannst du nur umsetzen, in dem du die Taster/Schalter direkt an den Arduino anschließt und die Zustände abfragst. Ich denke dafür gibt es auch keine Library, da du es direkt über "digitalRead(buttonPin);" machen kannst. Mir ist aktuell leider keine andere Lösung bekannt. Evtl. gibt es ja noch eine.

Erstmal danke.

Aber die Library ist doch extra für ein Keypad und seit der Version 3.0 für die gleichzeitige Eingabe von Tasten. Im Serial Monitor geht das ja auch, aber wie "übersetze" ich quasi das was dort angezeigt wird. Bestimmt mache ich da schon etwas falsch. Das offizielle Keypad Multikey Example selbst gibt auch nur eine Ausgabe im Serial Monitor aus, aber wie man letztlich mit dem Ergebnis etwas anfängt bleibt mir verborgen. Da hat der Entwickler zuviel KnowHow bei einem Anfänger vorausgesetzt :). HOLD PRESSES etc. sind ja prinzipiell super, aber ich kann es umsetzen. Wenn Taste xy gehalten wird, dann mache dies und das. Wenn Taste yx zeitgleich gedrückt wird, dann mache auch dies und das. Eigentlich doch ganz einfach.

Buttons direkt an das Board anschließen war meine erste Idee, aber dann habe ich nur 13 Pins. Ich benötige aber 18 Buttons und habe noch 3-5 LEDs die ich ein und ausschalten möchte. Geht also nicht. Es geht also nur mit einer Matrix. Und wie man einen Mega, der mehr Pins hat dazu bringt ein HID zu sein, habe ich nicht durchblickt.

Ok, habe mir die Lib aus Zeitmangel nicht komplett angeschaut und war evtl. zu voreilig.

Du musst das Ergebnis, was auch im SerialMonitor angezeigt wird, per Switch/Case auswerten und den entsprechenden Funktionen zuordnen.

Was wird denn angezeigt, wenn du 2 Tasten gleichzeitig drückst?

Habe ich das hiermit nicht gemacht?:

void keypadEvent(KeypadEvent key){
    switch (customKeypad.getState()){

    
    case PRESSED:  
        
        if (key == '9') {                                   //Headlights On/Off (cant use toggle switch)
            digitalWrite(ledpin12,!digitalRead(ledpin12));
            ledpin12_state = digitalRead(ledpin12);        // Remember LED state, lit or unlit.
          //  digitalWrite(ledpin12, HIGH);
            Keyboard.press(0x39);
            delay(50);
            Keyboard.release(0x39);

Aus dem Gedächtnis: Wenn ich z.B. 1 drücke und dann umgehend danach 2 3 4 (also die Buttons), dann wird mir 1222333444 als Key ausgegeben. Wenn ich nicht umgehend drücke, dann wird mir nur 1 als Key und mehr nicht ausgegeben, im Serial Monitor wird aber alles angezeigt. Hat aber denke ich nichts mit dem "customKeypad.setHoldTime(500);" zu tun, habe ich extra hoch gestellt, um das zu umgehen.

Mache ich das mit dem "void keypadEvent(KeypadEvent key){ switch (customKeypad.getState()){" evtl. falsch? Kommt das ggf. auch in den loop? Ich habe das ja nun separat.

Also wie übersetze ich das was im Serial Monitor angezeigt wird. Dort wird ja alles richtig protokolliert, zb. 6 wird gedrückt, gehalten, losgelassen oder macht nix. Ich möchte auswählen, wenn dort angezeigt wird "6 Pressed" dann gebe als Tastatur-Ausgabe auch einmalig "6" aus. Ist 6 (oder was auch immer) gedrückt und wird parallel z.B. "1 gedrückt", dann gebe, zusätzlich, "1" einmalig als Tastatur-Ausgabe aus.

Das ist z.B. der Original Multikey Code, mit dem ja in dieser Form nichts anfangen kann, da ja nur in dem SerialMonitor die Ausgabe erfolgt. Wenn ich z.B. unter “Serial.println(msg);” “Keyboard.press(customKeypad.key*.kchar);” ergänze (customKeypad weil ich es ja erzeugt habe), dann wird mir zwar alles im Serial Monitor angezeigt aber genau das auch als Tastatur- Key ausgegeben (auch mehrere Tasten gleichzeitig → gut!). Drücke ich Button 1 länger als 500 ms und lasse dann los wird mir z.B. 4 x die 1 ausgegeben. Ich will aber nur die 1 von “Pressed” angezeigt bekommen und nicht nochmal wenn sie Released oder Idle ist. *
Von meinem Anfängerdenken her hätte ich für jeden Button versucht, aus “case PRESSED:” → “case “1” PRESSED:” ,“case “2” HOLD:” etc. zu machen und das was ich nicht brauche (Pressed, Hold, RELEASE, IDLE) zu löschen. Habe ich aber nicht hinbekommen.
```
/ @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*
```