[Total: 1    Average: 5/5]
With this article I would like to clarify a hidden potential of Arduino that allows you to define interrupt actions by reading the input signal. With this action loop and ‘if’ delays in the code are avoided

With this program, Arduino generates a 20us impulse from the loop function. This impulse enters another Arduino entrance. An interrupt from this second input generates a serial command and a new output is generated. From the serial one gets one for each impulse and the new output represents a square wave whose faces are moments of impulses.




Introduction to Interrupts

Why would I need an interrupt? Robots spend a lot of time waiting for things to happen. A common example: your robot wants to drive straight until an IR sensor says that an object is too close. Seems fairly simple:


This code is ‘polling’ the sensor. It keeps checking the value over and over again manually (in software). This works of course, but what if your ‘other stuff’ starts to be a really long process – you might overshoot and run into the wall. What happens if the event we are trying to detect is really short – you might miss it. In these instances you want to use an interrupt. Common examples where interrupts are used:

  • Counting pulses from an encoder (they are really short, and come very often)
  • Catching some short pulse (like the 10ms pulse given off by a UVTron sensor)
  • Using switches or digital IR sensors as bumpers (and you want an instant stop)

What is an interrupt?
The really cool thing about microcontrollers is they have fancy hardware that can do things like PWM, analog-to-digital conversion — and interrupts. An interrupt is a little piece of hardware that sits, waiting to detect a trigger event, such as a particular pin going from a low state to a high state. When this event happens:

  1. the interrupt triggers
  2. the microcontroller stops executing it’s current program
  3. the microcontroller starts executing an Interrupt Service Routine, or ISR
  4. when the ISR is done, we return to the original program

So a hardware interrupt is sort of like when the President interrupts your nightly TV viewing to tell you the economy has crashed. The trigger event is the economy crashing, and immediately as that happens the hardware (President) runs an ISR (his talk to the nation).

In your ISR, you would have code that does some processing to handle the event. For instance, your ISR would:

  • Increment the value of a counter, if you were counting pulses from an encoder
  • Set a flag to say ‘fire found’ if you were monitoring a UVTron
  • Stop the robot if you were using interrupt bumpers

Most microcontrollers support a wide variety of interrupt triggers:

  • A particular pin state going from low to high
  • A particular pin state going from high to low
  • Any change on a particular pin

Typically, microcontrollers only have a few interrupts, on specific pins. We’ll discuss a slight change to this below in the section ‘Wait, I’ve run out of interrupts’. Another interesting point to note, that won’t really be discussed much  here, is that PWM and hardware timer/counters rely entirely on hardware that is similar to interrupts.

The Interrupt-Driven Bumper

Let’s now implement an example using the Arduino. The Arduino is based on an ATMEGA168 AVR. This chip has 2 hardware interrupts (named 0 and 1). The pins that can be used for interrupt triggers are tied to digital 2 and 3, respectively. The Arduino makes using interrupts quite easy, they have a function AttachInterrupt(interrupt, ISR, trigger):

  • interrupt is which hardware interrupt 0 (Digital 2) or 1 (digital 3).
  • ISR is the function with is to be used as the ISR
  • trigger is either: RISING, FALLING, or CHANGE, for which events to trigger on

The code below will use several psuedo functions which you will need to implement for your particular robot:

  • DriveForward() – make the robot move forward at some regular speed
  • DriveBackward() – make the robot move backward at some regular speed
  • Stop() – stops the robot
  • TurnLeft() – make a little turn left, like 45 degrees or so

For our example, we will assume you have a bump switch. It should be tied between ground and the digital input pin (we’ll use a pullup resistor to keep them at 5V when not pressed).

There are a few things going on here. First, we start rolling forward. We have an integer used as a flag, that is either 0 when we have not hit an object, or 1 when we hit something. An interrupt occurs when we hit something, it will stop the robot to avoid any damage, and also set our flag. Then, our main loop will handle backing the robot up when it gets a chance. There are a few reasons to implement our code like this. First, delay() relies on interrupts. Second, you don’t ever want interrupts to run for very long, as they will typically stop other interrupts from occurring — this can be devastating when you have something like a system clock that relies on interrupts (as the Arduino does).


Wait, I ran out of interrupts!
The Arduino library only supports 2 pin interrupts, because it only uses the 2 dedicated hardware interrupts. However, the ATMEGA168 (the chip that the Arduino is built out of) can actually generate interrupts on every port, it’s just slightly more complicated. These are called the Pin Change Interrupts. Each port of the AVR has it’s own interrupt vector, and you can turn on interrupts for as many of the pins as you want. There are a few limitations though. First, an interrupt is generated for any pin change, you can’t limit the hardware to rising or falling only, although you could implement that in your ISR. Second, because all of the pins in a port share an interrupt vector, if you use more than one pin in a port you will have to manually check which pin generated the interrupt. 
It should be noted that switching into the ISR takes several clock cycles, so your ISR will not run instantaneously, and thus it may be difficult to ‘check’ which pin generated the interrupt.Lastly, because there isn’t a library out there, you have to write a little more code.

Note that the Arduino has arbitrary names for its pins, that have no relevance to the AVR names, you’ll have to use the ATMEGA168 datasheet, plus the Arduino pin out chart to sort out register values. This is definately an advanced topic, but it is a great way to learn a few more details of the AVR architecture.


Some Warnings for Arduino Users
Don’t use the delay() or millis() functions inside an ISR on the Arduino. The reason being that they depend on the system clock, which itself is generated from an interrupt. On the AVR architecture, when one interrupt starts processing its ISR, all other intterupts are disabled temporarily. For this same reason, you want to keep your ISR as short as possible (to avoid messing with the system clock itself).

End Notes
That about covers the basics of interrupts, with some examples using the Arduino. Take a look at my tutorial on closed loop feedback for more information about using encoders.