Stepper motor control with buttons and rotary encoder
In this video I show you how to control your stepper motor using 2 buttons (direction control) and a rotary encoder (speed control). The code is relatively short and simple. I used the AccelStepper library as usual.
Arduino source code
#include <AccelStepper.h> //AccelStepper library AccelStepper stepper(1, 9, 8);// pulses Digital 9 (CLK); Direction Digital 8 (CCW) //16x2 LCD #include <LiquidCrystal_I2C.h> //SDA = A4, SCL = A5 LiquidCrystal_I2C lcd(0x27, 16, 2); //Defining pins const int RotaryCLK = 2; //CLK pin on the rotary encoder const int RotaryDT = 3; //DT pin on the rotary encoder const int ButtonCW = 4; //Button for clockwise rotation const int ButtonCCW = 5; //Button for counterclockwise rotation //Defining variables int RotateCounter = 0; //initial position int MotorSpeed = 50; //some default value for steps/s //Statuses int CLKNow; int CLKPrevious; int DTNow; int DTPrevious; // Time float TimeNow1; float TimeNow2; void setup() { Serial.begin(9600); //------------------------------------------------------ lcd.init(); // initialize the lcd lcd.init(); lcd.backlight(); //------------------------------------------------------ lcd.setCursor(0,0); //Defining positon to write from first row,first column . lcd.print("Button stepping with"); lcd.setCursor(0,1); lcd.print("AccelStepper()"); //You can write 16 Characters per line . delay(1000); //wait 1 sec //------------------------------------------------------ pinMode(2, INPUT_PULLUP); //we use the internal pullup resistor pinMode(3, INPUT_PULLUP); pinMode(4, INPUT); //CW button pinMode(5, INPUT); //CCW button //Store states CLKPrevious = digitalRead(RotaryCLK); DTPrevious = digitalRead(RotaryDT); attachInterrupt(digitalPinToInterrupt(RotaryCLK), rotate, CHANGE); stepper.setMaxSpeed(1000); //SPEED = Steps / second stepper.setAcceleration(5000); //ACCELERATION = Steps /(second)^2 printLCD(); //Print the things on the LCD TimeNow1 = millis(); //Start time } void loop() { //The motor only runs when one of the buttons are kept pressed CheckButtons(); //Checking the status of the buttons RunTheMotor(); //Running the motor TimeNow2 = millis(); if(TimeNow2 - TimeNow1 > 200) //if the time difference is more than 200 ms (increase the number to print to the LCD less often) { updateLCD(); //Printing LCD (This slows down the stepping significantly, so use it less frequently) TimeNow1 = millis(); } } void updateLCD() { //this function only updates the necessary parts lcd.setCursor(7,0); lcd.print(" "); //first we clear the area with spaces (it is important when you show a 3-digit number after a 4-digit number) lcd.setCursor(7,0); lcd.print(MotorSpeed); //Print the speed lcd.setCursor(10,1); lcd.print(" "); lcd.setCursor(10,1); lcd.print(stepper.currentPosition()); //Print the number of steps done from the origin (i.e. the position) } void printLCD() { lcd.setCursor(0,0); // Defining position to write from first row, first column . lcd.print("Speed: "); lcd.setCursor(8,0); lcd.print(" "); lcd.setCursor(8,0); lcd.print(MotorSpeed); //Print the speed lcd.setCursor(0,1); // Defining position to write from second row, first column . lcd.print("Position: "); lcd.setCursor(10,1); lcd.print(" "); lcd.setCursor(10,1); lcd.print(stepper.currentPosition()); //Print the number of pulses } void RunTheMotor() //function for the motor { stepper.enableOutputs(); //enable pins stepper.moveTo(RotateCounter); //tell the stepper to move to the 'RotateCounter'steps (absolute) position while(stepper.distanceToGo() != 0) { stepper.setSpeed(MotorSpeed); stepper.runSpeedToPosition(); //Serial.print("DistanceToGo: "); //for debugging //Serial.println(stepper.distanceToGo()); } //Serial.println(MotorSpeed); //for debugging } void CheckButtons() { //Serial.println(digitalRead(ButtonCW)); //Just for debugging if(digitalRead(ButtonCW) == HIGH) //if the button is pressed { RotateCounter++; //increase the value of the variable, this represents the absolute position of the stepper // Serial.print("ButtonCW: "); //for debugging // Serial.println(stepper.distanceToGo()); //you can add delay here which is also a type of debouncing. It is useful when you want to click the button //once and increase the steps (value of RotateCounter) only by one. //delay(100); //Simplest thing to be able to use this function to add just 1 step at a time to use delay } //Serial.println(digitalRead(ButtonCCW)); //Just for debugging if(digitalRead(ButtonCCW) == HIGH) { RotateCounter--; //decrease the value of the variable, this represents the absolute position of the stepper //Serial.print("ButtonCCW: "); //for debugging // Serial.println(stepper.distanceToGo()); //delay(100); } } void rotate() { 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) { MotorSpeed++; } else { // Encoder is rotating CW so decrease MotorSpeed--; } stepper.setSpeed(MotorSpeed); //as this functions is not started from the loop() it is maybe good to update the speed here } CLKPrevious = CLKNow; // Store last CLK state }