Hello,
I want to use a push-button to turn the stepper motor ON and OFF.
The code works, but when pressing the button again to turn it off nothing happens.
Could someone please take a look at the code and help me out?
const int stepPin = 5;
const int dirPin = 2;
const int ButtonPin = 7;
void setup()
{
pinMode(ButtonPin, INPUT_PULLUP);
pinMode(dirPin,OUTPUT);
pinMode(stepPin,OUTPUT);
digitalWrite(dirPin,LOW);
}
void loop()
{
int buttonState = digitalRead(ButtonPin);
while(buttonState == HIGH)))
{
MyFunction();
}
}
Some time ago I have written a demo-code that does exactly what you are asking for.
This code uses the MobaTools-Library for creating the stepper-signals.
You can install the MobaTools-library with the library-manager inside the Arduino-IDE
/* explanation of the most important details:
realising a functionality where using a momentary push-button
acts as a toogle-switch
push => activated push again => DE-activated
push again => activated push again => DE-activated
etc. etc. ...
This needs quite some code. This code is well organised in MULTIPLE functions
where each function is a senseful SUB-program
*/
#define ProjectName "momentary push-button toggle on/off stepper-motor"
#include <MobaTools.h>
const int FULLROT1 = 200;
const byte stepPin = 5;
const byte dirPin = 2;
const byte ToggleButtonPin = 7;
MoToStepper myStepper(FULLROT1,STEPDIR); // HALFSTEP is default
// define IO-states for inputs with pull-up-resistors
// pull-up-resistors invert the logig
#define unPressed HIGH
#define pressed LOW
bool forward = false;
unsigned long myCounter = 0;
void setup() {
Serial.begin(115200); // adjust baudrate in the serial monitor to match the number
Serial.println( F("Setup-Start") );
printFileNameDateTime();
pinMode (LED_BUILTIN, OUTPUT); // used for indicating logging active or not
digitalWrite(LED_BUILTIN, LOW);
// wire button between IO-pin and GND
// Pull-up-resistor inverts the logic
// unpressed: IO-pin detects HIGH
// pressed: IO-Pin detects LOW
pinMode(ToggleButtonPin, INPUT_PULLUP);
myStepper.attach(stepPin,dirPin);
myStepper.setSpeed( 300 ); // 30 rev/min (if stepsPerRev is set correctly)
myStepper.setRampLen( FULLROT1 / 2); // Ramp length is 1/2 revolution
}
void loop () {
forward = GetToggleSwitchState(); // must be executed all the time
if (forward) {
digitalWrite(LED_BUILTIN, HIGH);
myStepper.rotate(1);
}
else {
digitalWrite(LED_BUILTIN, LOW);
myStepper.stop();
}
}
bool GetToggleSwitchState() {
// "static" makes variables persistant over function calls
static bool toggleState = false;
static bool lastToggleState = false;
static byte buttonStateOld = unPressed;
static unsigned long buttonScanStarted = 0;
unsigned long buttonDebounceTime = 50;
unsigned long buttonDebounceTimer;
byte buttonStateNew;
if ( TimePeriodIsOver(buttonDebounceTimer, buttonDebounceTime) ) {
// if more time than buttonDebounceTime has passed by
// this means let pass by some time until
// bouncing of the button is over
buttonStateNew = digitalRead(ToggleButtonPin);
if (buttonStateNew != buttonStateOld) {
// if button-state has changed
buttonStateOld = buttonStateNew;
if (buttonStateNew == unPressed) {
// if button is released
toggleState = !toggleState; // toggle state-variable
} // the attention-mark is the NOT operator
} // which simply inverts the boolean state
} // !true = false NOT true is false
// !false = true NOT false is true
return toggleState;
}
void printFileNameDateTime() {
Serial.print( F("File : ") );
Serial.println( F(__FILE__) );
Serial.print( F("Date : ") );
Serial.println( F(__DATE__) );
Serial.print( F("Project: ") );
Serial.println( F(ProjectName) );
}
// helper-function for easy to use non-blocking timing
boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - expireTime >= TimePeriod ) {
expireTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}
Thanks for the hints. @ Stefan: I only edited the code, and it works, but i hold the push button a long time to turn it of. Maybe, something is not quite right with the code…
#include <MobaTools.h>
//const int FULLROT1 = 200;
const byte stepPin = 5;
const byte dirPin = 2;
const byte ToggleButtonPin = 7;
//MoToStepper myStepper(FULLROT1,STEPDIR);
#define unPressed HIGH
#define pressed LOW
bool forward = false;
unsigned long myCounter = 0;
void setup() {
pinMode (LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
pinMode(ToggleButtonPin, INPUT_PULLUP);
pinMode(dirPin,OUTPUT);
pinMode(stepPin,OUTPUT);
digitalWrite(dirPin,LOW);
}
void MyFunction()
{
for(int x = 0; x < 1000; x++)
{
digitalWrite(dirPin,HIGH);
digitalWrite(stepPin,HIGH);
delayMicroseconds(800);
digitalWrite(stepPin,LOW);
delayMicroseconds(800);
}
delay(800);
for(int x = 0; x < 1000; x++)
{
digitalWrite(dirPin,LOW);
digitalWrite(stepPin,HIGH);
delayMicroseconds(800);
digitalWrite(stepPin,LOW);
delayMicroseconds(800);
}
delay(800);
}
void loop ()
{
forward = GetToggleSwitchState();
if (forward)
{
digitalWrite(LED_BUILTIN, HIGH);
//myStepper.rotate(1);
MyFunction();
}
else
{
digitalWrite(LED_BUILTIN, LOW);
//myStepper.stop();
return(MyFunction);
}
}
bool GetToggleSwitchState()
{
// "static" makes variables persistant over function calls
static bool toggleState = false;
static bool lastToggleState = false;
static byte buttonStateOld = unPressed;
static unsigned long buttonScanStarted = 0;
unsigned long buttonDebounceTime = 50;
unsigned long buttonDebounceTimer;
byte buttonStateNew;
if ( TimePeriodIsOver(buttonDebounceTimer, buttonDebounceTime) ) {
// if more time than buttonDebounceTime has passed by
// this means let pass by some time until
// bouncing of the button is over
buttonStateNew = digitalRead(ToggleButtonPin);
if (buttonStateNew != buttonStateOld) {
// if button-state has changed
buttonStateOld = buttonStateNew;
if (buttonStateNew == unPressed) {
// if button is released
toggleState = !toggleState; // toggle state-variable
} // the attention-mark is the NOT operator
} // which simply inverts the boolean state
} // !true = false NOT true is false
// !false = true NOT false is true
return toggleState;
}
// helper-function for easy to use non-blocking timing
boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - expireTime >= TimePeriod ) {
expireTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}
Now your modification has two for-loops.
making the stepper-motor running clockwise and then counter-clockwise
You will have to describe in much more details what you want the code to do
For-loops are designed to always run from
start-value to end-value
and this needs time
And this is the reason why you have to press the button so long.
What is really strange is that you coded this line
This code-version prints to the serial monitor to make visible what your code is doing
#include <MobaTools.h>
//const int FULLROT1 = 200;
const byte stepPin = 5;
const byte dirPin = 2;
const byte ToggleButtonPin = 7;
//MoToStepper myStepper(FULLROT1,STEPDIR);
#define unPressed HIGH
#define pressed LOW
bool forward = false;
unsigned long myCounter = 0;
void setup() {
Serial.begin(115200);
Serial.println("Setup-Start");
pinMode (LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
pinMode(ToggleButtonPin, INPUT_PULLUP);
pinMode(dirPin, OUTPUT);
pinMode(stepPin, OUTPUT);
digitalWrite(dirPin, LOW);
Serial.println("exiting Setup");
}
void MyFunction()
{
Serial.println("entering first for-loop");
for (int x = 0; x < 1000; x++)
{
digitalWrite(dirPin, HIGH);
digitalWrite(stepPin, HIGH);
delayMicroseconds(800);
digitalWrite(stepPin, LOW);
delayMicroseconds(800);
}
Serial.println("first for-loop finished");
delay(800);
Serial.println("entering second for-loop ");
for (int x = 0; x < 1000; x++)
{
digitalWrite(dirPin, LOW);
digitalWrite(stepPin, HIGH);
delayMicroseconds(800);
digitalWrite(stepPin, LOW);
delayMicroseconds(800);
}
Serial.println("second for-loop finished");
delay(800);
Serial.println("delay(800) finished");
Serial.println("exiting MyFunction()");
}
void loop ()
{
forward = GetToggleSwitchState();
if (forward)
{
digitalWrite(LED_BUILTIN, HIGH);
//myStepper.rotate(1);
MyFunction();
}
else
{
digitalWrite(LED_BUILTIN, LOW);
//myStepper.stop();
return (MyFunction);
}
}
bool GetToggleSwitchState()
{
// "static" makes variables persistant over function calls
static bool toggleState = false;
static bool lastToggleState = false;
static byte buttonStateOld = unPressed;
static unsigned long buttonScanStarted = 0;
unsigned long buttonDebounceTime = 50;
unsigned long buttonDebounceTimer;
byte buttonStateNew;
if ( TimePeriodIsOver(buttonDebounceTimer, buttonDebounceTime) ) {
// if more time than buttonDebounceTime has passed by
// this means let pass by some time until
// bouncing of the button is over
buttonStateNew = digitalRead(ToggleButtonPin);
if (buttonStateNew != buttonStateOld) {
// if button-state has changed
buttonStateOld = buttonStateNew;
if (buttonStateNew == unPressed) {
// if button is released
toggleState = !toggleState; // toggle state-variable
} // the attention-mark is the NOT operator
} // which simply inverts the boolean state
} // !true = false NOT true is false
// !false = true NOT false is true
return toggleState;
}
// helper-function for easy to use non-blocking timing
boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - expireTime >= TimePeriod ) {
expireTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}
your code has a two for-loops
one rotating the stepper-motor clockwise
a second rotating the stepper-motor counter-clockwise
you will have to decribe with much more precision what you want to do
do you want the stepper-motor just to immidiately stop if the button is pressed again?
do you want the stepper-motor to rotate back to the position the axle was before starting rotating clockwise?
do you want the motor to rotate back 1000 steps if the button is pressed again?
do you want the motor to interrupt the 1000 steps clockwise
and if button is pressed again continue with rotating until the motor has rotated 1000 steps clockwise and then rotate back 1000 steps
and this behaviour shall be the same if the motor has already started rotating (back) counterclockwise?
if you press the button while motor is running back counter-clockwise) stop the motor
and resume rotating with the next button-press?
I want the stepper-motor just to immediately stop if the button is pressed again. And after this if the button is pressed again the stepper-motor continue with rotating until the motor has rotated 1000 steps clockwise and then rotate back 1000 steps.
Ok this clarifies what the functionality shall be.
This is completely different from a simple
Here is a WOKWI-Simulation that is able to start / stop on rotating clockwise counter-clockwise
Such a functionality is easier to write with a technique called state-machine.
I think now you understand why a very precise description of the wanted functionality is nescessary