Is it possible to reconfigure joystick + button code to use pins out of order?

Status
Not open for further replies.
Do you know how to program a hat switch? My current problems are just trying to get the digital joystick to work, and getting things to show up on joy.cpl.
 
Thats actually pretty similar to what has been suggested DrVinny ...

One note ... this code ...

Code:
{
int wantedval = joystickButton[i];
int wantedpos;
for (int i=0; i<numButtons; i++) {
   if (wantedval = joystickButton[i]) {
     wantedpos = i;
   }
}
Joystick.button(i + 1, allButtons[i]);
   }
  }
seems to have some bracketing issues, and I think it is (supposed to be?) logically identical to this code..

Code:
for (int i=0; i<numButtons; i++) {
Joystick.button(i + 1, allButtons[i]);
}

since you assign joystickButton to wantedval (but note the index is kind of hanging there???), and then test if wantedval is the same as joystickButton, wantedpos is always going to be i, and of course arrays are indexed 0 to n ... I don't have a compiler on me at the moment, so I'll try at home later .... anyway...

Lebowski...

I had a look at gamepad usb implementations online and it looks like the report descriptor for the X axis and Y axis is waht is usually used, so the dpad has no separate data stream ... I'll check the teensy implementation at home, but I guess it is the same, and it looks like you just have to equate left with X=0, middle X with 512, and X right with 1023, same with Y axis up/down.... will code something tonight when i check out Dr Vinny's stuff (apologies in advance DrVinny, if I have misunderstood the code (50% chance I didn't get it!!)

What pins are the joystick on?
 
Joystick is on pins 12 (right), 13 (left), 14 (down), and 15 (up). No idea how typing angles into the code would do anything when as far as it is concerned it is just 4 buttons right now, being digital and all.
 
Have you read the joystick tutorial? https://www.pjrc.com/teensy/td_joystick.html
If you don't see a joystick in joy.cpl when the teensy is plugged in. It is probably setup wrong, you'll have to go into Arduino go to tools and select an option that has joystick in it.
To read hat you'll probably have to use an If statement. A 4 way hat switch would have 4 buttons, So it would be something like
Code:
if (digitalRead(1))
{
  Joystick.hat(1);
  }
 if (digitalRead(2))
{
  Joystick.hat(90);
  } 
  if (digitalRead(3))
{
  Joystick.hat(180);
  }
  if (digitalRead(4))
{
  Joystick.hat(270);
  }

Something like that should give u a 4 way hat. If you wanted a 8 way hat, you could combine the pin reads with a And statement. IE IF read 1 and 2 would cause Joystick.hat(45). You might also need something to bring the hat back to null.
 
Last edited:
I read the guide but it didn't seem very relevant to the actual code I'm using. The joystick shows up in joy.cpl, but the window is empty, I'll show you what I mean.

Here is a normal window: td_joystick_sc3.png

Here is my window: 2016-02-09 19_08_32-Teensy Keyboard_Mouse_Joystick properties.png

My arcade stick shows up in Devices and Printers as "Teensy Keyboard/Mouse/Joystick" but when I go into the settings it is completely blank for some reason, I have no idea why. I have it setup as a USB joystick in Arduino, and it looked like this before I modified any of the code in the example, so I didn't cause it as far as I know.
 
Thats actually pretty similar to what has been suggested DrVinny ...

One note ... this code ...seems to have some bracketing issues, and I think it is (supposed to be?) logically identical to this code..

I think you're right about that example. I went and looked at a later iteration of that and found some changes.

Code:
  // read digital pins and use them for the buttons
  for (int i=0; i<numButtons; i++) {
    if (digitalRead(joystickButton[i])) {
      // when a pin reads high, the button is not pressed
      // the pullup resistor creates the "on" signal
      allButtons[i] = 0;
    } else {
      // when a pin reads low, the button is connecting to ground.
      allButtons[i] = 1;
    }
   {
int wantedval = (joystickButton[i]);
int wantedpos;
for (int i=0; i<numButtons; i++) {
   if (wantedval = joystickButton[i]) {
     wantedpos = i;
     
   }
}
    
   Joystick.button(wantedpos + 1, allButtons[i]);
   }
  }

I'll post my entire code that my joystick is running on below



Code:
const int numButtons = 22;  // 16 for Teensy, 32 for Teensy++

int joystickButton [] = {
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 31, 16, 17, 18, 19, 20, 21, 22, 23 };

void setup() {

  // you can print to the serial monitor while the joystick is active!
  Serial.begin(9600);
  // configure the joystick to manual send mode.  This gives precise
  // control over when the computer receives updates, but it does
  // require you to manually call Joystick.send_now().
Joystick.useManualSend(true);
  for (int i=0; i<numButtons; i++) {
    pinMode(joystickButton[i], INPUT_PULLUP);
  }
  Serial.println("Begin Complete Joystick Test");
}

byte allButtons[numButtons];
byte prevButtons[numButtons];
int angle=0;

void loop() {

  // read  analog inputs and use them for the joystick axis
  analogReadResolution(16);
  Joystick.X(analogRead(A0));
  Joystick.Y(analogRead(A1));
  
  // read digital pins and use them for the buttons
  for (int i=0; i<numButtons; i++) {
    if (digitalRead(joystickButton[i])) {
      // when a pin reads high, the button is not pressed
      // the pullup resistor creates the "on" signal
      allButtons[i] = 0;
    } else {
      // when a pin reads low, the button is connecting to ground.
      allButtons[i] = 1;
    }
   {
int wantedval = (joystickButton[i]);
int wantedpos;
for (int i=0; i<numButtons; i++) {
   if (wantedval = joystickButton[i]) {
     wantedpos = i;
     
   }
}
    
   Joystick.button(wantedpos + 1, allButtons[i]);
   }
  }
 
 // Because setup configured the Joystick manual send,
  // the computer does not see any of the changes yet.
  // This send_now() transmits everything all at once.
  Joystick.send_now();
  
  // check to see if any button changed since last time
  boolean anyChange = false;
  for (int i=0; i<numButtons; i++) {
    if (allButtons[i] != prevButtons[i]) anyChange = true;
    prevButtons[i] = allButtons[i];
  }
  
  // if any button changed, print them to the serial monitor
  if (anyChange) {
    Serial.print("Buttons: ");
    for (int i=0; i<numButtons; i++) {
      Serial.print(allButtons[i], DEC);
    }
    Serial.println();
  }
  
  // a brief delay, so this runs "only" 200 times per second
  delay(5);
}
 
"left X=0, middle X with 512, and X right with 1023" are not angles! They are fake analog values for your X and Y axis.

i would not worry about the hat switch at the moment ....


Try this .... I don't have a compiler on me .... so there could be errors ...
Code:
const int numButtons = 10;
const uint8_t buttons[numButtons] = { 0, 1, 2, 3, 16, 17, 18, 19, 20, 21};
byte allButtons[numButtons];
byte prevButtons[numButtons];
//int angle=0;

void setup() {
  Serial.begin(9600);
  // configure the joystick to manual send mode.  This gives precise
  // control over when the computer receives updates, but it does
  // require you to manually call Joystick.send_now().
  Joystick.useManualSend(true);
  for (int i=0; i<numButtons; i++) {
    pinMode(buttons[i], INPUT_PULLUP);
  }
pinMode(12, INPUT_PULLUP);
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
pinMode(15, INPUT_PULLUP);
  Serial.println("Begin joystick test excluding hat");
}

void loop() {

  
  // read digital pins and use them for the buttons
  for (int i=0; i<numButtons; i++) {
    if (digitalRead(buttons[i])) {
      // when a pin reads high, the button is not pressed
          allButtons[i] = 0;
    } else {
      // when a pin reads low, the button is connecting to ground and is pressed.
      allButtons[i] = 1;
    }
    Joystick.button(i + 1, allButtons[i]);
  }

  // make the hat switch automatically move in a circle
  //angle = angle + 1;
  //if (angle >= 360) angle = 0;
  //Joystick.hat(angle);
 
if (!(digitalRead(12))) {Joystick.X(1023);  }          // !active low
else if (!(digitalRead(13))) {Joystick.X(0);}
else {Joystick.X(512); }    
if (!(digitalRead(14))) {Joystick.Y(0);  }          // !active low
else if (!(digitalRead(15))) {Joystick.Y(1023);}
else {Joystick.Y(512); }  
 
 Joystick.send_now();
  
  // check to see if any button changed since last time
  boolean anyChange = false;
  for (int i=0; i<numButtons; i++) {
    if (allButtons[i] != prevButtons[i]) anyChange = true;
    prevButtons[i] = allButtons[i];
  }
  
  // if any button changed, print them to the serial monitor
  if (anyChange) {
    Serial.print("Buttons: ");
    for (int i=0; i<numButtons; i++) {
      Serial.print(allButtons[i], DEC);
    }
    Serial.println();
  }
    delay(2);
}
 
Its wierd about joy.cpl ...it seems to be seeing the device ...do you need to press OK, or is there a setting .... Its just weird, and I am not familiar with joy.cpl at all ...
 
Hmm maybe doing the joystick as a hat switch could be a go if you are having trouble with diagonals ...

DrVinny's suggestion as to 8way angles could be a good one ... although it does depend on what your PC game is expecting to see ...

I found this useful post ... the consensus seems to be to send axis info as per my code, but maybe DrVinnys angle code is a go ...

I guess it depends on what works with the program you are trying to control....
 
I'm going to be selling the thing to my friend so I need it to work as generically as possible. I know the standard does exist because I can take one of my other arcade sticks, they show up as an arcade stick in Devices and Printers, all the buttons and the joystick register properly in joy.cpl, and it works with every game I've tried as well as GGPO and MAME, my goal is to recreate a similar level of compatibility with the Teensy. I'll try your code to see if I can get the joystick working in the serial monitor but ultimately it is not productive trying to get that working if there is something preventing the stick from showing up in joy.cpl. I asked the people in the big thread about the 128 button code but haven't got a response yet.
 
I'm going to be selling the thing to my friend so I need it to work as generically as possible. I know the standard does exist because I can take one of my other arcade sticks, they show up as an arcade stick in Devices and Printers, all the buttons and the joystick register properly in joy.cpl, and it works with every game I've tried as well as GGPO and MAME, my goal is to recreate a similar level of compatibility with the Teensy. I'll try your code to see if I can get the joystick working in the serial monitor but ultimately it is not productive trying to get that working if there is something preventing the stick from showing up in joy.cpl. I asked the people in the big thread about the 128 button code but haven't got a response yet.

2 questions.
1. Are you trying to use a teensy 2.0 with the many axis stick files? If so the teensy 2.0 is incompatible with those files. The many axis stick has USB HID descriptors written specifically for the teensy 3.1.

2. Are your other arcade sticks hooked up to a teensy? Joy.cpl is just the windows contronl panel for joysticks. If your using the wrong HID descriptors with your teensy this could be the reason why u don't get the proper response with joy.cpl
 
I just tested the code I gave you on my mame arcade setup ... I compiled the code (no mistakes!!!) for my teensy 3.1 ...put in the pins I have connected my digital joystick to, and .... it works fine...indeed on joy.cpl I can move the plus sign around with my joystick ....

Untitled.jpgUntitled2.jpg



diagonals work pretty well!

Im on windows 7.... perhaps you need to tell us more about your setup ... are u using a teensy 3.x ... are you connecting through a hub (shouldn't make any difference...) ... can u upload blink, are you getting serialprint data on the arduino ide serial monitor? are you getting hid devices appear in windows device manager
 
Last edited:
Could well be, I don't understand the code though.

Perhaps spend a little time to go through these tutorials. They'll get you up to speed on some important basic concepts of Arduino.

http://www.pjrc.com/teensy/tutorial2.html

The Keyboard.print() and Joystick.button() and similar functions are similar to Serial.print(), except they send USB communication as the keyboard and joystick.

Even if you still have to ask question about the arcane programming syntax (a common issue when getting started), at least understanding this material about how the basic functions work will really help you to achieve better projects.
 
I just tested the code I gave you on my mame arcade setup ... I compiled the code (no mistakes!!!) for my teensy 3.1 ...put in the pins I have connected my digital joystick to, and .... it works fine...indeed on joy.cpl I can move the plus sign around with my joystick ....

View attachment 6348View attachment 6349



diagonals work pretty well!

Im on windows 7.... perhaps you need to tell us more about your setup ... are u using a teensy 3.x ... are you connecting through a hub (shouldn't make any difference...) ... can u upload blink, are you getting serialprint data on the arduino ide serial monitor? are you getting hid devices appear in windows device manager

I'm using a Teensy 2.0 with Windows 7, I'm getting serial print data, HiD devices show up find in the device manager, nothing else works. I have no idea what the other guy meant by HiD descriptors, I have no idea why nothing is working. I'm not using the many axis joystick file, I'm using the stock example complete joystick modified for certain pins and functions.
 
Perhaps spend a little time to go through these tutorials. They'll get you up to speed on some important basic concepts of Arduino.

http://www.pjrc.com/teensy/tutorial2.html

The Keyboard.print() and Joystick.button() and similar functions are similar to Serial.print(), except they send USB communication as the keyboard and joystick.

Even if you still have to ask question about the arcane programming syntax (a common issue when getting started), at least understanding this material about how the basic functions work will really help you to achieve better projects.

I wouldn't consider myself "getting started", I'm just building a project. I hate programming, I took a class once and failed with a 10% grade despite having a 90% in electronics, this is the bane of my existence and after this I have no interest in building better projects, I am just extremely incompetent with anything code related and it frustrates the hell out of me, so I'm just looking here for help so I can get it working and move on. I read all four tutorials multiple times and it's not helping me with this project at all.
 
Well, the code I posted works! As Mr Stoffregen said, its not too different from serial print ... the pin matrix and other tweaks are pretty standard too ... BTW I got buttons going too!

I'm happy to explain the code a bit for you. But maybe the problem is something to do with windows joy.cpl ...

A quick question ...
Are you compiling using the teensy 2 option in the IDE, and if so, maybe it is as DRVinny said .... maybe teensy 2 is not compatible with the joystick library (I don't know about that though)... I guess you are using the keyboard/mouse/joystick option...

Is everything tickitee boo in the windose device manager? To be honest, troubleshooting windows is out of my leauge... Check around that the joystick library works with teensy 2, and goodluck! Like I said, I got it all working on my setup, with the code posted above (win7, T3.1)
 
I can't imagine what would be wrong, it is a teensy 2.0 being coded in the arduino software on Windows 7, functioning as mouse+keyboard+joystick, same code you're using that you managed to get working. Probably one of those classic Windows super picky registry/driver issues that basically doesn't make sense. I'll make a new thread about that particular issue and see if someone can help me out.
 
Okay so I got everything working so far except the joystick, all my buttons are registering in joy.cpl in correct order and seemingly flawlessly, everything basically seems to be operating correctly besides the fact that all the joystick currently does is automatically rotate in a circle. Which code am I supposed to use to get an 8-way digital joystick working?

Here is everything as is

Code:
 const int numButtons = 10;
// Changes numButtons to be the specific pins that are wired rather than being incremental 0-16
const uint8_t buttons[numButtons] = { 21, 20, 19, 18, 0, 1, 2, 3, 17, 16 };

void setup() {
  // you can print to the serial monitor while the joystick is active!
  Serial.begin(9600);
  // configure the joystick to manual send mode.  This gives precise
  // control over when the computer receives updates, but it does
  // require you to manually call Joystick.send_now().
  Joystick.useManualSend(true);
  for (int i=0; i<numButtons; i++) {
    pinMode(buttons[i], INPUT_PULLUP);
  }
  Serial.println("Begin Complete Joystick Test");
}

byte allButtons[numButtons];
byte prevButtons[numButtons];
int angle=0;

void loop() {

  
  // read digital pins and use them for the buttons
  for (int i=0; i<numButtons; i++) {
    if (digitalRead(buttons[i])) {
      // when a pin reads high, the button is not pressed
      // the pullup resistor creates the "on" signal
      allButtons[i] = 0;
    } else {
      // when a pin reads low, the button is connecting to ground.
      allButtons[i] = 1;
    }
    Joystick.button(i + 1, allButtons[i]);
    
  }

  // make the hat switch automatically move in a circle
  angle = angle + 1;
  if (angle >= 360) angle = 0;
  Joystick.hat(angle);
  
  // Because setup configured the Joystick manual send,
  // the computer does not see any of the changes yet.
  // This send_now() transmits everything all at once.
  Joystick.send_now();
  
  // check to see if any button changed since last time
  boolean anyChange = false;
  for (int i=0; i<numButtons; i++) {
    if (allButtons[i] != prevButtons[i]) anyChange = true;
    prevButtons[i] = allButtons[i];
  }
  
  // if any button changed, print them to the serial monitor
  if (anyChange) {
    Serial.print("Buttons: ");
    for (int i=0; i<numButtons; i++) {
      Serial.print(allButtons[i], DEC);
    }
    Serial.println();
  }
  
  // a brief delay, so this runs 200 times per second
  delay(5);
}

My joysticks switches are: pin 15 = up, pin 14 = down, pin 13 = left, pin 12 = right.
 
Its going in a circle because of the pov hat code ... try the code from my post #32 and tell me how you get on ...
 
new code
Code:
const int numButtons = 10;
// Changes numButtons to be the specific pins that are wired rather than being incremental 0-16
const uint8_t buttons[numButtons] = { 21, 0, 1, 20, 18, 19, 3, 2, 17, 16 };

void setup() {
  // you can print to the serial monitor while the joystick is active!
  Serial.begin(9600);
  // configure the joystick to manual send mode.  This gives precise
  // control over when the computer receives updates, but it does
  // require you to manually call Joystick.send_now().
  Joystick.useManualSend(true);
  for (int i=0; i<numButtons; i++) {
    pinMode(buttons[i], INPUT_PULLUP);
  }
pinMode(12, INPUT_PULLUP);
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
pinMode(15, INPUT_PULLUP);
  Serial.println("Begin Complete Joystick Test");
}

byte allButtons[numButtons];
byte prevButtons[numButtons];
int angle=0;

void loop() {

  
  // read digital pins and use them for the buttons
  for (int i=0; i<numButtons; i++) {
    if (digitalRead(buttons[i])) {
      // when a pin reads high, the button is not pressed
      // the pullup resistor creates the "on" signal
      allButtons[i] = 0;
    } else {
      // when a pin reads low, the button is connecting to ground.
      allButtons[i] = 1;
    }
    Joystick.button(i + 1, allButtons[i]);
    
  }

 if (!(digitalRead(12))) {Joystick.X(1023);  }          // !active low
else if (!(digitalRead(13))) {Joystick.X(0);}
else {Joystick.X(512); }    
if (!(digitalRead(15))) {Joystick.Y(0);  }          // !active low
else if (!(digitalRead(14))) {Joystick.Y(1023);}
else {Joystick.Y(512); }  
  
  // Because setup configured the Joystick manual send,
  // the computer does not see any of the changes yet.
  // This send_now() transmits everything all at once.
  Joystick.send_now();
  
  // check to see if any button changed since last time
  boolean anyChange = false;
  for (int i=0; i<numButtons; i++) {
    if (allButtons[i] != prevButtons[i]) anyChange = true;
    prevButtons[i] = allButtons[i];
  }
  
  // if any button changed, print them to the serial monitor
  if (anyChange) {
    Serial.print("Buttons: ");
    for (int i=0; i<numButtons; i++) {
      Serial.print(allButtons[i], DEC);
    }
    Serial.println();
  }
  
  // a brief delay, so this runs 200 times per second
  delay(5);
}

Seems to work fine in Street Fighter, although for some reason some software reads the inputs differently than others, so say for USF4 it will decide that the fourth button on my top row of buttons (button 5 as the software says) is the button that is supposed to be used to select things as if it is the "X" button on playstation or the "A" button on xbox. If I change the code so that button 5 is actually where the software thinks it should be, suddenly it decides that button 3 should be used to select things, I have no clue why. Other than that it seems good though.

I would definitely rather have a hat switch if I could get one working, not sure what code to use or if it will ever end up making a practical difference, but it just seems right using what is effectively an 8 way hat as a hat instead of a simulated analog.

edit: it works natively on PS3 too!
 
Last edited:
DrVinnys approach will work for an eightway hat... If I get some time I'll try yo write some code for you following DrVinny's suggestion...
 
Try this ...I've commented out the serial print for the buttons since you have joy.cpl working!

Code:
const int numButtons = 10;
// Changes numButtons to be the specific pins that are wired rather than being incremental 0-16
const uint8_t buttons[numButtons] = { 21, 0, 1, 20, 18, 19, 3, 2, 17, 16 };
const uint8_t joy[] = {12,13,14,15};
bool joyread [4];
void joystick(bool*);
void setup() {
  Serial.begin(9600);
  Joystick.useManualSend(true);
  for (int i=0; i<numButtons; i++) {
    pinMode(buttons[i], INPUT_PULLUP);
  }
for (int i=0; i<4; i++) {
    pinMode(joy[i], INPUT_PULLUP);
  }
  Serial.println("Begin Complete Joystick Test");
}

byte allButtons[numButtons];
byte prevButtons[numButtons];
int angle=0;

void loop() {

  
  // read digital pins and use them for the buttons
  for (int i=0; i<numButtons; i++) {
    if (digitalRead(buttons[i])) {
      // when a pin reads high, the button is not pressed
      // the pullup resistor creates the "on" signal
      allButtons[i] = 0;
    } else {
      // when a pin reads low, the button is connecting to ground.
      allButtons[i] = 1;
    }
    Joystick.button(i + 1, allButtons[i]);
    
  }

/* if (!(digitalRead(12))) {Joystick.X(1023);  }          // !active low
else if (!(digitalRead(13))) {Joystick.X(0);}
else {Joystick.X(512); }    
if (!(digitalRead(15))) {Joystick.Y(0);  }          // !active low
else if (!(digitalRead(14))) {Joystick.Y(1023);}
else {Joystick.Y(512); }  */

for (int i=0; i<4; i++) {
    joyread[i] = digitalRead(joy[i]);
  }

joystick(joyread);
  
  // Because setup configured the Joystick manual send,
  // the computer does not see any of the changes yet.
  // This send_now() transmits everything all at once.
  Joystick.send_now();
  
  /* check to see if any button changed since last time
  boolean anyChange = false;
  for (int i=0; i<numButtons; i++) {
    if (allButtons[i] != prevButtons[i]) anyChange = true;
    prevButtons[i] = allButtons[i];
  }
  
  // if any button changed, print them to the serial monitor
  if (anyChange) {
    Serial.print("Buttons: ");
    for (int i=0; i<numButtons; i++) {
      Serial.print(allButtons[i], DEC);
    }
    Serial.println();
  }
  
  // a brief delay, so this runs 200 times per second*/
  delay(1);
}

void joystick(bool* read)
{
bool rest=true;
if (read[0]) {rest=false;if (read[2]) {Joystick.hat(45);} else if (read[3]) {Joystick.hat(135);} else {Joystick.hat(90);}}
if (read[1]) {rest=false;if (read[2]) {Joystick.hat(315);} else if (read[3]) {Joystick.hat(225);} else {Joystick.hat(270);}}
if (read[2] && (!read[0]) && (!read[1]) ) {rest=false;Joystick.hat(0);}
if (read[3] && (!read[0]) && (!read[1]) ) {rest=false;Joystick.hat(180);}
if (rest) {Joystick.hat(-1);}
}
 
Last edited:
Status
Not open for further replies.
Back
Top