I am trying to adpat a sketch written for a unipolar stepper to one to control a bipolar stepper motor. I am using an Arduino Uno, an easy driver motor controler and a NEMA 17 stepper motor. The sketch I am using will successfully execute the find zero routine but does not execute to rotate CW or CCW routine nor print out the step value as called for in the void loop. The cod is as follows.
\\Model Railroad Turntable Control
\\ Finding zero/homing position and printing out steps.
\\ Sketch adapted for a bipolar stepper motor.
#define ENABLE_PIN A0 // LOW = driver enabled
#define M1_PIN A1 // M1 microstepping mode
#define M2_PIN A2 // M2 microstepping mode
#define DIR_PIN A3 // to DIR pin of the driver
#define STEP_PIN A4 // to STP pin of driver
#define POTM_PIN A5 // stepper speed control
#define ENABLE_LED_PIN 4 // stepper running LED
#define DIR_LED_PIN 5 // stepper direction LED
#define DIR_CW_PIN 6 // CW stepper direction control
#define DIR_CCW_PIN 7 // CCW stepper direction control
#define ZERO_PIN 9 // Start the zero find routine
#define ZERO_FOUND_PIN 10 // Switch or sensor of zero position
#define PULSES_PER_REV 200 // Pulses per revolution of blue/metal toy motor
byte dir, current_pos, new_pos, rpm, rpm_old;
unsigned long pos, pos_old, timeoflaststep;
void motor_enable() {
digitalWrite(ENABLE_PIN, LOW); // LOW = driver enabled
digitalWrite(ENABLE_LED_PIN, HIGH);
digitalWrite(DIR_PIN, dir);
}
void motor_idle() {
digitalWrite(ENABLE_PIN, HIGH); // HIGH = driver disabled
digitalWrite(ENABLE_LED_PIN, LOW);
}
void find_zero() {
Serial.println("Finding zero sensor");
dir = 0;
motor_enable();
while (digitalRead(ZERO_FOUND_PIN) == HIGH) {
if ((micros() - timeoflaststep) > stepinterval()) {
timeoflaststep = micros();
digitalWrite(STEP_PIN, HIGH);
// delayMicroseconds(10); // only needed if step pulse is too short to be detected
digitalWrite(STEP_PIN, LOW);
}
}
motor_idle();
Serial.println("Zero sensor found");
Serial.println();
current_pos = 0;
new_pos = 1;
}
unsigned long stepinterval() { // calculates step timing based on potmeter input
rpm = map(analogRead(POTM_PIN), 0, 1024, 1, 21) * 10; // max 200 rpm, else pulses get lost
if (rpm != rpm_old) {
Serial.print("RPM: ");
Serial.println(rpm);
rpm_old = rpm;
}
return 60000000UL / PULSES_PER_REV / rpm;
}
void rotate() {
if ((micros() - timeoflaststep) > stepinterval()) {
timeoflaststep = micros();
digitalWrite(STEP_PIN, HIGH);
// delayMicroseconds(10); // only needed if step pulse is too short to be detected
digitalWrite(STEP_PIN, LOW);
}
}
void setup() {
pinMode(ZERO_PIN, INPUT_PULLUP);
pinMode(ZERO_FOUND_PIN, INPUT_PULLUP);
pinMode(DIR_CW_PIN, INPUT_PULLUP);
pinMode(DIR_CCW_PIN, INPUT_PULLUP);
pinMode(M1_PIN, OUTPUT);
pinMode(M2_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
pinMode(ENABLE_PIN, OUTPUT);
pinMode(ENABLE_LED_PIN, OUTPUT);
pinMode(DIR_LED_PIN, OUTPUT);
digitalWrite(M1_PIN, LOW); // set M1,M2 to 0,0 for no microstepping
digitalWrite(M2_PIN, LOW);
Serial.begin(9600);
Serial.println("Don't forget to find zero before tuning");
Serial.println();
}
void loop() {
stepinterval(); // read speed and show RPM on serial monitor
if (digitalRead(ZERO_PIN) == 0) find_zero();
while (!digitalRead(DIR_CW_PIN)) {
dir = 1;
rotate();
}
while (!digitalRead(DIR_CCW_PIN)) {
dir = 0;
rotate();
}
if (pos != pos_old) {
Serial.println(pos);
pos_old = pos;
}
}
Any help with this problem will be greatly appreciated . Ted
don''t understand what this code is attempting to do
shouldn't find_zero() be executed once in setup ()
why should there be loops for both CW and CCW?
don't understant the purpose the the if (pos != pos_old) since it just make the 2 variables equal
where are the input that determine what position to turn the turntable to by stepping the turntable either CW or CCW the appropriate # of steps to reach a desired position?
Oops.
The motor is only ever enabled bay a call to motor_enable() in find_zero(), and that finishes with a motor_idle() to disable the motor, so I'd say your code is doing what it's expected to do... nothing.
I have made changes to the sketch I posted originally. The command for CW and CCW rotation now includes a digital write statement changing the value of the dir pin input. The problem now is that after finding zero I can not rotate CW or CCW when pressing the appropriate button. the code is as follows :
void loop() {
motor_idle();
stepinterval(); // read speed and show RPM on serial monitor
if(digitalRead(ZERO_PIN) == 0) find_zero();
while(!digitalRead(DIR_CW_PIN)){
digitalWrite(DIR_PIN, LOW);
dir = 1;
rotate();
}
while(!digitalRead(DIR_CCW_PIN)){
digitalWrite(DIR_PIN, HIGH);
dir = 0;
rotate();
}
if(pos != pos_old) {
Serial.println(pos);
pos_old = pos;
}
}
won't as soon as you move off the Zero pt, it attempt to relocate it?
since it looks like you only rotate the turntable when a CW or CCW input is activated, that you don't turn the TT to a specific position, there's no need to zero it.
I have made changes to the setch I posted last. So now the command for CW and CCW rotate the stepper motor after the zero routine. The reason for the zero routine is so the exact number of steps to any point on the arc of the stepper motor is know and repeatable. Attached is a copy of the working sketch.
// Model Railroad Turntable Control //
// Finding zero/homing position and printing out steps. //
// Sketch adapted for a bipolar stepper motor. //
// 24.09.2025//
#define ENABLE_PIN A0 // LOW = driver enabled
#define M1_PIN A1 // M1 microstepping mode
#define M2_PIN A2 // M2 microstepping mode
#define DIR_PIN A3 // to DIR pin of the driver
#define STEP_PIN A4 // to STP pin of driver
#define POTM_PIN A5 // stepper speed control
#define ENABLE_LED_PIN 4 // stepper running LED
#define DIR_LED_PIN 5 // stepper direction LED
#define DIR_CW_PIN 6 // CW stepper direction control
#define DIR_CCW_PIN 7 // CCW stepper direction control
#define ZERO_PIN 9 // Start the zero find routine
#define ZERO_FOUND_PIN 10 // Switch or sensor of zero position
#define PULSES_PER_REV 200 // Pulses per revolution of blue/metal toy motor
byte dir, current_pos, new_pos, rpm, rpm_old;
unsigned long pos, pos_old, timeoflaststep;
void motor_enable() {
digitalWrite(ENABLE_PIN, LOW); // LOW = driver enabled
digitalWrite(ENABLE_LED_PIN, HIGH);
digitalWrite(DIR_PIN, dir);
}
void motor_idle() {
digitalWrite(ENABLE_PIN, HIGH); // HIGH = driver disabled
digitalWrite(ENABLE_LED_PIN, LOW);
}
void find_zero() {
Serial.println("Finding zero sensor");
dir = 0;
motor_enable();
while (digitalRead(ZERO_FOUND_PIN) == HIGH) {
if ((micros() - timeoflaststep) > stepinterval()) {
timeoflaststep = micros();
digitalWrite(STEP_PIN, HIGH);
// delayMicroseconds(10); // only needed if step pulse is too short to be detected
digitalWrite(STEP_PIN, LOW);
}
}
motor_idle();
Serial.println("Zero sensor found");
Serial.println(pos);
current_pos = 0;
new_pos = 1;
}
unsigned long stepinterval() { // calculates step timing based on potmeter input
rpm = map(analogRead(POTM_PIN), 0, 1024, 1, 21) * 10; // max 200 rpm, else pulses get lost
if (rpm != rpm_old) {
Serial.print("RPM: ");
Serial.println(rpm);
rpm_old = rpm;
}
return 60000000UL / PULSES_PER_REV / rpm;
}
void rotate() {
if ((micros() - timeoflaststep) > stepinterval()) {
timeoflaststep = micros();
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(10); // only needed if step pulse is too short to be detected
digitalWrite(STEP_PIN, LOW);
if(dir == 1) pos++;
else pos--;
}
}
void setup() {
pinMode(ZERO_PIN, INPUT_PULLUP);
pinMode(ZERO_FOUND_PIN, INPUT_PULLUP);
pinMode(DIR_CW_PIN, INPUT_PULLUP);
pinMode(DIR_CCW_PIN, INPUT_PULLUP);
pinMode(M1_PIN, OUTPUT);
pinMode(M2_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
pinMode(ENABLE_PIN, OUTPUT);
pinMode(ENABLE_LED_PIN, OUTPUT);
pinMode(DIR_LED_PIN, OUTPUT);
digitalWrite(M1_PIN,LOW); // set M1,M2 to 0,0 for no microstepping
digitalWrite(M2_PIN, LOW);
Serial.begin(9600);
Serial.println("Don't forget to find zero before tuning");
Serial.println();
}
void loop() {
motor_idle();
stepinterval(); // read speed and show RPM on serial monitor
if(digitalRead(ZERO_PIN) == 0) find_zero();
motor_enable();
while(!digitalRead(DIR_CW_PIN)){
digitalWrite(DIR_PIN, LOW);
dir = 1;
rotate();
}
while(!digitalRead(DIR_CCW_PIN)){
digitalWrite(DIR_PIN, HIGH);
dir = 0;
rotate();
}
if(pos != pos_old) {
Serial.println(pos);
pos_old = pos;
}
}
a turntable controller would have a programming mode to determine the position of various tracks that would be stored in EEPROM.
during normal operation, there is an input to specify a track and the controller turns the bridge the appropriate # of steps from its current position to align the bridge with that track. The controller would compare the required # of steps in the CW and CCW directions and choose the smaller # of steps and direction
the controller typically has a way to align the bridge 180 deg as well so that a loco on the bridge is facing the desired direction
the bridge is "zeroed" on start-up in both modes and resets the postion whenever it detects the zero position