Interrupt and loop not working as intended

Hi guys.

I´m trying to make a stepper which moves 45° every second and if I press a button it stops until I press it again. Now somehow the stepper just makes the "45 degree turn and wait 1000ms loop" without me doing anything and it also never leaves the loop.

So:

-my interrupt doesn´t seem to work
-the loops starts regardless of the conditions (stoporgo is false, so it shouldn´t move)...

I´m using a Digispark (ATtiny85) and a ULN2003 for the stepper,

I just can´t find the error :frowning:

#include <CheapStepper.h>
#include "PinChangeInterrupt.h"

// next, declare the stepper
// and connect pins 3,2,1,0 to IN1,IN2,IN3,IN4 on ULN2003 board

CheapStepper stepper (3,2,1,0); 

 // let's create a boolean variable to save the direction of our rotation

boolean moveClockwise = true;
boolean stoporgo = false;
#define interruptPin 4

void setup() {
  pinMode(interruptPin, INPUT_PULLUP);
  attachPCINT(digitalPinToPCINT(interruptPin), werte, CHANGE);
  
  // let's set a custom speed of 20rpm (the default is ~16.25rpm)
  
  stepper.setRpm(12); 
  /* Note: CheapStepper library assumes you are powering your 28BYJ-48 stepper
   * using an external 5V power supply (>100mA) for RPM calculations
   * -- don't try to power the stepper directly from the Arduino
   * 
   * accepted RPM range: 6RPM (may overheat) - 24RPM (may skip)
   * ideal range: 10RPM (safe, high torque) - 22RPM (fast, low torque)
   */
  
  // stepper.setTotalSteps(4076);
  /* you can uncomment the above line if you think your motor
   * is geared 63.68395:1 (measured) rather than 64:1 (advertised)
   * which would make the total steps 4076 (rather than default 4096)
   * for more info see: http://forum.arduino.cc/index.php?topic=71964.15
   */
}

void werte(void) {
stoporgo = !stoporgo;
}
void loop() {
if (stoporgo = true) {
    stepper.moveDegrees (moveClockwise, 45);
    // stepper.moveDegreesCW (90); <--- another way to do a clockwise 90 degree turn

    // wait a second
    
    delay(1000);
}
else {

}
}

Thanks in advance!

Thanks for the quick answer!

Delta_G:
That doesn't compare it to true. That sets it to true. = vs. ==.

Oh god I´m an idiot^^ Thanks, now it doesn´t always spin :slight_smile:

I also changed my boolean to a volatile one (writing volatile before it, I guess it´s the only way to go?)

I always thought, that interrupts are for cases in which a program is executing something and the time window for registering a pressed button is so short, that it doesn´t register it... And that they are the "safe" method to register buttons or other input signals.

You mean I should use digital.read() for checking the pressed button?

Cheers,
Dominik

Ups, I meant digitalRead() . Shouldn´t try to remember code snippets from my memory, I don´t have the routine...^^

I´ll try that, thanks!

So, this doesn´t work... Is my timing bad, or is my style of state reading simply wrong? Or is it the stepper.moveDegrees the problem?

#include <CheapStepper.h>
#include "PinChangeInterrupt.h"

// next, declare the stepper
// and connect pins 3,2,1,0 to IN1,IN2,IN3,IN4 on ULN2003 board

CheapStepper stepper (3,2,1,0); 

 // let's create a boolean variable to save the direction of our rotation

boolean moveClockwise = true;
volatile boolean stoporgo = false;
int Button = 4;
int val = 0;

void setup() {

  pinMode(Button, INPUT_PULLUP);
  // let's set a custom speed of 20rpm (the default is ~16.25rpm)
  
  stepper.setRpm(12); 
  /* Note: CheapStepper library assumes you are powering your 28BYJ-48 stepper
   * using an external 5V power supply (>100mA) for RPM calculations
   * -- don't try to power the stepper directly from the Arduino
   * 
   * accepted RPM range: 6RPM (may overheat) - 24RPM (may skip)
   * ideal range: 10RPM (safe, high torque) - 22RPM (fast, low torque)
   */
  
  // stepper.setTotalSteps(4076);
  /* you can uncomment the above line if you think your motor
   * is geared 63.68395:1 (measured) rather than 64:1 (advertised)
   * which would make the total steps 4076 (rather than default 4096)
   * for more info see: http://forum.arduino.cc/index.php?topic=71964.15
   */
}


void loop() {

val = digitalRead(Button);  // read input value
if (val == LOW) {         // check if the input is LOW (button released)
stoporgo = !stoporgo;
} 
  
if (stoporgo == true) {
    stepper.moveDegrees (moveClockwise, 45);
    // stepper.moveDegreesCW (90); <--- another way to do a clockwise 90 degree turn

    // wait a second
    
    delay(1000);
}
else {

}
}
if (val == LOW) {         // check if the input is LOW (button released)

Here the comment was wrong. I use the internal pullup and the button is wired to GND.

Code: [Select]
#include <CheapStepper.h>

Don't know that library. Why aren't you using the normal stepper library that comes with the IDE?
If you're using non-standard libraries then it's a good idea to at least link to them.

If I use the included library, it doesnt´move. Just vibrates a bit.
(With this code:)

#include <Stepper.h>

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 3 through 0:
Stepper myStepper(stepsPerRevolution, 3, 2, 1, 0);

void setup() {
  // set the speed at 12 rpm:
  myStepper.setSpeed(12);

}

void loop() {
  // step one revolution  in one direction:
  myStepper.step(stepsPerRevolution);
  delay(500);

  // step one revolution in the other direction:
  myStepper.step(-stepsPerRevolution);
  delay(500);
}

When you say it doesn't work, what do you mean by that? Describe what happens and compare with what you expected. "It doesn't work" is a totally useless statement that tells me nothing.

The stepper isn´t turning and nothing changes when I press the button.

This also didn´t work :frowning:

#include <CheapStepper.h>
#include "PinChangeInterrupt.h"

// next, declare the stepper
// and connect pins 3,2,1,0 to IN1,IN2,IN3,IN4 on ULN2003 board

CheapStepper stepper (3,2,1,0); 

 // let's create a boolean variable to save the direction of our rotation

boolean moveClockwise = true;

const int  buttonPin = 4;    // the pin that the pushbutton is attached to

int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {

// initialize the button pin as a input:
  pinMode(buttonPin, INPUT_PULLUP);
  
  stepper.setRpm(12); 
  /* Note: CheapStepper library assumes you are powering your 28BYJ-48 stepper
   * using an external 5V power supply (>100mA) for RPM calculations
   * -- don't try to power the stepper directly from the Arduino
   * 
   * accepted RPM range: 6RPM (may overheat) - 24RPM (may skip)
   * ideal range: 10RPM (safe, high torque) - 22RPM (fast, low torque)
   */
}

void loop() {
  
// read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == LOW) {
      // if the current state is LOW then the button went from off to on:
      buttonPushCounter++;
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;


  // stepper moves every two button pushes by checking the modulo of the
  // button push counter until ot gets turned off again. the modulo function gives you the remainder of the
  // division of two numbers:
  if (buttonPushCounter % 2 == 0) {
    stepper.moveDegrees (moveClockwise, 45);
    // wait a second
    delay(1000);
  } else {
  }
}

Note: CheapStepper library assumes you are powering your 28BYJ-48 stepper

  • using an external 5V power supply (>100mA)

What motor are you using, and how is it powered?

I´m using a 28BYJ-48 stepper. Wiring see photos :slight_smile:


Delta_G:
there's that useless statement again... :frowning:

Old habits die hard I guess^^

It´s turning regardless of the buttons state.

If I use the included library, it doesnt´move. Just vibrates a bit.
(With this code:)

#include <Stepper.h>

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 3 through 0:
Stepper myStepper(stepsPerRevolution, 3, 2, 1, 0);

void setup() {
  // set the speed at 8 rpm:
  myStepper.setSpeed(8);

}

void loop() {
  // step one revolution  in one direction:
  myStepper.step(stepsPerRevolution);
  delay(500);

// step one revolution in the other direction:
  myStepper.step(-stepsPerRevolution);
  delay(500);
}

With this the motor does one revolution, stops for 500ms and then continues the rotation in the same direction. And it only moves, when the speed is set to 8rpm (or lower, i guess. 12rpm doesn´t work)

Partly good news: I managed to get the Stepper.h library work. I had to change the two middle pins in Stepper myStepper(stepsPerRevolution, 3, 2, 1, 0)

to

Stepper myStepper(stepsPerRevolution, 3, 1, 2, 0)

Found it on a german site, that this is a common? problem with this stepper. Now I´ll try implementing a State change detection :slight_smile:

Now I´m getting frustrated...

I pulled out the jumper from the ULN2003 board, took out the driver itself and only wanted to register a pressed button with this:

const int ledPin =  1;
const int buttonPin = 5;

int buttonState = 0; 

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin 1 (internal LED) as an output.
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

// the loop function runs over and over again forever
void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
  } else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  }
}

It should turn the LED off as long as I hold the button, right?

The built in LED is on PIN1, I tried the Blink example and it worked.
I tried both PIN4 and PIN5 and checked the button, it works mechanically/electrically.
I tried with pinMode(buttonPin, INPUT_PULLUP); aswell as pinMode(buttonPin, INPUT);
I tried to change the state witch connecting the buttonPin to 5V.

The LED simply stays off.

What did I overlook? :frowning:

I got it working. My only issue is that I have to time the buttonpress. Is there an elegant way to avoid it?

Thanks for all the help until now :slight_smile:

#include <Stepper.h>

// constants won't change. They're used here to set pin numbers:
const int stepsPerRevolution = 2048;
const int buttonPin = 4;    // the number of the pushbutton pin

// Variables will change:
int State = LOW;         // the current state of the output 
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

int stepcount = 500;        // -->Set the Steps per movement<--
int delaytime = 500;        // -->Set the wait time between movements<--

int stpcnt = stepcount / 10;

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

// initialize the stepper library on pins 3 through 0, pins 1 and 2 changed!:
Stepper myStepper(stepsPerRevolution, 3, 1, 2, 0);

void setup() {
  pinMode(buttonPin, INPUT);
// set the speed at 12 rpm:
  myStepper.setSpeed(12);
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the stepper if the new button state is HIGH
      if (buttonState == HIGH) {
        State = !State;
      }
    }
  }

  // Start/Stop

if (State == HIGH){
  for (int i = 0; i <= stpcnt; i++) {
  myStepper.step(10);

if (i == stpcnt){
  delay (delaytime);
}
 }   
  }

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}

Nobody? :frowning:

dodoka:
I have to time the buttonpress.

I don't know what that means....

My only issue is that I have to time the buttonpress. Is there an elegant way to avoid it?

Eliminate the for() loop and the delay.

Move one step at a time controlled by loop(), and read the button every pass through loop().

Eliminate the for() loop and the delay.

Move one step at a time controlled by loop(), and read the button every pass through loop().

I want the pump to rotate discontinuously or at least very slow. I´m aiming for 1 drop every 1.5 seconds. So I either have to pump one drop and then wait or pump really slow :slight_smile: So I need the delay, right? And the for() loop to select the turning degree.

Eliminate the for() loop and the delay.
Move one step at a time controlled by loop(), and read the button every pass through loop().

I want the pump to rotate discontinuously or at least very slow. I´m aiming for 1 drop every 1.5 seconds.

You have set the speed to 12 rpm which with your 2048 steps/revolution gives about 410 steps/second. That gives a step timing of 2.44ms between steps.

You run the stepper for 500 steps in the for loop so that's 1220 milliseconds. Then you call a delay of 500ms. The result is that your program is putting out 500 steps in 1720 ms. I assume that is giving you something like the one drop every 1.5 seconds.

Given that math, I would start with a basic timing of 3500 microseconds between steps. Do not use .setSpeed() in the code.

You want to use myStepper.step(1) in a micros() timer loop. You want to declare an unsigned long stepDelay = 3500 and an unsigned long lastStepTime. The after the button press enables the cycle you use

if (micros() - lastStepTime >= stepDelay)
{ 
  lastStepTime += stepDelay;
  myStepper.step(1);
  stepcount++;
}

if (stepcount == 500)
{//do what you do when one drop is dispensed}

Thanks, I´ll try your suggestions once my silicone hose arrives. Only then I can measure how much the pump is really pumping :slight_smile: