/*  example for controlling a bipolar steppermotor
    with 4 buttons and a potentiometer (for adjusting the speed)
    in this example three different parts of the MobaTools are used
    MotoStepper, MoToButtons, MoToTimeBase

    each of the 4 button makes the steppermotor drive to a pre-defined position
    in case the button is pressed

    a double-press (double-click) of a button 1/2 activates ENDLESS rotation
    double-click of button 1 => endless rotation forward
    double-click of button 2 => endless rotation backward
    double-click of button 3 => stop
    looong press of button 4 => initiate reference

    in this example referenceing is coded as a blocking function
    this means if referencing is active the code can do nothing else but the referencing
    until referencing has finished successfully

    The internal LED is switched on if reference-switch is active
*/


#define MAX8BUTTONS // spart Speicher, da nur 4 myButtons benötigt werden
#include <MobaTools.h>

const int STEPS_REVOLUTION = 800;
//create stepper-object ( 800 steps / revolution = 1/4 Microstep )
MoToStepper myStepper( STEPS_REVOLUTION, STEPDIR );
const byte dirPin = 5;
const byte stepPin = 6;
const byte enaPin = 7;

// create buttons ( the code expects that the buttons are wired IO-Pin---button----GND )
enum { button1, button2, button3, button4 } ; // assign the button-names the index-numbers 0,1,2,3
const byte buttonPins[] = {A1, A2, A3, A4 }; // must be defined as byte that the calculation works
const byte buttonNr = sizeof(buttonPins);
const long buttonPos[] = { 1600, 3200, 6400, 7600 };
MoToButtons myButtons( buttonPins, buttonNr, 20, 500 );

// reference / limit-switch
const byte refPin = A5;         // IO-pin for limit-switch
const byte atRefpoint = LOW;   // if limit-switch is triggered the logic level is LOW

MoToTimebase speedIntervall;      // time-interval for reading speed potentiometer

const byte potiPin = A0;        //potentiometer for speed
int vspeed = 0;                 //Stepperspeed in rev/min*10 
int oldSpeed = 0;               // nescessary for detecting speed-changes

void toRefPoint() {
  // drive stepper to reference-point then set position to 0  
  Serial.println("drive fast towards reference-point");
  // driving fast to reference ...
  if ( digitalRead( refPin ) != atRefpoint ) {
    // ... onyl in case steppermotor is not already at reference-point
    myStepper.setSpeedSteps( 20000, 100 );
    myStepper.rotate(-1);
    while ( digitalRead( refPin ) != atRefpoint );
  }
  Serial.println("limit-switch triggered STOP");
  digitalWrite( LED_BUILTIN, digitalRead( refPin ) );
  // limit-switch reached stop
  myStepper.rotate(0);
  while ( myStepper.moving() );     // wait until deccelerating has finished;

  // drive slowly without acceleration until limit-switch changes state
  myStepper.setSpeedSteps( 1000 );
  myStepper.setRampLen(0); // de-activate acceleration through value zero

  // remark myStepper.rotate( 1 ) must be called only a SINGLE time
  // the MobaTools will create a infinite train of step-pulses
  // in the background until you execute function myStepper.rotate(0) or myStepper.stop()
  Serial.println("driving away from limit-switch until limit-switch is NOT triggered anymore");
  myStepper.rotate( 1 );

  // wait for limit-switch to change state
  while ( digitalRead( refPin ) == atRefpoint );

  digitalWrite( LED_BUILTIN, digitalRead( refPin ) );
  Serial.println("limit-switch unpressed => reference reached");

  myStepper.rotate(0);

  while (myStepper.moving() );
  myStepper.setZero();
  myStepper.setSpeed( 200 );

  // re-actiavte acceleration
  myStepper.setRampLen( 100 ); // number of steps for used for acceleration 100 Steps
  oldSpeed = 0;  // set to zero to make sure value of potentiometer is used
  Serial.println("end of referencing");
}

void setup() {
  Serial.begin(115200);
  while (!Serial);
  myStepper.attach( stepPin, dirPin );
  myStepper.attachEnable( enaPin, 10, LOW ); // activate Enable Pin ( LOW=active )
  myStepper.setSpeed( 200 );
  vspeed = 200;
  myStepper.setRampLen( 100 ); // number of steps for used for acceleration 100 Steps
  speedIntervall.setBasetime( 100 );  // set timer-intervall to 100 millisecons
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(refPin, INPUT_PULLUP );
  toRefPoint();
}

void loop() {
  myButtons.processButtons(); // reading in myButtons and check for pressed / released, double-press, long-press

  digitalWrite( LED_BUILTIN, digitalRead( refPin ) );

  // read in speed from potentiometer once every 100 milliseconds
  if ( speedIntervall.tick() ) {
    // if 100 milliseconds have passed by ( see function-call  speedIntervall.setBasetime(); in setup()
    vspeed = map((analogRead(potiPin)), 0, 1023, 20, 1800);  // map values to 2 ... 180 rev/Min
    //min speed =2 and max speed =180 rpm
    if ( abs( oldSpeed - vspeed ) > 5 ) {
      myStepper.setSpeed( vspeed );
      oldSpeed = vspeed;
    }
  }

  // initiate referencing
  if ( myButtons.longPress( button4 ) ) toRefPoint();

  //
  for ( byte tastIx = 0; tastIx < buttonNr; tastIx++ ) {
    // check myButtons for Click/double-click
    byte clickTyp = myButtons.clicked(tastIx);
    if ( clickTyp == SINGLECLICK ) {
      //button single-press
      Serial.print("rotate to Pos ");
      Serial.println( buttonPos[tastIx] );
      myStepper.writeSteps(buttonPos[tastIx]);
    }
    else if ( clickTyp == DOUBLECLICK ) {
      // button double-click detected
      switch ( tastIx ) {

        case button1:
          Serial.println("double-press of button 1 rotate endless forward");
          myStepper.rotate(1);
          break;

        case button2:
          Serial.println("double-press of button 2 rotate endless backwar");
          myStepper.rotate(-1);
          break;

        case button3:
          Serial.println("double-press of button 3 STOP!");
          myStepper.rotate(0);
          break;

        default:
          break;
      }
    }
  }
}
A4988