Stepper motor control panel for linear actuators

In this video I continue one of my previous project where I made a control panel for stepper motors. The control panel utilizes the AccelStepper library and it allows the user to manually move the stepper motor to a certain position. The user can enter the number of steps in terms of absolute and relative steps or can directly move the motor using the buttons or the rotary encoder on the control panel. The control panel provides all the necessary information. It keeps track of the position, speed, acceleration…etc. The control panel has a limit switch with a proper homing-parking function implemented. The user can compile the code with predefined positions which can be reached after the homing was performed.



Schematics

The Nokia 5110 LCD uses the SPI protocol and it is very important to use it with a +3.3 V system. Otherwise, it can be damaged because these units are usually not +5 V tolerant. You can use it with +5 V if you use a so-called logic level shifter/con…

The Nokia 5110 LCD uses the SPI protocol and it is very important to use it with a +3.3 V system. Otherwise, it can be damaged because these units are usually not +5 V tolerant. You can use it with +5 V if you use a so-called logic level shifter/converter. One side of the up and down buttons are directly connected to the +3.3 V, then the other side of the button goes to the microcontroller and also to the GND through a 10k resistor. The buttons are open by default. The rotary encoder’s DT and CLK pins are connected to the +3.3 V via a 10k resistor. The DT and CLK pins are also connected to the microcontroller. Furthermore a 100 nF capacitor is connected between the GND and the DT and CLK pins. Notice that the middle pin on the encoder (GND) is connected to the ground via the black cable. The connections for the stepper motor are A9 (step) and A8 (A8). I did not add any specific stepper motor control circuit, because you can use any of the popular ones with this code and arrangement.



Source code

//The LCD-related code was based on the following library:
//https://github.com/cbm80amiga/N5110_GUI_encoder_demo_STM32

//Defining the pins for the Nokia 5110 LCD
#define N5110_RST       PA0
#define N5110_CS        PA4
#define N5110_DC        PA1
#define N5110_BACKLIGHT PA2

//Nokia pins:
//RST: PA0
//CS: PA4
//DC: PA1
//BL: PA2 (optional)
//DIN: PA7
//CLK: PA5

#include "N5110_SPI.h"
#if USESPI==1
#include <SPI.h>
#endif
N5110_SPI lcd(N5110_RST, N5110_CS, N5110_DC); // RST,CS,DC
#include "c64enh_font.h" //smaller font
#include "term9x14_font.h" //larger font
//make sure that the font files are in the same folder as the project file!

//AccelStepper
#include <AccelStepper.h>
AccelStepper stepper(1, PA9, PA8);// pulses/steps 9; Direction 8

//Defining pins
const int RotaryCLK = PB9; //CLK pin on the rotary encoder
const int RotaryDT = PB8; //DT pin on the rotary encoder
const int RotarySW = PB7; //SW pin on the rotary encoder (Button function)
const int UpButton = PB12; //Up button which is also a start button
const int DownButton = PB13; //Down button which is also a stop button
const int LimitSwitch_1 = PB11; //Input for the limit switch

//Statuses of the DT and CLK pins on the encoder
int CLKNow;
int CLKPrevious;
int DTNow;
int DTPrevious;

//Timing related variables, act mainly as debouncing
float RotaryTime1; //Rotary encoder timing
float RotaryTime2;
unsigned long previousInterrupt; //Button timing

//Menu-related variables
//Values
int RotaryButtonValue; //Pressed or not pressed rotary switch
volatile int menuCounter = 0; //this is for counting the main menu (menu item number)
volatile int stepperMaxSpeed = 400; //for setMaxSpeed
volatile int stepperSpeed = 400; //for setSpeed
volatile int stepperAcceleration = 800; //for setAcceleration
volatile int stepperAbsoluteSteps; //moveTo()
volatile int stepperRelativeSteps; //move()
volatile int stepperRotarySteps; // This keeps track of the steps done with the rotary encoder
volatile int stepperButtonSteps; // This keeps track of the steps done with the buttons
volatile int stepperGoToLocation; //Go to steps
int stepperStepsize = 1; //Step size for changing the variable. One click on the encoder will in/decrease with this amount
int stepperPosition = 0; //position of the stepper motor, measured in steps
int previousStepperPosition = 0; //This helps us to update the display

//booleans
bool stepperMaxSpeed_Selected = false; //for setMaxSpeed
bool stepperSpeed_Selected = false; //for setSpeed
bool stepperSpeedRun = false; //for "indefinite" running
bool stepperAcceleration_Selected = false; //for setAcceleration
bool stepperAbsoluteSteps_Selected = false; //moveTo()
bool stepperRelativeSteps_Selected = false; //move()
bool rotaryStepping_Selected = false; //precisely step the motor with the rotary encoder
bool buttonStepping_Selected = false; //precisely step the motor with the buttons (UpButton/DownButton)
bool stepperStepsize_Selected = false; //Step size menu
bool stepperSetZero_Selected = false; //Reset to 0 menu
bool stepperGoTo_Selected = false; //Go To function
bool stepperhoming_Selected = false; //Homing with limit switch
bool menuChanged = false; //Switched between menus
bool valueChanged = false; //changed the value of a menu item
bool updateValueSelection = false; //if we want to change the value of a variable, it becomes true

char buf[25]; //buffer for printing on the LCD

void setup()
{
  //Definition of the pins, remember where you need
  pinMode(PB9, INPUT); //CLK
  pinMode(PB8, INPUT); //DT
  pinMode(PB7, INPUT_PULLUP); //SW
  pinMode(PB12, INPUT); //UP
  pinMode(PB13, INPUT); //DOWN
  pinMode(PB11, INPUT); //LimitSwitch_1 (default is 1 for me)
  //Store states
  CLKPrevious = digitalRead(RotaryCLK);
  DTPrevious = digitalRead(RotaryDT);

  //Rotary encoder interrupts
  attachInterrupt(digitalPinToInterrupt(RotaryCLK), RotaryEncoder, CHANGE);

  //Stepper setup
  stepper.setSpeed(stepperSpeed); //SPEED = Steps / second
  stepper.setMaxSpeed(stepperMaxSpeed); //SPEED = Steps / second
  stepper.setAcceleration(stepperAcceleration); //ACCELERATION = Steps /(second)^2

  lcd.init(); //initialize LCD
  lcd.clrScr(); //clear the whole display
  printLCD(); //print the welcome message


}

void loop()
{
  if (menuChanged == true)
  {
    updateMenuPosition();
  }

  if (valueChanged == true )
  {
    updateValue();
  }

  if (updateValueSelection == true)
  {
    updateSelection();
  }

  stepper.run(); //If a step is due, this function will do a step in each loop() iteration

  //Looping buttons
  CheckRotaryButton();
  UpButtonPressed();
  DownButtonPressed();
  LimitSwitchPressed();

  //The below part takes care of the position
  stepperPosition = stepper.currentPosition();

  if (stepperPosition != previousStepperPosition)
  {
    updatePosition(); //Pos. on the bottom of the LCD
    updateValue(); //Pos or value in the middle of the screen
    previousStepperPosition = stepper.currentPosition();
    //^if the motor does not move in the next loop() iteration, the code skips this part of the code
  }
}


void RotaryEncoder()
{
  if (stepperMaxSpeed_Selected == true)
  {
    CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin
    // If last and current state of CLK are different, then a pulse occurred
    if (CLKNow != CLKPrevious  && CLKNow == 1)
    {
      // If the DT state is different than the CLK state then
      // the encoder is rotating in A direction, so we increase
      if (digitalRead(RotaryDT) != CLKNow)
      {
        stepperMaxSpeed = stepperMaxSpeed + stepperStepsize; //1 step size increment
      }
      else
      {
        if (stepperMaxSpeed < 2)
        {
          //Don't decrease further, it should be at least 1
        }
        else
        {
          stepperMaxSpeed = stepperMaxSpeed - stepperStepsize;  //1 step size decrement
        }
      }
      valueChanged = true;
    }
    CLKPrevious = CLKNow;  // Store last CLK state
  }
  //Stepper acceleration
  else if (stepperAcceleration_Selected == true)
  {
    CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin
    // If last and current state of CLK are different, then a pulse occurred
    if (CLKNow != CLKPrevious  && CLKNow == 1)
    {
      // If the DT state is different than the CLK state then
      // the encoder is rotating in A direction, so we increase
      if (digitalRead(RotaryDT) != CLKNow)
      {
        stepperAcceleration = stepperAcceleration + stepperStepsize; //1 step size increment
      }
      else
      {
        stepperAcceleration = stepperAcceleration - stepperStepsize;     //1 step size decrement
      }
      valueChanged = true;
    }
    CLKPrevious = CLKNow;  // Store last CLK state
  }
  //Absolute rotation
  else if (stepperAbsoluteSteps_Selected == true)
  {
    CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin
    // If last and current state of CLK are different, then a pulse occurred
    if (CLKNow != CLKPrevious  && CLKNow == 1)
    {
      // If the DT state is different than the CLK state then
      // the encoder is rotating in A direction, so we increase
      if (digitalRead(RotaryDT) != CLKNow)
      {
        stepperAbsoluteSteps = stepperAbsoluteSteps + stepperStepsize; //1 step size increment
      }
      else
      {
        stepperAbsoluteSteps = stepperAbsoluteSteps - stepperStepsize;  //1 step size decrement
      }
      valueChanged = true;
    }
    CLKPrevious = CLKNow;  // Store last CLK state
  }
  //Relative rotation
  else if (stepperRelativeSteps_Selected == true)
  {
    CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin
    // If last and current state of CLK are different, then a pulse occurred
    if (CLKNow != CLKPrevious  && CLKNow == 1)
    {
      // If the DT state is different than the CLK state then
      // the encoder is rotating in A direction, so we increase
      if (digitalRead(RotaryDT) != CLKNow)
      {
        stepperRelativeSteps = stepperRelativeSteps + stepperStepsize; //1 step size increment
      }
      else
      {
        stepperRelativeSteps = stepperRelativeSteps - stepperStepsize; //1 step size decrement
      }
      valueChanged = true;
    }
    CLKPrevious = CLKNow;  // Store last CLK state
  }
  //Rotary movement
  else if (rotaryStepping_Selected == true)
  {
    CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin
    // If last and current state of CLK are different, then a pulse occurred
    if (CLKNow != CLKPrevious  && CLKNow == 1)
    {
      // If the DT state is different than the CLK state then
      // the encoder is rotating in A direction, so we increase
      if (digitalRead(RotaryDT) != CLKNow)
      {
        stepperRotarySteps = stepper.currentPosition() + stepperStepsize; //1 step size increment relative to the current position
      }
      else
      {
        stepperRotarySteps = stepper.currentPosition() - stepperStepsize; //1 step size decrement relative to the current position
      }
      valueChanged = true;
    }
    CLKPrevious = CLKNow;  // Store last CLK state
    stepper.moveTo(stepperRotarySteps);
  }
  else if (buttonStepping_Selected == true)
  {
    //do nothing
  }
  //Stepper step size
  else if (stepperStepsize_Selected == true)
  {
    CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin
    // If last and current state of CLK are different, then a pulse occurred
    if (CLKNow != CLKPrevious  && CLKNow == 1)
    {
      // If the DT state is different than the CLK state then
      // the encoder is rotating in A direction, so we increase
      if (digitalRead(RotaryDT) != CLKNow)
      {
        stepperStepsize++; //1 step increment of the step size
      }
      else
      {
        if (stepperStepsize < 2)
        {
          //If it goes below 2 (=1), it won't be decreased anymore further
        }
        else
        {
          stepperStepsize--;    //1 step decrement of the step size
        }
      }
    }
    CLKPrevious = CLKNow;  // Store last CLK state
    valueChanged = true;
  }
  //-------------------------------------------------------------------------------
  //GOTO
  else if (stepperGoTo_Selected == true)
  {
    CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin
    // If last and current state of CLK are different, then a pulse occurred
    if (CLKNow != CLKPrevious && CLKNow == 1)
    {
      // If the DT state is different than the CLK state then
      // the encoder is rotating in A direction, so we increase

      if (digitalRead(RotaryDT) != CLKNow)
      {
        if (stepperGoToLocation < 4) //5 menu items (0, 1, 2....4)
        {
          stepperGoToLocation++;
        }
        else
        {
          stepperGoToLocation = 0; //0 comes after 4, so we move in a "ring"
        }
      }
      else
      {
        // Encoder is rotating CW so decrease
        if (stepperGoToLocation > 0)
        {
          stepperGoToLocation--;
        }
        else
        {
          stepperGoToLocation = 4; //4 comes after 0 when we decrease the numbers
        }
      }
      valueChanged = true;
    }
    CLKPrevious = CLKNow;  // Store last CLK state
  }
  //-------------------------------------------------------------------------------
  //Homing
  else if (stepperhoming_Selected == true)
  {
    //do nothing
  }
  //Set new zeropoint
  else if ( stepperSetZero_Selected == true)
  {
    //do nothing
  }
  else //MENU COUNTER----------------------------------------------------------------------------
  {
    CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin
    // If last and current state of CLK are different, then a pulse occurred
    if (CLKNow != CLKPrevious  && CLKNow == 1)
    {
      // If the DT state is different than the CLK state then
      // the encoder is rotating CCW so increase
      if (digitalRead(RotaryDT) != CLKNow)
      {
        if (menuCounter < 9) //10 menu items (0, 1, 2....9)
        {
          menuCounter++;
        }
        else
        {
          menuCounter = 0; //0 comes after 9, so we move in a "ring"
        }
        menuChanged = true;

      }
      else
      {
        // Encoder is rotating CW so decrease
        if (menuCounter > 0)
        {
          menuCounter--;
        }
        else
        {
          menuCounter = 9; //9 comes after 0 when we decrease the numbers
        }
        menuChanged = true;
      }
    }
    CLKPrevious = CLKNow;  // Store last CLK state
  }
}

void printLCD() //Prints a "welcome screen"
{
  lcd.setFont(c64enh);
  lcd.printStr(ALIGN_CENTER, 0, "Stepper");
  lcd.printStr(ALIGN_CENTER, 1, "Controller");
  lcd.printStr(ALIGN_CENTER, 3, "Rotate the");
  lcd.printStr(ALIGN_CENTER, 4, "encoder");
  lcd.printStr(ALIGN_CENTER, 5, "to continue...");
}

void CheckRotaryButton()
{
  RotaryButtonValue = digitalRead(RotarySW); //read the button state

  if (RotaryButtonValue == 0) //0 and 1 can differ based on the wiring
  {
    RotaryTime1 = millis();
    if (RotaryTime1 - RotaryTime2 > 1000)
    {
      switch (menuCounter)
      {
        case 0:
          stepperMaxSpeed_Selected = !stepperMaxSpeed_Selected;  //we change the status of the variable to the opposite
          if (stepperMaxSpeed_Selected == false)//exiting
          {
            stepper.stop(); //stop upon exiting the menu
          }
          updateValueSelection = true;
          break;
        //
        case 1:
          stepperAcceleration_Selected = !stepperAcceleration_Selected;
          updateValueSelection = true;
          break;
        //
        case 2:
          stepperAbsoluteSteps_Selected = !stepperAbsoluteSteps_Selected;
          if (stepperAbsoluteSteps_Selected == false)//exiting
          {
            stepper.stop(); //stop upon exiting the menu
          }
          updateValueSelection = true;
          break;
        //
        case 3:
          stepperRelativeSteps_Selected = !stepperRelativeSteps_Selected;
          if (stepperRelativeSteps_Selected == false)//exiting
          {
            stepper.stop(); //stop upon exiting the menu
          }
          updateValueSelection = true;
          break;
        //
        case 4:
          rotaryStepping_Selected = !rotaryStepping_Selected;
          updateValueSelection = true;
          valueChanged = true;
          break;
        //
        case 5:
          buttonStepping_Selected = !buttonStepping_Selected;
          updateValueSelection = true;
          valueChanged = true;
          break;
        //
        case 6:
          stepperStepsize_Selected = !stepperStepsize_Selected;
          updateValueSelection = true;
          break;
        //
        case 7:
          stepperhoming_Selected = !stepperhoming_Selected;
          updateValueSelection = true;
          break;
        //
        case 8:
          stepperGoTo_Selected = !stepperGoTo_Selected;
          updateValueSelection = true;
          break;
        //
        case 9:
          stepperSetZero_Selected = true; //this always has to be set to true and we set it to false somewhere else
          updateValueSelection = true;
          break;
      }
      RotaryTime2 = millis();
      menuChanged = true; //Refresh LCD after changing the value of the menu
    }
  }
}

void updateMenuPosition()
{
  lcd.clrScr();//delete the entire screen

  switch (menuCounter) //this checks the value of the counter (0, 1, 2 or 3)
  {
    //MAX SPEED
    case 0:
      lcd.setFont(c64enh); //set the font (small one)
      lcd.printStr(ALIGN_CENTER, 0, "            "); //erase previous text
      lcd.printStr(ALIGN_CENTER, 0, "Max speed"); //print new text
      lcd.setFont(Term9x14); //Set another (larger) font
      snprintf(buf, 8, "%d", stepperMaxSpeed); //the decimal value of the variable is in the buf
      lcd.printStr(10, 2, buf); //set the cursor to 2nd line 10th pixel and print the buffer
      break;
    //-------------------------------
    //ACCELERATION
    case 1:
      lcd.setFont(c64enh);
      lcd.printStr(ALIGN_CENTER, 0, "            ");
      lcd.printStr(ALIGN_CENTER, 0, "Acceleration");
      lcd.setFont(Term9x14);
      snprintf(buf, 8, "%d", stepperAcceleration);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //ABSOLUTE STEPPING
    case 2:
      lcd.setFont(c64enh);
      lcd.printStr(ALIGN_CENTER, 0, "            ");
      lcd.printStr(ALIGN_CENTER, 0, "Absolute");
      lcd.setFont(Term9x14);
      snprintf(buf, 8, "%d", stepperAbsoluteSteps);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //RELATIVE STEPS
    case 3:
      lcd.setFont(c64enh);
      lcd.printStr(ALIGN_CENTER, 0, "            ");
      lcd.printStr(ALIGN_CENTER, 0, "Relative");
      lcd.setFont(Term9x14);
      snprintf(buf, 8, "%d", stepperRelativeSteps);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //MOVEMENT WITH ROTARY ENCODER
    case 4:
      lcd.setFont(c64enh);
      lcd.printStr(ALIGN_CENTER, 0, "            ");
      lcd.printStr(ALIGN_CENTER, 0, "Rotary-move");
      lcd.setFont(Term9x14);
      snprintf(buf, 8, "%d", stepperRotarySteps);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //MOVEMENT WITH BUTTONS
    case 5:
      lcd.setFont(c64enh);
      lcd.printStr(ALIGN_CENTER, 0, "            ");
      lcd.printStr(ALIGN_CENTER, 0, "Button-move");
      lcd.setFont(Term9x14);
      snprintf(buf, 8, "%d", stepperRelativeSteps);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //STEPSIZE
    case 6:
      lcd.setFont(c64enh);
      lcd.printStr(ALIGN_CENTER, 0, "            ");
      lcd.printStr(ALIGN_CENTER, 0, "Step size");
      lcd.setFont(Term9x14);
      snprintf(buf, 8, "%d", stepperStepsize);
      lcd.printStr(10, 2, buf);
      break;//-------------------------------
    //HOMING
    case 7:
      lcd.setFont(c64enh);
      lcd.printStr(ALIGN_CENTER, 0, "            ");
      lcd.printStr(ALIGN_CENTER, 0, "Homing");
      lcd.setFont(Term9x14);
      snprintf(buf, 8, "%d", stepper.currentPosition());
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //GOTO
    case 8:
      lcd.setFont(c64enh);
      lcd.printStr(ALIGN_CENTER, 0, "            ");
      lcd.printStr(ALIGN_CENTER, 0, "Go To...");
      lcd.setFont(Term9x14);
      snprintf(buf, 8, "%d", stepperGoToLocation);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //RESET
    case 9:
      lcd.setFont(c64enh);
      lcd.printStr(ALIGN_CENTER, 0, "            ");
      lcd.printStr(ALIGN_CENTER, 0, "Set zero");
      break;
  }
  //"Global" value
  lcd.setFont(c64enh);
  snprintf(buf, 8, "%s", "Pos: ");
  lcd.printStr(0, 5, buf);
  snprintf(buf, 8, "%d", stepperPosition);
  lcd.printStr(30, 5, buf);
  //
  menuChanged = false; //next loop() iteration will not enter again
}

void updateValue()
{
  switch (menuCounter) //this checks the value of the counter (0, 1, 2 or 3)
  {
    //Max speed menu
    case 0:
      stepper.setMaxSpeed(stepperMaxSpeed);
      lcd.setFont(Term9x14);
      lcd.printStr(10, 2, "        ");
      snprintf(buf, 8, "%d", stepperMaxSpeed);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //Acceleration menu
    case 1:
      stepper.setAcceleration(stepperAcceleration);
      lcd.setFont(Term9x14);
      lcd.printStr(10, 2, "        ");
      snprintf(buf, 8, "%d", stepperAcceleration);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //Absolute movement - moveTo()
    case 2:
      lcd.setFont(Term9x14);
      lcd.printStr(10, 2, "        ");
      snprintf(buf, 8, "%d", stepperAbsoluteSteps);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //Relative movement - move()
    case 3:
      lcd.setFont(Term9x14);
      //Command values
      lcd.printStr(10, 2, "        "); //block 8 in line 2
      snprintf(buf, 8, "%d", stepperRelativeSteps);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //Rotary encode movement - step by step
    case 4:
      lcd.setFont(Term9x14);
      lcd.printStr(10, 2, "        ");
      snprintf(buf, 8, "%d", stepperPosition); //location
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //Button movement - step by step
    case 5:
      lcd.setFont(Term9x14);
      lcd.printStr(10, 2, "        ");
      snprintf(buf, 8, "%d", stepperPosition); //location
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //Step size menu - increment-decrement
    case 6:
      lcd.setFont(Term9x14);
      lcd.printStr(10, 2, "        ");
      snprintf(buf, 8, "%d", stepperStepsize);
      lcd.printStr(10, 2, buf);
      break;
    //-------------------------------
    //GoTo menu - increment-decrement location ID
    case 8:
      lcd.setFont(Term9x14);
      lcd.printStr(10, 2, "        ");
      snprintf(buf, 8, "%d", stepperGoToLocation);
      lcd.printStr(10, 2, buf);
      break;
      //-------------------------------
  }
  //"Global" values
  //this is always shown on the bottom of the display
  lcd.setFont(c64enh);
  lcd.printStr(30, 5, "        ");
  snprintf(buf, 8, "%d", stepperPosition);
  lcd.printStr(30, 5, buf);
  //
  valueChanged = false; //next loop() iteration will not enter again
}

void updatePosition()
{
  lcd.setFont(c64enh);
  lcd.printStr(30, 5, "        ");
  snprintf(buf, 8, "%d", stepperPosition);
  lcd.printStr(30, 5, buf);
}

void updateSelection()
{

  lcd.setFont(Term9x14); //Large font size for the cursor (same as of the values)

  if (stepperMaxSpeed_Selected == true)
  {
    snprintf(buf, 8, "%s", ">"); //print the ">" as the cursor, the ">" indicates the selection/activation
    lcd.printStr(0, 2, buf); //put it on the display: 2nd line 0 pixel
  }
  else if (stepperAcceleration_Selected == true)
  {
    snprintf(buf, 8, "%s", ">");
    lcd.printStr(0, 2, buf);
  }
  else if (stepperAbsoluteSteps_Selected == true)
  {
    snprintf(buf, 8, "%s", ">");
    lcd.printStr(0, 2, buf);
  }
  else if (stepperRelativeSteps_Selected == true)
  {
    snprintf(buf, 8, "%s", ">");
    lcd.printStr(0, 2, buf);
  }
  else if (rotaryStepping_Selected == true)
  {
    snprintf(buf, 8, "%s", ">");
    lcd.printStr(0, 2, buf);
  }
  else if (buttonStepping_Selected == true)
  {
    snprintf(buf, 8, "%s", ">");
    lcd.printStr(0, 2, buf);
  }
  else if (stepperStepsize_Selected == true)
  {
    snprintf(buf, 8, "%s", ">");
    lcd.printStr(0, 2, buf);
  }
  else if (stepperhoming_Selected == true)
  {
    snprintf(buf, 8, "%s", "Homing");
    lcd.printStr(0, 2, buf);
  }
  else if (stepperGoTo_Selected == true)
  {
    snprintf(buf, 8, "%s", ">");
    lcd.printStr(0, 2, buf);
  }
  else if (stepperSetZero_Selected == true)
  {
    snprintf(buf, 8, "%s", "Reset!"); //we indicate that the position was reset to 0 by printing a message
    lcd.printStr(0, 2, buf);
    stepper.setCurrentPosition(0); //set the current position to zero
    stepperSetZero_Selected = false; //we reset this here
  }
  else
  {
    snprintf(buf, 8, "%s", " ");
    lcd.printStr(0, 2, buf);
  }
  updateValueSelection = false; //next loop() iteration will not enter
}

void UpButtonPressed()
{
  if (digitalRead(UpButton) == 1) //1 or 0, depends on your wiring also!
  {
    if (millis() - previousInterrupt > 300) //debounce, sort of. If another click comes within 300 ms, we don't care about it
    {
      if (stepperMaxSpeed_Selected == true) //runSpeed()
      {
        //Runs the motor "indefinitely", until it stopped by the user
        stepper.move(999999999); //some really large value, for demonstration
      }

      else if (stepperRelativeSteps_Selected == true) //move()
      {
        stepper.move(stepperRelativeSteps);   //start relative stepping
      }

      else if (stepperAbsoluteSteps_Selected == true) //moveTo()
      {
        stepper.moveTo(stepperAbsoluteSteps); //start absolute stepping
      }

      else if (stepperhoming_Selected == true)
      {
        //homing part - negative direction
        while (digitalRead(LimitSwitch_1) == 1) //0 or 1, depends on the wiring!
        {
          stepper.setSpeed(-400);
          stepper.runSpeed();
        }

        //parking part - positive direction
        while (digitalRead(LimitSwitch_1) == 0) //0 or 1, depends on the wiring!
        {
          stepper.setSpeed(200);
          stepper.runSpeed();
        }

        stepper.setCurrentPosition(0); //reset the position to 0
      }

      else if (stepperGoTo_Selected == true)
      {
        //List of programatically predefined positions
        //The positions are always measured from the limit switch-defined home position
        switch (stepperGoToLocation)
        {
          case 0:
            stepper.moveTo(4300); //~ 4.3 cm from home
            break;
          case 1:
            stepper.moveTo(7500); //~ 7.5 cm from home
            break;
          case 2:
            stepper.moveTo(15400); //~ 15.4 cm from home
            break;
          case 3:
            stepper.moveTo(22300); //~ 22.3 cm from home
            break;
          case 4:
            stepper.moveTo(25400); //~ 25.4 cm from home
            break;

          default:
            //
            break;
        }
        //Note: with the ball-screw+linear rail, 1 turn results in 4 mm linear displacement
        //1 turn = 400 steps (with my MS setting), so 1 mm = 100 steps.
      }

      previousInterrupt = millis(); //update the value so the counting from 300 ms is started over from 0
    }
    else if (buttonStepping_Selected == true)
    {
      //buttonstepping does not care about the 300 ms time limit
      //a little more explanation in the DownButtonPressed() function
      stepperButtonSteps = stepper.currentPosition() + stepperStepsize; //increase the target position by 1 stepsize
      stepper.moveTo(stepperButtonSteps);
    }
    valueChanged = true; //display has to be updated
  }
}

void DownButtonPressed()
{
  if (digitalRead(DownButton) == 1) //1 or 0, depends on your wiring also!
  {
    if (millis() - previousInterrupt > 300)
    {
      if (stepperMaxSpeed_Selected == true) //runSpeed()
      {
        stepper.stop(); //stop and note down the position (next line)
        stepperPosition = stepper.currentPosition();
      }

      else if (stepperRelativeSteps_Selected == true) //move()
      {
        stepper.stop();
        stepperPosition = stepper.currentPosition();
      }

      else if (stepperAbsoluteSteps_Selected == true) //moveTo()
      {
        stepper.stop();
        stepperPosition = stepper.currentPosition();
      }

      else if (stepperhoming_Selected == true) //Homing (interrupted)
      {
        stepper.stop();
        stepperPosition = stepper.currentPosition();
      }

      else if (stepperGoTo_Selected == true)
      {
        stepper.stop();
        stepperPosition = stepper.currentPosition();
      }

      previousInterrupt = millis(); //update the value so the counting from 300 ms is started over from 0

    }
    else if (buttonStepping_Selected == true)
    {
      //Optionally, this part should also be in a timing part, but then the time between two steps is limited.
      //On the other hand, that can be good if you just want one step per buttonclick
      //Otherwise, pressing the button continuously will still move the motor slowly, but even 1 click will cause several steps

      //We always want to move 1 stepsize away from the current position
      stepperButtonSteps = stepper.currentPosition() - stepperStepsize; //decrease the target position by 1 stepsize
      stepper.moveTo(stepperButtonSteps);
    }
    valueChanged = true; //display has to be updated
  }
}

void LimitSwitchPressed()
{
  if (digitalRead(LimitSwitch_1) == 0) //0 or 1, depends on the wiring!
  {
    if (millis() - previousInterrupt > 300)
    {
      stepper.stop(); //"soft" stop - decelerates to 0.
      previousInterrupt = millis();
      //Alternatively we can make it to go to a specific place:
      //stepper.moveTo(0); //This goes back to absolute 0, which is technically the homing
    }

    while (digitalRead(LimitSwitch_1) == 1) //0 or 1, depends on the wiring!
    {
      stepper.setSpeed(200);
      stepper.runSpeed();
    }

    stepper.setCurrentPosition(0); //Set the new position to zero
  }
}
Previous
Previous

TCA9548A i2C multiplexer

Next
Next

“Debunking” Peltier-based air conditioning