I have a stepper motor (28BYJ-48) that I want to control using a rotary switch (KY-04 Rotary Encoder Module). When the rotary switch is turned, the motor should take one step in the corresponding direction. Additionally, there is a button that, when pressed, should make the motor rotate 180°. The stepper motor is connected to an Arduino Nano ESP32 via a motor shield (ZC-A0591).
I managed to get the motor to rotate in one direction based on the rotary switch. However, it does not rotate in the other direction. The button is also not being properly registered, despite debouncing.
Here is the code I`ve been using:
#include "Stepper.h"
//Encoder Variables
const int CLK = 8;
const int DT = 9;
int Pos = 0;
int LastPos;
int NewPos;
boolean Dir;
//Motor Variables
const int StepsPerRev = 2048;
const int HalfRev = 1024;
Stepper Motor = Stepper(StepsPerRev, 4, 5, 6, 7);
int x = 5;
//Taster Variables
const int button = 2;
const int debounceDelay = 50;
unsigned long lastDebounceTime = 0;
bool lastButtonState = HIGH;
void setup()
{
pinMode (CLK, INPUT);
pinMode (DT, INPUT);
LastPos = digitalRead(CLK);
Motor.setSpeed(5);
pinMode (button, INPUT);
Serial.begin(9600);
}
void loop()
{
Encoder();
ButtonPress();
}
void Encoder()
{
NewPos = digitalRead(CLK);
if(NewPos != LastPos)
{
if(digitalRead(DT) != NewPos)
{
Pos ++;
Dir = true;
} else
{
Dir = false;
Pos --;
}
Movement();
delay(5);
Serial.println(Pos);
}
LastPos = NewPos;
}
void Movement()
{
if(Dir == true)
{
Serial.println("CW");
Motor.step(-x);
delay(5);
} else if (Dir == false)
{
Serial.println("CCW");
Motor.step(x);
delay(5);
}
}
void ButtonPress()
{
int reading = digitalRead(button);
if (reading != lastButtonState) {
lastDebounceTime = millis();
Serial.println("Debounce");
}
if ((millis() - lastDebounceTime) > debounceDelay)
{
Serial.println("In");
if (reading == LOW && ButtonState == false)
{
Serial.println("HalfRev");
Motor.step(HalfRev);
ButtonState = true;
} else if (reading == HIGH && ButtonState == true)
{
ButtonState = false;
Serial.println("Stop");
}
}
}
So far, I have:
Verified the wiring.
Implemented debouncing for the button.
Switched out the motor.
When turning the rotary encoder in the opposite direction, the motor makes noise and takes one step in the correct direction but immediately steps back. It seems as if the motor is trying to turn in both directions at the same time.
Pressing the button has no effect at all.
Does anyone have tips on what else I can try or spot anything obvious that I might have overlooked?
My recommendation would be to use libraries to make your job easy.
Here is what it could look like (the button is the one embedded in the rotary encoder)
In this version I'm using the accelStepper library and a driver, but you could configure the accelStepper instance to suit your needs.
click to see the code
/* ============================================
code is placed under the MIT license
Copyright (c) 2024 J-M-L
For the Arduino Forum : https://forum.arduino.cc/u/j-m-l
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/
#include <Encoder.h> // https://www.arduinolibraries.info/libraries/encoder$0
#include <Toggle.h> // https://www.arduinolibraries.info/libraries/toggle$0
#include <AccelStepper.h> // https://www.arduinolibraries.info/libraries/accel-stepper$0
const byte encoderCLKPin = 2;
const byte encoderDTPin = 3;
const byte encoderSWPin = 4;
const byte dirPin = 8;
const byte stepPin = 9;
const float maxSpeed = 400;
const float acceleration = 25;
const long stepsPerFullRotation = 200;
long targetPosition;
Encoder encoder(encoderDTPin, encoderCLKPin);
Toggle encoderSwitch;
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);
bool encoderChanged() {
long newPosition = encoder.read() >> 2; // divide by 4 as the rotary sends 4 ticks per click
if (newPosition != targetPosition) {
targetPosition = newPosition;
return true;
}
return false;
}
void testSwitch() {
encoderSwitch.poll();
if (encoderSwitch.onPress()) encoder.write(encoder.read() + (stepsPerFullRotation << 2));
}
void testEncoder() {
if (encoderChanged()) stepper.moveTo(targetPosition);
}
void setup() {
encoderSwitch.begin(encoderSWPin);
stepper.setMaxSpeed(maxSpeed);
stepper.setAcceleration(acceleration);
}
void loop() {
testEncoder();
testSwitch();
stepper.run();
}