Introduction: $5 Stepper Driver
Note: I recently redesigned and improved the stepper driver, as this has no microstepping, current limiting, and is prone to change direction erratically. The improved version is here: https://www.instructables.com/id/45-better-stepper-driver/
I have wanted to make a 3D printer or a CNC for quite a while, but as I don't have a lot of money, nor can I frequently order components online, I always ran into one obstacle. Almost all projects required stepper drivers with step-direction control. Those sorts of parts aren't avaliabe at stores, and the cheapest and most popular are around $15 a piece. I don't want to spend nearly that much on a single component that could fry in a second, so I decided to make something a little cheaper and more expendable. I ended up deciding on making my driver with an attiny and separate H-bridge chip. It uses an attiny85, and the ever-common L293 motor driver. together, they cost less than $5, and need almost no support circuitry.
Step 1: Other Parts
All parts except the attiny and L293 are optional, but highly recommended. In quantity, most cost as little as a few cents.
1x >47uf capacitor-the bigger the better
8x ~1k ohm resistor-doesn't have to be 1K, any value 330-2K2 will probably work
1x 1N4001 diode-or any diode that can take >=1 amp, again, the bigger the better
protoboard-you could free-form it, but it's best to use protoboard/perfboard.
header pins-if you want to breadboard with the driver or make it easy to replace. I didn't use them, but its generally a good idea to do so.
IC sockets-for the two chips, one 8 pin, one 16 pin. Again, I didn't use them, but highly recommended.
Finially, you will need an arduino. Any flavor, homemade or whatever, as long as it has serial and an atmega it will work.
Step 2: Programming Attiny.
It's been shown many, many times in other tutorials, and its fairly simple. Here's a link to the original blog post about it: http://toasterbotics.blogspot.com/2011/08/using-arduino-with-attinys.html then here: http://toasterbotics.blogspot.com/2011/08/programming-attiny85-arduino-style.html
After you have some test code running, move on to the next step.
Step 3: Stepper Code.
Now, on to the code! Copy and past this into arduino IDE and upload.
This code is just a test, and will step the motor foward and backward to test the electronics. We'll upload the real code later.
Note that the step-direction input will not work with this code.
//this is a test of the driver. Note that if you change pins, you must also
//change them in the real code. NEVER change a pin to pin 2,
//as that pin is needed for incrementing the desired distance to move
byte stepporty;
float val = 15; //inverse of the speed, lower value means faster movement.
short x;
byte db = 4;
byte da = 3;
byte pb = 1;
byte pa = 0;
byte in = 5;//not used here
void setup() {
pinMode(db, OUTPUT);
pinMode(da, OUTPUT);
pinMode(pb, OUTPUT);
pinMode(pa, OUTPUT);
pinMode(in, INPUT);
}
void loop() {
for(int x = 0; x < 408; x++){ //steps 408 half-steps, or one full rotation on 200 step-rev motors (as most of the NEMA motors are)
fwd();
delay(val);
}
delay(200);
for(x = 0; x < 408; x++){
bck();
delay(val);
}
delay(200);
}
void fwd() {
switch (stepporty) {
case 0:
one();
stepporty = 1;
break;
case 1:
onehalf();
stepporty = 2;
break;
case 2:
two();
stepporty = 3;
break;
case 3:
twohalf();
stepporty = 4;
break;
case 4:
three();
stepporty = 5;
break;
case 5:
threehalf();
stepporty = 6;
break;
case 6:
four();
stepporty = 7;
break;
case 7:
fourhalf();
stepporty = 0;
break;
} }
void bck() {
switch (stepporty) {
case 2:
one();
stepporty = 1;
break;
case 3:
onehalf();
stepporty = 2;
break;
case 4:
two();
stepporty = 3;
break;
case 5:
twohalf();
stepporty = 4;
break;
case 6:
three();
stepporty = 5;
break;
case 7:
threehalf();
stepporty = 6;
break;
case 0:
four();
stepporty = 7;
break;
case 1:
fourhalf();
stepporty = 0;
break;
} }
void fourhalf(){
digitalWrite(db, HIGH);//4
digitalWrite(da, LOW);
digitalWrite(pb, LOW);
digitalWrite(pa, HIGH);
}
void four(){
digitalWrite(db, HIGH);
digitalWrite(da, LOW);
digitalWrite(pb, LOW);
digitalWrite(pa, LOW);
}
void threehalf(){
digitalWrite(db, HIGH);
digitalWrite(da, HIGH);
digitalWrite(pb, LOW);
digitalWrite(pa, LOW);
}
void three(){
digitalWrite(db, LOW);
digitalWrite(da, HIGH);
digitalWrite(pb, LOW);
digitalWrite(pa, LOW);
}
void twohalf(){
digitalWrite(db, LOW);
digitalWrite(da, HIGH);
digitalWrite(pb, HIGH);
digitalWrite(pa, LOW);
}
void two(){
digitalWrite(db, LOW);
digitalWrite(da, LOW);
digitalWrite(pb, HIGH);
digitalWrite(pa, LOW);
}
void onehalf(){
digitalWrite(db, LOW);
digitalWrite(da, LOW);
digitalWrite(pb, HIGH);
digitalWrite(pa, HIGH);
}
void one(){
digitalWrite(db, LOW);//1
digitalWrite(da, LOW);
digitalWrite(pb, LOW);
digitalWrite(pa, HIGH);
}
Step 4: Circuit
Not much of a circuit, just connecting pins and some resistors. I don't have any schematic/CAD software, and can't seem to get any to work, so it's hand drawn. I would prototype on a breadboard before soldering, to correct for your motor phase, and make sure the attiny is programmed correctly. The numbers in boxes are paired, and these are connected. I find it much less confusing this way than drawing each wire. All resistors are 1K except the 10K and 33K in the upper-right hand corner. Note that all pins except the dir-step pin can be re-ordered, but you MUST use only pins 0,1,3, and 4. "IN" MUST remain 1
i would also suggest some high-wattage resistors (maybe about 10ohm worth) between the supply and diode, just to make sure the current stays down.
Step 5: Real Code
One the electronics are working, upload this code. Then, connect the step-direction pins to your input (I used an arduino running grbl). Once you've checked that this code is working, solder up your circuit. and test it again.
byte stepporty;//what part of the step to go to
byte val = 3;//delay between steps
byte db = 4;//db, da, pb, pa, and in can all be any pin EXCEPT pin 7 (digital pin2, andalog in1)on the standard pinout
//that pin MUST be the clock/step input pin.
//db is out4
byte da = 3;//out3
byte pa = 0;//out1
byte pb = 1;//out2
byte in = 1;//direction input pin DO NOT CHANGE THIS
long dsd = 100;//where we want the motor to be
long pos;//where it is
void setup() {
// Serial.begin(9600);
attachInterrupt(0, count, RISING);//executes "void count" whenever pin 7 (interrupt 0) is brought HIGH
pinMode(db, OUTPUT);//sets outputs and inputs
pinMode(da, OUTPUT);
pinMode(pb, OUTPUT);
pinMode(pa, OUTPUT);
// pinMode(in, INPUT);
}
void loop() {//this just checks to see if it needs to move foward or backward and moves accordingly
// if (dsd != pos){
if(dsd < pos){
bck();
delay(val);
}
if (dsd > pos){
fwd();
delay(val);
// }
}}
void count(){//this increments the desired position whenever this pin is brought high
//it must use the same pin because
//the attiny85 only has 5 pins (though reset COULD be used as an i/o pin, it cannot
//be reprogramed after this is done.
if (analogRead(in)>1){//this determines whether direction is high or low
//dont ask me why one works, but it does. After about 7 straight hours of trying to fix
//this ONE line of code, I dont give a rat's behind WHY it works as long as it does
dsd-=1; //foward if positive
}else{
dsd+=1;//backward if its not
}}
void fwd() {//both fwd and bck figure which part of the step is next, and increment the position
//and power the motor accordingly.
pos++;
switch (stepporty) {
case 0:
one();
stepporty = 1;
break;
case 1:
onehalf();
stepporty = 2;
break;
case 2:
two();
stepporty = 3;
break;
case 3:
twohalf();
stepporty = 4;
break;
case 4:
three();
stepporty = 5;
break;
case 5:
threehalf();
stepporty = 6;
break;
case 6:
four();
stepporty = 7;
break;
case 7:
fourhalf();
stepporty = 0;
break;
} }
void bck() {
pos--;
switch (stepporty) {
case 2:
one();
stepporty = 1;
break;
case 3:
onehalf();
stepporty = 2;
break;
case 4:
two();
stepporty = 3;
break;
case 5:
twohalf();
stepporty = 4;
break;
case 6:
three();
stepporty = 5;
break;
case 7:
threehalf();
stepporty = 6;
break;
case 0:
four();
stepporty = 7;
break;
case 1:
fourhalf();
stepporty = 0;
break;
} }
void fourhalf(){
digitalWrite(db, HIGH);//4
digitalWrite(da, LOW);
digitalWrite(pb, LOW);
digitalWrite(pa, HIGH);
}
void four(){
digitalWrite(db, HIGH);
digitalWrite(da, LOW);
digitalWrite(pb, LOW);
digitalWrite(pa, LOW);
}
void threehalf(){
digitalWrite(db, HIGH);
digitalWrite(da, HIGH);
digitalWrite(pb, LOW);
digitalWrite(pa, LOW);
}
void three(){
digitalWrite(db, LOW);
digitalWrite(da, HIGH);
digitalWrite(pb, LOW);
digitalWrite(pa, LOW);
}
void twohalf(){
digitalWrite(db, LOW);
digitalWrite(da, HIGH);
digitalWrite(pb, HIGH);
digitalWrite(pa, LOW);
}
void two(){
digitalWrite(db, LOW);
digitalWrite(da, LOW);
digitalWrite(pb, HIGH);
digitalWrite(pa, LOW);
}
void onehalf(){
digitalWrite(db, LOW);
digitalWrite(da, LOW);
digitalWrite(pb, HIGH);
digitalWrite(pa, HIGH);
}
void one(){
digitalWrite(db, LOW);//1
digitalWrite(da, LOW);
digitalWrite(pb, LOW);
digitalWrite(pa, HIGH);
}
Step 6: El Fin
Now that you finished, bask in the sweet glory of your easy to move stepper motors. I would add some duct tape so that there's no way that the pins could short, because it's not good for microcontrollers when they're exposed directly to power. When you connect the drivers to power, make sure to connect ground, then 5V, then motor - to ground, then motor +. If the steppers move 50 steps (1/4 turn on 200 step motors), then check that you connected 5V first, as when the attinys recieve logic power, they will quickly take 50 steps. This will not affect your accuracy if everthing is connected properly, but will if you connect power out of order.

Participated in the
Arduino Contest

Participated in the
Epilog Challenge V
19 Comments
7 years ago on Introduction
Very interesting. I have a suggestion though. Currently your code takes up some 1600 bytes so it would fit in an attiny85 with room to spare.
However, if you want to put it in an attiny 25 or 45 or maybe even a 13, it pays to do direct portmanipulation, each of your step routines like void "two()" takes 38 bytes. With direct portmanipulation that takes only 8 bytes. As you have 8 such routines, that would save 240 bytes to start with. That is already 1/6th of yr current program.
Setting of yr pinMode's takes up 166 bytes. If you would replace that by 1 write to the port direction register DDRB that would take only 4 bytes, so there is already a saving of 402 bytes. That is slightly over a quarter of your program.
Dont get me wrong, not critisizing you at all and in an Attiny85 there might be ample space, but just in case there is someone who has an Attiny25 lying around, with just some simple changes he or she would have a lot more space available for some other things.
Now you are trying to preserve pin2 so you would probably have to OR your portB with a mask rather than a direct write, but still that saves space over pinMode writes :-)
It has the added benefit that the pins change all at the same time which (in theory) should make yr motor run smoother :-)
9 years ago on Introduction
Do you know if this will work with an Arduino Mega im using it to control 3 motors?
Reply 9 years ago on Introduction
If you mean to build three of these drivers and connect it to a mega, yes, that would work, though I would recommend the "$4.5 better stepper driver" instructable, because, as the name implies, it's much better and slightly cheaper. If you meant replacing the attinies with a mega, you could, but you'd have to modify the code, and I would suggest adding other features like microstepping and current control.
Reply 9 years ago on Introduction
Yeah im just making three of these drivers to connect to one mega :), thanks ill give it a look
9 years ago on Introduction
I'm unable to understand the schematics.
As per your advice I have got a pre boot-loaded Atmega328p chip, but have failed to get better drivers like A4983 . All I have right now is L293D , so Can I use Arduino , Atmega 328 p and then further grbl controller to control my stepper by sending Gcodes ?
If so is the case please explain me how Arduino and Atmega will be connected as that is not much clearer with the pictures you have uploaded.
I'm pre-assuming the following steps that I need to do to run atleast one motor :
-Make sure grbl firmware is already uploaded to arduino
-Program i.e. upload the "Real Code" (as per step 5 of your instructable) to ATmega328p
-Connect L293d as per data sheet to four wire bipolar stepper wire and ATmega328p (or ATtiny2313, as in your instructable)
-Open grbl controller and viola , your motor should be running up.
Now it would really be a favor if you could just let me know the proper connection of Atmega328 with Arduino (i.e. the inputs )
Reply 9 years ago on Introduction
That could work, but as I've had some problems with this driver, I would modify the code significantly. This driver uses an attiny 85, which does not have enough pins to drive the four motor wires plus two inputs, so I made one pin do double-duty. It works most of the time, but occasionally, the direction spontaneously flips. Since the 328 has tons of pins to spare, you could make a better driver. The code for the $4.5 diver with the L2619 is "bettter", and can be quickly adapted for a different processor and driver. If I have the time, I'll re-write some code, and make a diagram, but I'm occupied for most of the next few months, starting saturday.
If I can't get to it, just use the stepper librairy for arduino, and write a program that counts up or down on the interrupts, using another pins input for direction.
Reply 9 years ago on Introduction
Actually, immediately after posting that I noticed that no, the 328 cannot use the same code, even should you want to, as it does not have any analog pins and interrputs on the same pin, which is required for this code.
9 years ago on Introduction
Hey Hi, the schematics are not very clear , from where you got the schematics , I saw the data sheet of L298 and to me it seems very much similiar to l293D , except for the fact that L293D has 16 pins.Moreover both the pins have 4 inputs .
Your both the drivers are awesome , you must include a video running all four motors for the 3d printer with grbl or any other software you use , it would be a great learning experience for noobs like me .
Reply 9 years ago on Introduction
I would not use the l293 or 293d as neither has current regulation, and thus neither can do microstepping, unless complemented with a chip that can (an a4989 should actually be able to do so).
If you can get some a4989s, you should definitely use those, as their performance will be much greater than my driver.
Also, what is unclear about the schematic? It seems fairly straightforward, it needs an oscillator resistor, connections to current sense resistors, an h bridge and power.
9 years ago on Introduction
Can i use atmega8 in stead of attiny??? if yes then how?
Reply 9 years ago on Introduction
I would think so, though I haven't tried it. You would want to use different code, as the code for this specific project uses a single pin for step and direction, which makes it prone to read direction incorrectly. I have another instructable which uses an attiny 2313, and more importantly, separate step-dir input pins.
https://www.instructables.com/id/45-better-stepper-driver/
Using this instructable: https://www.instructables.com/id/Arduino-on-all-sorts-of-Atmels/step1/A-list-of-that-Atmels-can-be-programmed-with-this-/
You should be able to use the same code on your atmega without a problem. If you want to use L293 instead of L2619, then just change out the line in the code in "void count" that checks the analogRead pin, and replace it with "if (digitalRead(directionpin)==0){" replacing "directionpin" with the pin number you chose.
I would, however, suggest using the same controllers, as though it SHOULD work, I have no idea if it will.
9 years ago on Introduction
Using numbers to indicate which pins are connected is a bit confusing as they could be pin numbers, which is what I thought at first. Usually we use small letters to do this (a) to (a) (b) to (b) ,etc. Just for future reference. Thanks for the 'able & the clarification ! CHEERS!!
9 years ago on Introduction
Can't follow your schematic at all & a Google search for L298 doesn't have same DIP package or pinout. Can you please clarify ?
Reply 9 years ago on Introduction
In the schematic, anywhere where a wire goes to a box with a number, just put a jumper between the two boxes. If it's something else thats confusing, then could you please clarify what you're asking about?
jumpers 5,6,7, and 8 go to the stepper.
9 years ago on Introduction
Could it be a L293 IC ?
Reply 9 years ago on Introduction
Yes, it is a 293. For some reason I can never remember which one it is. I'll change it in the instructable presently.
Reply 9 years ago on Introduction
It's changed now. Thanks for pointing that out.
9 years ago on Introduction
Thanks much!
9 years ago on Introduction
https://www.instructables.com/id/OA7UYG1H143LO81/?editMode=true
take a look