Now that you have seen my proof of concept Arduino shield, let's take a look back at the development.
After I came up with the core idea, prototyping went quick. At the end of the first day, I had this device. Nice and simple, I had two momentary buttons as well as two LEDs connected to the digital pins on the Arduino. If the button on the left was pressed, the Arduino would send a keypress to the host OS it was connected to, and light up the left LED. If the button on the right was pressed, a different key press would be sent, and the other LED would illuminate.
With a working concept I tackled the next issue, I/O. I knew that I wanted at least 8 buttons and 8 LEDs (ideally 16×16 or more), however the Arduino only has 13 digital IO ports. After doing some research, and comparing the merits of Shift registers and different IO expanders, I settled on the Microchips MCP23017. The MCP23017 is a 16-bit port I/O Expander which communicates over the I2C serial protocol. Using one of these ICs would allow me to expand to 8 inputs, and 8 outputs on the same chip. The interesting part comes when you daisy chain the chips, allowing expansion up to 128bit (64 in, 64 out in my case).
Arduino provides support for I2C through a library called Wire, which makes this process a breeze. The basic idea is to designate the two separate busses of the controller as input or output, and then you can request the current state of each bus. The output is returned as binary, and is positional as to what inputs are high. For example, if the 1st input on one bank of the controller were high, it would return 1. However, if the 4th input were high, it would return 1000. To combat this, I had to create a function, which contains a bunch of cases to return a decimal number from this nonstandard binary input.
int convertDecimal (byte binary)
int dec = 0;
if(binary == B1000)
dec = 3;
After the input is sanitized to a decimal number, it is sent to a Keyboard.press command which specifies an array. Inside of this array are ASCII keyboard IDs, which correspond to buttons on a standard keyboard. In this case, I am using 225-232, which end up translating to NumPad 1-8. This is because I used the number pad to switch shots previously, but could be set to any group of keys. The decimal number which is outputted from the conversion function is then used in the array to determine what key to "press" when the emulated HID device sends a signal to the computer. I set up the array to correspond to the button positions, so button number 1 on the shield is position 0 of the array, also known as NumPad 1 to the host OS.
In later iterations of the code, I have implemented loading the contents of this "keycode" array from a CSV file stored on a SD card, which is hooked up through the SPI Serial interface to the Arduino. This will allow for user reconfiguration of what keys are being used without having to recompile and upload the microcode to the Arduino, and will be way easier for the end user to tailor it to their own needs.