Difference between revisions of "49-Way Joystick Conversion Board"
Jump to navigation
Jump to search
Line 64: | Line 64: | ||
</gallery> | </gallery> | ||
− | Amtel Microprocessor Source Code: | + | ==Amtel Microprocessor Source Code:== |
<nowiki> | <nowiki> | ||
//Program Written By: Brad Raedel | //Program Written By: Brad Raedel | ||
+ | //03242020 - Revision A | ||
+ | //** All 8 Profiles active | ||
+ | //** Outputs now change to inputs when not active - This allows the pull-up resistors to control the high logic | ||
//03162020 - Revision 1 - Just get it working | //03162020 - Revision 1 - Just get it working | ||
Revision as of 13:12, 25 March 2020
Contents
49-Way Joystick Information
The Williams 49-Way Optical Joystick was advanced for the time. As the device relied on optical interrupter switches, there were no contacts to wear out or adjust.
Operation - Pinout
- 3 Optical Interrupter Switches are used for each direction (Up/Down-Y and Left/Right -X) .Total of 6 switches
- This provides a total of 7 possible positions in each X and Y axis. (3 Up/1 Center/3 Down - 3 Left/1 Center/3 Right) (7 * 7 = 49 Unique positions)
- There are 8 unique outputs
- Opto Swtich 1 (U/D)
- Opto Switch 2 (U/D)
- Opto Switch 3 (U/D)
- Up/Down Direction
- Opto Switch 4 (L/R)
- Opto Switch 5 (L/R)
- Opto Switch 6 (L/R)
- Left/Right Direction
- 12 Pin Molex Header Pin-Out
- +5 Volts
- Opto Switch 1 (U/D)
- Opto Switch 2 (U/D)
- Opto Switch 3 (U/D)
- Up/Down Direction (Up=Low / Down = High)
- Opto Switch 4 (L/R)
- Opto Switch 5 (L/R)
- Opto Switch 6 (L/R)
- Left/Right Direction (Right = Low / Left = High)
- Key - No Connection
- Ground
- Ground
Custom PCB - Drop-In
Original 49-Way
Programmed Joystick Emulations
- The images and most of the information below is from Sean Riddle's site and the work he did building an EPROM based translator. You can visit his site HERE. (Thanks Sean!)
Amtel Microprocessor Source Code:
//Program Written By: Brad Raedel //03242020 - Revision A //** All 8 Profiles active //** Outputs now change to inputs when not active - This allows the pull-up resistors to control the high logic //03162020 - Revision 1 - Just get it working //Up int Opto1 = 2; //Input Pin 2 int Opto2 = 3; //Input Pin 3 int Opto3 = 4; //Input Pin 4 int Up = 9; //Output to Game - Pin 10 int Dn = 10; //Output to Game - Pin 11 //Down int Opto4 = 5; //Input Pin 5 int Opto5 = 6; //Input Pin 6 int Opto6 = 7; //Input Pin 7 int Left = 11; //Output to Game - Pin 12 int Right = 12; //Output to Game - Pin 13 //Option Switches - These will be used to select mode/options (0 to 15) int Op1 = A0; //1 int Op2 = A1; //2 int Op3 = A2; //4 int Op4 = A3; //8 int OpVal = 0; //Default to zero bool Opto1St; //Opto States bool Opto2St; bool Opto3St; bool Opto4St; bool Opto5St; bool Opto6St; bool UpSt; //Set HIGH when stick is UP bool DnSt; //Set HIGH when Stick is DOWN bool LtSt; //Set HIGH when stick is LEFT bool RtSt; //Set HIGH when Stick is RIGHT bool LockedStUD;//Used to Latch the UP or DOWN position bool LockedStLR;//Used to Latch the LEFT or RIGH postion int UpVal = 3; //Store the Up position (0-2) int DnVal = 3; //Store the Down postion (0-2) int UpDnPos = 3; //Absolute postion of Up/Down 0 = Top, 6 = Bottom, 3 is Center/Neutral int LtVal = 3; //Store the Left position (0-2) int RtVal = 3; //Store the Right position (0-2) int LtRtPos = 3; //Absolute postion of Left/Right 0 = Left, 6 = Right, 3 is Center/Neutral int AbsPos = 24; int i = 0; //Rows Then Columns - Stored Like this { {Row 0 - 0 to 48},{Row 2 - 0 to 48}...etc.. // 8-Way Standard const bool Up8WayStd[49] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Dn8WayStd[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1} ; const bool Lt8WayStd[49] = {1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0} ; const bool Rt8WayStd[49] = {0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1} ; // 8-Way with NO Dead Zone const bool Up8WayNoDZ[49] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Dn8WayNoDZ[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1} ; const bool Lt8WayNoDZ[49] = {1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0} ; const bool Rt8WayNoDZ[49] = {0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1} ; // 8-Way with Dead Zone const bool Up8WayDZ[49] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Dn8WayDZ[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1} ; const bool Lt8WayDZ[49] = {1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0} ; const bool Rt8WayDZ[49] = {0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,1} ; //4-Way Standard const bool Up4WayStd[49] = {0,1,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Dn4WayStd[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,0} ; const bool Lt4WayStd[49] = {0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Rt4WayStd[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0} ; //4-Way Corners L/R const bool Up4WayLR[49] = {0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Dn4WayLR[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,0} ; const bool Lt4WayLR[49] = {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0} ; const bool Rt4WayLR[49] = {0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1} ; //4-Way Corners U/D const bool Up4WayUD[49] = {1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Dn4WayUD[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1} ; const bool Lt4WayUD[49] = {0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Rt4WayUD[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0} ; // 2-Way Horizontal const bool Up2WayH[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Dn2WayH[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Lt2WayH[49] = {1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0} ; const bool Rt2WayH[49] = {0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1} ; // 2-Way Vertical const bool Up2WayV[49] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Dn2WayV[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} ; const bool Lt2WayV[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; const bool Rt2WayV[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ; bool UpOut[49] = {}; bool DnOut[49] = {}; bool LtOut[49] = {}; bool RtOut[49] = {}; void setup() { //Serial.begin(57600); //Disable when not debugging pinMode(Opto1,INPUT); //Set Direction of physical inputs/outputs pinMode(Opto2,INPUT); pinMode(Opto3,INPUT); pinMode(Opto4,INPUT); pinMode(Opto5,INPUT); pinMode(Opto6,INPUT); pinMode(Up,INPUT); pinMode(Dn,INPUT); pinMode(Left,INPUT); pinMode(Right,INPUT); pinMode(Op1,INPUT); pinMode(Op2,INPUT); pinMode(Op3,INPUT); pinMode(Op4,INPUT); //Let's get our DIP Switch settings (Will = 0 to 15) if (digitalRead(Op1) == HIGH) { OpVal = 1; } if (digitalRead(Op2) == HIGH) { OpVal = OpVal + 2; } if (digitalRead(Op3) == HIGH) { OpVal = OpVal + 4; } if (digitalRead(Op4) == HIGH) { OpVal = OpVal + 8; } //Serial.println(OpVal); switch (OpVal) { case 0: //DIP Switch 0 - 8-Way - No Dead zone - This routine copies the array - Only on setup, not during loop/runtime // 8WayStd i = 0; while( i < 49 ){ UpOut[ i ] = Up8WayStd[ i ]; DnOut[ i ] = Dn8WayStd[ i ]; LtOut[ i ] = Lt8WayStd[ i ]; RtOut[ i ] = Rt8WayStd[ i ]; ++i;} break; case 1: //DIP Switch 1 - // 8WayNoDZ i = 0; while( i < 49 ){ UpOut[ i ] = Up8WayNoDZ[ i ]; DnOut[ i ] = Dn8WayNoDZ[ i ]; LtOut[ i ] = Lt8WayNoDZ[ i ]; RtOut[ i ] = Rt8WayNoDZ[ i ]; ++i;} break; case 2: //DIP Switch 2 - // 8WayDZ i = 0; while( i < 49 ){ UpOut[ i ] = Up8WayDZ[ i ]; DnOut[ i ] = Dn8WayDZ[ i ]; LtOut[ i ] = Lt8WayDZ[ i ]; RtOut[ i ] = Rt8WayDZ[ i ]; ++i;} break; case 3: //DIP Switch 3 - // 4WayStd i = 0; while( i < 49 ){ UpOut[ i ] = Up4WayStd[ i ]; DnOut[ i ] = Dn4WayStd[ i ]; LtOut[ i ] = Lt4WayStd[ i ]; RtOut[ i ] = Rt4WayStd[ i ]; ++i;} break; case 4: //DIP Switch 4 - // 4WayLR i = 0; while( i < 49 ){ UpOut[ i ] = Up4WayLR[ i ]; DnOut[ i ] = Dn4WayLR[ i ]; LtOut[ i ] = Lt4WayLR[ i ]; RtOut[ i ] = Rt4WayLR[ i ]; ++i;} break; case 5: //DIP Switch 5 - // 4WayUD i = 0; while( i < 49 ){ UpOut[ i ] = Up4WayUD[ i ]; DnOut[ i ] = Dn4WayUD[ i ]; LtOut[ i ] = Lt4WayUD[ i ]; RtOut[ i ] = Rt4WayUD[ i ]; ++i;} break; case 6: //DIP Switch 6 - // 2WayH i = 0; while( i < 49 ){ UpOut[ i ] = Up2WayH[ i ]; DnOut[ i ] = Dn2WayH[ i ]; LtOut[ i ] = Lt2WayH[ i ]; RtOut[ i ] = Rt2WayH[ i ]; ++i;} break; case 7: //DIP Switch 7 - // 2WayV i = 0; while( i < 49 ){ UpOut[ i ] = Up2WayV[ i ]; DnOut[ i ] = Dn2WayV[ i ]; LtOut[ i ] = Lt2WayV[ i ]; RtOut[ i ] = Rt2WayV[ i ]; ++i;} break; } } //Main Program that loops void loop() { // Up/Down Logic Opto1St = digitalRead(Opto1); //Read Optical Switch 1 Opto2St = digitalRead(Opto2); //Read Optical Switch 2 Opto3St = digitalRead(Opto3); //Read Optical Switch 2 if (Opto1St == true && Opto2St == true && Opto3St == true) //Determine if the joystick is in the center { LockedStUD = false; //Unlatch to allow Up or Down to assume control UpSt = false; //Clear Up State DnSt = false; //Clear Down State UpDnPos = 3; //Set Vertical position to center } //Latch Direction (Determines if up or down if (Opto1St == false && LockedStUD == false) //UP if True { UpSt = true; //Set UP State to TRUE LockedStUD = true; //We lock the State so DOWN can't Steal it! } if (Opto3St == false && LockedStUD == false) //DOWN if True { DnSt = true; //Set DOWN State to TRUE LockedStUD = true; //We lock the State so UP can't Steal it! } //We will figure out what row we are in (0 to 6 - 3 is center) if (UpSt == true) //Up doesn't need any change since adding the Optical Switches is 0 to 2 { UpVal = Opto1St + Opto2St + Opto3St; UpDnPos = UpVal; } if (DnSt == true) //For Down, we determine how many Optical Switches are Low, add them up then use a look-up table to generate the position 4 to 6 { DnVal = Opto1St + Opto2St + Opto3St; switch (DnVal) { case 0: //All Optos are LOW UpDnPos = 6; break; case 1: //Two of the Optos are LOW UpDnPos = 5; break; case 2: //One of the Optos are LOW (The others are still High) UpDnPos = 4; break; } } // Left/Right Logic Opto4St = digitalRead(Opto4); //Read Optical Switch 4 Opto5St = digitalRead(Opto5); //Read Optical Switch 5 Opto6St = digitalRead(Opto6); //Read Optical Switch 6 if (Opto4St == true && Opto5St == true && Opto6St == true) //Determine if the joystick is in the center { LockedStLR = false; //Unlatch to allow Left or Right to assume control LtSt = false; //Clear Left State RtSt = false; //Clear Right State LtRtPos = 3; //Set Horizontal position to center } //Latch Direction (Determines if Left or Right if (Opto4St == false && LockedStLR == false) //Right if True { RtSt = true; //Set Right State to TRUE LockedStLR = true; //We lock the State so Left can't Steal it! } if (Opto6St == false && LockedStLR == false) //Left if True { LtSt = true; //Set Left State to TRUE LockedStLR = true; //We lock the State so Right can't Steal it! } //We will figure out what row we are in (0 to 6 - 3 is center) if (LtSt == true) //Up doesn't need any change since adding the Optical Switches is 0 to 2 { LtVal = Opto4St + Opto5St + Opto6St; LtRtPos = LtVal; } if (RtSt == true) //For Down, we determine how many Optical Switches are Low, add them up then use a look-up table to generate the position 4 to 6 { RtVal = Opto4St + Opto5St + Opto6St; switch (RtVal) { case 0: //All Optos are LOW LtRtPos = 6; break; case 1: //Two of the Optos are LOW LtRtPos = 5; break; case 2: //One of the Optos are LOW (The others are still High) LtRtPos = 4; break; } } //Calculate the absolute position AbsPos = (UpDnPos * 7) + LtRtPos; //Serial.println(AbsPos); //Output //UP if (UpOut[AbsPos] == true){ pinMode(Up,OUTPUT); digitalWrite(Up,LOW); } else { pinMode(Up,INPUT); } //Down if (DnOut[AbsPos] == true){ pinMode(Dn,OUTPUT); digitalWrite(Dn,LOW); } else { pinMode(Dn,INPUT); } //Left if (LtOut[AbsPos] == true){ pinMode(Left,OUTPUT); digitalWrite(Left,LOW); } else { pinMode(Left,INPUT); } //Right if (RtOut[AbsPos] == true){ pinMode(Right,OUTPUT); digitalWrite(Right,LOW); } else { pinMode(Right,INPUT); } }