Sunday, 27 November 2011

Using a multiplexed keypad for other input ideas

After a less-than-successful show-and-tell session at the weekend (yes, the one we've been devoting so much time and effort to over the last few weeks, and putting all our own personal projects on the backburner for!) the few people who did turn up spent some time discussing the various projects we were working on.

A few old ideas were explored once again - sometimes a fresh pair of ideas on an old problem can turn up some really interesting ideas in themselves - and a few new ideas were chewed over.

One of the ideas that came up was using a keypad style matrix, not for output (lighting LEDs like we were doing with our charlie-plexed array for the word clock) but for input. It came following the announcement that some of the members of BuildBrighton were looking to set up a monthly board-game-geek meeting (ok, we left Brighton some time ago, but it's important to keep in touch and see what those crazy guys are up to every now and again!). A few of us here at Nerd Towers remember fondly playing uber-geek board games like Blood Bowl, HeroQuest and Space Crusade, as pimply-faced youths, when they were first released during the 80s.

The idea being investigated is using a microcontroller to load data about each piece (a lot of playing pieces in these role-play type games had a range of different values associated with them) and then to place them on the board in a specific sequence. Each piece will be a "dumb" token - i.e. does not contain or broadcast data about itself - but the board-game controller would keep track of each piece on the board, based on when it was placed on the board, and comparing the current board state with a previously known state, to work out which piece has been lifted off the board.

A quick search on Google turned up some interesting results, but most solutions broadly follow one of two methods - a multi-plex approach (using a pin to activate a full row of inputs, then querying each pin on the row to see if it has been activated) and an analogue approach, to reduce the number of pins required.
Because we're potentially dealing with hundreds of squares on a typical board game (even the simplest of board games, chess, uses 64 squares in an 8x8 grid) we're keen to keep the number of pins required down to an absolute minimum:

With the correct value resistors, we should be able to read which key has been pressed using a single input pin. This idea looks perfect for what we need. However, in practice this is quite a difficult method to implement. Why?

The solution above is better suited to single-key entry, such as a telephone keypad or security pad, where each key is pressed, one at a time.

To be able to detect multiple key presses using a single analogue input pin, we'd need to use resistor values in roughly base-2 increments. i.e. 200 ohms, 400 ohms, 800 ohms, 1600 ohms, 3200 ohms etc.
Now we know that 
a) resistors don't always come in exactly the value we want so we have to go for a best match
b) resistors have up to 10% error in them already
c) reading an analogue input is not accurate - you need to take an average over time, or work with "bands" or thresholds, to decide the true value of the input on the analogue pin.

In fact, to get to 16 inputs, we'd end up using really huge value resistors - the error in which could be more than some of the lowest-value resistors, further down the array. In short, calculating unique key combinations on a single analogue input pin is going to be, at best, difficult and in practice, almost impossible!

Which takes us back to the multi-plex approach:

Here, we need to strobe each of D0, D1, D2, D3 and take multiple readings to calculate which pins are pressed. So, for example, we could force Port1 (output) D0 low (since the outputs are tied to Vcc through a pull-up resistor) and then read the values on input pin D3 on the Port2 (input).
Under normal circumstances, D3 is pulled high through the pull up resistor at the top left of the circuit. If, however, D3 is LOW, we know that button 3 must be being pressed down. Now we read the value of Port2 D2. Like before, we expect it to be high (no button pressed) but if it is low, this tells us that button 2 must be being pressed. Similarly, if Port2 D1 is low, button 1 is pressed, and if Port2 D0 is low, button 0 must be being held down.

Now we sent Port1 (output) D0 high and pull Port1 D1 (output) low.
Checking the input pins again this time tells us whether buttons 7,6,5 or 4 are held down.

Although this approach uses more pins and appears more complex (in execution rather than in hardware) it does allow us to tell exactly which combination of buttons are pressed, even if two, three or more buttons are pressed all at the same time.

We're looking at the 18F4550 which is a 40-pin PIC microcontroller (and includes USB so we can easily download game data onto the chip) but when you take out all the used pins (2 x power, 2 x ground, usb etc) we're lucky if we have up to 28 pins to play with.
In a grid arrangement, this gives us not much more than a 14 x 14 matrix which is pretty small for anything but the simplest of board games......