4x4 Keypad Decoder - the Hard Way
doggiedoc
Posts: 2,241
I've been working on a solution to get some surplus 4x4 Keypads I found interfaced to the Propeller. Ultimately I noticed that the LEDs I had connected to decipher the row and column connections made a pattern for each key pressed. I'm sure this is a very round about way to do it but once I got it in my head that I should be able to do it this way, I kept at it until I made it work. I suspect someone will point out an easier solution but hey, I did it my way.
I drew the schematic with Fritzing but I think it's fairly accurate to what I've done on the breadboard. The TLP621 optoisolator was just an easy image to use. I actually home-brewed them from infrared LEDs and phototransistors heat-shrinked together.
I don't really understand why it works but I have germanium diodes reversed biased at the anode of the phototransistor and I am pretty sure the photo resistor is connect backwards. But it works.
The blue wires connect the Prop pins P0-P7 to the anode of the phototransistor which are all read into a long and the bit pattern compared with a case statement to determine which key was pressed.
{16 Key Matrix Test 10/21/2012 Paul A. Willoughby, DVM} CON _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz _xinfreq = 5_000_000 VAR long key, keyPattern OBJ pst : "Parallax Serial Terminal" PUB Main Initialize repeat GetKeyPress if (key) DisplayKey PUB DisplayKey 'pst.Home 'pst.str(string("Key Pattern = ")) 'pst.bin(keyPattern, 8) 'pst.str(string(" ")) pst.str(key) key := 0 waitcnt(clkfreq/5 + cnt) 'pst.NewLine PUB GetKeyPress keyPattern := ina[0..7] waitcnt(clkfreq/30 + cnt) case keyPattern %1000_1000 : key := string("0") %1000_0100 : key := string("1") %1000_0010 : key := string("2") %1000_0001 : key := string("3") %0100_1000 : key := string("4") %0100_0100 : key := string("5") %0100_0010 : key := string("6") %0100_0001 : key := string("7") %0010_1000 : key := string("8") %0010_0100 : key := string("9") %0010_0010 : key := string("A") %0010_0001 : key := string("B") %0001_1000 : key := string("C") %0001_0100 : key := string("D") %0001_0010 : key := string("E") %0001_0001 : key := string("F") PUB Initialize dira[0..7]~ pst.start(115_200) pst.Home keyPattern := %0000_0000
Comments
The other way I have seen this done is using different value resistors on the rows and columns coupled with a voltage input. By reading the output voltage you can determine which key is pressed.
I think I tried just resistors in place of the diodes at some point but I got no high logic on the Prop pins. I'll try again. Sometimes it's hard to keep track of other changes that could have been a factor.
I have 3 H24A1 optocouplers in my bin (from some kit) that I had in the circuit at first - they are so long obsolete that I can't find more of them anywhere.
Thank you for the help.
I'm sure you know this but in case you just forgot....:)
If you wanna use a chip, why not to put a SX28 in your design? Despite the EOL you can buy a bunch of them to satisfy any non high volume demand you can imagine..
I'm also sure you can think in many clever ways to extract the last drop of juice from the remaining processor power.
The price is great and board real state can be compared to the trhough hole parts needed (resistors, diodes ...;)
Yanomani
Actually, that is a pretty ingenious way of decoding a keyboard. With 2 of the chips Beau suggested the cost is reasonable, and it would work/fit well on a system with an 8 bit data bus for interfacing peripherals. Have to add both the circuit and opto chips to my store of useful circuits and parts.
I can't believe I missed it in the first schematic, but the emitters of the output transistors are going to 3.3V and the collectors to ground. Shouldn,t they be the other way around? Were they actually connected like that or is it an error in the schematic? I know the transistors will work when connected backwards, but usually the gain is pretty poor.
I saw that also.. probably why only a 1 Meg resistor works. Notice the diodes are also backwards.... You can run a transistor like that with the E-C swapped, but it doesn't work nearly as well. I noticed this after I PM'd doggiedoc with a simplified design of what he has posted that eliminates the opto-isolators.
This would make a good student exercise. Find the ones who can think outside the square a little
You can eliminate R1-R7 is you want, as this is a series-current design, and you only expect one cross-point at a time.
Increase R17 and move the output sides, so they are not driven via R17. ( ie R17 is IR diodes only)
I would split R17 so it was equally in both sides of the Opto path, as that gives highest ESD protection.
If you flip the Photo TX around the right way, you should be able to lower Diode drive to ~1mA or lower.
I see Quad-opto couplers, can come as low as 32c/1k
For a more conventional scanned design, the HC194 or HEF4021 can be used.
Or, you could implement the same series-current approach, using 4 x PUMD24, in place of the OptoCouplers.
( PUMD24 is a SOT363, Dual PNP/NPN Resistor/Transistor - Mouser show them @ 5c/1+, 3.3c/3k+)
Very low current, and the WAITPNE could wait-on-keypress, at low RC Osc speed.
Its called reverse biased leakage current. All electronic devices exhibit this. Some more some less.
Germanium diodes generally have more leakage current than most. So, in your circuit, they appear to be high value pull down resisters.
In a completely different application, an Experimental Solar Tracker, I needed some high valued resistors, around 100MΩ, not a readily available value. I found that generic 1N4148 diodes worked nicely. BAS416 didn't work because the leakage current was much to low. Your 1N34A germanium diodes have even higher leakage current than the 1N4148 diodes.
A nice thing to keep in ones electronic "Bag of Tricks".
Also, you were surprised that you observer 3.6V on the input pin which is higher than VDD of 3.3V. This is caused by the photo transistor acting as a photovoltaic cell generating enough current to overcome the diode leakage current of the diode resulting in a net +0.3V in your case.
A bit off topic:
Steve Ciarcia of Circuit Cellar, many years ago, used a 64k bit dynamic ram chip with the top popped off as a rudimentary camera. Essentially the light caused the tiny capacitors of the memory cells to leak current and change the bit values resulting in an image.
Duane J
Thanks for making me feel really old Duane
-MattG
Btw, the glass case signal diodes also photo-conduct. (and I assume they also emit IR when forward biased) If you ever need a bad photo-diode they work great.
Lawson
In some applications this can be quite troublesome making it very difficult to diagnose some circuit problems.
I once had a circuit that had erratic operation when outdoors. It was in a black project box with a plexiglass top.
When brought inside to fix it everything worked just fine in the dim light of my shop.
I finally figured out the thing worked outdoors when my head cast a shadow on it. Then just with my finger
over the glass diodes. Bingo! Light sensitivity of the glass diodes in a high impedance op-amp circuit.
The simple fix was a little piece of black electrical tape. A bit crude but it worked.
I now have some glass diodes in my junk box that I coated with black Silicone Rubber. Just in case I need them.
Or use surface mount diodes in black epoxy packages.
Duane J
But on the other hand it will fail miserable on multi press unlike a 4x4 scan would not
but with 4x4 scan stopped (sleep) you're limited to one selective row of keys for wakeup.
That is 24 parts, vs just 4 if you use 4 x PUMD24.
It also will likely have a Static Icc cost, as the pins are not at logic levels, so not be great for very low power waits.
Not if you have a 5th scan choice, which many chips and designs do.
You drive all rows low, and look for any column low, and then remove the Row drives one at a time until the Column goes hi.
You can also save a pin, as one row can be always low, or scan 20 keys on a 4+4 connection.
This allows a WAITPNE, but does need some decode tests, tho they are similar to the case statement decode anyway..