Well well well, Look who’s back for more already. If you’re pushing through these Arduino tutorials screaming give me more then I’d like to be the first to tell you good job and keep it up. Soon you will have this thing called the Arduino mastered and that creation that you had in mind (The one that got you into this mess in the first place) will seem like child’s play once I’m through with you. So throw on another pot of coffee and indulge in whatever other vexes you may have because its 4AM here near Detroit Michigan and I am right there going strong with you.
OK so in order to be here you should have already read the first LED tutorial entitled Advanced LED Blink. That tutorial will give you the background on this tutorial and will also help you get started into Arduino’s.
So where we left off previously is that we had a working LED blink circuit that was triggered by a momentary push button, the problem was that once we were in the LED blink loop it was difficult to get back out due to the program periodically sleeping and thus ignoring all commands. We are now going to tackle this issue with whats known as an interrupt, we will still have another annoying issue which is known as button de-bouncing but there are plenty of guides for this on the internet so I will not go over that in great detail here. I will say generally you have two options to debounce a button, hardware and software. Hardware is compromised of actual physical hardware to do the debouncing and software generally consist of sleeping the code for short periods of time combined with a check to see how rapid the button is pressed to determine if the presses are faster than a human can physically press the button and if so they are disregarded.
You will notice the circuit has slightly changed from the previous tutorial and the reason behind that is because we are now triggering our LED even from the switch input transitioning from High to Low where as previously we triggered on a change from Low to High. If you remember from the previous article I explained that in order to give the micro controller a solid stable signal when the line was not in use we had to “pull” the signal either “low” or “high” by using a pull-up or pull-down resistor. So an easy way to picture that is previously our line was Ground and we would apply a Positive to the line taking it High and now it is the opposite where our line is already Positive but then we introduce a Ground signal and Pull it Low which then causes our event to trigger in our code.
Comparing the new circuit layout with the old located here you can clearly see how we have switch the polarity of the push button switch. This allows us to trigger on a High to Low signal rather than a Low to High signal. Like I said previously the circuit hasn’t changed much at all so let’s go ahead and dive into the code. I will post the code and then go over some of the specifics but I would like to mention that you will notice the code has become what I like to call “tight” or tighter than the last bit of code I posted. What this means is that for the sake of simplicity in the last example I broke some of the code out to better showcase where the end of a statement was and how the symbols where used in the code and so forth. In this example and future examples I will be tightening up the code to show my preferred coding which at times can be a little unconventional in the C language standards but its easier to view as whole in my opinion due to better code density. One example of this would be as follows
Standard C++ Code example
if (1==1) { Do something; } else { Do something else; } }
Tightened Code Example
if (1==1){ Do something;} else{ Do something else;} }
So you see how this could complicate things for a beginner when trying to read and work with the code but it keeps the code clean and compact which in my opinion makes the code easier to read overall when you can see more of the code at once.
Now that we have that out the way lets see the actual code we will be using, again this should be a direct copy-paste-upload-run for you project if you have followed the example image I posted above.
/* Advanced Blink with an Interrupt Sketch By: David M. Orlo www.DaviedOrlo.com */ byte SWITCHPIN=2; //Set Pin 2 as Switch byte LEDPIN=6; //Set Pin 6 as LED byte brightness; //Create a Integer variable named brightness byte delayedoff; //Create a Integer variable named delayedoff byte delayedon; //Create a Integer variable named delayedon //If you want to go higher than 255 you must change from "byte" to "int" volatile boolean trigger=LOW; //This is our interrupt connected to the button switch void setup(){ attachInterrupt(0, interrupttrigger, LOW); //Interrupt 0 is Digital Pin 2 //When the Input goes from High to Low it will trigger a function called crazyLED pinMode(LEDPIN, OUTPUT); //Set Pin 6 as Output } void loop(){ delay(200); //Wait a moment to help debounce the switch if (trigger==1){ //Check to see if the interrupt was triggered crazyLED();} //Enter our LED blinking function else{ //If the button was pressed again analogWrite(LEDPIN, 0);} //Turn the LED off } void crazyLED(){ delay(200); //Wait a moment to help debounce the switch while(trigger == HIGH){ //Will run this loop until the interrupt value changes brightness = random(1, 254); //Generates a random number from 1-254 and assigns it to the variable named brightness delayedoff = random(1, 125); //A random amount of time the LED is turned off delayedon = random(1, 250); //A random amount of time the LED is turned on analogWrite(LEDPIN, brightness); //Uses the random number we generated to write the value to our LED delay(delayedon); //random delay on time analogWrite(LEDPIN, 0); //We turn the LED off for a blinking effect delay(delayedoff);} //Random delay off time } void interrupttrigger(){ //When the switch is pressed (Interrupt is triggered) the arduino enters this function if (trigger ==LOW){ //Checks to see what the last value was (high or low) trigger=HIGH;} //If its low it is now set to high else{ trigger=LOW;} //If its high it is now set to low }
As you can see we don’t have much more code than we did previously and the operation of the code is nearly the same with the introduction of a new function which I will explain in a moment. I would like to point out a very important note and I really want you to pay attention to this because over time this will become very important to you and the success of how much code you can fit in your project. As you may already be aware there is a limit to how much code you can pack into that little micro controller chip on your Arduino board and that limit is expressed every time you verify and upload your code. This is represented as “X bytes used out of X bytes maximum” or something to that effect. This is telling you how much space in memory your code is actually taking up, there is actually more to than just that and I am just giving you an overall explanation of memory size so you understand there is a limit to the size of your code but there are things you can do to reduce the size of your code and one very easy thing to do is just simply telling your micro controller the proper data types when declaring variables, so what the hell does that mean? Its really quite simple, do you remember how in the last tutorial I said a variable is basically a word that represents something else like a number or set of numbers? Well at the top of our code we declare some variables and if you take a look at this code in particular you will see that each variable is a representation of numbers but I declare them differently. The most common one you will see is “int” which is short for integer, if your not a math wiz and don’t already know these like the back of your hand you can simply just bookmark the Arduino Reference page and they have them listed out which a description of each. Generally what I will do is use “int” for each variable because I do NOT know them by heart, and then later I will go through and correct them unless it is just some small sample code that I am playing with. It’s good to get in the habit of using the proper data types for your variables because it can add up quickly in a large project.
Next up is the Setup function in which you will notice we got rid of the setup of our Input Pin and added an interrupt in its place. The interrupt is really quite simple but first thing you must know is that each Arduino board model (i.e. Mega vs. Duemilnove) has a different amount of interrupts and they are also on different pins. The Duemilanove for example has 2 interrupts and they are on digital pins 2 & 3, this is detailed in the AttachInterrupt function page as well as how to use the function. To use the function we specify the Interrupt number rather than the pin number, Interrupt 0 is pin 2 and interrupt 1 is pin 3. Next we need to tell it how we want the interrupt to be triggered as their are several options which again are detailed on the function page. In my example I decided to use the LOW trigger because it made the most sense for how I would be using the interrupt, in a future tutorial I will show you how to use an interrupt to read a changing state and calculate RPM on several objects.
Now if your paying attention you are probably thinking I skipped right over something else which is new and peculiar and that is the word “volatile” before our trigger variable declaration. Don’t worry I didn’t forget it, this actually has to do with the interrupt itself and this is what I waited until after the interrupt to describe it. My next description of the interrupt and what is actually does is quite simple, basically look at the interrupt as a function that interrupts the micro controller at any time and then forces the micro controller to enter a specific function which you define when you create the attach interrupt function, in my example this is called “interrupttrigger”. Before we go any further there is one important catch to interrupts in the Arduino and it gave me a lot of grief when I was first learning them and that is that you can not use delays in the interrupt function and you can’t have another interrupt, interrupt the interrupts function(man that’s confusing) along with a few other catches. What that meant to me was that I only wanted to use the interrupt function for very simple things like changing a few variables, then exit the function and allow the main code to read those changed variables and then do what you actually needed to do in the first place. So generally I try to get out of the interrupt function as quickly as possible and get back into my code. Now the volatile part, in the Arduino attach interrupt documentation it is written “You should declare as volatile any variables that you modify within the attached function” So that tells us if the variable will be changed within the “attachinterrupt” function we need to declare it as volatile. For now this all you need to know and remember about using interrupts.
It should be plain as day at this point what the code does but just in case its not I will run over it real quick. First we enter the main loop and at this point the code doesn’t really do anything. The code is checking to see if something has changed but we know nothing has because we haven’t pressed the button yet. Once you do press the button the code will skip right down to the interrupttrigger function and there is where the most simple thing in the world happens, its the old 1 2 switch-a-roo. The code looks at the volatile variable named trigger and checks its value, the value can only be High or Low (1 or 0) and which ever it is the code will now make it the opposite. From there the interrupt function is complete and the code re-enters the main loop, at this point the main loop notices something has changed, our trigger variable is now a 1 when it was a 0 and the code knows to enter our good ol CrazyLED function that we created in the previous tutorial. So how do we get back from here? Well the code is still able to be interrupted by the ?, you guess it, the interrupt, and when that happens it will just simply switch that variable back to a 0 (LOW) from a 1 (HIGH) and when the code enters the previous function it notices it should no longer be running the CrazyLED function and we are back at square 1. So very simple when you walk through the code like this and I bet at first you were a little perplexed if this were your first interrupt lesson but in the end it turned out to be a very simple yet very useful function that I bet you will get tons of use out of.
Until next time, Dave