Arduino Software Interrupts

In this tutorial, we will learn about Multitasking in Arduino, how can we implement the concept of Arduino Multitasking, what are the factors we need to consider for Multitasking in Arduino and finally I will show you a simple project of multitasking.

Before proceeding further with Arduino Multitasking tutorial, I strongly recommend you to refer to ARDUINO INTERRUPTS TUTORIAL and ARDUINO MILLIS TUTORIAL.

The Arduino Uno supports four interrupt modes:. RISING, which activates an interrupt on a rising edge of the interrupt pin,. FALLING, which activates on a falling edge,. CHANGE, which responds to any change in the interrupt pin's value. Number of Arduino interrupts in different Arduino boards Different types of Arduino board have different numbers of interrupts pins e.g. Arduino UNO have two interrupt ports and Arduino Mega2560 have six interrupt ports named as INT1,INT0.

A Brief Note on Multitasking

In computing terminology, multitasking is a concept of executing multiple tasks or processes by a computer over a period of time. The concept of Interrupts come into picture in the scenario of multitasking.

Interrupt is a process of letting the computer know that a different task is in need for its service. Consider a situation where there are no interrupts in a computing system. In this case, if a new task requires the service of the computer, it must wait until the present task is fully executed by the computer.

This is not feasible as the new task might be critical and requires urgent attention from the computer. Interrupts play an important role here. When a task interrupts the computer, it puts the present task on hold, executes the new task and returns back to the original task.

Multitasking in Arduino

Arduino is a simple microcontroller based platform without the concept of operating system. This means that only one program can run in Arduino at a time.

Arduino Interrupt Software Debounce

Arduino

Even though there is no operating system, we can still achieve the concept of multitasking i.e. handling multiple tasks in Arduino.

In order to handle multiple tasks in Arduino, you need to make use of two concepts. They are Interrupts and millis.

Get rid of delay ();

In my previous tutorial, I have spoken about millis function in Arduino. I have also spoken about why using delay function is bad and doesn’t help us in multitasking.

When you use the delay (); function in Arduino, you are actually putting the processor in a busy state for the time period mentioned in the delay. During this time, the Arduino processor cannot do any other tasks like read from a button, for example.

Here comes millis to the rescue. Millis is a timekeeper function that starts when the Arduino is powered on (or reset) and the program in Arduino starts running. Whenever we call the millis function in our program, it returns the time in milliseconds from the moment the program started running.

I have already spoken about millis and how to use millis in my previous tutorial. Please refer to that for more information.

Interrupts in Arduino

Arduino, or the microcontroller on the Arduino UNO board to be specific, supports Interrupts. Arduino UNO board has support for two external interrupts on Digital IO pins 2 and 3.

Using these external interrupt pins, you can trigger external interrupts and advice Arduino to perform a special task.

In an earlier tutorial called Arduino Interrupts Tutorial, I have spoken about interrupts in Arduino, how to enable them, what is an interrupt service routine (ISR), what care must be taken while writing an ISR function and an example program.

Blinking Two LEDs at different Rates without using delay

In the Arduino Millis Tutorial, I have shown you a simple program which can be used to blink and LED but without using the delay function.

This is possible with the millis function. If you are using delay function for blinking two LEDs, you cannot achieve different ON and OFF times for the LEDs and make then blink simultaneously at different rates.

But you can implement this with the help of millis in Arduino. Before seeing an example on Arduino Multitasking, let me show you an example of how to achieve the above mentioned functionality.

Arduino Multitasking Example

Let me now show a simple Arduino Multitasking code. For this, let us take the above example as a reference i.e. I will use the above code and extend it a little bit to achieve multitasking in Arduino.

In the above example, I am blinking two LEDs at different rates simultaneously. Continuing the same task, I will add a new task where an LED connected to a different pin must be toggled every time I press a button. This should happen instantaneously as soon as I press the button with any delay.

Circuit Diagram for Arduino Multitasking Example

Components Required

  • Arduino UNO
  • LEDs x 3
  • 1KΩ Resistors x 3
  • Push Button
  • Connecting Wires
  • Mini Breadboard
  • 5V Power Supply

Circuit Design

This is a simple demonstration of multitasking in Arduino and doesn’t involve a complex circuit. Three LEDs (preferably of three different colors) are connected to Pins 8, 9 and 10 of Arduino through respective current limiting resistors.

Arduino Uno Software Interrupts

A push button is connected to Pin 2 of Arduino (important to connect it to this pin).

Code

Working

When the Arduino starts running the program (after uploading it), it will just blink the LEDs connected to Pins 8 and 9 as per the mentioned ON and OFF Times.

As the button is connected to the external interrupt pin Digital IO Pin 2, whenever it is pressed, an interrupt is generated and the status of the buttonflag is updated. Based on this flag, the Arduino will then toggle the LED connected to Pin 10.

Conclusion

This is a simple example of implementing multitasking in Arduino. You can implement complex projects involving several components like motors, LEDs, servos, etc. and use interrupts to achieve multitasking.

Related Posts:

Nano Every - Interrupt Handling - Rotary Encoder #every#arduino#nano#rotary

#9734

Hi all -
Here is a programming difference between the Arduino Nano and Nano Every you will need if you use pin change interrupts. The setup is slightly different on the Every and the rotary encoder pins (2 and 3) use different interrupt vectors on the Every which means you need two ISRs rather than one. The following code can be used and will work on both the Nano and the Every - it detects the board and compiles differentially based on whether you have an Uno/Nano or Every.
//
//
#define Every 1
#define _BOARDTYPE Nano
#if defined(ARDUINO_AVR_NANO_EVERY)
#endif
#define _BOARDTYPE Uno
#endif
///////////////////////////////////////////////////////////
// Interrupt service routine, called on encoder movement //
// +1 for Clockwwise //
// Ignore intermediate values //
///////////////////////////////////////////////////////////
#if _BOARDTYPE != Every
unsigned char result = encoder.process();
encoder_count++;
encoder_count--;
}
#else
#define PA0_CLEAR_INTERRUPT_FLAG PORTA.INTFLAGS &= PIN0_bm
#define PF5_CLEAR_INTERRUPT_FLAG PORTF.INTFLAGS &= PIN5_bm
ISR(PORTA_PORT_vect) {
PA0_CLEAR_INTERRUPT_FLAG;
if (result DIR_CW) {
} else if (result DIR_CCW) {
}
unsigned char result = encoder.process();
if (PF5_INTERRUPT)
encoder_count++;
encoder_count--;
#endif
//*******************Setup Interrupt Service Routine********************
void setupEncoderISR() {
// Set up for the rotary encoder interrupts
PCICR |= (1 << PCIE2);
#endif
PORTA.PIN0CTRL |= PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
PORTF.PIN5CTRL |= PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
sei();

#9773

Thanks for this Dean. Is this meant to be used in the main sketch before the void setup?
#9784

The simple answer to your question is yes - this all goes before the main loop.
But there are a few other bits you need to make it work You need an Encoder library(or code to read the pins). You need to call setupEncoderISR() from your main setup() routine. The interrupt routine I supplied just keeps a count +! for rotate step clockwise, -1 for rotate step counter clockwise. From your main loop you need to determine what you want to do with that. If your encoder has a push button and you want to check that you'll need code in your loop to do that as well.
I've attached a sketch that I used to test this. Quick wireup on a breadboard - the Encoder A/B gets wired to pins 2 and 3 and ground goes to ground. The Encoder button goes to pin A3 and ground - change RotaryTest.h if you wire the button to a different pin. Open a debug window and the sketch will report encoder changes as you turn the knob. Each time you press the button it will rotate through a set of values that I use to adjust the tuning increment.
73 and good luck, let me know if you get it working.
Dean
KK4DAS
#10077

Dean,
Thanks for the code. It's helping with converting my uBITX sketch from the Nano to the Every.
When you say that the encoder is on pins 2 and 3, what do you mean? I have a uBITX v6, and the rotary encoder is on A0 and A1, the pushbutton is A2 (and the PTT is A3). Currently, my Nano sketch catches all four inputs with a single pin change interrupt.
Also, your code above calls an method encoder.process() which doesn't seem to be included.
73 and thanks,
Mark, N8ME
#10088

On Thu, Jan 7, 2021 at 06:00 PM, Mark Erbaugh wrote:
Also, your code above calls an method encoder.process() which doesn't seem to be included.
Hi Mark -
encoder.process returns DIR_CW, DIR_CCW, or DIR_NONE based on encoder movement. It is part of a small encoder library that I use. You should be able to replace encoder.process with whatever code you use to read the encoder. My build is not a uBitx and uses pins D2 and D3 (the external interrupt pins on the Nano) for the encoder. You should be able to adapt it the interrupt code for whatever pins you want. The code I posted should be a good roadmap for creating code that will compile and run on either the Nano or the Every.
For completeness, my test sketch is attached. The test sketch demonstrates reading the encoder and how I use it to adjust frequency. No display is needed - it prints results on the serial monitor.
73,
Dean
KK4DAS
#10089
Edited

Hi
Unfortunately I don't have an Arduino Nano Every here. But I will be surprised if you can't use the code I use in the RFzero https://www.rfzero.net/tutorials/rotary-encoder/ which also works directly on a Nano and Uno - prego!
Of course if you skip the Arduino attachInterrupt function abstraction things become much more MCU specific. But using the attachInterrupt makes the code much more portable in the Arduino world.
Bo
www.rudius.net/oz2m :: www.rfzero.net
#10093

On Sat, Jan 9, 2021 at 10:33 AM, Bo, OZ2M wrote:
But using the attachInterrupt makes the code much more portable in the Arduino world.
Hi Bo - yes - attachinterrupt is more portable, but the limitation is that it only works on specific digital pins. On the Nano or Uno - the only pins it works on are 2 and 3. If you want interrupts on other pins you're pretty much stuck with using Pin Change Interrupts at the lower level. There are some Pin Change Interrupt libraries out there that attempt to hide the hardware details but I haven't used any of them.
73,
Dean
KK4DAS
#10097

On the Nano or Uno - the only pins it works on are 2 and 3.
Dean:
Are you sure? It's true that external interrupts only work on pins 2 and 3 for both, but I'm pretty sure that software interrupts work on all digital pins.
Jack, W8TEE
toggle quoted messageShow quoted text
On Saturday, January 9, 2021, 3:45:04 PM EST, Dean Souleles <dsouleles@...> wrote:

On Sat, Jan 9, 2021 at 10:33 AM, Bo, OZ2M wrote:
But using the attachInterrupt makes the code much more portable in the Arduino world.
Hi Bo - yes - attachinterrupt is more portable, but the limitation is that it only works on specific digital pins. If you want interrupts on other pins you're pretty much stuck with using Pin Change Interrupts at the lower level. There are some Pin Change Interrupt libraries out there that attempt to hide the hardware details but I haven't used any of them.
73,
Dean
KK4DAS
#10099

Hello
Indeed there are some restrictions to the attachInterrupt function https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/ However, the need for interrupt may be a bit overrated. As shown at https://www.rfzero.net/tutorials/rotary-encoder/ scanning is also possible and used specifically in the RFzero Signal Generator: https://www.rfzero.net/examples/signal-generator/ that can do a lot of things without missing a beat.
Bo
www.rudius.net/oz2m :: www.rfzero.net
#10106

Hi

This may not be relevant but I have been working on a rig that was designed with a Nano v2 and I could only source Nano v3 boards. There are pin differences between the variants.

Here is a link with some info.

Jim G4EQX

toggle quoted messageShow quoted text
On 09/01/2021 21:51, jjpurdum via groups.io wrote:
On the Nano or Uno - the only pins it works on are 2 and 3.
Dean:
Are you sure? It's true that external interrupts only work on pins 2 and 3 for both, but I'm pretty sure that software interrupts work on all digital pins.
Jack, W8TEE
On Saturday, January 9, 2021, 3:45:04 PM EST, Dean Souleles <dsouleles@...> wrote:

On Sat, Jan 9, 2021 at 10:33 AM, Bo, OZ2M wrote:
But using the attachInterrupt makes the code much more portable in the Arduino world.
Hi Bo - yes - attachinterrupt is more portable, but the limitation is that it only works on specific digital pins. If you want interrupts on other pins you're pretty much stuck with using Pin Change Interrupts at the lower level. There are some Pin Change Interrupt libraries out there that attempt to hide the hardware details but I haven't used any of them.
73,
Dean
KK4DAS
#10122

On Sat, Jan 9, 2021 at 04:51 PM, jjpurdum wrote:
Are you sure? It's true that external interrupts only work on pins 2 and 3 for both, but I'm pretty sure that software interrupts work on all digital pins.
Hi Jack,
Aarduino interrupt nomenclature is endlessly confusing. The attachinterrupt function in only for external interrupts - specified per board. On advantage of the Every over the Nano or the Uno is that every digital pin is an externa interrupt pin. Bo posted the link to the documentation so I won't repeat it - but to satisfy myself I tried different pins for encoder A & B when using attachinterrupt and, sure enough, it only works on the external interrupt pins. But if you setup the registers properly you can use pin change interrupts on any pin - but you have to be careful because multiple pins share interrupt vectors so you need to add code if it is possible for more than one pin to trigger the interrupt.
73,
Dean
KK4DAS
#10127

On Sat, Jan 9, 2021 at 05:23 PM, Bo, OZ2M wrote:
as shown at https://www.rfzero.net/tutorials/rotary-encoder/ scanning is also possible
Thank you for the reference Bo. Unfortunately some of our Nano based sketches don't quite keep up and have been known to miss or have very inconsistent encoder reading when polling. Using interrupts clears it right up and tuning is now smooth and reliable.
The RFzero looks like a very nice board - with the M0, and SI5351 and GPS well integrated. I had not heard of it before. It is a little pricey for our kit radios - it is close to 1/2 the price of a uBitx V6. That said, it looks like a very cool project board. Is it your design?
73
Dean
KK4DAS
#10132

Hello Dean
Yes the RFzero is a project I have done with three other OZ-stations. The original idea was to make a low cost 6 m beacon driver for the Synchronized Beacon Project since the Next Generation Beacons project https://rudius.net/oz2m/ngnb for OZ7IGY is overkill and a lot more expensive but also in a very different performance category. So to get the volume up we decided to rub it in Arduino. Subsequently a lot of other applications were identified from a cheap GPSDO over WSPR on 23 cm to 10 GHz QO-100 dual LO and 10 GHz beacon driver if you can live with the phase noise. A lot of effort has been put into the design and construction, e.g. four layer immersion gold PCB and good RF design techniques applied for best RF performance while observing the cost. There are already to many bad Si5351A RF designs around. The RFzero is professionally assembled by a Danish EMS.
The KH6HME/B beacon on 2 m uses a RFzero.
Bo
www.rudius.net/oz2m :: www.rfzero.net