Multiple push buttons one interrupt

I'm in the planning stages of a greenhouse automation project.

I wish to have a LCD menu for user configuration with multiple push buttons.

I've seen how a resistor network and one analogue pin can be used to read multiple button states but as there is no interrupt on analogue pins I'd appreciate some pointers for research on how I can achieve the same with an interrupt pin (and analogue if necessary) taking debounce into account.

Interupts are digital and I don't believe you can have it triggered at certain analog values simply because the analog reading itself takes time and isn't an instant change the resistor network method works fine, and with either some high quality pushbuttons or software debouncing you should be fine

Except I can't interrupt the program. What I thought is I could maybe do the analog resistor network for the multiple buttons and somehow in hardware convert the lowest voltage push button signal and anything between that and 5v to a high signal for the interrupt pin.

Thereby when any button is pressed the interrupt is triggered and I could read the analog pin to determine which button was pressed.

So I guess the question is, how can I convert for example a 0.5v or above to 5v or what ever is considered enough to register as high.

How long is your loop? Are you sure you need an interrupt driven button and not just poll it?

Could you use the analog comparator interrupt?

Delta_G: How long is your loop? Are you sure you need an interrupt driven button and not just poll it?

It isn't written yet, so possibly I could but then I wouldn't learn anything from that. I specifically wanted to use interrupts. I could be lazy and use one for each button but that isn't really the point. Maybe over the top for the intended application but that's deliberate.

Delta_G: Could you use the analog comparator interrupt?

You maybe onto something - quick google pops up http://www.fiz-ix.com/2012/01/introduction-to-arduino-interrupts-and-the-atmega328-analog-comparator/ So I'll read up and let you know.

I'm curious what other techniques are used to multiplex buttons.

If you want an interrupt you would need to mux the switches to digital inouts with 2 diodes from each switch - 1 of the diodes going to the interrupt pin, and the other going to an input pin.

Run your analogue voltage to a comparator (eg LM393) set to flip just below (or above depending on how they are wired) the voltage produced with no buttons pressed.


Rob

kf2qd: If you want an interrupt you would need to mux the switches to digital inouts with 2 diodes from each switch - 1 of the diodes going to the interrupt pin, and the other going to an input pin.

Do you have an example? I don't follow how the two diodes would alter anything other than dropping more voltage to the interrupt pin making the problem worse? I must be missing something.

Graynomad:
Run your analogue voltage to a comparator (eg LM393) set to flip just below (or above depending on how they are wired) the voltage produced with no buttons pressed.


Rob

Ah, this makes sense. I will see what I can come up with first and post back. Many thanks.

dannix:

Delta_G: Could you use the analog comparator interrupt?

You maybe onto something - quick google pops up http://www.fiz-ix.com/2012/01/introduction-to-arduino-interrupts-and-the-atmega328-analog-comparator/ So I'll read up and let you know.

This looks like it would work without additional components so long as a button press presents above 1.1v

fiz-ix.com: This allows me to detect analog inputs above 1.1 V on pin 7 and do something when the input is detected. Now back to the explanation of the code above.

How about an 8-input NAND gate with pullups on the switches?

It will hold low until one or more switches are pressed, then it will go high.

For determining the button pressed, assuming you want to know just one of them, how about a priority encoder?

We have now provided for 8 buttons using 4 lines, one of them being an interrupt.

JoeN:
How about an 8-input NAND gate with pullups on the switches?

http://www.cs.uml.edu/~fredm/courses/91.305/data/74HC30.pdf

It will hold low until one or more switches are pressed, then it will go high.

For determining the button pressed, assuming you want to know just one of them, how about a priority encoder?

http://www.jameco.com/Jameco/Products/ProdDS/914988.pdf

We have now provided for 8 buttons using 4 lines, one of them being an interrupt.

Having a quick look at the data sheets I follow what you mean. I don’t envisage requiring 8 push buttons so I will go for one of the above cheaper alternatives that will save more arduino pins too. Thanks for the suggestion though :slight_smile:

Hey, no problem. I suggested it just in case you wanted to be able to expand out. You can cascade those parts up and support pretty much as many buttons as you want on a single interrupt. It's just that the system would only know the highest priority switch if two were pressed at the same time.

dannix:

Graynomad:
Run your analogue voltage to a comparator (eg LM393) set to flip just below (or above depending on how they are wired) the voltage produced with no buttons pressed.

Ah, this makes sense. I will see what I can come up with first and post back. Many thanks.

Here is my attempt. I’m not sure on the resistor values of the comparator with a 1.4v Vref as R2 calculates a very low value??
As I understand it the output is connected to Gnd until one of the buttons are pressed.

Updated the schematic as it was a bit small.

That looks about right.

I don't think you need the 1M (R3) and 10k (R2) on the + input, I haven't used a comparator for years but IIRC you just run the voltage you are comparing directly to the pin. Your reference is on the - input.


Rob

Graynomad: I don't think you need the 1M (R3) and 10k (R2) on the + input, I haven't used a comparator for years but IIRC you just run the voltage you are comparing directly to the pin. Your reference is on the - input.

I think your right, already created a voltage divider with the buttons anyway, may need some hystrisis though. I'll bread board it.

Sorry it’s been a while, as an update I bread board it but had to swap LM393 comparator for a LM741 op amp as it’s what I had available. I couldn’t reference below 1.9v so I had to swap the 3K3 pull down resistor in the button array to up the lower, no button pressed voltage. I used a 10K

It triggered int0 ok, I just haven’t tested reading which button was pressed yet. Code below:

int pin = 13; //use led on pin 13
volatile int state = LOW; //pin13 state
volatile int lastState = HIGH;
void setup()
{
  pinMode(pin, OUTPUT);
  attachInterrupt(0, blink, RISING); // int0 on pin2, flash P13 LED on low to high interrupt
}

void loop()
{
  if(state != lastState){
  digitalWrite(pin, state); //turn pin 13 led on/off
  lastState = state;
  }
}

void blink()
{
  state = !state; //flip the state
}

Hi,

I am trying to do roughly the same thing, except i am using a four way rotary switch. So basically, I have soldered 1k resistors between the output connectors of the rotary switch, setting it up as a resistor ladder, and connected the switch to an analog pin on the arduino. Works perfectly, as each setting on the switch gives a different analog value (1023-5v; 512- 2,5v; 330-1,8v; 250-1,25v)

However, the loop I am writing is somewhat long - as I am generating a crossfade between various colours on a rgb led. I could poll multiple times for a change within the same loop, but that isn't very aesthetically pleasing.

So I thought of using interrupts and the analog comparator. However, how can i get it to notice a change in voltage for each of the switch settings? Eg. I want the interrupt to occur when the voltage changes from 5v to 2,5v, but also when it changes from 1,25 to 1,8. So both rising and falling, and for all voltages which correspond to the four switch settings. The reference voltage which triggers an interrupt changes which the different settings of the switch.

So my question boils down to this: how create interrupts for a rotary switch with a resistorladder?

Any help would be greatly appreciated!

my suggestion would be to start delegating the work to another ic, you could use a attiny85 that just monitors the rotary and provides a count of the current position and the difference from the last one, then in your main program just communicate with it via serial (fast a"s possible to avoid delays, maybe 57600 or higher) to gather that information and reset the count, this way the main "brain" doesnt have to worry about time consuming analog reads and the other ic doesnt have to worry about anything but those time consuming reads and responding to requests you can use an attiny85 which i would say is the easiest if you know how or perhaps come up with a more discrete method(which would need more supporting hardware and not as easily reconfigured best part about the attiny 85 is its relatively cheap and can be programmed with the arduino software once set up properly(with an isp programmer) and can be run at 8mhz without any extra hardware so with literally just a decoupling cap and the ic you can accompish this for less than a few dollars extra p

winner10920:
my suggestion would be to start delegating the work to another ic, you could use a attiny85 that just monitors the rotary and provides a count of the current position and the difference from the last one, then in your main program just communicate with it via serial (fast a"s possible to avoid delays, maybe 57600 or higher) to gather that information and reset the count, this way the main “brain” doesnt have to worry about time consuming analog reads and the other ic doesnt have to worry about anything but those time consuming reads and responding to requests
you can use an attiny85 which i would say is the easiest if you know how or perhaps come up with a more discrete method(which would need more supporting hardware and not as easily reconfigured
best part about the attiny 85 is its relatively cheap and can be programmed with the arduino software once set up properly(with an isp programmer) and can be run at 8mhz without any extra hardware so with literally just a decoupling cap and the ic you can accompish this for less than a few dollars extra p

It’s interesting you mention this. I came to this conclusion last year and I did it with a Xilinx CPLD instead of a uC. I wanted to learn a bit about CPLDs so I thought this would be a good first project. I built it based on the theory of Grumpy Mike’s project below, implementing this hardware in the CPLD. My design allows for four rotary encoder channels and tracks them all asynchronously into a 12-bin “absolute” position. One channel is selected for output (via two pins) which outputs a that position.

Rotary Max (Grumpy Mike)