Questions about using Interrupts

I have a few Questions about interrupts. I understand how to set up an interrupt and how they work but still confused on a few things.
Say I have a long code moving 3 stepper motors to specific coordinates and their motion is determined by a piezo sensor set as interrupt named "void piezo()".

  1. Where does the main code go? All the tutorials I've watched have codes that are just a few lines long and doesn't have any code in the void loop.
  2. Where do I put the "void piezo()"? void setup or void loop? At the end or beginning?
  3. Once the code starts running and an interrupt occurs, after the interrupt does it's thing, does the code start running from where it left off when the interrupt occurred?
  4. Can I use interrupt "void piezo()" inside a for, if, or while loop?
    There's not any tutories that really go into depth on interrupts. Any help would be appreciated. Thanks.
  1. The interrupt service routine should be very short. Very very short. The shorter the better. Most of the time there should only be code that sets a flag. The loop code will check the state of the flag every time through loop, if the flag is set, run code to service the interrupt then clear the flag.

  2. Either place. The iSR function must be defined outside of any other function.

  3. Execution returns to the place that it was when the interrupt occurs.

  4. No.

1 Like

What do you mean by "flag"?

A variable that indicates a particular state.

1 Like

Usually a type bool that could indicate if the interrupt has been triggered or not.

As already mentioned, the interrupt routine should be short. In many cases, so short that it doesn't actually exist at all.

In your case for example, I suspect that most of your CPU time will be expended waiting until it's time to do another step. As long as you don't use delay to do that, you will have plenty of time to check what the piezo is up to.

There should be TONS of information on the Internet, although not necessarily Arduino related.

An interrupt is good for something temporary/transient (like maybe a piezo trigger). Without an interrupt you are only reading the piezo for one instant every-time through a loop. If the piezo is not getting a continuous vibration you might not be reading when the piezo sends-out a pulse and you you might miss it. Does that make sense? If you push a button and and the program isn't reading the button at that moment, you'd miss it...

It's also good if you need to know exactly when something happened.

Here is a short sketch to illustrate what the flag is and how it is used. Now, in the real world, we would never use an interrupt to sense a switch that is activated by a human. This is just for illustration.

const byte buttonPin = 2;
const byte ledPin = 13;

volatile bool flag = false; 

void setup()
   pinMode(buttonPin, INPUT_PULLUP);
   pinMode(ledPin, OUTPUT);
   digitalWrite(ledPin, LOW);
   attachInterrupt(digitalPinToInterrupt(buttonPin), buttonISR, FALLING);

void loop()
   // if a button press, flash LED
   if (flag == true)
      digitalWrite(ledPin, HIGH);
      digitalWrite(ledPin, LOW);
      flag = false;  // clear flag

void buttonISR()
   flag = true;  // set flag

Here is what I'm trying to accomplish.
I have 2 steppers. One is the x axis and one is the y axis.
I have 1 stepper motor (Z axis) that is going to be used as a carousel to that delivers medication (pills, capsules etc.) to a specific container.
There are 64 individual containers on a table that will be moved by the x and y axis.
I'm going to use a piezo sensor to detect whether or not a pill has fell into it's container that will trigger the table to move to the next container. That way the table won't move if the carousel fails to deliver a pill.
Is it possible to accomplish what I want to do with interrupts. Here's the code I've wrote to basically go through the motions. In this code if the carousel fails to deliver a pill, the table moves regardless..

#include <FlexyStepper.h>

const int LED = 13;
const int piezo = A0;
int threshold = 50;

// Using EasyDriver stepper driver with MS1 and MS2
// pins set to ground so I'm at 200 steps per revolution.
const int xMOTOR_STEP_PIN = 3;
const int xMOTOR_DIRECTION_PIN = 2;
const int yMOTOR_STEP_PIN = 5;
const int yMOTOR_DIRECTION_PIN = 4;
const int zMOTOR_STEP_PIN = 7;
const int zMOTOR_DIRECTION_PIN = 6;
int Xdelay = 250;
int Xspeed = 1200;
int Xaccel = 1200;
int Ydelay = 250;
int Yspeed = 1200;
int Yaccel = 1200;
int Zdelay = 250;
int Zspeed = 300;
int Zaccel = 200;
int a = 0;
int b = 0;
int c = 0;
int d = 0;

FlexyStepper stepperX;
FlexyStepper stepperY;
FlexyStepper stepperZ;

void setup()
  stepperX.connectToPins(xMOTOR_STEP_PIN, xMOTOR_DIRECTION_PIN);
  stepperY.connectToPins(yMOTOR_STEP_PIN, yMOTOR_DIRECTION_PIN);
  stepperZ.connectToPins(zMOTOR_STEP_PIN, zMOTOR_DIRECTION_PIN);



void loop() {

  //StepperZ is a carousel that rotates
  //Steppers X and Y are Axis

  // Row 1.
  while (a < 7) {
    stepperZ.moveRelativeInSteps(-25);// Carousel rotates
    stepperX.moveRelativeInSteps(-685);// Table moves left to next container
  stepperZ.moveRelativeInSteps(-25);  //Carousel rotates
  stepperY.moveRelativeInSteps(685); // Move To 2nd Row.

  //2nd Row
  while (b < 7) {
    stepperZ.moveRelativeInSteps(-25); //Carousel rotates
    stepperX.moveRelativeInSteps(685); //Table moves right to next container

  stepperZ.moveRelativeInSteps(-25);  //Carousel rotates
  stepperY.moveRelativeInSteps(665);  // Move To 3rd Row.

  3rd Row
  while (c < 7) {
    stepperZ.moveRelativeInSteps(-25);//Carousel rotates
    stepperX.moveRelativeInSteps(-685); //Table moves left to next container

  stepperZ.moveRelativeInSteps(-25);  //Carousel rotates
  // Move To 4th Row
  stepperY.moveRelativeInSteps(665);  // Move To 4th Row.

  //Table Right  4th Row
  while (d < 7) {
    stepperZ.moveRelativeInSteps(-25); //Carousel rotates
    stepperX.moveRelativeInSteps(685);  //Table moves right to next container

  stepperZ.moveRelativeInSteps(-25);  //Carousel rotates
  stepperY.moveRelativeInSteps(-1995);// Table moves to it's starting position.started.
  for (;;); //stops code


This is the carousel disc that the z stepper rotates to pick up a pill. The pill is then dropped down a chute that has a piezo sensor at the bottom that detects if a pill had dropped. So basically I need the carousel to continue turning until a pill is detected. Then move the table.

It is possible to do what you want entirely without interrupts. Interrupts may be useful in certain circumstances.

I'm going to use a piezo sensor to detect whether or not a pill has fell into it's container that will trigger the table to move to the next container.

That sounds very dubious to me, and an interrupt would probably not be the solution to any of the problems that are guaranteed to arise. You will want to carefully research that aspect of the mechanism, not the programming, before deciding on a reliable design. A photogate would very likely be more reliable.

I've tried sound sensors, PIR motion sensor, IR sensor, and an ultrasonic sensor. None of those really worked being that the pills range from 1/8" to 1/2" in diameter. I couldn't get them to detect 100%. I can get 100% detection with the piezo. I may be diving to deep to fast. This is my first project. I bought my first Arduino about a month ago and I've learned a lot since then. The code I sent is the first code I've ever written by myself. I appreciate your help and will look into other mechanical ways that may be more full proof. Do you have any links, to point me in the right direction?

Except for the word "can", that sounds promising.

But how does it work? What happens when it doesn't? There is nothing in the posted code that refers to the piezo sensor.

Google "beam break sensor" or "optointerruptors" to learn about photogates.

I am just now reading this thread and this statement bothers me because it is illogical. You really want the carousel to turn only after a time-out period that is longer than the time needed for a pill to register. And then turn only enough to release another pill. likely your code will need to count the number of times that a pill is missed.

1. An Arduion IDE based sketch/program has the following four spaces:

//Global Space (to hold global variables, header files. and the like)

void setup()  //Setup Space (holds tasks to be executed only once or a number of times) 


void loop()  //Loop Space (holds tasks that will be excuted repeatedly)


//User Space (holds user-defined functions and Interrupt Sub Routines (ISR))

2. The program execution begins from the setup() function and then the control goes into loop() function from where the user-defined functions and ISRs are called upon as needed and dictated.

3. When an interrupt occurs, the MCU disables the "interrupt logic" before entering into the corresponding ISR. This is to ensure that the MCU is not interrupted until the current ISR is completed. The interrupt logic is re-enabled at the time of returning to the MLP (main line program), and it happens just after the excution of the ISR.

4. In a system, there could be many other processes that are interrupt driven; therefore, the ISR must contain minimum number of codes so that they are executed as quick as possible and the interrupt logic is re-enabled without much appreciable delay. This arrangement helps the interrupt driven processes to appear as in the "running states".

5. The arrangemnt of Step-4 is implemented with the help of the flag concept, which is set to "true" state when an interrupt happens and the MCU goes to the ISR. The ISR codes are placed in the loop() function; where, the codes are executed by testing the flag's value. the flag is reset to "false" state after the execution of the ISR codes in the loop() function. The following example may help to understand the role of flag.

6. Create a sketch to blink L (bulit-in LED of UNO) for five times at 1-sec interval using delay() function when the MCU is interrupted over the INT0-pin.

Note that the delay() function needs "enabled interrupt logic" to work.; so, the delay() function can not be put in the ISR() as the interrupt logic remains disabled in the ISR(). This is just an example. If someone really needs to insert this amount of high delay in the loop() function, then he will be required to implemet it in some other ways (like using TC Module) where interrupt logic is not disabled.

volatile bool flag = false; //Global space

void setup()
    pinMode(2, INPUT_PULLUP);    //internal pull-up is enabled for DPin-2  (INT0-pin) 
    pinMode(13, OUTPUT);     //L is connected at DPin-13 of UNO
    attachInterrupt(digitalPinToInterrupt(2), ISRINT0, FALLING); 

void loop()
   if(flag == true)
       for(int i = 0; i<5; i++)
           digitalWrite(13, HIGH);
           digitalWrite(13, LOW);
       flag = false;

void ISRINT0()
    flag = true;
1 Like

This isn't COBOL

This is just my conceptual understanding so that the learners (including myself) know which code to put where.

1 Like

But everything you labelled is "Global space" - you're creating (again) unnecessary complication and obfuscation.

Then what is the name of the space just above the setup() function? I want to give a name.

How about "more global space"?
Or "potential compilation-unit-static space"

What do you call the the space between setup and loop?
What if you reverse the order of setup and loop?

Why do you want to give stuff that already has a name, another name?
That's just going to confuse someone, eventually.

No point in being over-prescriptive