Skip to content

Arduino - Stepper Motor

A stepper motor is a brushless DC motor that divides a full rotation into a number of equal steps. This allows for extremely precise control over position, making them ideal for applications like 3D printers, CNC machines, and robotics, where exact movement is critical.

Unlike a standard DC motor that spins continuously, a stepper motor moves in discrete increments or ‘steps’. You control it by telling it how many steps to move and in which direction.

While many stepper motor configurations exist, the most common and beginner-friendly setup uses a 28BYJ-48 unipolar stepper motor and a ULN2003 driver board. This combination is inexpensive, widely available, and easy to interface with an Arduino.

  • 1 × Arduino UNO (or any compatible board)
  • 1 × 28BYJ-48 Stepper Motor
  • 1 × ULN2003 Driver Board (comes with the motor)
  • Jumper Wires
  • Optional: A 5V external power supply for the motor to avoid drawing too much current from the Arduino’s 5V pin, which is a best practice.

Follow this wiring guide carefully. The 28BYJ-48 motor’s connector is keyed and only fits one way into the ULN2003 board.

ULN2003 Driver Board | Arduino UNO
-----------------------|----------------
IN1 | Pin 8
IN2 | Pin 9
IN3 | Pin 10
IN4 | Pin 11
ULN2003 Driver Board | Power Source
-----------------------|----------------
+ (5V-12V) | Arduino 5V Pin (or external 5V +)
- (GND) | Arduino GND Pin (and external 5V GND)

Important: The ULN2003 board has a jumper. Keep it on if you are powering the motor from the same source as the logic (e.g., the Arduino’s 5V pin). Remove it if you are using a separate, higher voltage external power supply for the motor.

Beyond Stepper.h: Introducing the AccelStepper Library

Section titled “Beyond Stepper.h: Introducing the AccelStepper Library”

The built-in <Stepper.h> library is functional but has a major drawback: it uses delay() for movement, which blocks your entire program. While the motor is moving, your Arduino can’t do anything else, like read sensors or check for button presses.

A much more powerful and modern alternative is the AccelStepper library. It enables non-blocking control, acceleration, and deceleration, allowing your motor to start and stop smoothly while your loop() continues to run freely. You’ll need to install it via the Arduino IDE’s Library Manager (Sketch > Include Library > Manage Libraries... and search for “AccelStepper”).

Non-Blocking Control Example with AccelStepper

Section titled “Non-Blocking Control Example with AccelStepper”
#include <AccelStepper.h>
// Define the stepper motor connections and motor interface type
#define MOTOR_INTERFACE_TYPE 4 // For ULN2003 driver, use 4-pin half-step mode
#define MOTOR_PIN_1 8
#define MOTOR_PIN_2 9
#define MOTOR_PIN_3 10
#define MOTOR_PIN_4 11
// Initialize the stepper library with the pin connections
// Note the pin order for 28BYJ-48 is often 1-3-2-4 (IN1, IN3, IN2, IN4)
AccelStepper myStepper(MOTOR_INTERFACE_TYPE, MOTOR_PIN_1, MOTOR_PIN_3, MOTOR_PIN_2, MOTOR_PIN_4);
void setup() {
// Set the maximum speed and acceleration.
// These values will depend on your motor and power supply.
myStepper.setMaxSpeed(1000); // Steps per second
myStepper.setAcceleration(500); // Steps per second squared
// Move the motor to a starting position
myStepper.moveTo(2048); // 2048 steps is approx. one half-revolution for a 28BYJ-48
}
void loop() {
// This is the core of non-blocking control.
// run() checks if it's time to step the motor and executes a step if needed.
// It must be called as frequently as possible in the loop.
if (myStepper.distanceToGo() == 0) {
// If the motor has reached its target, set a new one.
// This will make it move back and forth continuously.
// The -myStepper.currentPosition() calculation sets the target to the negative of the current position.
myStepper.moveTo(-myStepper.currentPosition());
}
// This is the magic! This line moves the motor.
myStepper.run();
// You can do other things here, and the motor will keep moving!
// For example, you could read a sensor or print to Serial.
}
  • AccelStepper(type, p1, p3, p2, p4): We initialize the stepper object. The 4 indicates a 4-pin driver. The pin order (8, 10, 9, 11) is crucial for the 28BYJ-48 motor to spin correctly.
  • setMaxSpeed() and setAcceleration(): These methods define the motor’s performance profile, allowing for smooth starts and stops.
  • moveTo(position): Sets a target absolute position for the motor. It does not block the code; it just tells the library where to go.
  • run(): This is the most important function. You must call it repeatedly in your loop(). It checks if it’s time to make a step and, if so, energizes the correct motor coils. Because it runs and returns very quickly, it doesn’t block other code in your loop.

For more power and precision, especially with bipolar stepper motors (which have 4 wires), you’ll want to use more advanced drivers:

  • A4988 / DRV8825: These are single-chip microstepping drivers, very popular in 3D printers and small CNC machines. They only require two pins from the Arduino (STEP and DIR) and handle all the complex coil switching internally. They also allow for ‘microstepping’, which gives smoother, quieter motion.