button box

Hello

I'm doing a button box for xbox for sim racing, but the game only have keyboard support so when i press a button it need to emulate a key press like "a". I use a arduino micro so I know it's possible but i'm pretty new to arduino so i don't really know how to code. I need a lot of help, it would be cool.
it's a 4x4 matrix with 8 buttons, 6 switches, 2 rotary encoder.
sorry for my bad english i'm french

Thanks

There are Arduinos that have a chip with USB built-in. You can code them to appear as HID controller/keyboard to PC or XBox.

The Micro and Leonardo are two such. The compatibles Teensy 2.0 and Teensy++ 2.0 are also so, the company they are from (PJRC.com) made the libraries to do this.

And those are just the AVR boards. There are ARM boards that I think can do USB but I am not sure, they run on 3.3V, USB is 5V.

AVR pins are more robust than ARM pins, more hobby-friendly.

Thanks for the awnsers

Yes i know i already have all the button and wire solder on the arduino. My problem is i don’t Find a topic about matrix and keyboard on the internet
So i don’t really know how to do for the code

dlizet:
Thanks for the answerers

Yes i know i already have all the button and wire solder on the arduino. My problem is i don’t Find a topic about matrix and keyboard on the internet
So i don’t really know how to do for the code

How is the button box wired?

Did you use diodes with the buttons, needed if you want to press more than 1 button at once?

I have an example but I have to hunt up the drive it's on.

When you read a matrix, all but 1 row and 1 column pin are moded INPUT and set LOW, electrically neutral. 1 row pin is moded INPUT_PULLUP to supply a weak 5V and 1 column pin in moded OUTPUT and set LOW. If a button along that row is down and the button is on that column, the row pin will go LOW. The diodes are to ensure that other buttons pushed don't provide false hits.

You mode the column pin back to INPUT and mode the next to OUTPUT and read the row pin through the entire column, switch to the next row and run through the columns again. When you reach the end you start again.
If you write fast code you can scan 32 buttons in less than a millisecond.

And here's the example. I forgot to mention that it also debounces pretty quickly.

// addasketch_matrix_buttons 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, May 9/2018 by GFS. Compiled on Arduino IDE 1.6.9.
/*  Button Debounce Example

  This example requires a diode per button in the row&column matrix.
  Each row and column pin has its own wire. Where they cross a button and diode
  connect in series allowing current to flow from the row wire to th column wire
  only. The diode is to allow multiple buttons pressed at once detected correctly.

  OTOH for this test, jumper a row pin (2 or 3) to a column pin (4 or 5) while
  watching serial monitor.

  Yes I'm using a 16 bit micros timer to time fractions of millis as micros.
  The button reader only reads 1 button per call so as to not block void loop().
  Each button has a history byte that holds the last 8 reads with 256 possible
  states but only 4 of them being significant.
  0 is the button held down
  255 is the button left up
  127 is the buton transitioning from up to down, button just released.
  128 is the button transititioning from down to up, button just pressed.
  everything else is to be ignored as bounce.

  For multiple buttons the between-reads time is reduced and each pin is read in
  turn.
*/


// matrix_buttons vars --- 2D matrix
const byte rows = 2; // test with 4 buttons or jumper
const byte cols = 2;
byte rowIdx, colIdx = 255;
byte buttonRowPin[ rows ] = { 6, 7 };
byte buttonColPin[ cols ] = { 4, 5 };
byte buttonHistory[ rows ][ cols ];
word markButtonTime;        // 16-bit micros timers
const word waitButtonTime = 50; // micros, 50 us
// type word as micros can time across 65.535 millis before rollover, can be a few late


void matrixButtonsTask()
{
  if ( word( micros()) - markButtonTime >= waitButtonTime ) // read occaisoinally
  {
    // iterate the row and column indexes
    if ( ++colIdx >= cols ) // ++rowIdx pre-increments rowIdx before comparing to rows
    {
      colIdx = 0;
      if ( ++rowIdx >= rows ) // ++rowIdx pre-increments rowIdx before comparing to rows
      {
        rowIdx = 0;
      }
    }

    pinMode( buttonRowPin[ rowIdx ], INPUT_PULLUP ); // supplies weak 5V
    pinMode( buttonColPin[ colIdx ], OUTPUT ); // is LOW, grounds pressed buttons

    buttonHistory[ rowIdx ][ colIdx ] <<= 1; // shift history bits up 1 for the new read
    buttonHistory[ rowIdx ][ colIdx ] += digitalRead( buttonRowPin[ rowIdx ] ); // read history streams through buttonHistory
    markButtonTime = micros(); // gets the low 16 bits of micros(), time to 60 ms + margin

    pinMode( buttonRowPin[ rowIdx ], INPUT );
    pinMode( buttonColPin[ colIdx ], INPUT ); // was OUTPUT LOW
  }
}


void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Button Matrix Example, free by GoForSmoke\n" ));

  for ( byte i = 0; i < rows; i++ )
  {
    pinMode( buttonRowPin[ i ], INPUT ); // mode INPUT pin is electrically neutral
    for ( byte j = 0; j < cols; j++ )
    {
      if ( i == 0 ) // only set the column pins once
      {
        pinMode( buttonColPin[ j ], INPUT ); // mode INPUT pin is electrically neutral
      }

      buttonHistory[ i ][ j ] = 255; // all buttons start UP
    }
  }
};


void loop()
{
  matrixButtonsTask();
  /*
    0 is the button held down
    255 is the button left up
    127 is the buton changing from up to down, button just released.
    128 is the button changing from down to up, button just pressed.
    everything else is to be ignored as bounce.
  */
  static byte row, col;

  switch ( buttonHistory[ row ][ col ] )
  {
    case 128 : // pin is HIGH in bit 7, LOW for 7 reads, up to down detected
      buttonHistory[ row ][ col ] = 0; // change detected, make it into no change now
      Serial.print( F( "button " ));
      Serial.print( rowIdx );
      Serial.print( F( ", " ));
      Serial.print( colIdx );
      Serial.print( F( "  press detected     " ));
      Serial.println( millis());
      break;

    case 127 : // pin is LOW in bit 7, HIGH for 7 reads, down to up detected
      buttonHistory[ row ][ col ] = 255; // change detected, make it into no change now
      Serial.print( F( "button " ));
      Serial.print( rowIdx );
      Serial.print( F( ", " ));
      Serial.print( colIdx );
      Serial.print( F( "  release detected   " ));
      Serial.println( millis());
      break;
  }

  if ( ++col >= cols )
  {
    col = 0;;

    if ( ++row >= rows )
    {
      row = 0;;
    }
  }
}

No i don’t use diodes.
Normally only 2 switches would be on at the Same Time, one for contact and one for ignition
For the wirings i follow this:

But with a 4x4 matrix

Hi,
Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Have you tried the code supplied with the YouTube presentation?

Thanks.. Tom.. :slight_smile:

dlizet:
No i don’t use diodes.
Normally only 2 switches would be on at the Same Time, one for contact and one for ignition
For the wirings i follow this:
https://m.youtube.com/watch?v=Z7Sc4MJ8RPM#
But with a 4x4 matrix

The youtube you linked to has a link to their sketch and library.

With my method I think it takes 3 buttons pressed to get a false read, it will have a true read as well.

Here my circuit, i know it’s a bit of mess but i hope you understand it

Yes i tried but mine has to be different because it’s a 4x4 matrix and I need to emulate a key press when I press a button.
But in fact I think I could take the code for example and modify for my version.

The sketch they give should have comments that tell you what to change or variable names that make it obvious beyond comment.

In my sketch you have row and column pins as 2 groups, you can pick which is row/column. They are { 7,8,9,10 } and { A0,A1,A2,A3 ). In my sketch you'd have to change

// matrix_buttons vars --- 2D matrix
const byte rows = 2; // test with 4 buttons or jumper        
const byte cols = 2;
byte rowIdx, colIdx = 255; // don't change this line but the rest kind of explain themselves?
byte buttonRowPin[ rows ] = { 6, 7 };
byte buttonColPin[ cols ] = { 4, 5 };

Yes, the sketch has some comments but not a lot and I think they aren’t really explicit. But i’m Not good at all so it’s maybe for that

Annnnnnd the lines in my post, the ones to change in my sketch that at least will tell you if your wiring works?

// matrix_buttons vars --- 2D matrix
const byte rows = 2; // test with 4 buttons or jumper       
const byte cols = 2;
byte rowIdx, colIdx = 255; // don't change this line but the rest kind of explain themselves?
byte buttonRowPin[ rows ] = { 6, 7 };
byte buttonColPin[ cols ] = { 4, 5 };

I spent time writing about rows and columns connected to pins, you wired that up, how hard can it be to make that a 4x4 with your pins as rows and columns? Think, the practice will do you good.
-- your row pins can be 7,8,9,10 or A0 to A3 and the other 4 are your columns, it doesn't matter as long as the pins of each set stay together because all the pins are the same and you don't have diodes to set a direction. You have 4 things wired to each pin to make rows x cols.
The youtube video shows rows and columns, changing how many is just changing two values, changing the pins is just replacing the ones in the example with yours. That is all the change in mine because it doesn't send to HID. I'd have to add that which is not a problem. With theirs you probably have to replace the example keys with your set of keys to be sent when buttons are pressed.

I don't know the other code. You might get help from whoever made that. They might have a forum. It's probably drop dead easy to change. Read the variable names, they should be explicit enough.

I'm sure that you can do at least one of those if you try, what's really could happen worse than all that work and cost doing nothing?

Hi,
OPs Circuit;


Thanks.. Tom.. :slight_smile:

I traced it out which is why I'm sure about the matrix pin groups 7 to 10 and A0 to A3. It did take a while, the A0 line is tricky but there is a matrix.

PS - I changed the last 2 lines of my sig. How does that read to you, who knows this stuff?

dlizet:
sorry for my bad english i'm french

Thanks

Please, I forgot! Pardon me! It's just that you seem more than bright enough to learn the terms and solve this puzzle.

Do you have crossword puzzles? Words across are on rows, words vertical are on columns.

Although your buttons are not arranged as 4x4, they are wired so. I traced the schematic line by line.

With 1 diode per button between the button and row pin pointing away from the row pin, you can press any or all of the buttons at the same time and in less time than 1 frame on TV the sketch knows every one of them correctly. The number of possible combinations of 16 buttons at once is what number 16 bits (tech term) can express is 65536. It is more than a Micro has room to code for.

That allows you to have 1 big matrix with buttons in sets that you can hold buttons in sets without conflict on the overall matrix. I think now you have a 4x4 matrix with one set of 4x3 and then a 4x1?

Buttons are fun and all but have you any dials or sliders? Those should be on analog pins.
And I forgot, you can make the Micro look like a mouse, joystick and keyboard all at the same time.

Hi
so I try to do it, like you said , for the moment i made this:

#include <Keyboard.h>

const byte rows = 4;
const byte cols = 4;
byte rowIdx, colIdx = 255;
byte buttonRowpin[ rows ] = { 9, 10, 14, 16 };
byte buttonColpin[ cols ] = { A0, A1, A2, A3 };
int button_1 = (A2,9);
int button_2 = (A2,10);
int button_3 = (A2,16);
int button_4 = (A2,14);
int button_5 = (A1,9);
int button_6 = (A1,10);
int button_7 = (A1,16);
int button_8 = (A1,14);
int switche_1 = (A0,10);
int switche_2 = (A0,9);
int switche_3 = (A3,9);
int switche_4 = (A3,10);
int switche_5 = (A3,16);
int switche_6 = (A3,14);


void setup() 
 
{
  pinMode (A0,OUTPUT);
  pinMode (A1,OUTPUT);
  pinMode (A2,OUTPUT);
  pinMode (A3,OUTPUT);
  pinMode (9, INPUT);
  pinMode (10, INPUT);
  pinMode (14, INPUT);
  pinMode (16, INPUT);

And i start to learn how to use the keyboard Library so i try to make a sketch :

#include <Keyboard.h>

void setup() {
  // put your setup code here, to run once:
int button_1 = (A3,10);
pinMode (A3,OUTPUT);
pinMode (10, INPUT);
Keyboard.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
if (digitalRead(9) == HIGH);
Keyboard.press("Q");
delay(200);
Keyboard.releaseAll();

the first issue is the key press is not "Q" like said in the sketch but "=" and the second it's that the key stay pressed

GoForSmoke:
Please, I forgot! Pardon me! It's just that you seem more than bright enough to learn the terms and solve this puzzle.

Do you have crossword puzzles? Words across are on rows, words vertical are on columns.

No problems:-) THANKS!!

Yes i understand that

GoForSmoke:
Buttons are fun and all but have you any dials or sliders? Those should be on analog pins.
And I forgot, you can make the Micro look like a mouse, joystick and keyboard all at the same time.

Not for the moment, i'm not really sure if it's possible with arduino on xbox but it's probably, but on phone you can have all the telemetry in race with an app.
If i succeed this project (button box) i think i'm gonna make a handbrake also with an arduino micro and a slider potentiometer and the keyboard library

dlizet:
Hi
so I try to do it, like you said , for the moment i made this:

#include <Keyboard.h>

const byte rows = 4;          <<======== this is how many rows
const byte cols = 4;
byte rowIdx, colIdx = 255;

byte buttonRowpin[ rows ] = { 9, 10, 14, 16 };  <<=== this has as many pins as there are [rows]
byte buttonColpin[ cols ] = { A0, A1, A2, A3 };

int button_1 = (A2,9);    <<======== int is 1 value and {A2,9} only puts the first in that variable, not 2

That code can't work. You only need to make the example matrix the size as yours and use the pins that you do, 7,8,9,10 and A0,A1,A2,A3. I don't know why thos other pin numbers are there.