Since that i am now using multiple encoders and interrupts, i am now using direct port manipulation to read the pin states as it is many times faster than regular digitalReads.
I found a way better way to write the Arduino values to the virtual joystick; PPJoyCom. It is a add-on type program for the PPJoy virtual joystick driver. PPJoyCom waits for a initialization byte over the serial port from the Arduino(print a byte value 240+number of channels). then the encoder values range from 0 to 255(max value of a byte) and are sent to PPJoyCom and written to the joystick. way easier than a C# app. :) basic sample PPJoyCom arduino sketch below, along with encoder code.
basic flow:
1. arduino reads HDD encoders for position, button states etc. sends the data to the PPJoyCom program.
3. PPJoyCom program "writes" the values from the Arduino to the virtual joystick.
3. racing game reads the virtual joystick; X axis is turning, Y is throttle, Z is brake, buttons for shifting, menu keys...
#define Xpin 2
#define Ypin 3
#define Btn1Pin 11
#define Btn2Pin 12
byte Xaxis;
byte Yaxis;
byte Btn1 = 0;
byte Btn2 = 0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
Btn1 = digitalRead(Btn1Pin);
Btn2 = digitalRead(Btn2Pin);
Xaxis = analogRead(Xpin) / 4;
Yaxis = analogRead(Ypin) / 4;
Serial.print(244,BYTE); // 240 + # of channels, 2 Buttons and 2 axis
Serial.write(0);
Serial.print(Btn1,BYTE);
Serial.print(Btn2,BYTE);
Serial.print(x,BYTE);
Serial.print(y,BYTE);
delay(25);
}
#include <PinChangeInt.h>
#include <PinChangeIntConfig.h>
#define WheelPinA 2
#define WheelPinB 3
#define GasPinA 4
#define GasPinB 5
#define BrakePinA 6
#define BrakePinB 7
#define ClutchPinA 8
#define ClutchPinB 9
#define Gear1pin 10
#define Gear2pin 11
#define Gear3pin 12
#define Gear4pin 13
#define Gear5pin 14 //A0
#define Gear6pin 15 //A1
#define ShiftModepin 16 //A2, real shifting or speed shift
#define Aux1pin 17 //A3
#define Aux2pin 18 //A4
#define Aux3pin 19 //A5
volatile unsigned int Encoders[3] = {0}; //wheel, gas, brake, clutch
volatile boolean ButtonStates[3] = {0}; //current gear, shift mode, aux: 1, 2, or 3
void setup()
{
// 76543210
//(PIND & B00001000) check only the pin '1' (in this case digital 3) in this line for low or high, & means dont check any others
//would be the same as: PIND & (1 << 3);
//1111111 checking for true would be 128+64+32+16+8+4+2+1
//(PIND & B00001000) checking for true would be 8
//goes from left to right
// 76543210
DDRD = B00000000; //sets 2 through 7 as inputs
PORTD &= B11111100; //enable pullups on all but tx/rx
// ..13...8
DDRB &= B11000000; //sets through 13 as inputs excpet for crytsl pins
PORTB &= B00111111; //enable pullups on all but crystal pins
// ..543210
DDRC = B00000000; //sets analog 0 through 5 as inputs
PORTC &= B00111111; //enable pullups on all but analog 6 an 7 (6 and 7 arent avaliable on atmega 328)
PCattachInterrupt(WheelPinA, WheelTrigA, CHANGE);
PCattachInterrupt(WheelPinB, WheelTrigB, CHANGE);
PCattachInterrupt(GasPinA, GasTrigA, CHANGE);
PCattachInterrupt(GasPinB, GasTrigB, CHANGE);
PCattachInterrupt(BrakePinA, BrakeTrigA, CHANGE);
PCattachInterrupt(BrakePinB, BrakeTrigB, CHANGE);
PCattachInterrupt(ClutchPinA, ClutchTrigA, CHANGE);
PCattachInterrupt(ClutchPinB, ClutchTrigB, CHANGE);
PCattachInterrupt(Gear1pin, GearItrig, CHANGE);
PCattachInterrupt(Gear2pin, GearIItrig, CHANGE);
PCattachInterrupt(Gear3pin, GearIIItrig, CHANGE);
PCattachInterrupt(Gear4pin, GearIVtrig, CHANGE);
PCattachInterrupt(Gear5pin, GearVtrig, CHANGE);
PCattachInterrupt(Gear6pin, GearVItrig, CHANGE);
PCattachInterrupt(Aux1pin, AuxItrig, CHANGE);
PCattachInterrupt(Aux2pin, AuxIItrig, CHANGE);
PCattachInterrupt(Aux3pin, AuxIIItrig, CHANGE);
PCattachInterrupt(ShiftModepin, ShiftTrig, CHANGE);
Serial.begin (115200);
}
void loop()
{
for(int x=0; x<4; x++)
{
Serial.print(Encoders[x]);
Serial.print(","); //delimiter
}
for(int x=0; x<4; x++)
{
Serial.print(ButtonStates[x]);
Serial.print(","); //delimiter
}
Serial.println();
}
void GearItrig()
{
ButtonStates[0]=1;
}
void GearIItrig()
{
ButtonStates[0]=2;
}
void GearIIItrig()
{
ButtonStates[0]=3;
}
void GearIVtrig()
{
ButtonStates[0]=4;
}
void GearVtrig()
{
ButtonStates[0]=5;
}
void GearVItrig()
{
ButtonStates[0]=6;
}
void ShiftTrig()
{
ButtonStates[1]=~ButtonStates[1];
}
void AuxItrig()
{
ButtonStates[2]=1;
}
void AuxIItrig()
{
ButtonStates[2]=2;
}
void AuxIIItrig()
{
ButtonStates[3]=3;
}
void WheelTrigA()
{
// look for a low-to-high on pin A
if ((PIND & B00000100) == 4)
{
// check pin B to see which way encoder is turning
if ((PIND & B00001000) == 0)
{
Encoders[0] -= 1; // CW
}
else
{
Encoders[0] += 1; // CCW
}
}
else // must be a high-to-low edge on pin A
{
// check pin B to see which way encoder is turning
if ((PIND & B00001000) == 8)
{
Encoders[0] -= 1; // CW
}
else
{
Encoders[0] += 1; // CCW
}
}
//Serial.println (Encoders[0], DEC);
// use for debugging - remember to comment out
}
void WheelTrigB()
{
// look for a low-to-high on pin B
if ((PIND & B00001000) == 8)
{
// check pin A to see which way encoder is turning
if ((PIND & B00000100) == 4)
{
Encoders[0] -= 1; // CW
}
else
{
Encoders[0] += 1; // CCW
}
}
// Look for a high-to-low on pin B
else
{
// check pin B to see which way encoder is turning
if ((PIND & B00000100) == 0)
{
Encoders[0] -= 1; // CW
}
else
{
Encoders[0] += 1; // CCW
}
}
}
void GasTrigA()
{
// look for a low-to-high on pin A
if ((PIND & B00010000) == 16)
{
// check pin B to see which way encoder is turning
if ((PIND & B00100000) == 0)
{
Encoders[1] -= 1; // CW
}
else
{
Encoders[1] += 1; // CCW
}
}
else // must be a high-to-low edge on pin A
{
// check pin B to see which way encoder is turning
if ((PIND & B00100000) == 32)
{
Encoders[1] -= 1; // CW
}
else
{
Encoders[1] += 1; // CCW
}
}
//Serial.println (Encoders[1], DEC);
// use for debugging - remember to comment out
}
void GasTrigB()
{
// look for a low-to-high on pin B
if ((PIND & B00100000) == 32)
{
// check pin A to see which way encoder is turning
if ((PIND & B00010000) == 16)
{
Encoders[1] -= 1; // CW
}
else
{
Encoders[1] += 1; // CCW
}
}
// Look for a high-to-low on pin B
else
{
// check pin B to see which way encoder is turning
if ((PIND & B00010000) == 0)
{
Encoders[1] -= 1; // CW
}
else
{
Encoders[1] += 1; // CCW
}
}
}
void BrakeTrigA()
{
// look for a low-to-high on pin A
if ((PIND & B01000000) == 64)
{
// check pin B to see which way encoder is turning
if ((PIND & B10000000) == 0)
{
Encoders[2] -= 1; // CW
}
else
{
Encoders[2] += 1; // CCW
}
}
else // must be a high-to-low edge on pin A
{
// check pin B to see which way encoder is turning
if ((PIND & B10000000) == 128)
{
Encoders[2] -= 1; // CW
}
else
{
Encoders[2] += 1; // CCW
}
}
//Serial.println (Encoders[2], DEC);
// use for debugging - remember to comment out
}
void BrakeTrigB()
{
// look for a low-to-high on pin B
if ((PIND & B10000000) == 128)
{
// check pin A to see which way encoder is turning
if ((PIND & B01000000) == 64)
{
Encoders[2] -= 1; // CW
}
else
{
Encoders[2] += 1; // CCW
}
}
// Look for a high-to-low on pin B
else
{
// check pin B to see which way encoder is turning
if ((PIND & B01000000) == 0)
{
Encoders[2] -= 1; // CW
}
else
{
Encoders[2] += 1; // CCW
}
}
}
void ClutchTrigA()
{
// look for a low-to-high on pin A
if ((PINB & B00000001) == 1)
{
// check pin B to see which way encoder is turning
if ((PINB & B00000010) == 0)
{
Encoders[3] -= 1; // CW
}
else
{
Encoders[3] += 1; // CCW
}
}
else // must be a high-to-low edge on pin A
{
// check pin B to see which way encoder is turning
if ((PINB & B00000010) == 2)
{
Encoders[3] -= 1; // CW
}
else
{
Encoders[3] += 1; // CCW
}
}
//Serial.println (Encoders[3], DEC);
// use for debugging - remember to comment out
}
void ClutchTrigB()
{
// look for a low-to-high on pin B
if ((PINB & B00000010) == 2)
{
// check pin A to see which way encoder is turning
if ((PINB & B00000001) == 1)
{
Encoders[3] -= 1; // CW
}
else
{
Encoders[3] += 1; // CCW
}
}
// Look for a high-to-low on pin B
else
{
// check pin B to see which way encoder is turning
if ((PINB & B00000001) == 0)
{
Encoders[3] -= 1; // CW
}
else
{
Encoders[3] += 1; // CCW
}
}
}
I've modified your code to work with a single linear pot and it the analog signal always comes up as a digital one when I check it with the windows game controller.
ReplyDeleteAny help would be awesome.
[code]
#define Xpin 0
byte Xaxis;
void setup(){
Serial.begin(9600);
}
void loop()
{
Xaxis = analogRead(Xpin) / 4;
Serial.write(241); // 240 + # of channels, 2 Buttons and 2 axis
Serial.write(Xaxis);
delay(25);
}
[/code]
Oh, just thought of something! in PPjoy you have to setup the buttons/analog inputs correctly. like if you have:
ReplyDeleteSerial.write(241);
Serial.write(Xaxis);
then a analog input would need to be set as the first input in PPjoy, not a digital. http://www.etheli.com/simulator/simulator.html look at first pic here.
Thanks alot!
DeleteThat solved the issue.
Been searching for long time for a tutorial for PPjoy with Ardiuno.
I need some help with something regarding arduino or ppjoy... Iva used your code exactly as it is and axes work great but buttons keeps flashing in game controller properties.
ReplyDeleteDo you have a clue what could be?? I tried every code ive found but axes work and buttons dont
Ive set up ppjoy to read all 16 buttons, however button 1 keeps flashing and button 2 doesnt exist.
I hope ive made some sense here. English is not my first lenguaje.
(using windows 7 64)
Tranks!!
strange, so do the other buttons work? are you using actual buttons on the arduino, or are you just testing the code? if you are using actual buttons, try taking out the button read and make the arduino always send one state(high or low) to ppjoy and see if ppjoy lines up with it.
ReplyDeleteHey, I am having an issue getting the ppjoycom to recognize the serial signal from the arduino. The serial monitor on the arduino program shows that a signal is coming through. However ppjoycom does not even register a initiation. It just says "Error 2 opening port" Any ideas?
ReplyDeletethat sounds more like something else is using the COM port at the same time. you say "arduino program shows that a signal is coming through" which im guessing mean you have the serial window open in the arduino IDE... close that serial window, then try.
ReplyDeletewhere do i put the code? should i use both codes or what ?
ReplyDeletefirst is an example, second is actual project
Deleteim having a problem, ppjoy recognice the first button, but not the second one, im using actual buttons.
ReplyDeleteim ussing pullups because i was haven missreadings on open buttons
[code]
#define B4Pin 10
#define B3Pin 11
#define B2Pin 12
#define B1Pin 13
#define Xpin A5
#define acelPin A0
#define frenoPin A2
byte Xaxis;
byte acel;
byte freno;
byte Bot1;
byte Bot2;
byte Bot3;
byte Bot4;
void setup()
{
Serial.begin(9600);
pinMode(B4Pin,INPUT_PULLUP);
pinMode(B3Pin,INPUT_PULLUP);
pinMode(B2Pin,INPUT_PULLUP);
pinMode(B1Pin,INPUT_PULLUP);
}
void loop()
{
Xaxis = analogRead(Xpin)/8;
acel= analogRead(acelPin)/4;
freno= analogRead(frenoPin)/4;
Bot4=digitalRead(B4Pin);
Bot3= digitalRead(B3Pin);
Bot2= digitalRead(B2Pin);
Bot1=digitalRead(B1Pin);
byte Ib1= !Bot1;
byte Ib2= !Bot2;
byte Ib3= !Bot3;
byte Ib4= !Bot4;
Serial.write(245); // 240 + # of channels, 2 Buttons and 2 axis
//Serial.write(Ib1);
//Serial.write(Ib2);
Serial.write(Ib3);
Serial.write(Ib4);
Serial.write(Xaxis);
Serial.write(acel);
Serial.write(freno);
delay(25);
}
[/code]
in serial write, that should be 247, not 245
Deleteyeah i was alittle desperate, i tried everything, but 2 buttons are comented
Deletesetup yours just like mine and see if it works, then add stuff
Deleteyou mean 2 axis 2 buttons?
Deleteyes
Deletesorry for taking me so long to answer, now buttons dont respond, no problem with pedals.
DeleteSerial.write(244); // 240 + # of channels, 2 Buttons and 2 axis
Serial.write(Ib1);
Serial.write(Ib2);
//Serial.write(Ib3);
//Serial.write(Ib4);
//Serial.write(Xaxis);
Serial.write(acel);
Serial.write(freno);
Just send a Serial.write(0); after the initialization byte (240 + # of channels). It is needed (but not documented). After that all my axis and buttons worked.
ReplyDeleteSerial.write(244);
Serial.write(0);
Serial.write(Ib1);
Serial.write(Ib2);
//Serial.write(Ib3);
//Serial.write(Ib4);
//Serial.write(Xaxis);
Serial.write(acel);
Serial.write(freno);
thanks, ill add that
DeleteOf course, the tuorial doesnt have it, but the project code does, DOH! haha anyways, its fixed now.
Deletebyte Btn1;
ReplyDeletebyte Btn2;
byte Xaxis;
void setup(){
Serial.begin(9600);
}
void loop(){
Btn1 = digitalRead(28);
Btn2 = digitalRead(26);
Xaxis = analogRead(A0) / 4;
Serial.write(byte(243));
Serial.write(byte(0));
Serial.write(byte(Xaxis));
Serial.write(byte(Btn1));
Serial.write(byte(Btn2));
delay(25);
}
This code is not recognizing the two buttons, i have changed it a lot of times, but still id doesent work, any help please?