Fun with Arduino 31 Stepper Motor with 4 Input Driver, using a Function()

With some applications it can be useful to use a stepper motor in stead of a servo. For instance when a continuous rotation is required to rotate, say, a wind mill model. Also with applications like a turn table, a linear shift table or an elevator, a stepper motor can be of great help … it can be positioned with accuracy.

After startup a stepper motor does not know where it is. To overcome this, what we can do after startup is to rotate the stepper in a given direction until it triggers an micro switch or an optical or a magnetic sensor. This position then becomes ‘zero’. From there we can position the stepper by sending exact amounts of pulses to the driver and by remembering where we are in the software.

Stepper_ToyThe picture shows a very affordable stepper motor … it can be had at Aliexpress for less than €2,- … including the driver.

A gear box is built in, the output shaft of this motor has 2048 steps per revolution. It is not a very strong motor, it can only be used in applications that do not require high torque.

The driver has 4 inputs. What we need to accomplish with our Arduino code is to send the following sequence to 4 output pins: 1000 – 0100 – 0010 – 0001 – 1000 – 0100 – … and so on.

We can either do this continuously, which runs the motor at a predetermined speed, or we can count up or down to a given number and then stop, via which we can accurately position the stepper motor.

The time between the changes determines the rotation speed. With this particular (toy) motor the interval time should not be less than 1 ms, or it may start to lose pulses and we lose accurate positioning. 

Read on below the video:

 

Let’s first write code that makes the stepper rotate when an input pin is made LOW.

In the code we use two functions. A function is a cluster of code that we gave a name and that we can call from either setup() or from loop() with this name. Functions can be helpful in a couple of ways.  One reason to use a function is when we need the same code at several different places in our program. In that case it is highly efficient to write that code as a function and then call that function from every spot where we need it. Another reason can simply be to divide our code into smaller more manageable parts, such that our setup() or loop() stay better readable.

The latter is how functions are used here … our loop() is kept very small, easy readable. The actual work is done in two functions that are marked in red:

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

What happens is that as long as the ONOFF_PIN is LOW, every stepinterval µs the function do_one_step() is called. When the ONOFF_PIN is HIGH we stop stepping and the motor_idle() function is called, which makes all four outputs LOW to prevent a current keeps flowing through a motor coil, which could burn the motor or the driver.

The complete code:

#define MOTOR_PIN_1      A1
#define MOTOR_PIN_2      A2
#define MOTOR_PIN_3      A3
#define MOTOR_PIN_4      A4
#define ONOFF_PIN         9 // LOW = motor runs
#define LED_PIN           5 // Motor running indicator LED
#define DIR_PIN           8 // Direction of rotation
#define PULSES_PER_REV 2048 // Pulses per revolution
#define RPM               5 // speed max 12 rpm, else pulses get lost

byte stepnr;
unsigned long timeoflaststep, stepinterval;

void do_one_step() { 
  digitalWrite(LED_PIN, HIGH);
  stepnr = (stepnr + 1) % 4; // remembers 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(LED_PIN,     LOW);
}

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(LED_PIN,     OUTPUT);
  digitalWrite(LED_PIN,LOW);
  stepinterval = 60000000UL / PULSES_PER_REV / RPM; // [us]
}

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

Let’s have a look how this works out in practice. Yes … the motor is running as long as the ONOFF_PIN pin is kept LOW.

In the next video we are going to add speed and direction control to it.

— 0 —

One thought on “Fun with Arduino 31 Stepper Motor with 4 Input Driver, using a Function()

Leave a comment