« Back to project details
Newest
-
PC Gameport - Basic circuit
04/12/2020 at 03:25 • 0 commentsThe basic PC Gameport provides connection for up two controllers with 2 axes and 2 buttons each.
Each axis is composed by a 100k potentiometer in series with a internal capacitor to form the RC timing network of a timer chip. Every time the PC wants to sample the axes it discharges the capacitors and then counts the time that it takes until each axis reach the Vih (input threshold voltage of the timer chip).
When in idle, both axes shall present half of the potentiometer value (50K). When the stick LEFT and UP the potentiometer of X and Y axes shall respectively present a resistance close to zero. On the opposite side, when the the stick is RIGHT and DOWN the resistance should be close to 100K.To measure the potentiometers using the Arduino, there are two possibilities:
- Adding a capacitor on each axis and measuring the time just like the PC does.
- Using the ADC altogether with external pulldown resistors.
First method provides a more precise method but requires a protection resistor and a timing capacitor for each axis.
The timing measured shall be done using a constant time loop so the value of one axis do not interfere in the measurement of another. That can be accomplished without counting cycles in assembly. The trick is simple: Make a loop and add the variable that counts each axis with the corresponding bit of that axis. The time required to mask and shift the bits is independent of their values
void samplePCjoystick() { static volatile uint16_t counter=0; uint8_t sample; a1X=0; a1Y=0; a2X=0; a2Y=0; releaseCaps(); delayMicroseconds(5); counter = 1024; do { // sample inputs with time constant loop sample = ~PINC; delayMicroseconds(3); a2Y+=sample & 1; sample>>=1; a2X+=sample & 1; sample>>=1; a1Y+=sample & 1; sample>>=1; a1X+=sample & 1; } while (--counter); // reset caps holdCaps(); }
The second method requires only a pull down resistor but provides a non-linear curve that must be linearized.
If we choose a 39k ohm for the pull down resistor we can count on PCJoy library that perform the linearization
int8_t PCJoy::_adcTo100(uint16_t adc) { int32_t retval = ((int32_t) 79794 / adc) - 178; if (retval < -99) return -99; else if (retval > 99) return 99; else return retval; }
That will return a value within -99 to 99.