Am I correct in thinking that if you have two pins causing the same AVR PCINT interrupt, (e.g. PCINT0 vector caused by either PCINT0 or PCINT1 pins — I think the naming overlap of vectors and pins is confusing) the only way to determine which pin(s) caused the interrupt is to record their state after each interrupt and compare the previous and current values of all the pins which are enabled in PCMSKn?
Electronic – Determining which pin triggered a PCINTn interrupt
atmelavrinterrupts
Related Solutions
Edit: Changed answer after clarification by OP about simultaneous presses
If multiple detectors, up to 6, need to be sensed for possible simultaneous interruptions, the solution described in this posting on the Arduino forums is usable. Substitute the "buttons" referred to in the post, with your high-when-interrupted lines from the 6 sensors. Each detector line will connect to the resistor specified in that post, and the ADC values received will indicate what combination of detectors is interrupted:
BUTTONS VALUES RESISTORS
btn 1 837-838 220
btn 2 737-738 390
btn 3 610-611 680
btn 4 318-319 2.2k
btn 5 178-179 4.7k
btn 6 91-92 10k
btn 1 + btn 2 896-897
btn 1 + btn 3 877-878
btn 1 + btn 4 851-852
btn 1 + btn 5 844-845
btn 1 + btn 6 840-841
btn 2 + btn 3 821-822
btn 2 + btn 4 769-770
btn 2 + btn 5 753-754
btn 2 + btn 6 745-746
btn 3 + btn 4 674-675
btn 3 + btn 5 643-644
btn 3 + btn 6 627
btn 4 + btn 5 408-409
btn 4 + btn 6 363-364
btn 5 + btn 6 243
If your MCU of choice has a comparator with edge triggering on analog inputs, generating an interrupt each time the voltage rises over 0.5 Volt or so will work.
If you need more that 2 simultaneous interruptions detected, an alternative would be to use a key scanning IC that provides serial output, like MAX6955 or TCA8418, then read said IC's output using an I2C read on a single input line.
Pin change interrupts are usually not a good way to detect button actions. This is because mechanical buttons bounce, and you will get lots of meaningless interrupts, and then you still have to do debouncing anyway.
A better way is to have a periodic interrupt, like every 1 ms (1 kHz rate). That's a long time on most processors, so the fraction of time spent in the interrupt will be small. Simply sample the button state every interrupt. Declare a new button state if you have seen the new state 50 ms in a row. 50 ms is longer than most buttons bounce, but is still short enough so that humans won't notice or care about the lag.
Note that this way you can also handle multiple buttons in the same periodic 1 ms interrupt. All you need is one counter for each button.
More on debounce time:
Occasionally, as in this case, someone says 50 ms is too long a debounce time. This is not true for ordinary buttons pressed by humans. It might be a issue perhaps in very timing-critical applications like a stopwatch, but so far I haven't run into one. I did test on this in the early 1980s, and lots of other people have too.
It is true that typical pushbutton bounce time is around 10 ms, with just about all settling by 25 ms. The limiting factor on debounce time is human perception. 50 ms is a bit shorter than where people start to notice a delay when they aren't looking for it. Even then, it takes a much longer time for it to be annoying. It can be possible in some cases for a human to detect a difference between 50 ms and 0 ms delay if they are specifically looking for it, but that is quite different from pushing a button and seeing something happen and not thinking about the delay.
50 ms is therefore a good debounce time because the delay is below the perception limit in ordinary applications, way below the annoyance limit, and well above the bounce time of most switches. I have found switches that did bounce for nearly that long, so you might as well push to the perception limit since there is nothing to loose.
I have done many products with firmware-debounced buttons using 50 ms debounce time. Not once did a customer mention even noticing a delay. They all accepted the buttons as working fine without issue.
Best Answer
It is!
The reason there are 8 different external pins for an interrupt vector is to make it easier to layout the PCB or to use a different pin if there is a conflict with another pin function.
Pretty much, lets say you only care about PB0 (PCINT0) and PB1 (PCINT1). So the pin change enable mask PCMSK0 would be set to 0x03.
So if
pins
is 0x01 you know it was PB0... And if you need to know what changed you need to compare it topreviousPins
, pretty much exactly what you thought.Keep in mind in some cases,
pins
may not be accurate if the pin has changes state since the interrupt but beforepins = (PINB & 0x03)
.Another option would be to use separate interrupt vectors with one pin from each vector so you know which one is changed. Again, this also has some issues, like interrupt priority and once the CPU enters the ISR, the global interrupt enable bit
I-bit
inSREG
will be cleared so that all other interrupts are disabled, although you can set it inside the interrupt if you want, that would be a nested interrupt.For more information, take a look at Atmel's app note Using External Interrupts for megaAVR Devices.
Update
Here is a complete code example I just found here.