Attached is modified code of something that I wrote to cycle neopixels light patterns and sound effects from an AudioFX all driven with an Uno. Normally the main loop runs through a fixed and timed series of lights and sounds and then settles into a pulsing pattern. A button press is read on pin 2 which breaks the pulse loop and causes it to step through solid, off, and back to pulsing with each press. I wanted to update my old button read method because if i don't release the button right away the program rapidly cycles through each state. The old method simply looked for a logic LOW. I recently attempted to use an interrupt to check the button instead so as to trigger a mode change only on the falling edge transition of a button press and not when it just reads low. I'm having an issue now where the interrupt is getting triggered without my hitting the button. Pin 2 is initialized and held high, with the interrupt set to FALLING. Yet every time I run the code, the BreathingLed function is broken immediately because the interrupt has already flipped the "breakflag" and "tripped" bools without my input. I can see it through use of the code between //DEBUG serial. The second my code runs it seems the interrupt pin is triggered and flips the both. Pin 2 is wired to an open momentary switch which goes to ground when pressed. I could use some help here. When the code has finished its initial series of timed events, I can hit the button and see the interrupt fire in Serial Monitor. A single press fires the interrupt about 5-7 times. It also fails to advance to the next state but I think thats due to the bad flags. They wont reset as they are supposed to once the interrupt is chacked and the next state is picked. So is suspect there to be a bounce issue but I'm not sure how to debounce the falling edge and I dont have the hardware on hand to switch to rising edge and a hardware debounce. I was hoping someone could help with a software debounce approach.
I've attached the .ino file since its too long to paste
From a cursory reading of the code, it looks like it uses variable currentmode to keep track of three states, enumerated as 1, 2 and 3. currentmode is initialized to 1, and is modified only in function checkTrigger(), in this snippet:
currentmode++;
if (currentmode<3){
currentmode=1;
}
This snippet increments currentmode, compares it to 3, and, if it's less that 3, resets it to 1.
currentmode starts at 1. After it's incremented, it will be 2. 2 is less than 3, so the test will pass, and currentmode will be set to 1. It looks to me that currentmode will always be 1 when checkTrigger() exits. I don't think that's what you wanted. I think you wanted to reset currentmode to 1 when currenmode is more than three, rather than when it's less than 3.
As to whether there are other problems with the sketch, I can't say. This post is based on a very cursory reading of the sketch, and I'll confess that I haven't even read all of the original post. The sketch is quite long, and it seems to have a lot of code that you're not asking about here. I suspect that almost everyone that's read your post has moved on without responding, because the initial post and the sketch are long and complicated. You will probably get better participation, and better responses, if you post a minimal sketch that illustrates the problem.
tmd3:
From a cursory reading of the code, it looks like it uses variable currentmode to keep track of three states, enumerated as 1, 2 and 3. currentmode is initialized to 1, and is modified only in function checkTrigger(), in this snippet:
currentmode++;
if (currentmode<3){
currentmode=1;
}
This snippet increments currentmode, compares it to 3, and, if it's less that 3, resets it to 1.
currentmode starts at 1. After it's incremented, it will be 2. 2 is less than 3, so the test will pass, and currentmode will be set to 1. It looks to me that currentmode will always be 1 when checkTrigger() exits. I don't think that's what you wanted. I think you wanted to reset currentmode to 1 when currenmode is more than three, rather than when it's less than 3.
As to whether there are other problems with the sketch, I can't say. This post is based on a very cursory reading of the sketch, and I'll confess that I haven't even read all of the original post. The sketch is quite long, and it seems to have a lot of code that you're not asking about here. I suspect that almost everyone that's read your post has moved on without responding, because the initial post and the sketch are long and complicated. You will probably get better participation, and better responses, if you post a minimal sketch that illustrates the problem.
Sonovagun. Thats why it helps to have fresh eyes. Totally missed the flipped comparison sign. That should aleast explain why it wont step through modes. just gets stuck at 1. I'll mock up a simpler sketch with all the other unneeded mess per your suggestion to see if that helps make my use of the interrupt a bit less cumbersome to figure out too. In the end it may even be better if i start totally over instead of trying to modify existing messy code.
Edit: actually just flipped that symbol and the button is responding and stepping now through modes. Only problem is either the sounds and mode are out of sync or its not sticking in the mode I want. I think this has something to do with the interrupt firing more than once and also bouncing when initialized which throws kicks it immediately out of the initial breathing pattern mode. I'm not sure if its a wiring issue or if its an inherent risk with using the internal pull up resistors. The break flag gets set true which throws it from the loop, and the tripped flag allows the checkTrigger function to run which advances the modes. So what I basically need is a way to debounce a falling edge interrupt. Or rewire my entire light, sound and button PCB to provide a hardware debounced raising edge button.
Hutkikz:
I can't open you file on my phone but I think you should forget the interrupt and just debounce the button.
Frankly I'd love to, but the best I've been able to make work is this in my existing working version:
void CheckButton(){
if (!digitalRead(BUTTON_PIN)){
delay(ButtonDelay);//debounce
switch (nextmode) {
case 1:
sfx.playTrack(12);//play mode change sound
Serial.println("Mode 1:Breathing");
strip.setBrightness(MINBRIGHT);
delay(1000);
ChangeColor(r4,g4,b4);
BreathingLED(r4,g4,b4); //breathe LEDs
nextmode=2; //increment next mode to case 2
break;
case 2:
Serial.println("Mode 3:Blue");
sfx.playTrack(7);//play mode change sound
strip.setBrightness(SOLIDBRIGHT);
FlipColor(r4,g4,b4); //set color to steady color
nextmode=3; //increment next mode to case 3
break;
case 3:
sfx.playTrack(6); //play mode change sound
Serial.println("Mode 6:OFF");
nextmode = 1; //reset next mode to case 1
FlipColor(0,0,0); //set color to steady color
break;
}
}
}
BUTTONDELAY is currently 200 which is fine enough for me since I've practiced it but people I show the project to hold it down too long which makes it wig out. Call me a perfectionist
I had guessed this because I recently tried to use interrupt to detect a button press also.
As Robin also pointed out to me avoiding delay through proper use of millis() and detecting transitions
Is key to solving the problem.
This is NOT how you use millis(). The millis() value will only be 2500 about once in every 49 days
There should be no need to use interrupts to detect a button pressed by a human - humans are very slow at things.
void ModeSwitch (){ //When button is pressed to ground pin, toggle necessary flags to break loops and change mode
Serial.println("INTERRUPT");
tripped=true;
breakflag=true;
}
And you should not have any Serial.print()s in your ISR
...R
I appreciate the input. The delays are used extremely sparingly in areas where there is no need for an input detection. As far as millis, thats why i used them. They are there to control a sequence that runs at power up and only runs once. I'll never have this thing on for 49 days straight. All the serial prints are also just there for pure debugging so i can see where the program is. Unless you mean that may be the cause of the multiple INTERRUPT prints. Still doesnt explain why the flags in that function get flipped before i ever press the button. But to your advice of abandoning the interrupt for human input, im going to explore a better software debounce option for the basic button input im using now.
devsfan1830:
All the serial prints are also just there for pure debugging
Even for debugging you can't have Serial.print in an ISR. Serial uses interrupts and interrupts are OFF in an ISR. Call the print stuff from loop() in response to a flag set by the ISR.
Hutkikz:
I had guessed this because I recently tried to use interrupt to detect a button press also.
As Robin also pointed out to me avoiding delay through proper use of millis() and detecting transitions
Is key to solving the problem.
This tutorial fixed it! Thank you and thank you to others who took the time to help. I managed to replace my old button checking code with the debounced w/o delay code from the tutorial and bypass the need for interrupts entirely. Also found a great breathingled function here: “Breathing” Sleep LED | The Custom Geek
This allowed me to ditch the last of my delays. This thing works PERFECTLY now. Thanks again!
Hutkikz:
You should put [SOLVED] in the topic header so if someone searching the same issue finds it they will know they can find a solution here
And that was the solution:
devsfan1830:
I managed to replace my old button checking code with the debounced w/o delay code from the tutorial and bypass the need for interrupts entirely.
Which is always the best solution for using interrupts to monitor pushbuttons (or any form of mechanical switch).