Stepper Motor Control Using Arduino – Wokwi Simulator Project Guide

Arduino Stepper Motor Control (28BYJ-48 + ULN2003) | Wokwi Simulator
⚙️ Advanced 🔩 Motors & Actuators 🟢 Wokwi

Stepper Motor Control
28BYJ-48 + ULN2003

Control a 28BYJ-48 stepper motor with an Arduino UNO and ULN2003 driver — including forward/reverse rotation, variable speed, button controls, and serial commands. Fully simulated in Wokwi, no hardware needed.

~20 min read 9 Components Arduino C++
How a stepper motor works Stepper vs DC motor Arduino interfacing Speed & direction control Serial command interface
0Requirements

Components Required (Wokwi)

🔵
Arduino UNO
Main microcontroller
⚙️
28BYJ-48 Motor
5V stepper, 64:1 gear
🔌
ULN2003 Driver
IN1–IN4 driver board
🟢
5× Push Buttons
Fwd/Rev/Speed/Stop
💡
2× LEDs
Green (Fwd) + Red (Rev)
〰️
2× Resistors
220Ω for LEDs
🔌
Jumper Wires
For all connections

All components are simulated — use the free Wokwi Arduino Simulator at wokwi.com. No physical hardware required.

✨ Overview

Project Features

↩️Forward / Reverse Rotation
🎚️Variable Speed (1–15 RPM)
🔢Step Count Tracking
🕹️5 Push Button Controls
💻Serial Command Interface
📐90°, 180°, 360° Presets
💡LED Direction Indicators
🔄Position Reset (Z command)
1Wiring

Pin Connections

⚙️ Stepper Motor (28BYJ-48)
IN1 (A−)Pin 8
IN2 (A+)Pin 9
IN3 (B−)Pin 10
IN4 (B+)Pin 11
V+5V
GNDGND
🕹️ Push Buttons (INPUT_PULLUP)
Forward BTNPin 2 / GND
Reverse BTNPin 3 / GND
Speed+ BTNPin 4 / GND
Speed− BTNPin 5 / GND
Stop BTNPin 6 / GND
💡 LED Indicators (220Ω)
LED Green (Fwd)Pin 12 → R1 → A
LED Red (Rev)Pin 13 → R2 → A
Both cathodesGND

⚠️ Note: The Stepper() constructor uses the pin order IN1, IN3, IN2, IN4 — this is correct for the 28BYJ-48's coil sequence.

2Controls

Button Controls

🟢 Forward
Pin 2 — INPUT_PULLUP
🔴 Reverse
Pin 3 — INPUT_PULLUP
🔵 Speed +
Pin 4 — up to 15 RPM
🔵 Speed −
Pin 5 — down to 1 RPM
🟡 Stop
Pin 6 — halt motor

All buttons use hardware debouncing (50ms) in software. They are wired with INPUT_PULLUP — no external resistors needed.

3Wokwi Config

diagram.json

Paste this into the diagram.json tab in Wokwi to auto-wire all components instantly.

diagram.json
{
  "version": 1,
  "author": "28BYJ-48 Stepper Motor Control",
  "editor": "wokwi",
  "parts": [
    {
      "type": "wokwi-arduino-uno", "id": "uno",
      "top": 0, "left": 0, "attrs": {}
    },
    {
      "type": "wokwi-stepper-motor", "id": "stepper1",
      "top": -100, "left": 300,
      "attrs": { "size": "28BYJ-48" }
    },
    {
      "type": "wokwi-pushbutton", "id": "btn1",
      "top": 120, "left": -200,
      "attrs": { "color": "green", "label": "Forward" }
    },
    {
      "type": "wokwi-pushbutton", "id": "btn2",
      "top": 120, "left": -100,
      "attrs": { "color": "red", "label": "Reverse" }
    },
    {
      "type": "wokwi-pushbutton", "id": "btn3",
      "top": 180, "left": -200,
      "attrs": { "color": "blue", "label": "Speed+" }
    },
    {
      "type": "wokwi-pushbutton", "id": "btn4",
      "top": 180, "left": -100,
      "attrs": { "color": "blue", "label": "Speed-" }
    },
    {
      "type": "wokwi-pushbutton", "id": "btn5",
      "top": 240, "left": -150,
      "attrs": { "color": "yellow", "label": "STOP" }
    },
    {
      "type": "wokwi-led", "id": "led1",
      "top": -80, "left": 500,
      "attrs": { "color": "green", "label": "Forward" }
    },
    {
      "type": "wokwi-led", "id": "led2",
      "top": -20, "left": 500,
      "attrs": { "color": "red", "label": "Reverse" }
    },
    {
      "type": "wokwi-resistor", "id": "r1",
      "top": -60, "left": 480,
      "attrs": { "value": "220" }
    },
    {
      "type": "wokwi-resistor", "id": "r2",
      "top": 0, "left": 480,
      "attrs": { "value": "220" }
    }
  ],
  "connections": [
    [ "uno:GND.1", "stepper1:GND", "black",  [ "v0" ] ],
    [ "uno:5V",   "stepper1:V+", "red",    [ "v0" ] ],
    [ "uno:8",    "stepper1:A-", "orange", [ "v0" ] ],
    [ "uno:9",    "stepper1:A+", "yellow", [ "v0" ] ],
    [ "uno:10",   "stepper1:B-", "green",  [ "v0" ] ],
    [ "uno:11",   "stepper1:B+", "blue",   [ "v0" ] ],
    [ "btn1:1.l", "uno:2",         "green",  [ "v0" ] ],
    [ "btn1:2.l", "uno:GND.2",     "black",  [ "v0" ] ],
    [ "btn2:1.l", "uno:3",         "red",    [ "v0" ] ],
    [ "btn2:2.l", "uno:GND.2",     "black",  [ "v0" ] ],
    [ "btn3:1.l", "uno:4",         "blue",   [ "v0" ] ],
    [ "btn3:2.l", "uno:GND.2",     "black",  [ "v0" ] ],
    [ "btn4:1.l", "uno:5",         "blue",   [ "v0" ] ],
    [ "btn4:2.l", "uno:GND.2",     "black",  [ "v0" ] ],
    [ "btn5:1.l", "uno:6",         "yellow", [ "v0" ] ],
    [ "btn5:2.l", "uno:GND.2",     "black",  [ "v0" ] ],
    [ "uno:12",   "r1:1",          "green",  [ "v0" ] ],
    [ "r1:2",     "led1:A",        "green",  [ "v0" ] ],
    [ "led1:C",   "uno:GND.3",     "black",  [ "v0" ] ],
    [ "uno:13",   "r2:1",          "red",    [ "v0" ] ],
    [ "r2:2",     "led2:A",        "red",    [ "v0" ] ],
    [ "led2:C",   "uno:GND.3",     "black",  [ "v0" ] ]
  ],
  "dependencies": {}
}
4Sketch

Arduino Code

⚙️
28BYJ-48 Stepper Motor
⏸ Stopped — click Run Simulation to start
sketch.ino — Arduino C++
/*
  28BYJ-48 Stepper Motor Control with ULN2003 Driver
  =====================================================
  Forward/Reverse, variable speed, 5 buttons,
  serial commands, step tracking
  Author: Arduino Project | Wokwi Simulator
*/

#include <Stepper.h>

// Motor: 28BYJ-48 has 64:1 gear ratio → 32 steps × 64 = 2048
#define STEPS_PER_REV 2048

// ULN2003 driver pins (IN1–IN4)
#define IN1 8
#define IN2 9
#define IN3 10
#define IN4 11

// Button pins
#define BTN_FORWARD    2
#define BTN_REVERSE    3
#define BTN_SPEED_UP   4
#define BTN_SPEED_DOWN 5
#define BTN_STOP       6

// LED indicators
#define LED_FORWARD 12
#define LED_REVERSE 13

// Note: Stepper(steps, IN1, IN3, IN2, IN4) — coil order for 28BYJ-48
Stepper myStepper(STEPS_PER_REV, IN1, IN3, IN2, IN4);

// State variables
int           motorSpeed     = 10;    // RPM (1–15 recommended)
int           currentPosition = 0;
bool          motorRunning   = false;
int           direction      = 1;     // 1 = fwd, -1 = rev
unsigned long stepCount      = 0;

// Debounce state
bool lastBtnForward   = HIGH;
bool lastBtnReverse   = HIGH;
bool lastBtnSpeedUp   = HIGH;
bool lastBtnSpeedDown = HIGH;
bool lastBtnStop      = HIGH;

void setup() {
  Serial.begin(9600);
  Serial.println("========================================");
  Serial.println("  28BYJ-48 Stepper Motor Controller");
  Serial.println("========================================");

  pinMode(BTN_FORWARD,    INPUT_PULLUP);
  pinMode(BTN_REVERSE,    INPUT_PULLUP);
  pinMode(BTN_SPEED_UP,   INPUT_PULLUP);
  pinMode(BTN_SPEED_DOWN, INPUT_PULLUP);
  pinMode(BTN_STOP,       INPUT_PULLUP);
  pinMode(LED_FORWARD, OUTPUT);
  pinMode(LED_REVERSE, OUTPUT);

  myStepper.setSpeed(motorSpeed);
  digitalWrite(LED_FORWARD, LOW);
  digitalWrite(LED_REVERSE, LOW);
  printInstructions();
}

void loop() {
  checkButtons();
  checkSerialCommands();

  if (motorRunning) {
    myStepper.step(direction);
    stepCount++;
    currentPosition += direction;
    if (stepCount % 100 == 0) displayStatus();
  }
  delay(1);
}

void checkButtons() {
  bool b;

  b = digitalRead(BTN_FORWARD);
  if (b == LOW && lastBtnForward == HIGH) {
    delay(50);
    if (digitalRead(BTN_FORWARD) == LOW) rotateForward();
  }
  lastBtnForward = b;

  b = digitalRead(BTN_REVERSE);
  if (b == LOW && lastBtnReverse == HIGH) {
    delay(50);
    if (digitalRead(BTN_REVERSE) == LOW) rotateReverse();
  }
  lastBtnReverse = b;

  b = digitalRead(BTN_SPEED_UP);
  if (b == LOW && lastBtnSpeedUp == HIGH) {
    delay(50);
    if (digitalRead(BTN_SPEED_UP) == LOW) increaseSpeed();
  }
  lastBtnSpeedUp = b;

  b = digitalRead(BTN_SPEED_DOWN);
  if (b == LOW && lastBtnSpeedDown == HIGH) {
    delay(50);
    if (digitalRead(BTN_SPEED_DOWN) == LOW) decreaseSpeed();
  }
  lastBtnSpeedDown = b;

  b = digitalRead(BTN_STOP);
  if (b == LOW && lastBtnStop == HIGH) {
    delay(50);
    if (digitalRead(BTN_STOP) == LOW) stopMotor();
  }
  lastBtnStop = b;
}

void checkSerialCommands() {
  if (Serial.available() > 0) {
    char cmd = Serial.read();
    switch (cmd) {
      case 'F': case 'f': rotateForward();  break;
      case 'R': case 'r': rotateReverse();  break;
      case 'S': case 's': stopMotor();      break;
      case '+':            increaseSpeed();  break;
      case '-':            decreaseSpeed();  break;
      case '1':            rotate90Degrees();  break;
      case '2':            rotate180Degrees(); break;
      case '3':            rotate360Degrees(); break;
      case 'I': case 'i': displayStatus();  break;
      case 'Z': case 'z': resetPosition();  break;
      case 'H': case 'h': printInstructions(); break;
    }
  }
}

void rotateForward() {
  motorRunning = true; direction = 1;
  digitalWrite(LED_FORWARD, HIGH);
  digitalWrite(LED_REVERSE, LOW);
  Serial.println(">>> FORWARD ROTATION <<<");
}

void rotateReverse() {
  motorRunning = true; direction = -1;
  digitalWrite(LED_FORWARD, LOW);
  digitalWrite(LED_REVERSE, HIGH);
  Serial.println(">>> REVERSE ROTATION <<<");
}

void stopMotor() {
  motorRunning = false;
  digitalWrite(LED_FORWARD, LOW);
  digitalWrite(LED_REVERSE, LOW);
  Serial.print(">>> STOPPED — Total steps: ");
  Serial.println(stepCount);
}

void increaseSpeed() {
  if (motorSpeed < 15) { motorSpeed++; myStepper.setSpeed(motorSpeed); }
  Serial.print("Speed: "); Serial.print(motorSpeed); Serial.println(" RPM");
}

void decreaseSpeed() {
  if (motorSpeed > 1) { motorSpeed--; myStepper.setSpeed(motorSpeed); }
  Serial.print("Speed: "); Serial.print(motorSpeed); Serial.println(" RPM");
}

void rotate90Degrees() {
  int steps = STEPS_PER_REV / 4;
  Serial.println("Rotating 90°...");
  myStepper.step(steps);
  currentPosition += steps; stepCount += steps;
  Serial.println("Done!");
}

void rotate180Degrees() {
  int steps = STEPS_PER_REV / 2;
  Serial.println("Rotating 180°...");
  myStepper.step(steps);
  currentPosition += steps; stepCount += steps;
  Serial.println("Done!");
}

void rotate360Degrees() {
  Serial.println("Full rotation 360°...");
  myStepper.step(STEPS_PER_REV);
  currentPosition += STEPS_PER_REV; stepCount += STEPS_PER_REV;
  Serial.println("Done!");
}

void resetPosition() {
  currentPosition = 0; stepCount = 0;
  Serial.println("Position counter reset to zero");
}

void displayStatus() {
  Serial.println("=== Motor Status ===");
  Serial.print("Running: ");    Serial.println(motorRunning ? "YES" : "NO");
  Serial.print("Direction: ");  Serial.println(direction == 1 ? "FORWARD" : "REVERSE");
  Serial.print("Speed: ");      Serial.print(motorSpeed); Serial.println(" RPM");
  Serial.print("Position: ");   Serial.print(currentPosition); Serial.println(" steps");
  Serial.print("Rotations: ");  Serial.println((float)currentPosition / STEPS_PER_REV, 2);
  Serial.println("===================");
}

void printInstructions() {
  Serial.println("BUTTON: Btn1=Fwd Btn2=Rev Btn3=Spd+ Btn4=Spd- Btn5=Stop");
  Serial.println("SERIAL: F=Fwd R=Rev S=Stop +=Spd+ -=Spd- 1=90° 2=180° 3=360° I=Info Z=Reset H=Help");
  Serial.println("Ready!");
}
💻 Interface

Serial Command Reference

Open the Serial Monitor at 9600 baud and send single characters to control the motor in real time.

FForward rotation
RReverse rotation
SStop motor
+Increase speed (+1 RPM)
Decrease speed (−1 RPM)
1Rotate exactly 90°
2Rotate exactly 180°
3Rotate exactly 360°
IDisplay motor status
ZReset position counter
HShow help / instructions
5Simulate

Run the Simulation

Paste diagram.json

Copy the diagram.json into Wokwi's diagram tab to auto-wire everything.

Paste the Code

Copy the sketch into the code editor tab.

Click ▶ Play

Press the green start button to run the simulation.

Use Buttons

Click the virtual push buttons to control direction and speed.

Serial Monitor

Open Serial Monitor, type F, R, 13 for precise control.

More Arduino Projects

🟢 Beginner — Foundation & Basics
🔵 Intermediate — Displays & Sensors
🔴 Advanced — Motors & Actuators
🟣 Expert — Security & Automation
📡 IoT & Advanced Displays

© 2026 MakeMindz · Arduino & IoT Projects for Students, Makers & STEM Learners

Comments

try for free