To successfully execute stepper motor code in Arduino, you need three things: a bipolar stepper motor (typically a NEMA 17), a STEP/DIR driver module (like the A4988, DRV8825, or TMC2209), and an acceleration-profiling library like AccelStepper. Steppers do not run well on raw digital pins; they require precisely timed current pulses to sequence their internal electromagnetic coils. This guide covers the physical selection, wiring, and exact code required to get your motor moving reliably.
Motor & Drive Selection Matrix
Before writing a single line of code, you must verify that a stepper is actually the right tool for your mechanical load. A common mistake in embedded projects is treating steppers and servos as interchangeable. They are not. Steppers excel at low-speed, high-holding-torque applications in open-loop systems, while servos dominate high-speed dynamic loads requiring closed-loop feedback.
| Motor Type | Torque Curve Profile | Control Needs | Relative Cost | Best Load Profile |
|---|---|---|---|---|
| Bipolar Stepper (NEMA 17/23) | Peak holding torque at 0 RPM; drops sharply after 300-600 RPM. | Open-loop STEP/DIR pulses; requires microstepping driver. | Low ($10-$25 for motor + driver) | 3D printers, CNC routers, linear actuators, camera sliders. |
| AC/DC Servo | Flat, consistent torque curve up to rated maximum RPM. | Closed-loop; requires encoder feedback and complex tuning. | High ($100-$300+) | Robotic arms, high-speed pick-and-place, dynamic joints. |
| Brushed DC | High speed, low holding torque; torque drops linearly with speed. | Simple H-bridge for speed/direction; needs encoder for position. | Lowest ($3-$10) | Conveyor belts, drive wheels, continuous rotation fans. |
| Brushless DC (BLDC) | High efficiency, flat torque curve, requires electronic commutation. | 3-phase ESC or FOC driver; hall sensors or sensorless back-EMF. | Medium ($30-$80) | Drones, gimbals, high-speed spindles, electric skateboards. |
Which motor fits your load? If your application requires the motor to hold a heavy load perfectly still without power (or with minimal holding current) and move at speeds under 1000 RPM, choose the bipolar stepper. If you need to swing a 5kg arm at 3000 RPM and stop on a dime, you must use a servo.
Sizing the Stepper and Wiring the Driver
Stepper motors are rated by holding torque (the torque required to move the shaft one full step when the coils are fully energized and the motor is stationary). However, dynamic torque (torque while moving) is significantly lower.
Worked Load Example
Suppose you are building a vertical Z-axis lift using a standard 2mm lead screw (TR8x2) to raise a 3 kg (29.4 N) load.
- Formula: Torque = (Force × Lead) / (2 × π × Efficiency)
- Calculation: (29.4 N × 0.002 m) / (2 × 3.1415 × 0.90 efficiency) = 0.0104 Nm.
- Safety Factor: 0.0104 Nm × 3 = 0.0312 Nm required.
A standard NEMA 17 motor (like the popular 17HS4401) provides roughly 0.40 Nm to 0.45 Nm of holding torque. While this seems like massive overkill for a 3kg lift, it is necessary because dynamic torque at 500 RPM might drop to 20% of the holding torque, and you need enough reserve to overcome static friction (stiction) and accelerate the load's inertia without stalling.
Wiring and Terminal Identification
A standard bipolar NEMA 17 has four wires representing two internal coils (Coil A and Coil B). To identify them without a datasheet, set your multimeter to continuity or resistance mode. Probe the wires until you find two pairs that show a low resistance (typically 1.5Ω to 5Ω). Wires that show infinite resistance (open loop) belong to different coils.
For the driver, we will use the TI DRV8825 or the Trinamic TMC2209 (preferred for silent operation). The driver demands two logic signals from the Arduino: STEP (a pulse to move one microstep) and DIR (HIGH for clockwise, LOW for counter-clockwise).
Writing the Stepper Motor Code in Arduino
Raw digitalWrite() commands are insufficient for steppers because instant speed changes cause the rotor to stall. You must ramp the speed up and down. The industry-standard library for this is AccelStepper by Mike McCauley.
Pin Mapping Table
| Driver Pin | Arduino Uno Pin | Function |
|---|---|---|
| STEP | D3 | Receives pulse to advance one microstep |
| DIR | D4 | HIGH = CW, LOW = CCW |
| EN (Enable) | D5 | LOW to enable driver, HIGH to disable |
| VMOT | External PSU (+12V to +24V) | Motor power supply (DO NOT use Arduino 5V) |
| GND | External PSU GND + Arduino GND | Common ground is mandatory for logic reference |
Complete Arduino Code
Install the AccelStepper library via the Arduino Library Manager before uploading this sketch. This code moves the motor 6400 steps (one full revolution on a 1/16th microstepping driver), pauses, and returns.
#include <AccelStepper.h>
// Define pin connections
const int stepPin = 3;
const int dirPin = 4;
const int enablePin = 5;
// Initialize AccelStepper object (Interface type 1 = STEP/DIR driver)
AccelStepper stepper(1, stepPin, dirPin);
void setup() {
// Configure enable pin as output and enable the driver
pinMode(enablePin, OUTPUT);
digitalWrite(enablePin, LOW); // LOW enables most STEP/DIR drivers
// Set motor parameters
// Max speed in steps per second (e.g., 6400 steps/sec = 1 rev/sec at 1/16 microstepping)
stepper.setMaxSpeed(3200);
// Acceleration in steps per second per second
stepper.setAcceleration(1600);
// Set initial position
stepper.setCurrentPosition(0);
}
void loop() {
// If motor has reached its target, set a new target
if (stepper.distanceToGo() == 0) {
// Move 6400 steps forward (1 full rev at 1/16 microstepping)
// Next loop iteration will move it back to 0
if (stepper.currentPosition() == 0) {
stepper.moveTo(6400);
} else {
stepper.moveTo(0);
}
}
// Must be called as frequently as possible to execute steps
stepper.run();
}
Diagnosing Failure Signatures: Hum, Overheat, and Stall
When your stepper motor code in Arduino fails to produce smooth motion, the physical symptoms will tell you exactly what is wrong. Do not blindly change the code; check the physics and the current limits first.
| Symptom | Probable Cause | Measurement / Fix |
|---|---|---|
| Humming / Vibrating but not rotating | Coil pairs are mixed (e.g., A+ and B+ on the same coil) OR acceleration is set too high for the load inertia. | Verify coil pairs with a multimeter. If wiring is correct, halve the setAcceleration() value in code. |
| Motor or Driver Overheating (>60°C) | Driver current limit (Vref) is set too high, or motor is holding 100% current while stationary without cooling. | Measure Vref on the driver potentiometer. For DRV8825: Vref = I_limit × 8 × R_sense. For 1A limit with 0.1Ω sense resistor, Vref should be 0.8V. |
| Stalling / Missed Steps at High Speed | Dynamic torque drops below load torque at the target RPM, or power supply voltage is too low to push current fast enough. | Reduce setMaxSpeed(). If higher speed is mandatory, increase driver supply voltage (e.g., from 12V to 24V) to overcome coil inductance faster. |
| Erratic Jitter / Random Direction Changes | Logic voltage brownout, missing common ground, or EMI from stepper cables inducing noise on the STEP/DIR lines. | Ensure Arduino GND and Driver GND are tied together. Route STEP/DIR wires away from the high-current motor coil wires. |
By matching the correct motor to your mechanical load, sizing the driver current accurately, and using acceleration profiling in your Arduino code, you will eliminate the vast majority of stepper motor issues encountered in DIY CNC, 3D printing, and automation projects.






