Charlieplexing switches - Page 1
Forum section: electronics / beginners

author: edy
author_rank: Super Contributor
timestamp: January 27, 2013, 04:52:40 am
content: I have some push-button switches and I want to detect when they are pressed down. I was hoping to charlieplex a few and then run a loop that scans through all of them to see if any are pressed down. However, I believe I ran into a technical problem with having pull-down (or up) resistors tied into the circuit. This is to be used on Arduino.Take for example the simplest case... 2 switches charlieplexed with a couple LED or simple diodes. The switches would be in parallel, with each line of the parallel having a diode but in opposite directions. When you have pin #1 High and pin #2 as Input, then one of the switches would be read (due to the diode in line with one branch of the parallel circuit). The other switch would not influence because whether pressed or not it's diode would be opposite direction and not allow the HiGH voltage through.Flip the situation and make pin #2 HIGH and pin #1 an input, and now you are readng the status of the other switch on the parallel branch that has the diode going the other direction (from pin #2 to 1). In both situations, I would digitalRead the input pin and see if it is feeling the voltage off the HIGH to determine if the switch was closed or open.Only problem with this setup is I need to integrate pull-up or pull-down resistors so that the inputs aren't "floating" as I switch them around. That means I need to use more pins that I would toggle as OUTPUT pins but make them Low to act as ground. Which means I may need to use 2 "global" pins that basically connect to each directionality of diode across the entire circuit simply to ground the inputs as needed for a pull-down.Anyways, just wondering if anyone has thought about this and whether the technique just doesn't work for switches in a way that makes it more efficient.

author: mariush
author_rank: Super Contributor
timestamp: January 27, 2013, 05:46:19 am
content: What's wrong with using a voltage divider? If you select the resistors properly, the ADC will give you a value from 0 to 255 or 0 to 1023 depending on which button was pressed...See Microchip's Tips and Tricks pdf :http://ww1.microchip.com/downloads/en/DeviceDoc/01146B.pdfThe first pages actually explain how to use a single input pin to detect multiple buttons.

author: edy
author_rank: Super Contributor
timestamp: January 27, 2013, 05:47:16 pm
content: Thanks for the tip. I guess the voltage divider would work but if I press multiple buttons down at the same time I will have to figure out the possible combinations and what resistance values are possible with combinations.I was thinking of doing this in a way by using the resistor values to control the range in such a way that it converts to a binary representation. For example, my ADC on Arduino goes from say 0 to 255. So the first button when pressed alone would either show value 0 or 128 (binary 00000000 or 1000000). Then my second button would be resistors such that it would only add a 64 (binary 0100000). So if I press button 2 alone it shows 64. But if I press button 1 and 2, it would show up as 128+64=192 (binary 11000000). Button 3 would be made to add 32, button 4 would add 16, and so on...So theoretically the value 8-bit corresponds to which buttons are being held down, with each place in the 8-bit binary digit corresponding to a button. The entire array of switches could be read by one ADC. If I wanted more switches I would use another ADC input.I will have to look up my resistor math to figure out if this is possible in this linear additive way using proprly selected resistors, or if there are other non-linear complications that make the value being read on different resistor combinations unpredictable. Needless to say you can't get every possible resistor value easily, so I will be limited to standard ohm values, and also the resolution is limited (I doubt I will be able to distinguish down to the 1/255 part on my ADC.Could end up just being a trial-and-error and trying every possible combo and recording the values I get.

author: mariush
author_rank: Super Contributor
timestamp: January 27, 2013, 06:35:34 pm
content: It is possible but you'd need some pretty accurate resistors, let's say 1%, and even so with just an 8 bit ADC you'd probably want to hand pick out of about 10-20 pieces, the resistor that's closer to the value you want.PICs are much easier to work with, with 10bit ADC you get 0 to 1023 values.If 0v is 0 , and 255 is 5v, you basically have 5v / 256 = 0.02v ... the power supply you feed the mcu with probably has more ripple than that, so you probably can't go with 256 values unless you use some voltage reference for the ADC.I'd aim for values of 5 +/- 3 , 15 +/- 3 , 25 +/- 3 so basically anything that falls within 3-8 is button 1 , 12-18 is 2 and so on. Though I'd probably ignore anything below 10, so 12-18 would be button 1.Also, keep in mind the mcu needs a few microseconds to do the conversion between what's on the pin and the voltage. It's slower than just checking if a pin is 1 or 0. If you put a button on each pin, that's fast. But if you use the pin as an ADC to get the actual voltage, it's a bit slower.If you loop and check the state of the buttons often, it may take too much time waiting for conversions. Sure, some microcontrollers have capability to start the ADC process and continue, then get an interrupt when the ADC is done determining the value but it gets complicated.When people push buttons, they usually keep the finger on the button for a few ms, so that's OK, but you'd still need to check the state of the buttons every few ms, which might still be too often. You could link all the buttons together through some small signal diodes and connect that to another pin of your microcontroller and then you can set an interrupt on that pin.Now when the pin is high, you know one or more buttons were pressed and the interrupt gets triggered and you can start the ADC conversion to retrieve the voltage on the other input pin.There's one more thing you have to keep in mind, buttons are problematic, as in when you push the button between the OFF state and steady ON state of the button there may be a few ON and OFF cycles that are very short in length, due to the way the contact is made inside the buttons. Because of this, it's possible for the button to be detected as pressed several times while user only wants to press one.This is usually filtered in software or hardware and it's a term called debouncing, see the video below.You can debounce each button in hardware with a very small capacitor or a capacitor+resistor combo, or it can be done in software if it's just one or two buttons. I personally like the hardware approach, but if you do something commercially, they may want to save costs or you don't have the space on the board for the ceramic capacitorsIf you're not limited by the pcb size you could also use a shift register, to get 8 or more inputs converted into a serial stream... basically the chip gets 0v or 5v from buttons through a resistor to limit the current, and when the microcontroller sends a signal through a pin to the shift register, it sends the 8 bits one after another to the microcontroller.The chip in this video is this one:http://www.digikey.com/product-detail/en/74HC165N,652/568-1410-5-ND/763014datasheet:http://www.nxp.com/documents/data_sheet/74HC_HCT165.pdfWhenever you want to read the state of all the 8 buttons connected to the parallel inputs of the shift register, you just send a high signal to one pin of the shift register, then read the state of the input from the other pin. Set the signal low. Repeat 8 times and you get all 8 input signals in a row. So your microcontroller only needs to connect to 2 or 3 pins on the shift register. The advantage is you get all eight bits separately so no need to mess around with resistors and conversions.And, there's also shift registers that have 16 inputs or more that work just the same.

author: edy
author_rank: Super Contributor
timestamp: January 27, 2013, 07:08:31 pm
content: Thanks for the replies, I'm learning a lot! I read up more on voltage dividers and was thinking to approach it as follows. I would have a string of resistors in series, let us say 4 for simplicity. Each push-button switch would actually be a bypass around a resistor. So when you press say button B1 it shorts around resistor R1. Button B2 shorts around R2 and so on.Now if you press ALL the buttons you short through all resistors and get 5V straight through to the ADC, it reads a 255 value. I assume there is an internal resistor at the pin so it limits current and I don't need another one, so if I apply 5V directly to the ADC pin it will be fine.The resistors are chosen in values that are non-overlapping if say more than one button is pushed. For example, let us say we use 30, 90, 180 and 540 if they existed, theoretically). So total resistance when no buttons are pressed would be 30+90+180+540. So you can figure out the voltage drop based on the various resistor combinations, there would be unique voltage ranges due to different resistor ranges for each button.I guess there would have to be one more resistor (a 5th) at the end of the series of resistor/button pairs, connected to ground, at which point the actual measurement is taken since it needs a divider point. The total resistance at the first half of the divider would be some combination of R1+R2+R3+R4 depending on what switches are pressed (switches assumed to be 0 resistance when they bypass their resistor), and the second half of the divider is constant resistance chosen as R5... I would have to work out the math and choose the best values.

author: Thor-Arne
author_rank: Unknown
timestamp: January 27, 2013, 07:46:12 pm
content: Any particular reason that you don't want to do it the "normal" way?I've seen people struggle with the various alternative ways to do this on the arduino forum.The basic prinsiple is like the attached image.One feeds the S0-S7 pins from a shift register (74HC595 or similar) and then decode the D0-D7 pins for each "step" in the shift register. By using the diode as illustrated, one can press as many buttons at the same time as needed. The D0-D7 lines should have a pull-down resistor, or the internal pull-down enabled.

author: edy
author_rank: Super Contributor
timestamp: January 27, 2013, 08:53:46 pm
content: Thank you for all the explanations of various options. I will need to study a bit more on the use of shift registers and the alternatives mentioned. Thank you! The only reason I am looking at this other way is because I thought it was simpler.Meanwhile I tried the voltage-divider method scenario using 4 switches and came up with an Excel spreadsheet (attached to this post) which lets you try various Resistor values for R1, R2, R3, R4 (being summed on first half of divider) and for R5 (second half of divider) with the voltage reading to the ADC being taken between the two.The spreadsheet calculates the total resistance based on what buttons are being pressed (all 16 possible combinations of pressing 4 buttons are shown) and figures out the Voltage output as V-out = (V-in * R5)/(R1+R2+R3+R4+R5).So far I haven't been able to come up with R-values that would give a good-enough separation between all 16 possible combinations to make them uniquely identifiable. The resistor tolerances are too wide, or the voltage ripple would be too difficult to differentiate between some combinations. Also, this is only using 4 buttons/resistors, and I was hoping to manage a pad of 12 buttons (like a phone dial pad).Please see the attached EXCEL file... It may be helpful to some people, or may hint at problems using this approach.

author: Thor-Arne
author_rank: Unknown
timestamp: January 27, 2013, 09:06:46 pm
content: Quote from: edy on January 27, 2013, 08:53:46 pmI suggest you try using 7 of the arduino pins (remember you can use the analog pins to).It should be very easy to accomplish a 3*4 matrix with that, you can skip the diodes for the initial testing.Pin usage might be a problem if you need to hook up a lot to the arduino, but you can add shift registers later if needed.

author: edy
author_rank: Super Contributor
timestamp: January 27, 2013, 09:40:40 pm
content: Regarding the use of a shift-register, I understand the concept of serial-in/parallel-out to control LED with use of the 74HC595, but do I need a parallel-in/serial-out shift-register instead to read switches? I was looking at the following which uses that type of shift register:http://www.openmusiclabs.com/learning/digital/input-matrix-scanning/shift-in-mux/It looks like we are reading in each row at a time, similar to your diagram above. The state of all the switches (being 0 or 1) in the row of 8 is read into the shift-register and then output as serial information to the Arduino. Then the next row is read in, and so on, until we have read the status of all of the switches. The cycle is repeated again.I would be able to use a serial-to-parallel shift-register to control up to 8 rows across, and the parallel-to-serial shift-register to read in up to 8 columns, producing an 8x8 grid of switches potentially which can be scanned this way.The serial-to-parallel shift-register would basically "energize" only the row that I am trying to read in, so I would pass to it the bytes as follows:0000 00010000 00100000 01000000 10000001 00000010 00000100 00001000 0000This would sequentially activate only 1 row of switches at a time, because the other rows would be at 0 voltage.Using the parallel-to-serial shift-register I could read in the columns by seeing which of the switches were being pressed in that active row. Then I could push out the data as serial to the Arduino.Does this make sense? I guess for a 3x4 pad application this is over-kill, I could just activate 4 rows of 3 switches each using a shift-register, and read in the data I get from the 3 columns to see which switch in each row is on. My shift-register would basically just cycle through all the rows and repeat.If my shift-register lets me handle 8 parallel outputs at a time, I could even just do a 8x2=16 and activate 8 rows of 2 switches in each row, cycling through all 8 rows... and for each row I would read in on 2 input digital pins which of the switches were being pressed. That would use up a total of 5 pins on my Arduino....3 to control the shift-register and 2 digital inputs.Does this approach sound logical?

author: Thor-Arne
author_rank: Unknown
timestamp: January 27, 2013, 09:56:30 pm
content: Yes, this is how you normally do it for a lot of switches.However, it you need less than 8*8 switches it makes more sense to not use both serial-to-parallell and parallel-to-serial shift registers.And, yes. It is a bit overkill.I'd either use pins directly on the arduino (7 pins) or a parallel-to-serial shift register with two extra pins (5 pins) to achieve up to 16 switches. for more than 16 it makes sense to have a bit more electronics.

author: mariush
author_rank: Super Contributor
timestamp: January 27, 2013, 10:34:23 pm
content: For 3x4 buttons, I'd just use 2 shift registers. It would just use 4 pins of the mcu, two separate to get data off each shift register, two for the shared pins of both registers (clock and the other)Actually I'd probably use a pic or atmel counterpart like pic16f57 simply because it takes less space than two shift registers and it's cheap, a few cents more than two shift registers. No need for oscillators for something like this, just a resistor and capacitor to form a rc oscillator, uses very little power, no-brainer.And in addition, with 20 i/o pins i could just - for example - do a loop and monitor up to 16 buttons constantly and when the state of one button changes I can set one of the other pins high to trigger an interrupt on the parent controller, who can then get the data through two other pins (one for clock and one for the data).So there's no need to constantly waste cpu time on the main controller, just retrieve two bytes of button state whenever state changes.Seems silly to use a full fledged microcontroller just for a few buttons but hey, if it's cheap and does the job...

author: Thor-Arne
author_rank: Unknown
timestamp: January 27, 2013, 10:54:05 pm
content: Yes, there is a lot of ways to do this.One could use an io-expander like MCP23S17 to get more pins available, or just go all the way and make a SPI/I2C keyboard controller.IMO for the sake of experience/learning one should start off with the simplest implementations first.One can use a handful of signal diodes to trigger a interrupt if that's needed.Bottom line, just start tinkering with the easiest approach first.