Pushbuttons and motor control with Adafruit motor shield? SIMPLE Problem!

Hello, my hope is that this challenge in my design will come as nothing more than a game of tic-tac-toe to those who are willing to help.

Basically, what I have is an Arduino Uno board, an Adafruit Motorshield V2.3, and a unipolar/bipolar stepper motor. Along with these items are a handful of resistors, LEDs, and a couple of four-pronged pushbuttons, and a 9V AC to DC wall plug to power my Arduino independently of the computer.

MY GOAL is all too simple; first, I want to be able to have a simple “on” switch extended from the processor so that it can be accessible from the outside of the prototype. In its nature, the switch is there to activate and deactivate my motor, where it spins back and forth as previously programmed by me.

Currently, I have gotten as far as programming the motor to start and stop spinning based on a digital input “state change detection” when pressing the pushbutton. The issue with this is that first of all, the breadboard and pushbutton are inaccessible by hand when the prototype is fully assembled.

The second issue is that the pushbutton activates the motor on the first attempt, as it should, however -getting it to stop instantaneously upon the second button press does not happen. The motor will stop when the pushbutton is pressed at just the right time, held down and then released at just the right time, or any annoying combination of that.

I figured that the simplest way around this was splicing a switch into my 9V Wall Adapter and cleanly running it from the guts to the exterior of the prototype, programming the Arduino such that the motor spins continuously so long as power is available. This is good, since stepper motors constantly draw power even when they aren’t spinning. However, this is a bad way to lead into later development stages, where different button inputs could set different motor cycles (for example.)

So to summarize, here is what I have accomplished:
Motor activation upon pushbutton press (see attached code)
Motor deactivation with mysteriously correct timing of button press

Here is what I need help accomplishing:
Getting a single pushbutton press to instantaneously interrupt and cancel the motor cycle wherever it is in its cycle. If it is pressed again, then the motor cycle will start over again. I have attached the code I was using to try to accomplish this. I have been pointed in the direction of “interrupts” before, but little more than telling me to go research interrupt commands.

Lastly, I would appreciate guidance finding a user-friendly, external button panel that works with Arduino and Adafruit Motorshield. I could 3D print some sort of fitment for it, but at the very least, I need to know what sort of compatible tactile “button” there is that can easily be extended from the breadboard or motor shield itself. At all costs, I’m trying to avoid some sort of brittle mechanical linkage from an external button to a pushbutton on the breadboard within.

/*
  State change detection (edge detection)

 Often, you don't need to know the state of a digital input all the time,
 but you just need to know when the input changes from one state to another.
 For example, you want to know when a button goes from OFF to ON.  This is called
 state change detection, or edge detection.

 This example shows how to detect when a button or button changes from off to on
 and on to off.

 The circuit:
 * pushbutton attached to pin 2 from +5V
 * 10K resistor attached to pin 2 from ground
 * LED attached from pin 13 to ground (or use the built-in LED on
   most Arduino boards)

 created  27 Sep 2005
 modified 30 Aug 2011
 by Tom Igoe < Naw this niggas lame

This example code is in the public domain.

 http://arduino.cc/en/Tutorial/ButtonStateChange

 */

// Adding shit to this shit because we're about to get RICHHHH
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);

// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to
const int led2Pin = A0;

// Variables will change:
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);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  pinMode(led2Pin, OUTPUT);

  // initialize serial communication:
  Serial.begin(9600);
  // set up Serial library at 9600 bps
  Serial.println("Giving ");

  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz
}

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 == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
      Serial.println("Click!");
      //Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
      //Serial.println(digitalRead(2));
      //Serial.println(buttonState);     
    }
//    else {
//      // if the current state is LOW then the button
//      // wend from on to off:
//      Serial.println("off");
//    }
    // 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;}


  // turns on the LED every ___ button pushes by
  // checking the modulo of the button push counter.
  // the modulo function gives you the remainder of
  // the division of two numbers:
  if (buttonPushCounter % 2 == 0) {
    digitalWrite(ledPin, HIGH);
    digitalWrite(led2Pin, LOW);
    myMotor->setSpeed(0);
} else {
      digitalWrite(ledPin, LOW);
      digitalWrite(led2Pin, HIGH);
      digitalWrite
      
      //motor block
      myMotor->setSpeed(75);  // 50 rpm   
      myMotor->step(200, FORWARD, DOUBLE); //"SINGLE" implies single motor steps
      myMotor->step(150, BACKWARD, DOUBLE);
      myMotor->step(50, FORWARD, DOUBLE); //"SINGLE" implies single motor steps
      myMotor->step(50, BACKWARD, DOUBLE);
      myMotor->step(80, FORWARD, DOUBLE); //"SINGLE" implies single motor steps
      myMotor->step(100, BACKWARD, DOUBLE);
  //     {if (buttonState == HIGH)
  //     Serial.println("High");
  //     if (buttonState == LOW)
  //     Serial.println("low");
  //     }
    }
}

MY GOAL is all too simple; first, I want to be able to have a simple “on” switch extended from the processor so that it can be accessible from the outside of the prototype. In its nature, the switch is there to activate and deactivate my motor, where it spins back and forth as previously programmed by me.

My coding issue is that the pushbutton activates the motor on the first attempt, as it should, however -getting it to stop instantaneously upon the second button press does not happen. The motor will stop when the pushbutton is pressed at just the right time, held down and then released at just the right time, or any annoying combination of that.

I figured that the simplest way around this was splicing a switch into my 9V Wall Adapter and cleanly running it from the guts to the exterior of the prototype, programming the Arduino such that the motor spins continuously so long as power is available. This is good, since stepper motors constantly draw power even when they aren’t spinning. However, this is a bad way to lead into later development stages, where different button inputs could set different motor cycles (for example.)

In summary, I need help getting a single pushbutton press to instantaneously interrupt and cancel the motor cycle wherever it is in its cycle. If it is pressed again, then the motor cycle will start over again. I have attached the code I was using to try to accomplish this. I have been pointed in the direction of “interrupts” before, but little more than telling me to go research interrupt commands.

/*
  State change detection (edge detection)

 Often, you don't need to know the state of a digital input all the time,
 but you just need to know when the input changes from one state to another.
 For example, you want to know when a button goes from OFF to ON.  This is called
 state change detection, or edge detection.

 This example shows how to detect when a button or button changes from off to on
 and on to off.

 The circuit:
 * pushbutton attached to pin 2 from +5V
 * 10K resistor attached to pin 2 from ground
 * LED attached from pin 13 to ground (or use the built-in LED on
   most Arduino boards)

 created  27 Sep 2005
 modified 30 Aug 2011
 by Tom Igoe < Naw this niggas lame

This example code is in the public domain.

 http://arduino.cc/en/Tutorial/ButtonStateChange

 */

// Adding shit to this shit because we're about to get RICHHHH
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);

// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to
const int led2Pin = A0;

// Variables will change:
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);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  pinMode(led2Pin, OUTPUT);

  // initialize serial communication:
  Serial.begin(9600);
  // set up Serial library at 9600 bps
  Serial.println("Giving ");

  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz
}

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 == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
      Serial.println("Click!");
      //Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
      //Serial.println(digitalRead(2));
      //Serial.println(buttonState);     
    }
//    else {
//      // if the current state is LOW then the button
//      // wend from on to off:
//      Serial.println("off");
//    }
    // 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;}


  // turns on the LED every ___ button pushes by
  // checking the modulo of the button push counter.
  // the modulo function gives you the remainder of
  // the division of two numbers:
  if (buttonPushCounter % 2 == 0) {
    digitalWrite(ledPin, HIGH);
    digitalWrite(led2Pin, LOW);
    myMotor->setSpeed(0);
} else {
      digitalWrite(ledPin, LOW);
      digitalWrite(led2Pin, HIGH);
      digitalWrite
      
      //motor block
      myMotor->setSpeed(75);  // 50 rpm   
      myMotor->step(200, FORWARD, DOUBLE); //"SINGLE" implies single motor steps
      myMotor->step(150, BACKWARD, DOUBLE);
      myMotor->step(50, FORWARD, DOUBLE); //"SINGLE" implies single motor steps
      myMotor->step(50, BACKWARD, DOUBLE);
      myMotor->step(80, FORWARD, DOUBLE); //"SINGLE" implies single motor steps
      myMotor->step(100, BACKWARD, DOUBLE);
  //     {if (buttonState == HIGH)
  //     Serial.println("High");
  //     if (buttonState == LOW)
  //     Serial.println("low");
  //     }
    }
}

I think this comment explains the problem (though I'm not sure that was the author's intention :) )

//motor block

All the subsequent code must complete before the button is tested again.

I can't figure what you want to happen. However if you want a button to stop a motor instantly you must test the button state between every single step of the motor.

The second example in this simple stepper code uses millis() to manage the step timing and could be adapted to check a button pin between steps.

...R

Please don't waste our time by double posting.

...R

Please do not cross-post. This wastes time and resources as people attempt to answer your question on multiple threads.

Threads merged.

  • Moderator