Oct 30 2009
Audio Memory / Concentration Game : Part 2
In the previous step I created the button panel, installed the buttons, and wired the matrix. This time, I talk about the technique I’m using to read the 4×4 matrix of 16 buttons.
In a typical matrix, you need wires for the rows and for the columns. My 4×4 configuration of buttons means that I would need 8 digital data lines: Four for the columns, four for the rows. This, unfortunately, is a big waste of a very limited number of data lines. I could use some encoder chips, but wanted to avoid that. I wanted a more old school, yet perfectly capable, solution.
Microcontrollers, like the Atmel chip used on the Arduino board, have a selection of I/O pins. Most can be set (via code) to be either input or output. Some are digital (meaning only high/low), but some — and this is the important part — are analog. Not true analog, but they do use an Analog-to-Digital Converter (otherwise known as an ADC).
For the Arduino chips, these ADC pins (there are 6 total) can read voltages between 0V and 5V. They translate voltages within that range into a number between 0 and 1023. For example, 2.5 V would be 511 (it’s a zero base system–you start counting at zero).
Now most often people use these analog pins to monitor analog type inputs, such as potentiometers. Put a resistor in a circuit and it will reduce the voltage (a potentiometer is a variable resistor–it’s what you use to adjust the volume on your stereo). This is the key to saving a bunch of data lines.
One method is to use a ladder type resistor setup. What this means is that all of the switches are tied together with a common wire (say “positive”). Between each switch you put a fixed resistor, all of the same value (say 100 ohms). When you press button one, the circuit is completed with a 100 ohm resistance in there. Second button, 200 ohms. Third button, 300 ohms. And so on. You can tell which button was pressed because it will have a unique resistance. And the ADC on the microcontroller can “convert” that resistance (voltage drop) to a value you can code to.
For a matrix of buttons, as I’m using, I chose a different method: A matrix based switchable resistor network. In this case, each column and row gets its own unique resistor. Something like this:
Column 1 : 100 ohms
Column 2: 200 ohms
Column 3: 300 ohms
Column 4: 400 ohms
Row 1 : 1000 ohms
Row 2 : 2000 ohms
Row 3: 3000 ohms
Row 4 : 4000 ohms
(These are not actual values, just using them as an example.)
Here’s the idea: If you press the button in Column 1 Row 1 you get a resistance of 1100 ohms. Column 1 Row 2 would be 2100 ohms. And so on. Each button will have a unique resistance.
I went with the switchable resistor network in matrix form because this means you don’t need a resistor between each button. This allowed me to make a generic matrix of buttons, with all of the resistor “logic” on a daughter board. So, if the resistor matrix didn’t work out, I could always fall-back to an alternate method (either using 8 data lines or an encoder).
Here is how the 8 wires of switch matrix connect to my little (1″ x 2″) daughterboard:
The blue lines are the columns, the yellow lines the rows. (Four of each.) The braided wires in the middle are all I need to connect to the microcontroller board! Power, Ground, and Data.
Here is a closeup of the little board:
The four resistors on the left are tied to the four columns. Four resistors on the right are the rows. You’ll also notice another resistor in there. That is the voltage divider resistor. It’s also keeps the circuit at 0 volts when nothing is pressed.
Think of the flow of power as this: Power comes into board via the red wire, then goes up through the four resistors on the right (yellow rows) up to the switches. Once a switch is pressed, the power flows “down” the blue wires and through their resistors. The reduced voltage then goes to the Data line (green jumper connected to blue outbound wire). The power also goes though the voltage divider resistor to ground.
So with 9 resistors you have reduced 8 data lines down to 1! Now that’s a good investment in parts!
If you are an Arduino user and you want to use a switched resistor network, in a matrix format, you are probably asking: Well, what the heck resistor values should did you use?
Well, there are resistance calculators out there, but I found two problems: First, they are often for 4×3 “telephone” type matrices. I wanted 4×4. Second, they assume simpler ADCs (with only a resolution of 0 to 254). The Arduino has a better ADC, so why not take advantage of it. (It’s a 10 bit divider, so not that much better than an 8 bit, but so be it.) After some trial and error (I’m not a big “calculate all the voltage drops” kind of guy), I came up with a mix of common resistors that work well:
Side A: 10 (or zero), 1000 (1K), 2000 (2K), 3300 (3.3K)
Side B: 220, 470, 680, 1000 (1K)
And I used a 2000 ohm (2K) resistor for the voltage divider.
Update: I updated these values — got rid of the 5.6K on the high end and added the 2K.
These resistor values gave me a good range on the ADC analog readings on the Arduino – between 920 to 237. And most values are at least 10 apart, so you can do +/- 5 and take into account resistance changes (due to temperature, humidity, etc).
Now the only downside with all this stuff is that you can only reliably read one button at a time. If you press more than one, the power will go though the path of least resistance, meaning the lowest resistance value. Basically, if you mash on the buttons, you’ll get unpredictable results. I tried to accommodate this by “stepping” the resistance in decent increments, but there is certainly a chance that two (or more) sets of buttons will show the same resistance, when pressed in tandem. (I haven’t done the math.)
I’ve probably bored to death most of my readers with this talk of ADCs and Arduinos and resistance matrices, but the web is sparse when it comes to 4×4 (and more) matrices, so I thought I’d do my part and share what I’ve learned. (Leave a comment if you need a schematic or more help.)
Next up: Coding to the ADC / Analog input values, and seeing if I can get this thing talking.
Update: I changed some of the text above, because the “9th” resistor is part of the voltage divider, not a pull down per se. I’m also working on some of the values to get better voltage separation. My first set of buttons ( 1 through 8 ) are well separated, but things get wonky from 9 through 16. I’m working on a spreadsheet so that I can easily see the voltage values.
Update: I built out a spreadsheet for the voltage drops so that I could better determine the gaps. Things seem to be better now and the above values have been updated to reflect the ones I’m currently using.


























