In this tutorial, you will learn how to use the UNL2003 driver to control a simple stepper motor. To make precise movements with control distance, such as 3D printers, then you should totally follow this tutorial.
Parts Required
- ESP8266 NodeMCU v1.0;
- Micro-USB to USB cable;
- Stepper motor (Ex: 28BYJ-48) + ULN2003 Driver;
- Female to Female jumper wires (optional);
- Male to Female jumper wires (optional);
- 9V Battery (optional);
- LM2596S Step Down Converter or LM7805 Voltage regulator (optional);
The Stepper Motor and ULN2003 Driver

A stepper motor converts electronic signals into mechanical movement each time an incoming pulse is applied to the motor. Each pulse moves the shaft in fixed increments. If the stepper motor has a 1.8° step resolution, then in order for the shaft to rotate one complete revolution, in full step operation, the stepper motor would need to receive 200 pulses, 360° ÷ 1.8 = 200.
For that to happen, we need to use stepper drives, which control how a stepper motor operates. There are three commonly used excitation modes for stepper motors: full step, half step and micro-stepping. These excitation modes have an effect on both the running properties and torque the motor delivers. In our case, is half step excitation mode and it is a 28BYJ-48 – 5V Stepper Motor.
So, half step excitation mode is a combination of one phase and two-phase. This results in half the basic step angle. This smaller step angle provides smoother operation due to the increased resolution of the angle. We can see an example in figure 2.

It is not recommended to directly power the stepper motor from the output of the NodeMCU board. When the stepper motor draws too much current you can damage the Board.
In order to be able to deliver all the current to the stepper motor, we will use the ULN2003 driver board. The ULN2003 is a high-voltage, high-current Darlington drivers comprised of seven NPN Darlington pairs. This board only uses 4. All units feature integral clamp diodes for switching inductive loads.
In figure 3 you can observe the internal transistor of one channel.

Circuit

Since the voltage output of the ESP8266 NodeMCU board is 3.3V, and hence insufficient to power our stepper motor, a 9V battery was used, along with an LM7805 voltage regulator in order to feed the ULN2003 driver with the desired 5V. Connect the IN pins on the ULN2003A driver to pins on NodeMCU board:
- IN1 pin on the ULN2003A driver to pin D1 on NodeMCU board
- IN2 pin on the ULN2003A driver to pin D2 on NodeMCU board
- IN3 pin on the ULN2003A driver to pin D3 on NodeMCU board
- IN4 pin on the ULN2003A driver to pin D4 on NodeMCU board
Instaling Libraries For VS1838B
To get our stepper motor up and running, we first need to install a library to control its driver, which is the AccelStepper library. Although the Arduino IDE already includes a library for stepper motors (http://arduino.cc/en/Reference/Stepper), this library introduces some significant improvements, such as acceleration and deceleration support, capability to control multiple simultaneous stepper motors and many more.
To install it, go to Sketch > Include Library > Manage Libraries… and then type in the research box “accelstepper”. Look for AccelStepper by Mike McCauley, click on that entry and then select Install, as shown in figure 1. This way, we are ready to start coding!

Coding
In this tutorial, we simply want to make the stepper motor to go back and forward in 90 and 180-degree angles and then go back to the original position (0 degrees), over and over again.
We think that, with this code, you are able to understand how to control the stepper motor, so now you just need to apply this knowledge to your future applications. Enjoy!
#include <AccelStepper.h> // Load the AccelStepper library
#define motorPin1 5 // IN1 pin on the ULN2003A driver to pin D1 on NodeMCU board
#define motorPin2 4 // IN2 pin on the ULN2003A driver to pin D2 on NodeMCU board
#define motorPin3 0 // IN3 pin on the ULN2003A driver to pin D3 on NodeMCU board
#define motorPin4 2 // IN4 pin on the ULN2003A driver to pin D4 on NodeMCU board
int stepsPerRevolution = 64; // steps per revolution
int degreePerRevolution = 5.625; // degree per revolution
/*
* AccelStepper::FULL2WIRE (2) means: 2 wire stepper (2 pins needed).
* AccelStepper::FULL3WIRE (3) means: 3 wire stepper, like a harddisk motor (3 pins needed).
* AccelStepper::FULL4WIRE (4) means: 4 wire stepper (4 pins needed).
* AccelStepper::HALF3WIRE (6) means: 3 wire half stepper, like a harddisk motor (3 pins needed)
* AccelStepper::HALF4WIRE (8) means: 4 wire half stepper (4 pins needed)
*
* AccelStepper uses AccelStepper::FULL4WIRE (4 pins needed) by default.
*/
AccelStepper stepper(AccelStepper::HALF4WIRE, motorPin1, motorPin3, motorPin2, motorPin4);
void setup() {
Serial.begin(9600); // initialise the serial monitor
stepper.setMaxSpeed(1000.0); // set the max motor speed
stepper.setAcceleration(100.0); // set the acceleration
stepper.setSpeed(200); // set the current speed
}
// Degrees of the momevement. So first to 90 degrees, then to -90 graden then to 180 degrees etc.
int steps[] = { 90, -90, 180, -180, 0 };
// The total entries in steps[]
int stepsCount = 5;
// Keeps track of the position in steps[] we are about to run
int stepsIndex = 0;
void loop() {
// If the stepper isn't moving and doesn't have to go any distance
if (!stepper.isRunning() && stepper.distanceToGo() == 0) {
// Move the stepper to the degrees on the position of stepIndex in steps[]
stepper.moveTo(degToSteps(steps[stepsIndex]));
// Increase the index when each movement has finished
stepsIndex++;
// If we have executed all positions of steps[]
if (stepsIndex > stepsCount) {
// Set the index to 0 to restart the process
stepsIndex = 0;
}
}
stepper.run();
}
/*
* Converts degrees to steps
*
* 28BYJ-48 motor has 5.625 degrees per step
* 360 degrees / 5.625 = 64 steps per revolution
*
* Example with degToSteps(45):
* (64 / 5.625) * 45 = 512 steps
*/
float degToSteps(float deg) {
return (stepsPerRevolution / degreePerRevolution) * deg;
}
References:
- https://www.airspayce.com/mikem/arduino/AccelStepper/classAccelStepper.html
- https://www.makerguides.com/28byj-48-stepper-motor-arduino-tutorial/
- https://www.makerguides.com/wp-content/uploads/2019/04/ULN2003-Datasheet.pdf
- https://www.makerguides.com/wp-content/uploads/2019/04/ULN2003-Stepper-Motor-Driver-PCB.pdf
- https://www.makerguides.com/wp-content/uploads/2019/04/28byj48-Stepper-Motor-Datasheet.pdf
Hi, I do think this is a great blog. I stumbledupon it 😉
I am going to come back yet again since I saved as
a favorite it. Money and freedom is the greatest way to change, may you be rich and
continue to help others.
sketch_mar09a:33:11: error: stray ‘#’ in program
int steps[] = { 90, -90, 180, -180, 0 };
^
sketch_mar09a:47:37: error: stray ‘#’ in program
stepper.moveTo(degToSteps(steps[stepsIndex]));
^
sketch_mar09a:33:10: error: expected initializer before ‘&’ token
int steps[] = { 90, -90, 180, -180, 0 };
^
sketch_mar09a:33:15: error: expected unqualified-id before ‘]’ token
int steps[] = { 90, -90, 180, -180, 0 };
^
C:\Users\oskar\OneDrive\Dokumenty\Arduino\sketch_mar09a\sketch_mar09a.ino: In function ‘void loop()’:
sketch_mar09a:44:29: error: ‘amp’ was not declared in this scope
if (!stepper.isRunning() && stepper.distanceToGo() == 0) {
^
sketch_mar09a:44:32: error: expected ‘)’ before ‘;’ token
if (!stepper.isRunning() && stepper.distanceToGo() == 0) {
^
sketch_mar09a:44:34: error: ‘amp’ was not declared in this scope
if (!stepper.isRunning() && stepper.distanceToGo() == 0) {
^
sketch_mar09a:44:66: error: expected ‘;’ before ‘)’ token
if (!stepper.isRunning() && stepper.distanceToGo() == 0) {
^
sketch_mar09a:75:1: error: expected ‘}’ at end of input
}
^
exit status 1
stray ‘#’ in program
Same here… any ideas? Thanks!
In the code, change the places where appears “[]” with “[]”
where appears “& # 9 1 ; ]”
#include // Load the AccelStepper library
#define motorPin1 5 // IN1 pin on the ULN2003A driver to pin D1 on NodeMCU board
#define motorPin2 4 // IN2 pin on the ULN2003A driver to pin D2 on NodeMCU board
#define motorPin3 0 // IN3 pin on the ULN2003A driver to pin D3 on NodeMCU board
#define motorPin4 2 // IN4 pin on the ULN2003A driver to pin D4 on NodeMCU board
int stepsPerRevolution = 64; // steps per revolution
int degreePerRevolution = 5.625; // degree per revolution
/*
* AccelStepper::FULL2WIRE (2) means: 2 wire stepper (2 pins needed).
* AccelStepper::FULL3WIRE (3) means: 3 wire stepper, like a harddisk motor (3 pins needed).
* AccelStepper::FULL4WIRE (4) means: 4 wire stepper (4 pins needed).
* AccelStepper::HALF3WIRE (6) means: 3 wire half stepper, like a harddisk motor (3 pins needed)
* AccelStepper::HALF4WIRE (8) means: 4 wire half stepper (4 pins needed)
*
* AccelStepper uses AccelStepper::FULL4WIRE (4 pins needed) by default.
*/
AccelStepper stepper(AccelStepper::HALF4WIRE, motorPin1, motorPin3, motorPin2, motorPin4);
void setup() {
Serial.begin(9600); // initialise the serial monitor
stepper.setMaxSpeed(1000.0); // set the max motor speed
stepper.setAcceleration(100.0); // set the acceleration
stepper.setSpeed(200); // set the current speed
}
// Degrees of the momevement. So first to 90 degrees, then to -90 graden then to 180 degrees etc.
int steps[] = { 90, -90, 180, -180, 0 };
// The total entries in steps[]
int stepsCount = 5;
// Keeps track of the position in steps[] we are about to run
int stepsIndex = 0;
void loop() {
// If the stepper isn’t moving and doesn’t have to go any distance
if (!stepper.isRunning() && stepper.distanceToGo() == 0) {
// Move the stepper to the degrees on the position of stepIndex in steps[]
stepper.moveTo(degToSteps(steps[stepsIndex]));
// Increase the index when each movement has finished
stepsIndex++;
// If we have executed all positions of steps[]
if (stepsIndex > stepsCount) {
// Set the index to 0 to restart the process
stepsIndex = 0;
}
}
stepper.run();
}
/*
* Converts degrees to steps
*
* 28BYJ-48 motor has 5.625 degrees per step
* 360 degrees / 5.625 = 64 steps per revolution
*
* Example with degToSteps(45):
* (64 / 5.625) * 45 = 512 steps
*/
float degToSteps(float deg) {
return (stepsPerRevolution / degreePerRevolution) * deg;
}
change on code where appears “& # 9 1 ; ]” by “[]”