Multiple interrupts causing board fe freeze or not working

I have a motion detector (PIR), a few LEDs and a toggle button on my breadboard, with a Particle Photon running it.

The button works with an interupt, and simple sets a boolean value.

attachInterrupt(SILENT_BOTTON_INTERRUPT, handleButtonStateISR, RISING);

Where SILENT_BOTTON_INTERRUPT is the pin number the button is connected it.

The code for that ISR is:

void handleButtonStateISR() {
Particle.publish(“EVENT”, “Button pressed”, PUBLIC);
isSilent = !isSilent;

My PIR was using the loop function and checking the state, but it seems Interrupts are better for the PIR. The PIR has no jumper on it, so it goes to HIGH when motion is detected and stays HIGH for 8 seconds after motion stops.

So I created two interrupts. One for when the pin goes HIGH, and one for it goes LOW.

attachInterrupt(PIR_PIN, handleMovementStart, RISING);
attachInterrupt(PIR_PIN, handleMovementStop, FALLING);

The two methods are:

void handleMovementStart() {
if(AllStill) {
if(isSilent==false) {
// Particle.publish(“Event”, “Movement Detected!”, PUBLIC);
buzzer.Beep(160, 1500);
AllStill = false; // All still is false if we have movement.

void handleMovementStop() {
AllStill = true; // All still is false if we have movement.

So, when we go HIGH, we set a boolean to false. And when we go LOW, we set the boolean to true.

I also have these values that get set in these functions as volatile.

// Setup global variables.
bool AllStill = true;
volatile bool isSilent = false;

But it’s failing.

When I make movement, nothing happens at all.
If I click the button, the board freezes. Breathing light stops at the brightness it was hen I pressed the button. Need to reset the board.

If I comment out the ‘FALLING’ attachInterrupt, and make movement, the boolean changes as expected, but never deactivates (As I commented out the ‘falling’ code).

And if I press the button, the board freezes again.

Can anyone spot the issue?

edit: replied too soon, should have read more carefully :slight_smile:

Make sure you’re setting the volatile variable in your interrupt handler, not the non-volatile one. It might also simply be that you’re attaching two interrupts to the same pin. Maybe try triggering on a change, and just using one interrupt?

Thanks Dave. I was thinking of using ‘CHANGE’ instead, so one intetrrupt, but then, do I need to do a digitalRead to work out what the change was?

Note that changing to ‘CHANGE’, and siply toggling the boolean flag -works, but it seems like the wrong thing to do. Each time the PIR voltage changes, it toggles. Might be OK, but wonder why having the RISING and FALLING types on the same pin - fails.

Also, my button (Separate pin) still freezes the board.

(BTW, why PUBLIC? Who else may be interested in that event?)

Particle.publish() is not a function suitable for calling from an ISR.

So may be the call to buzzer.Beep().
You need to be careful what you do in an ISR.

Because the hardware only has one register for the interrupt trigger edge and one pointer for the ISR to call per pin, so it’s a HW limitation (as is for virtuall every controller).

I’ll remove that log line, but that method worked when it was my only ISR. That is, the log line, the beep etc. It’s only since I added the two new ISRs on a different pin - that the button now freezes up the board.

But agree- I believe the ISR needs to be quick, so removing that publish.

With regards the PUBLIC. I’m not sure. I learnt from a YouTube tutorial. I’ll read up and fix that.


Removing the publish - fixed the button! That’s amazing.
Not sure why though…


These are very high level functions that do a load of stuff, including some stuff that cannot - under no circumstances - be done inside an ISR.

Thanks for that help. Learnt something new.
So, hardware allows only one interrupt per pin, and don’t do long processes such as ‘publish’ within the ISR.

What’s the best method for debug logging then? Something like a ‘Serial.println’, so that I can check that the ISR fires.

Serial.print() shouldn’t be used either inside an ISR.
For demos and quick tests it may be used, but it should never appear in production code.
Debugging real life ISRs that actually do some severe work isn’t a simple task since whatever you put in the ISR for debugging may impact your result - especially when it comes to critical timing.
On the other hand, simple ISRs like the ones above don’t really require a lot more debugging than maybe setting some flags or setting the D7 LED :wink:

When I wrote my ParticleSoftSerial library - which does the actual communication via ISRs - I donated a debug pin and some debug buffers during development and checked the state of the pin with a logic analyser and printed the debug buffer from loop() when there was time.
Once in production state these debug block got “removed” from the library via compiler directives.