ButtonBox Arduino Mega Help!

Hi guys,

I started a button box project from a 3D Print model, and after getting the parts and printing the box all I have is the image of the connections on the Arduino Mega 2560.

From there I create my own wiring schema:

and adapted this code:

#include <Joystick.h>
#include <Keypad.h>


//DEFINITIONS
#define ENABLE_PULLUPS
#define NUMROTARIES 7 //replace "?" with number of rotary encoders you are using
#define NUMBUTTONS 20 //replace "?"with number of buttong you are using
#define NUMROWS 5 //replace "?" with number of rows you have
#define NUMCOLS 4 //replace "?" with number of columns you have

//BUTTON MATRIX
//first change number of rows and columns to match your button matrix, 
//then replace all "?" with numbers (starting from 0)
byte buttons[NUMROWS][NUMCOLS] = {
  {0,1,2,3,4},
  {5,6,7,8,9},
  {10,11,12,13,14},
  {15,16,17,18,19},
  {20,21,22,23}
  
 
 
};

struct rotariesdef {
  byte pin1;
  byte pin2;
  int ccwchar;
  int cwchar;
  volatile unsigned char state;
};

//ROTARY ENCODERS
//each line controls a different rotary encoder
//the first two numbers refer to the pins the encoder is connected to 
//the second two are the buttons each click of the encoder wil press 
//do NOT exceed 31 for the final button number
rotariesdef rotaries[NUMROTARIES] {
  {0,1,16,17,0}, //rotary 1
  {2,3,18,19,0}, //rotary 2
  {4,5,20,21,0}, //rotary 3
  {6,7,22,23,0}, //rotary 4
  {8,9,24,25,0}, //rotary 5
  {10,11,26,27,0}, //rotary 6
  {12,13,28,29,0} //rotary 7

};

#define DIR_CCW 0x10
#define DIR_CW 0x20
#define R_START 0x0

#ifdef HALF_STEP
#define R_CCW_BEGIN 0x1
#define R_CW_BEGIN 0x2
#define R_START_M 0x3
#define R_CW_BEGIN_M 0x4
#define R_CCW_BEGIN_M 0x5
const unsigned char ttable[6][4] = {
  // R_START (00)
  {R_START_M,            R_CW_BEGIN,     R_CCW_BEGIN,  R_START},
  // R_CCW_BEGIN
  {R_START_M | DIR_CCW, R_START,        R_CCW_BEGIN,  R_START},
  // R_CW_BEGIN
  {R_START_M | DIR_CW,  R_CW_BEGIN,     R_START,      R_START},
  // R_START_M (11)
  {R_START_M,            R_CCW_BEGIN_M,  R_CW_BEGIN_M, R_START},
  // R_CW_BEGIN_M
  {R_START_M,            R_START_M,      R_CW_BEGIN_M, R_START | DIR_CW},
  // R_CCW_BEGIN_M
  {R_START_M,            R_CCW_BEGIN_M,  R_START_M,    R_START | DIR_CCW},
};
#else
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6

const unsigned char ttable[7][4] = {
  // R_START
  {R_START,    R_CW_BEGIN,  R_CCW_BEGIN, R_START},
  // R_CW_FINAL
  {R_CW_NEXT,  R_START,     R_CW_FINAL,  R_START | DIR_CW},
  // R_CW_BEGIN
  {R_CW_NEXT,  R_CW_BEGIN,  R_START,     R_START},
  // R_CW_NEXT
  {R_CW_NEXT,  R_CW_BEGIN,  R_CW_FINAL,  R_START},
  // R_CCW_BEGIN
  {R_CCW_NEXT, R_START,     R_CCW_BEGIN, R_START},
  // R_CCW_FINAL
  {R_CCW_NEXT, R_CCW_FINAL, R_START,     R_START | DIR_CCW},
  // R_CCW_NEXT
  {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};
#endif

//BUTTON MATRIX PART 2
byte rowPins[NUMROWS] = {40,42,44,46,48}; //change "?" to the pins the rows of your button matrix are connected to
byte colPins[NUMCOLS] = {41,43,45,47,49}; //change "?" to the pins the rows of your button matrix are connected to

Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS);

//JOYSTICK SETTINGS
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,
  JOYSTICK_TYPE_JOYSTICK,
  32, //number of buttons
  0, //number of hat switches
  //Set as many axis to "true" as you have potentiometers for
  false, // y axis
  false, // x axis
  false, // z axis
  false, // rx axis
  false, // ry axis
  false, // rz axis
  false, // rudder
  false, // throttle
  false, // accelerator
  false, // brake
  false); // steering wheel

const int numReadings = 20;
 
int readings[numReadings];      // the readings from the analog input
int index = 0;              // the index of the current reading
int total = 0;                  // the running total
int currentOutputLevel = 0;

//POTENTIOMETERS PART 1
//add all the axis' which are enabled above
//int zAxis_ = 0;
//int RxAxis_ = 0;   

               
//POTENTIOMETERS  PART 2
//Which pins are your potentiometers connected to?
//int potentiometerPin1 = ?; //Change "?" to the pin your potentiometer is connected to
//int potentiometerPin2 = ?;
//const bool initAutoSendState = true;


void setup() {
  Joystick.begin();
  rotary_init();
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}

void loop() {

  CheckAllEncoders();
  CheckAllButtons();
  CheckAllPotentiometers();
 
}

//POTENTIOMETERS PART 3
//change the details to match teh details above for each potentiometer you are using
void CheckAllPotentiometers(){
                           
  //potentiometer 1
  currentOutputLevel = getAverageOutput(potentiometerPin1);
  zAxis_ = map(currentOutputLevel,0,1023,0,255);
  Joystick.setZAxis(zAxis_); 

  //potentiometer 2
  currentOutputLevel = getAverageOutput(potentiometerPin2);
  RxAxis_ = map(currentOutputLevel,0,1023,0,255);
  Joystick.setRxAxis(RxAxis_);


}

int getAverageOutput(int pinToRead){
  index = 0;
  total = 0; 
 
  while (index < numReadings){
    readings[index] = analogRead(pinToRead);
    total = total + readings[index];
    index = index + 1;
    //delay (1);
  }
  return total / numReadings;
}


void CheckAllButtons(void) {
      if (buttbx.getKeys())
    {
       for (int i=0; i<LIST_MAX; i++)   
        {
           if ( buttbx.key[i].stateChanged )   
            {
            switch (buttbx.key[i].kstate) { 
                    case PRESSED:
                    case HOLD:
                              Joystick.setButton(buttbx.key[i].kchar, 1);
                              break;
                    case RELEASED:
                    case IDLE:
                              Joystick.setButton(buttbx.key[i].kchar, 0);
                              break;
            }
           }   
         }
     }
}


void rotary_init() {
  for (int i=0;i<NUMROTARIES;i++) {
    pinMode(rotaries[i].pin1, INPUT);
    pinMode(rotaries[i].pin2, INPUT);
    #ifdef ENABLE_PULLUPS
      digitalWrite(rotaries[i].pin1, HIGH);
      digitalWrite(rotaries[i].pin2, HIGH);
    #endif
  }
}


unsigned char rotary_process(int _i) {
  //Serial.print("Processing rotary: ");
  //Serial.println(_i);
  unsigned char pinstate = (digitalRead(rotaries[_i].pin2) << 1) | digitalRead(rotaries[_i].pin1);
  rotaries[_i].state = ttable[rotaries[_i].state & 0xf][pinstate];
  return (rotaries[_i].state & 0x30);
}

void CheckAllEncoders(void) {
  Serial.println("Checking rotaries");
  for (int i=0;i<NUMROTARIES;i++) {
    unsigned char result = rotary_process(i);
    if (result == DIR_CCW) {
      Serial.print("Rotary ");
      Serial.print(i);
      Serial.println(" <<< Going CCW");
      Joystick.setButton(rotaries[i].ccwchar, 1); delay(50); Joystick.setButton(rotaries[i].ccwchar, 0);
    };
    if (result == DIR_CW) {
      Serial.print("Rotary ");
      Serial.print(i);
      Serial.println(" >>> Going CW");
      Joystick.setButton(rotaries[i].cwchar, 1); delay(50); Joystick.setButton(rotaries[i].cwchar, 0);
    };
  }
  Serial.println("Done checking");
}

Now I am missing 3 buttons and the rotary encoders (CLK, DT, SW) are not the ones used in this code. Since it's my first approach with Arduino, I am learning a lot but I can't find more info.

oh the 3D Print model is here Mobeartec button box clone - Small printbed - Sim racing + extra stickers - buttonbox by GuidoHagen - Thingiverse and the pic of the connections on the Arduino is this

As long as You only press one button at the time, that keybord rigging will work. Pressing several buttons at the same time You will read false things.

Thanks for the reply. I read about ghosting, in this case, no need to press multiple buttons at the same time. Sorry for my nick, I didn't notice it was "corrected" somehow to something horrible. I can't find a way to change it so far. Anyway, back to the code. Any idea how can adapt it to what I am building?

I don't understand what the obstacle is. Where are You stuck?

The encoder code is odd. Your struct is looking for two pins to read but your wiring shows three. The pins specified in rotaries don't correspond to your wiring either. For example, the first row specifies pins 0 and 1 but there is nothing attached to them.

Bad idea to use 0 and 1 anyway - you'll need them for the serial port for debugging.

The value 0 is reserved for "NO_KEY" in the Keypad library. You can't use it as a character value without problems. Put in arbitrary unique non-zero values (like 'A' through 'Y') and use "buttbx.key[i].kcode" in place of "buttbx.key[i].kchar". The "kcode" is the position in the matrix from 0 to (rows*columns - 1)..

Your wiring shows a 4x5 matrix but your code shows a 5x5 matrix.

You are sending a key press on both PRESSED and HOLD events and a key release on both RELEASED and IDLE event. There is no need to handle the HOLD and IDLE events.

Are you sure the pin numbers are right for your matrix?

1 Like

Thanks for the heads up, I am going to fix it now. I am not sure of the wiring like I am not sure about the code. I am trying to replicate that button box without much knowledge.

The pins for the matrix are right. I didn't change the pins for the encoders because the joystick library won't work on the Mega.

I also have two questions:

  1. The rotary encoders I use have CLK, DT, SW, +, GND and I am not sure that piece of code applies because while I understand how to code CLK and DT and I don't see where SWITCH goes.
  2. the Joystick library is not supported on Arduino Mega, how can I replace it?

Thanks

You just connect it to an input and use it as you need to.

You decide what to use it for. :+1:

How did the project you are copying work around that problem?

I thought it was just red hat backwards. No one cares.

a7

1 Like

That would be tahder! :rofl:

1 Like

Do you mean they can go on the matrix?

I have no idea, he just posted pictures of 3D print files and the picture of the Arduino mega with the pins used. So I worked backward, I tried to contact the creator but I guess he is busy.

This is how he connected, so my schema and code start from here.

1 Like

I think it would be rather tricky to matrix the push switches on the encoders if you are using the little PCB modules.

Since the modules also include pull-up resistors, it would be difficult to matrix the encoders themselves, even if you could scan a matrix sufficiently fast.

yeah, I also see that the creator did not included them on the matrix, but he has a 5x5 matrix that I can't replicate.

I am not sure of the wiring and I have no idea what code to use to make it work.

Check out this version of the project:
https://3dmixers.com/m/157096-mobeartec-button-box-clone-small-printbed-sim-racing-

It says he used Simhub with the Arduino Mega.