I just didn't want to post it yet if this wasn't the right place to do that. You've explained that it is though, so here it is, below.
I added a 2nd button and wanted it to do something slightly different. The first button is still doing what I had originally asked (just backwards--I had the CW and CCW backwards in my original post and request, but that was an easy switch in the code).
What I wanted the 2nd button to do: rotate the motor CCW 200 steps, pause for 2 seconds, rotate CW 200 steps, pause for 1.5 seconds, rotate CCW 200 steps again, pause for 2 seconds again, rotate continuously CW, and when the beam is broken, stop continuous rotation and rotate CW 200 steps, then back to idle.
Once I started playing around with the code in the 2nd Switch (for button 2), the compiler started giving me this error:
'printStateIfChanged' was not declared in this scope
Thanks again for your insight!
#include <MobaTools.h>
const byte dirPin = 2;
const byte stepPin = 3;
const byte sensorPin = 4;
const byte buttonPin1 = 5;
const byte buttonPin2 = 9;
const int STEPS_REVOLUTION = 200;
// modes of operation = states of the state-machine
const byte sm_idling = 0;
const byte sm_RotFwd1Rev = 1;
const byte sm_wait1Rev = 2;
const byte sm_PausingA = 3;
const byte sm_CheckForBeamBreak = 4;
const byte sm_WaitRotBack1Rev = 5;
const byte sm_PausingB = 6;
const byte sm_PausingC = 7;
// 2D-array of chars for indicating the state
// the state-machine is in with letters instead of a number
// which makes it easier to understand by just reading
const char stateName[][20] = {"sm_idling",
"sm_RotFwd1Rev",
"sm_wait1Rev",
"sm_PausingA",
"sm_CheckForBeamBreak",
"sm_WaitRotBack1Rev"
"sm_PausingB",
"sm_PausingC",
};
const byte pressed = LOW;
const byte unPressed = HIGH;
byte myState = sm_idling;
const int oneRevolution = 200;
unsigned long waitTimer;
MoToStepper myStepMotor(STEPS_REVOLUTION, STEPDIR); // HALFSTEP ist default
void setup() {
Serial.begin(115200);
Serial.println("Setup-Start");
pinMode(sensorPin, INPUT);
pinMode(buttonPin1, INPUT_PULLUP);
pinMode(buttonPin2, INPUT_PULLUP);
myStepMotor.attach(stepPin, dirPin);
myStepMotor.setSpeed( 240 ); // = 24 rotations/Min
myStepMotor.setRampLen( oneRevolution / 4 ); // = 1/4 Revolution
myStepMotor.setZero(); // Set reference point for motor 1
myState = sm_idling;
Serial.println("press button for start" );
printStateIfChanged(myState);
}
void loop() {
// everything happens inside the function myStepperStateMachine
myStepperStateMachine();
}
void myStepperStateMachine() {
printStateIfChanged(myState);
switch (myState) {
// through the break;-statement each case is mutually exclusive
case sm_idling:
// check if button is pressed
if ( digitalRead(buttonPin1) == pressed) {
// if button is pressed
myState = sm_RotFwd1Rev; // change to other state
}
break; // immediately jump down to END-OF-SWITCH
case sm_RotFwd1Rev:
myStepMotor.doSteps(-oneRevolution); // set new targetposition
myState = sm_wait1Rev;
break; // immediately jump down to END-OF-SWITCH
// wait for stepper-motor to reach target position
case sm_wait1Rev:
if ( !myStepMotor.moving() ) { // if motor HAS reached target-position
waitTimer = millis(); // store snapshot of time as time-reference for waiting
myState = sm_PausingA;
}
break; // immediately jump down to END-OF-SWITCH
// wait until pausing time is over
case sm_PausingA:
// check if 2000 milliseconds have passed by (since waitTimer = millis(); )
if ( TimePeriodIsOver(waitTimer, 2000) ) {
// if REALLY 2000 milliseconds have passed by
myStepMotor.rotate(1); // start continous rotating // opposite direction is .rotate(-1);
myState = sm_CheckForBeamBreak;
}
break; // immediately jump down to END-OF-SWITCH
case sm_CheckForBeamBreak:
if ( digitalRead(sensorPin) == pressed) {
myStepMotor.stop(); // stop continous rotation
Serial.print("Beam interrupted at step-position ");
Serial.println(myStepMotor.readSteps() );
// start rotation one rev CW
myStepMotor.doSteps(oneRevolution);
Serial.println("rotating back to step-position " );
// as the step-pulses are created in the backround
// code executes the lines below
myState = sm_WaitRotBack1Rev;
}
break; // immediately jump down to END-OF-SWITCH
case sm_WaitRotBack1Rev:
//if ( !myStepMotor.moving() ) { // if motor has reached target-position
if ( myStepMotor.distanceToGo() == 0 ) {
Serial.println(myStepMotor.readSteps() );
myState = sm_idling;
Serial.println("press button for new start" );
}
//myState = sm_idling;
break; // immediately jump down to END-OF-SWITCH
} //END-OF-SWITCH
switch (myState) {
// through the break;-statement each case is mutually exclusive
case sm_idling:
// check if button is pressed
if ( digitalRead(buttonPin2) == pressed) {
// if button is pressed
myState = sm_RotFwd1Rev; // change to other state
}
break; // immediately jump down to END-OF-SWITCH
case sm_RotFwd1Rev:
myStepMotor.doSteps(-oneRevolution); // set new targetposition
myState = sm_wait1Rev;
break; // immediately jump down to END-OF-SWITCH
// wait for stepper-motor to reach target position
case sm_wait1Rev:
if ( !myStepMotor.moving() ) { // if motor HAS reached target-position
waitTimer = millis(); // store snapshot of time as time-reference for waiting
myState = sm_PausingB;
}
break; // immediately jump down to END-OF-SWITCH
// wait until pausing time is over
case sm_PausingB:
// check if 2000 milliseconds have passed by (since waitTimer = millis(); )
if ( TimePeriodIsOver(waitTimer, 2000) ) {
// if REALLY 2000 milliseconds have passed by
myStepMotor.doSteps(oneRevolution); // set new targetposition
myState = sm_wait1Rev;
break; // immediately jump down to END-OF-SWITCH
// wait for stepper-motor to reach target position
case sm_wait1Rev:
if ( !myStepMotor.moving() ) { // if motor HAS reached target-position
waitTimer = millis(); // store snapshot of time as time-reference for waiting
myState = sm_PausingC;
}
break; // immediately jump down to END-OF-SWITCH
// wait until pausing time is over
case sm_PausingC:
// check if 1500 milliseconds have passed by (since waitTimer = millis(); )
if ( TimePeriodIsOver(waitTimer, 1500) ) {
// if REALLY 1500 milliseconds have passed by
myStepMotor.doSteps(-oneRevolution); // set new targetposition
myState = sm_wait1Rev;
break; // immediately jump down to END-OF-SWITCH
// wait for stepper-motor to reach target position
case sm_wait1Rev:
if ( !myStepMotor.moving() ) { // if motor HAS reached target-position
waitTimer = millis(); // store snapshot of time as time-reference for waiting
myState = sm_PausingA;
}
break; // immediately jump down to END-OF-SWITCH
// wait until pausing time is over
case sm_PausingA:
// check if 2000 milliseconds have passed by (since waitTimer = millis(); )
if ( TimePeriodIsOver(waitTimer, 2000) ) {
// if REALLY 2000 milliseconds have passed by
myStepMotor.rotate(1); // start continuous rotating // opposite direction is .rotate(-1);
myState = sm_CheckForBeamBreak;
}
break; // immediately jump down to END-OF-SWITCH
case sm_CheckForBeamBreak:
if ( digitalRead(sensorPin) == pressed) {
myStepMotor.stop(); // stop continuous rotation
Serial.print("Beam interrupted at step-position ");
Serial.println(myStepMotor.readSteps() );
// start rotation one rev CW
myStepMotor.doSteps(oneRevolution);
Serial.println("rotating back to step-position " );
// as the step-pulses are created in the background
// code executes the lines below
myState = sm_WaitRotBack1Rev;
}
break; // immediately jump down to END-OF-SWITCH
case sm_WaitRotBack1Rev:
//if ( !myStepMotor.moving() ) { // if motor has reached target-position
if ( myStepMotor.distanceToGo() == 0 ) {
Serial.println(myStepMotor.readSteps() );
myState = sm_idling;
Serial.println("press button for new start" );
}
//myState = sm_idling;
break; // immediately jump down to END-OF-SWITCH
} //END-OF-SWITCH
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long & startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
void printStateIfChanged(byte p_state) {
static byte lastState;
// check if value of p_state is different than last time calling the function
if (lastState != p_state) {
// if it IS different
Serial.print("state changed from ");
Serial.print(stateName[lastState]);
Serial.print(" to ");
Serial.println(stateName[p_state]);
lastState = p_state; // update lastState to new value
}
}