Fun with Arduino 32 Stepper Motor Change Direction and Control Speed

Now that we have our stepper motor running we can add some extra features, like:

  • change direction
  • change speed
  • rotate an exact amount of steps for accurate positioning

Read on below the video …

 

To change direction and to also show a direction indicator LED, a function is created. There’s no real need to make it a function, it’s used here to show the concept of how a function can return a value. The function is named dir() and it has the type byte. When it is called, it reads an input pin, switches the indicator LED accordingly and then returns a byte that represents the direction switch, which in this case is either 1 or 0.

byte dir() {
  byte dir_switch = digitalRead(DIR_PIN);
  digitalWrite(DIR_LED_PIN, !dir_switch);
  return dir_switch;
}

To change the rotation speed we have to change the number of microseconds between the driver pulses that we send out. We’re again going to use a function that returns a value, this time an unsgined long number. The stepinterval() function looks like this:

unsigned long stepinterval() { // calculates step timing based on potmeter input
  rpm = map(analogRead(POTM_PIN), 0, 1024, 1, 13); // max 12 rpm, else pulses get lost
  if(rpm != rpm_old) {
    Serial.print("RPM: ");
    Serial.println(rpm);
    rpm_old = rpm;
  }
return 60000000UL / PULSES_PER_REV / rpm; // [us] stepinterval
}

A potentiometer is used to create a voltage on an Arduino input. This is analog read and mapped to a speed in RPM from 1 to 12. The RPM value is translated to a step interval time in microseconds which is returned with data type unsigned long.

The complete code now becomes:

#define MOTOR_PIN_1      A1
#define MOTOR_PIN_2      A2
#define MOTOR_PIN_3      A3
#define MOTOR_PIN_4      A4
#define POTM_PIN         A5
#define ONOFF_PIN         9 // LOW = motor runs
#define ONOFF_LED_PIN     5 // Motor running LED
#define DIR_PIN           8 // LOW = rotate LEFT, HIGH = rotate RIGHT
#define DIR_LED_PIN       4 // Motor direction LED
#define PULSES_PER_REV 2048 // Pulses per revolution

byte rpm, rpm_old, stepnr;
unsigned long timeoflaststep;

unsigned long stepinterval() { // calculates step timing based on potmeter input
  rpm = map(analogRead(POTM_PIN), 0, 1024, 1, 13); // max 12 rpm, else pulses get lost
  if(rpm != rpm_old) {
    Serial.print("RPM: ");
    Serial.println(rpm);
    rpm_old = rpm;
  }
  return 60000000UL / PULSES_PER_REV / rpm; // [us] stepinterval
}

byte dir() {
  byte dir_switch = digitalRead(DIR_PIN);
  digitalWrite(DIR_LED_PIN, !dir_switch);
  return dir_switch;
}

void do_one_step() { 
  digitalWrite(ONOFF_LED_PIN, HIGH);
  if(dir() == 1) stepnr++;
  else stepnr--;
  stepnr = stepnr % 4; // remember in which of the 4 phases the motor is

  switch (stepnr) {
    case 0:
      digitalWrite(MOTOR_PIN_1, HIGH);
      digitalWrite(MOTOR_PIN_2, LOW);
      digitalWrite(MOTOR_PIN_3, LOW);
      digitalWrite(MOTOR_PIN_4, LOW);
    break;
    case 1:
      digitalWrite(MOTOR_PIN_1, LOW);
      digitalWrite(MOTOR_PIN_2, HIGH);
      digitalWrite(MOTOR_PIN_3, LOW);
      digitalWrite(MOTOR_PIN_4, LOW);
    break;
    case 2:
      digitalWrite(MOTOR_PIN_1, LOW);
      digitalWrite(MOTOR_PIN_2, LOW);
      digitalWrite(MOTOR_PIN_3, HIGH);
      digitalWrite(MOTOR_PIN_4, LOW);
    break;
    case 3:
      digitalWrite(MOTOR_PIN_1, LOW);
      digitalWrite(MOTOR_PIN_2, LOW);
      digitalWrite(MOTOR_PIN_3, LOW);
      digitalWrite(MOTOR_PIN_4, HIGH);
    break;
  }
}

void motor_idle() {
  digitalWrite(MOTOR_PIN_1,   LOW);
  digitalWrite(MOTOR_PIN_2,   LOW);
  digitalWrite(MOTOR_PIN_3,   LOW);
  digitalWrite(MOTOR_PIN_4,   LOW);
  digitalWrite(ONOFF_LED_PIN, LOW);
  dir(); // to switch the LED when motor not running
}

void setup() {
  pinMode(ONOFF_PIN,     INPUT_PULLUP);
  pinMode(DIR_PIN,       INPUT_PULLUP);
  pinMode(MOTOR_PIN_1,   OUTPUT);
  pinMode(MOTOR_PIN_2,   OUTPUT);
  pinMode(MOTOR_PIN_3,   OUTPUT);
  pinMode(MOTOR_PIN_4,   OUTPUT);
  pinMode(ONOFF_LED_PIN, OUTPUT);
  pinMode(DIR_LED_PIN,   OUTPUT);
  Serial.begin(9600);
}

void loop() {
  while(digitalRead(ONOFF_PIN) == LOW) {
    if ((micros() - timeoflaststep) > stepinterval()) {
      timeoflaststep = micros();
      do_one_step();
    }
  }
  motor_idle();
}

Let’s try this out and see if we can change the direction and the speed.

Yes … we can!

On to the next video, where we are going to add a ‘zero find’ routine, which we need in preparation of accurate positioning the stepper motor. Unlike a servo, a stepper does not know where it is after startup.

— 0 —

 

 

Leave a comment