Click here if you are stuck in someone else's frames.
Writing the Joystick Software Library

Okay, now that we've got an understanding on how we can read the joystick port, let's look at writing functions that we can use in other programs (in other words, writing library functions).  Well, when dealing with the reading of the joystick pots, we can either read them one at a time, or all at once and cache their values in variables (the way our last program did).  If you are interested in writing functions that read a single port at a time, here's some sample code that allows you to do just that.

     /* This function returns the value on a single joystick pot. */

     #include <conio.h>    /* Needed for inp and outp functions. */

     #define JsA_Xaxis 0x01
     #define JsA_Yaxis 0x02
     #define JsB_Xaxis 0x04
     #define JsB_Yaxis 0x08

     unsigned int GetPotVal(char bitMask)
     {
         unsigned int retVal = 0;

         disable();                                  /* Disables interrupts */
         outp(0x201, 0);                             /* Discharge caps */
         while(++retVal && (inp(0x201) & bitMask));  /* Count while capacitor is charging */ 
         enable();                                   /* Reenable interrupts */
         return retVal;
     }

To use that code in your programs just simply call it with the appropriate bit mask.  Some constants were also defined for the appropriate bit mask values.  For example:

     x = GetPotVal(JsA_Xaxis);

returns the joystick pot value for the X-axis on joystick A.  Another way is to return them all at once.  This technique is covered because when the code executes the command to discharge the joystick caps, they're discharged all at once.  So it makes sense to go ahead and test all of them at once in a single count loop (like we did earlier).  Here's a function that does just that:

     /* This code reads all the joystick pots at once. */

     #include <conio.h>    /* Needed for inp and outp functions. */

     #define JsA_Xaxis 0x01
     #define JsA_Yaxis 0x02
     #define JsB_Xaxis 0x04
     #define JsB_Yaxis 0x08

     unsigned short jsPotVal[4];

     void Joyin(void)
     {
         unsigned short limit = 0;
         char joyState;

         /* Initialize joystick pot values to zero */
         jsPotVal[0] = jsPotVal[1] = jsPotVal[2] = jsPotVal[3] = 0;

         disable();         /* Disable interrupts */
         outp(0x201, 0);    /* Discharge caps */
         joyState = inp(0x201) & 0x0F;
         do {
             jsPotVal[0] += (joyState & 1);
             joyState >>= 1;
             jsPotVal[1] += (joyState & 1);
             joyState >>= 1;
             jsPotVal[2] += (joyState & 1);
             joyState >>= 1;
             jsPotVal[3] += (joyState & 1);
             limit++;
         } while (limit && (joyState = (inp(0x201) & 0x0F)));
         enable();          /* Enable interrupts */
     }

Now I must caution you about this function.  As it is currently written, it will always test all four joystick pots.  If only one joystick is plugged in then only two joystick pots will return valid values, the other two will time out when the limit rolls back to zero.  Waiting for the loop to time out every time you wish to query the joystick pot values is time consuming and can cause the software using this function to slow down considerably.  To prevent this, we should have a way to test which joystick pots are available and mask out the bits that time out so those joystick pots will not be tested again.  The question here is, how can we determine whether or not a joystick pot is present?  Looking at the do...while loop and you can see that it ends when either all four caps become fully charged ((inp(0x201) & 0x0F) == 0) or when the limit variable times out (rolls back to zero).  The limit variable will count up by one in each loop to its maximum value, 65535.  At the 65536th loop, the limit variable will become zero again.  The four variables for all four joystick pots are also counting up by one on each loop (as long as the corresponding capacitors haven't fully recharged yet) and will also roll back to zero on the 65536th loop along with limit.  This means that if any of these variables are equal to zero when the loop finishes, that variable timed out and the corresponding joystick pot is not available.

There are, of course, some flaws in this and in any software timing loop used to read the joystick.  What if you have a screaming fast system that can perform 65536 loops before any of the capacitors recharge?  What if your system is so slow that the capacitors fully recharge between the time it discharges the caps and the time it checks the port again for their status?  This loop is designed so that the joystick pot values will always be at least a one no matter how slow your system is.  The other end of the problem cannot be as easily fixed, however there are a few suggestions that I can make to help your situation.

You may have also noticed that the software routines above disable the interrupts before running the counting loop.  This is done to get a more accurate reading of the joystick pots.  You typically don't want the timing loop interrupted while it is checking the status of the capacitors.

Previous Page | Main Page | Next page

Send your questions, comments, or ideas here.