Interrupting with push buttons has failed.

Hi y'all,

I have the task to let multiple steppers run in various modes. (One Drop to a ceratain height, a random movement, an assertation of length, and and do nothing mode)

So i thought i could write these into functions, and let them be executed by a switch case structure.

The modes would be set by 4 push buttons, which would change the mode in a neat Interrupt.

This did not work, so i wrote a serial print into the ISR (I know i shouldn't) and it alway gives me back the same numbers on startup. I pressed no pin. Nothing happens if i press them.

Serial Monitor is

1
2
0

I don't know where i got it wrong. I measured the Buttons, and read a negative 3,3V, which dropped to 0 when i pressed them.

Appreciate the help.

Board is an Arduino Due.

Code:

// define the pins for the mode buttons
const byte homingbutton = 11;
const byte randombutton = 13;
const byte dropbutton = 12;
const byte nobutton = 10;

/* define the pins for the home switch
const int homingswitch1 = 50;
const int homingswitch2 = 49;
const int homingswitch3 = 48;
const int homingswitch4 = 45;
const int homingswitch5 = 46;
*/

// set the mode to 0, a do nothing case in the loop
volatile int mode = 0; 



// defines an array of five position to be driven to (in absolute mm from top), to be used in later random number choosing

int microsteps = 200;
// RandomPosition is calculated for 10mm Spool. Number of rotations is equal to distance divided by the cirumference of the spool. In our case
long  RPosSteps[] ={0,1600,3200,4800,6400};
// define Drop Position 48 approx. 1500 mm
long DPosSteps = 9600;

// defining speed variables
const int globalspeed = 2000; // all speeds remain the same throuout the programm
const int steps = 200; // fullstepping = 200

void setup() {

  Serial.begin(9600);
  
  // set up of the three interrupts for the buttons
  attachInterrupt(digitalPinToInterrupt(homingbutton), homingchange, LOW);
  attachInterrupt(digitalPinToInterrupt(randombutton), randomchange, LOW);
  attachInterrupt(digitalPinToInterrupt(dropbutton), dropchange, LOW);
  attachInterrupt(digitalPinToInterrupt(nobutton), nochange, LOW);

  // set up the 3 Pins as Input Pullups, pin number according to the variables
  pinMode (homingbutton,INPUT_PULLUP);
  pinMode (randombutton,INPUT_PULLUP);
  pinMode (dropbutton,INPUT_PULLUP);
  pinMode (nobutton,INPUT_PULLUP);

  // set up the 5 Homing Switches
  /*
  pinMode (homingswitch1,INPUT_PULLUP);
  pinMode (homingswitch2,INPUT_PULLUP);
  pinMode (homingswitch3,INPUT_PULLUP);
  pinMode (homingswitch4,INPUT_PULLUP);
  pinMode (homingswitch5,INPUT_PULLUP);
  */
  
  // give the steppers to the MultiStepper to handle
  steppers.addStepper(stepper1);
  steppers.addStepper(stepper2);
  steppers.addStepper(stepper3);
  steppers.addStepper(stepper4);
  steppers.addStepper(stepper5);
}

// set up of the isr to change the buttonstatus
  void nochange() {
    mode = 0;
    Serial.println("0");
  }
  void homingchange() {
    Serial.println("1");
    mode = 1;
  }
  void randomchange() {
    Serial.println("2");
    mode = 2;  
  }
  void dropchange() {
    Serial.println("3");
    mode = 3; 
  }



void homing(){
  
  stepper1.setCurrentPosition(6600);
  stepper2.setCurrentPosition(6600);
  stepper3.setCurrentPosition(6600);
  stepper4.setCurrentPosition(6600);
  stepper5.setCurrentPosition(6600);
  
  
  /*
  long initial_homing =-1;

  while (digitalRead(homingswitch1)== LOW) {  // Make the Stepper move CCW until the switch is activated   
    stepper1.moveTo(initial_homing);  // Set the position to move to
    initial_homing--;  // Decrease by 1 for next move if needed
    stepper1.run();  // Start moving the stepper
    delay(5);
}
    stepper1.setCurrentPosition(0);  // Set the current position as zero for now
    stepper1.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
    stepper1.setAcceleration(100.0);  // Set Acceleration of Stepper
    initial_homing=1;

  while (digitalRead(homingswitch[motornumber] == HIGH)) { // Make the Stepper move CW until the switch is deactivated
    stepper1.moveTo(initial_homing);  
    stepper1.run();
    initial_homing++;
    delay(5);
  }
  
    stepper1.setCurrentPosition(0);
*/
  }

void randomise(){

  long positions[5];

  positions[0]= RPosSteps[random(6)];
  positions[1]= RPosSteps[random(6)];
  positions[2]= RPosSteps[random(6)];
  positions[3]= RPosSteps[random(6)];
  positions[4]= RPosSteps[random(6)];
  
  stepper1.setMaxSpeed(globalspeed);
  stepper2.setMaxSpeed(globalspeed);
  stepper3.setMaxSpeed(globalspeed);
  stepper4.setMaxSpeed(globalspeed);
  stepper5.setMaxSpeed(globalspeed);

  

  steppers.moveTo(positions);
  
  steppers.runSpeedToPosition();
  delay(500); 
      
  }

void drop(){

  long dropposition[5];

  dropposition[0] = DPosSteps;
  dropposition[1] = DPosSteps;
  dropposition[2] = DPosSteps;
  dropposition[3] = DPosSteps;
  dropposition[4] = DPosSteps;
  
  stepper1.setMaxSpeed(globalspeed);
  stepper2.setMaxSpeed(globalspeed);
  stepper3.setMaxSpeed(globalspeed);
  stepper4.setMaxSpeed(globalspeed);
  stepper5.setMaxSpeed(globalspeed);

  steppers.moveTo(dropposition);

  steppers.runSpeedToPosition();
  delay(5000); 
  
}
  
void loop() {
  // the switch case loops through the 3 subroutines as long as the button state remains equal
  switch (mode) {
    case 0:
      break;
    case 1:
      homing();
      break;
    case 2:
      randomise();
      break;
    case 3:
      drop();
      break;
    default:
      break;
          
  }





}

If find two errors:

First you use LOW as the interrupt cause so as long as the pin gets a LOW input it fires the interrupt. That's many times while you push a button because the Arduino is much faster than you.

Second you do something you must not do:

  void nochange() {
    mode = 0;
    Serial.println("0");
  }

You use the Serial object inside an interrupt service routine. This will fill up the serial buffer very fast and as soon as the buffer is full it waits for the serial interrupt to push out some bytes. This will never happen because interrupts are blocked inside ISRs, your code will freeze.

Hi Pylon,

you were absolutely right. Just read up on the Serial Print. It seems, that this is also some kind of an Interrupt.

Also i found out that the digitalpintointerrupt() is not recommended on the Due, since all DPins are able to interrupt.

However, what should i set the ISR to? I think FALLING would be the best, since it's pulled down?

so i wrote a serial print into the ISR (I know i shouldn't)

Says it all

However, what should i set the ISR to? I think FALLING would be the best, since it's pulled down?

Yes. And remove all Serial stuff from all interrupt routines.

Also i found out that the digitalpintointerrupt() is not recommended on the Due, since all DPins are able to interrupt.

You should tell us if you use another type of Arduino than the UNO. Without any mention of a special type we expect you to use an UNO.

That is not your complete code. Where is the variable 'steppers' defined?

Accesses of the 'mode' variable may not be atomic. They need to be protected from interrupts in non-ISR code (i.e. loop()).

Button presses are ssssssllllllloooooooowwwww. Totally not something you should use an interrupt for. Just poll the buttons from loop.

pylon:
Yes. And remove all Serial stuff from all interrupt routines.

You should tell us if you use another type of Arduino than the UNO. Without any mention of a special type we expect you to use an UNO.

I stated it in my opening question right before the code.

Delta_G:
Button presses are ssssssllllllloooooooowwwww. Totally not something you should use an interrupt for. Just poll the buttons from loop.

Yeah thinking about that to. I think the MultiStepper and AccelStepper use interrupts for the timing, so my button presses don't come through anyway all the time.

gfvalvo:
That is not your complete code. Where is the variable 'steppers' defined?

Accesses of the 'mode' variable may not be atomic. They need to be protected from interrupts in non-ISR code (i.e. loop()).

Sorry, i cut something off there. What do you mean atomic?

Here is the latest version of the Code. Though i get only jerky motion out of it.
However the buttons work now except Mode 3 Randomise.

Can't get out of there.

#include <AccelStepper.h>
#include <MultiStepper.h>
MultiStepper steppers;

// Creation of AccelStepper Instances
// stepperx(1 for driver card, Pul-,Dir-)

AccelStepper stepper1(1,52,53);
AccelStepper stepper2(1,43,42);
AccelStepper stepper3(1,39,38);
AccelStepper stepper4(1,30,31);
AccelStepper stepper5(1,35,34);

// define the pins for the mode buttons
const int homingbutton = 11;
const int randombutton = 13;
const int dropbutton = 12;
const int nobutton = 10;

/* define the pins for the home switch
const int homingswitch1 = 50;
const int homingswitch2 = 49;
const int homingswitch3 = 48;
const int homingswitch4 = 45;
const int homingswitch5 = 46;
*/

// set the mode to 0, a do nothing case in the loop
volatile int mode = 0; 



// defines an array of five position to be driven to (in absolute mm from top), to be used in later random number choosing

int microsteps = 200;
// RandomPosition is calculated for 10mm Spool. Number of rotations is equal to distance divided by the cirumference of the spool. In our case
long  RPosSteps[] ={0,1600,3200,4800,6400};
// define Drop Position 48 approx. 1500 mm
long DPosSteps = 9600;

// defining speed variables
const float globalspeed = 2000; // all speeds remain the same throuout the programm
const float globalacc = 1000;
const int steps = 200; // fullstepping = 200

void setup() {

  Serial.begin(9600);


  // set up the 3 Pins as Input Pullups, pin number according to the variables
  pinMode (homingbutton,INPUT_PULLUP);
  pinMode (randombutton,INPUT_PULLUP);
  pinMode (dropbutton,INPUT_PULLUP);
  pinMode (nobutton,INPUT_PULLUP);
  
  // set up of the three interrupts for the buttons
  attachInterrupt(homingbutton, homingchange, FALLING);
  attachInterrupt(randombutton, randomchange, FALLING);
  attachInterrupt(dropbutton, dropchange, FALLING);
  attachInterrupt(nobutton, nochange, FALLING);



  // set up the 5 Homing Switches
  /*
  pinMode (homingswitch1,INPUT_PULLUP);
  pinMode (homingswitch2,INPUT_PULLUP);
  pinMode (homingswitch3,INPUT_PULLUP);
  pinMode (homingswitch4,INPUT_PULLUP);
  pinMode (homingswitch5,INPUT_PULLUP);
  */
  
  // give the steppers to the MultiStepper to handle
  steppers.addStepper(stepper1);
  steppers.addStepper(stepper2);
  steppers.addStepper(stepper3);
  steppers.addStepper(stepper4);
  steppers.addStepper(stepper5);
}

// set up of the isr to change the buttonstatus
  void nochange() {
    mode = 0;

  }
  void homingchange() {

    mode = 1;
  }
  void randomchange() {

    mode = 2;  
  }
  void dropchange() {

    mode = 3; 
  }



void homing(){

  Serial.println("Homing 1");
  
  stepper1.setCurrentPosition(6600);
  stepper2.setCurrentPosition(6600);
  stepper3.setCurrentPosition(6600);
  stepper4.setCurrentPosition(6600);
  stepper5.setCurrentPosition(6600);
  
  
  /*
  long initial_homing =-1;

  while (digitalRead(homingswitch1)== LOW) {  // Make the Stepper move CCW until the switch is activated   
    stepper1.moveTo(initial_homing);  // Set the position to move to
    initial_homing--;  // Decrease by 1 for next move if needed
    stepper1.run();  // Start moving the stepper
    delay(5);
}
    stepper1.setCurrentPosition(0);  // Set the current position as zero for now
    stepper1.setMaxSpeed(100.0);      // Set Max Speed of Stepper (Slower to get better accuracy)
    stepper1.setAcceleration(100.0);  // Set Acceleration of Stepper
    initial_homing=1;

  while (digitalRead(homingswitch[motornumber] == HIGH)) { // Make the Stepper move CW until the switch is deactivated
    stepper1.moveTo(initial_homing);  
    stepper1.run();
    initial_homing++;
    delay(5);
  }
  
    stepper1.setCurrentPosition(0);
*/
  }

void randomise(){

    Serial.println("Randomise 3");

  long positions[5];

  positions[0]= RPosSteps[random(6)];
  positions[1]= RPosSteps[random(6)];
  positions[2]= RPosSteps[random(6)];
  positions[3]= RPosSteps[random(6)];
  positions[4]= RPosSteps[random(6)];
  
  stepper1.setMaxSpeed(globalspeed);
  stepper2.setMaxSpeed(globalspeed);
  stepper3.setMaxSpeed(globalspeed);
  stepper4.setMaxSpeed(globalspeed);
  stepper5.setMaxSpeed(globalspeed);

  stepper1.setSpeed(globalspeed);
  stepper2.setSpeed(globalspeed);
  stepper3.setSpeed(globalspeed);
  stepper4.setSpeed(globalspeed);
  stepper5.setSpeed(globalspeed);

  steppers.moveTo(positions);
  
  steppers.run();
 
  }

void drop(){

    Serial.println("Dropping 2");

  long dropposition[5];

  dropposition[0] = DPosSteps;
  dropposition[1] = DPosSteps;
  dropposition[2] = DPosSteps;
  dropposition[3] = DPosSteps;
  dropposition[4] = DPosSteps;
  
  stepper1.setMaxSpeed(globalspeed);
  stepper2.setMaxSpeed(globalspeed);
  stepper3.setMaxSpeed(globalspeed);
  stepper4.setMaxSpeed(globalspeed);
  stepper5.setMaxSpeed(globalspeed);

  steppers.moveTo(dropposition);

  steppers.runSpeedToPosition();

  
}
  
void loop() {
  // the switch case loops through the 3 subroutines as long as the button state remains equal
  switch (mode) {
    case 0: {
      Serial.println("I do nothing 0");
      break;
    }
    case 1: {
      homing();
      break;
    }
    case 2:{
      randomise();
      break;
    }
    case 3: {
      drop();
      break;
    }
    default:
      break;
          
  }





}

As noted several times in previous replies, there's no good reason to use interrupts for the push buttons in this application. A properly-written, non-blocking loop() function will do the trick.

Benni_Lorenzo:
Sorry, i cut something off there. What do you mean atomic?

In this context an atomic operation is per the definition here:

It executes as a single, indivisible operation. Nothing else can happen while it's executing. On an 8-bit machine, accesses to 16 and 32 bit values may not be atomic. Any interrupt and associated ISR could fire while it's in progress. If that ISR changes the value you're trying to access part way through, you will get unpredictable results. Since you're running on a 32-bit machine (Due), the risk is less. Still, I'd protect any accesses to shared (volatile) variables in non-ISR code with noInterrupt() / interrupt() pairs.