In all of the sections that we've covered so far we've been using buttons and other hardware devices as inputs to control changes in the program, such as manipulating outputs and in the case of a button we've had to make sure that our program runs a check to see what the button state is really regularly at a high frequency so that we don't miss a press or a release. This method is known as polling as you involve constantly polling or checking the state of the button. This is all well and good for simple programs with little else going on however once your program starts to grow and become more complex, polling doesn't work as well because you've got heaps of other stuff going on at the same time. It requires your microcontroller to stop whatever it's doing and frequently check the state of the button even if most of the time it's exactly the same as it was before fortunately there is a much more efficient way to read the state of a digital input using interrupts.
You may have heard of interrupts before and imagine them as a scary complicated procedure, but Arduino does a really good job of making them incredibly user-friendly. So, what is an interrupt? An interrupt is a section of hardware on the microcontroller which is capable of monitoring the state of an input pin by itself and can literally interrupt the microcontroller in whatever it's doing to let it know that there is an interrupt vector ready that the state of a pin has changed in this case whether it is high or low. The beauty of this is that the interrupts are all taken care of with hardware flags and some very low-level microcontroller instructions, which means you can be doing other things to not have to worry about constantly checking the button step. A good way to think of interrupts is imagine you're expecting a letter from the postman, you could go out and check the letter box every two minutes or more regularly to see if it's been delivered, which wouldn’t allow you to get much done in between or you could have a mailbox that makes a loud noise when a letter is delivered so you can forget about it but being notified instantly as soon as it arrives leaving you free to do whatever you like until that point.
As mentioned before, there are three basic types of interrupts change, rising and falling. When you tell the Arduino that you wish for a pin to have a corresponding interrupt for it enabled you tell it under what condition you wish to trigger the interrupt. On a rising edge, a signal going from low to high, on a falling edge which is a signal going from high to low or either which is rising or falling known as change. When this condition is met your Arduino will run a specific function, that is unique to that interrupt. This function is known as the interrupt service routine or ISR as we’ll refer to it. The key to interrupts is that the code it executes in your ISR should be as short as possible, because as soon as the interrupt is triggered it will jump from wherever your microcontroller was in your program and service the interrupted, complete the ISR, before it can go back to where it left off and that means that it can't do anything else while it's running the ISR so if you are using an LCD display or connecting to a Wi-Fi network or something that requires tight timing and integration, those processors will often fail because whilst they might appear severe only running in the background, if your microcontroller is locked up executing an ISR it can't do anything else. It can be a bit confusing trying to remember all that there is to using interrupts so here is a list of some basic do's and don'ts when using interrupts with Arduino.
Keep ISRs or the interrupt service routine, the function or the cause of the interrupts as short as possible usually you're only using these interrupt service routines to set a flag or change a state rather than executing an entire section of code. ISRs cannot return values or take parameters the delay in “millis” function native to Arduino, they will not work inside ISRs because they're based on interrupt functions and you can only have one interrupt being executed at a time. Delayed microseconds which is a subcategory of the delay function, except it stores and measures in microseconds will work because it's not interrupt based. Any variable which is changed inside an ISR should be declared with the volatile modifier and only certain pins have interrupt capabilities. On the Arduino Uno only digital pins 2 and 3 have interrupt capabilities and be aware that not all chips support all three kinds of interrupts across all of the pins. Some pins may only allow for a change interrupt which can determine whether the signal is rising or falling but it will be run on either and you will have to run additional code to determine the state of the input to determine whether it was a rising or falling edge.
Other pins will have the option for all three so you can set it for a falling edge, a rising edge or a pin change. Now that we've talked about what interrupts are let's look at how to use them. So, I'll take a look at the Arduino IDE. So, I've got a basic function going on here and it's incredibly similar to the more advanced concept that we use for “if” statements where we looked at “Debouncing” a push-button and using some “F” logic and some variables to keep track of the state using “Debouncing” to ensure that our switches press cleanly and “if” statements to determine whether it's been held or released. So, it's almost exactly the same, we've got LED pins, button pins and some global variables and the only one that's different here that you'll notice is this volatile int button flag. Now button flag we're going to use as a binary one or zero flag variable just like any other except we've used the modifier of volatile which declares that this integer can be changed without the rest of the Arduino body knowing about its put in perspective, the whole microcontroller has its mind focused on executing its interrupt service routine and not all the rest of those functions aren’t running at all, so you need to declare as volatile to make sure the Arduino knows this variable could change at any time inside an interrupt service routine.
We have our “Debounce” variable as normal declaring some pin modes and here we can see that we're initializing this interrupt to the pins. So we use attached interrupts then inside there we use digital pin to interrupts and in brackets, the pin that you're using so we could change that from “2” to button pin, the “2” makes is easier to remember that we're using a specific interrupt capable pin. Then a “,” and you need to declare the name of the function that you wish to run so “ISR_button” is a general rule of thumb for declaring functions that you’re running as ISRs. So, interrupt service routine button and then we want it to run on a change, meaning transitions from high to low signal or from a low to a high signal and vice-versa. So, you don't always have to use digital pin to interrupt, there's a couple of different syntax formats for doing this inside Arduino, however digital pin to interrupt is the safest, it largely depends on the model of Arduino board that you’re using but generally speaking if you use digital pin to interrupt rather than just the pin itself most boards are going to work without a hitch.
Now in this void loop we have the exact same set of instructions that we were using for standard debouncing, so we won't go through that too much. The only difference is we've added an extra condition to determine whether our Arduino enters into this hole debouncing function as normal before we had “((millis ()– LastPress) > debounceTime”, if that is true then we're going to run a section of code that was ensuring that it was only run at a certain frequency filtering out that noise. Now we're also adding an extra condition for button flagging. The button flag has to be true or one in order for this to run at all and the reason for this is that it's going to bypass all of this because the “if” statement isn't met and the loop is going to iterate doing nothing and the only way that button flag can be equal to 1 is if “ISR_Button” function, the interrupt service routine for pin 2 is run. In which case all it does is set button flag and that process of changing the state of a flag variable like that is so short. It’s a really good example of how to use interrupt service routines, we could put all of that code inside the interrupt service routine if we wanted and that would work perfectly fine in this example but if we had a lot of other background processes running it would show up more time and then the Arduino is stuck in that service routine because as it is if it's only running through instructions in the void loop, especially if you're running a whole bunch of other libraries as we talked about, especially for you know timing specific hardware or services it's going to be running the void loop sure but every so often it will branch off into it another hidden interrupt service routine that's running in the background and jump to all these different parts of the code that you won't actually realize is going on but if it's inside this ISR it can't. So, that's why it's really important that it's really short and then it can only run that toggle function if the interrupt service routine has already been run. In other words if it has detected a change via press or a release and the only other thing we've added in is button flag is equal to “0” in other words when it executes the toggle function, including all of the debouncing, no matter whether it's a press or release, button flag is set to “0” which means it will not run that section of code until the interrupt service routine has run again to reset that flag.
So, let's go ahead and load it up make sure it's got the correct settings, hit upload and it's going to work exactly the same as our previous toggle button example did because it's achieving the same goal but it's doing it in a much more efficient manner so when we press it, it’s a nice little toggle switch. I'm using pin 3 here but you could also use pin 13 or any other digital pin for LED. The important thing is though is that if you want to use an interrupt for button pin it can only be pin 2 or 3 and you can find out what pins are interrupt capable just by googling the board and searching “Arduino Uno Interrupt Pins” or “Teensy interrupt pins” or whatever board you're using, a quick Google will bring up a data sheet or a documentation reference page and let you know what they are and which pins can deal with change interrupts or they can deal with all three so arriving, falling, state changes as well. So, that's a little bit on using interrupts they are incredibly powerful, you can do all kinds of things with them. You can attach multiple pins to the same ISR or you can you can use it however you like as long as you follow those guidelines that we've set down before for the basic general best practices for using interrupts.
Makers love reviews as much as you do, please follow this link to review the products you have purchased.