Drive a Stepper Motor With an AVR Microprocessor
by The Real Elliot in Circuits > Robots
175545 Views, 137 Favorites, 0 Comments
Drive a Stepper Motor With an AVR Microprocessor
Got some scavenged stepper motors from printers/disk drives/etc lying around?
Some probing with an ohmeter, followed by some simple driver code on your microprocessor and you'll be stepping in style.
Some probing with an ohmeter, followed by some simple driver code on your microprocessor and you'll be stepping in style.
Get to Know Steppers
Basically, you're going to need to figure out where all the little wires go.
First step is to figure out if it's a unipolar or bipolar motor. Have a look at Jones on Steppers for some deeper background, then at Ian Harries' Site for a simple method to figure out an unknown motor.
Read up a bit, then join me in a walkthrough of this motor I got for cheap. (They're on sale for $0.99 right now. They're small, relatively light, but don't have much torque. Don't know what it'll be good for yet.)
First step is to figure out if it's a unipolar or bipolar motor. Have a look at Jones on Steppers for some deeper background, then at Ian Harries' Site for a simple method to figure out an unknown motor.
Read up a bit, then join me in a walkthrough of this motor I got for cheap. (They're on sale for $0.99 right now. They're small, relatively light, but don't have much torque. Don't know what it'll be good for yet.)
Find Common Ground
So you've got five (or four, or six) wires. Your motor's going to have two halves, and you can probably even tell just by looking which side each wire belongs to.
If you're only looking at four wires, you're in luck -- it's a bipolar motor. All you have to do is figure out which two pairs of wires go together.
If you've got a unipolar motor, or more than 4 wires, you're going to have to break out your ohmeter. What you're looking for is the common (ground) wire for each half. You can tell which is ground in a bipolar motor because it has half the resistance to either of the poles than the poles do across themselves.
Pictured is my notes from hooking up wires to wires and noting the resistance (or if they're connected at all). You can see that White is the ground for the bottom trio b/c it has half the resistance to Red or Blue that they have to each other.
(This motor's strange and doesn't have a center tap on the top magnet coil. It's like it's half-bipolar, half-unipolar. Maybe you could use this to sense rotation in the Red-White-Blue coil when the Black-Yellow coil is being driven.)
If you're only looking at four wires, you're in luck -- it's a bipolar motor. All you have to do is figure out which two pairs of wires go together.
If you've got a unipolar motor, or more than 4 wires, you're going to have to break out your ohmeter. What you're looking for is the common (ground) wire for each half. You can tell which is ground in a bipolar motor because it has half the resistance to either of the poles than the poles do across themselves.
Pictured is my notes from hooking up wires to wires and noting the resistance (or if they're connected at all). You can see that White is the ground for the bottom trio b/c it has half the resistance to Red or Blue that they have to each other.
(This motor's strange and doesn't have a center tap on the top magnet coil. It's like it's half-bipolar, half-unipolar. Maybe you could use this to sense rotation in the Red-White-Blue coil when the Black-Yellow coil is being driven.)
Figure Out the Stepping Order
I was going to drive this motor as a bipolar one, so I'm ignoring the White ground wire. I've only got four wires to worry about.
You might want to run your unipolar motor as bipolar anyway, because it uses the whole coil in both phases instead of alternating between the two halves of each coil. More coil = more torque.
Run current through a pair (noting the polarity you chose) and then run current through the other pair at the same time. When you hook up the second pair, watch which way the motor turns. Write this down.
Now reverse the polarity on the first pair you chose. Then hook up the second pair again with their polarity also reversed. Note the direction.
From this you should be able to figure out the sequence for rotating the motor in either direction. In my example, both ended up turning counterclockwise, so stepping through the sequence in the same way I chose will step the motor CCW.
You might want to run your unipolar motor as bipolar anyway, because it uses the whole coil in both phases instead of alternating between the two halves of each coil. More coil = more torque.
Run current through a pair (noting the polarity you chose) and then run current through the other pair at the same time. When you hook up the second pair, watch which way the motor turns. Write this down.
Now reverse the polarity on the first pair you chose. Then hook up the second pair again with their polarity also reversed. Note the direction.
From this you should be able to figure out the sequence for rotating the motor in either direction. In my example, both ended up turning counterclockwise, so stepping through the sequence in the same way I chose will step the motor CCW.
Taking the Motor for a Test Drive
If you're not already tooled up for microprocessor programming, you could do worse than the Ghetto Development Kit or any of the various PIC programmers.
Hook up the wires directly up to your microproc and burn it up with the following code:
How simple is that code? Really simple.
All it does is make some nice definitions so I could refer to the wires by color rather than their pin-names, and then it toggles them on in sequence with an adjustable delay in between. For starters, I selected a half-second delay between steps.
See the short video for the results. If you're really on your game, count the number of steps per cycle to figure out the motor's single-stepping angular resolution.
(Oh yeah. PS. Drives with no load at 3.6v easily. See battery in video.)
Hook up the wires directly up to your microproc and burn it up with the following code:
/* Playing with getting the small stepper motors driven. */ /* Include delay function */#define F_CPU 1000000UL #include /* Pin defs for ATTiny2313 */ /* Clockwise order */ #define BLUE _BV(PB0) #define BLACK _BV(PB1) #define RED _BV(PB2) #define YELLOW _BV(PB3) #define DELAY 200 /* milliseconds between steps */ int main(void){ DDRB = 0xff; /* Enable output on all of the B pins */ PORTB = 0x00; /* Set them all to 0v */ while(1){ /* main loop here */ PORTB = BLUE; _delay_ms(DELAY); PORTB = BLACK; _delay_ms(DELAY); PORTB = RED; _delay_ms(DELAY); PORTB = YELLOW; _delay_ms(DELAY); } }
How simple is that code? Really simple.
All it does is make some nice definitions so I could refer to the wires by color rather than their pin-names, and then it toggles them on in sequence with an adjustable delay in between. For starters, I selected a half-second delay between steps.
See the short video for the results. If you're really on your game, count the number of steps per cycle to figure out the motor's single-stepping angular resolution.
(Oh yeah. PS. Drives with no load at 3.6v easily. See battery in video.)
Downloads
Swing It Back and Forth
So you've got it running clockwise. Anything more interesting?
A little code-cleanup, and we can run it back and forth.
I put the clockwise sequence into an array so that you can step through the phases with a simple for loop. Now you can run the loop up or down to go clockwise or counterclockwise.
See the racy video for the back-and-forthing.
A little code-cleanup, and we can run it back and forth.
I put the clockwise sequence into an array so that you can step through the phases with a simple for loop. Now you can run the loop up or down to go clockwise or counterclockwise.
int main(void){ const uint8_t delay = 50; const uint8_t clockwise[] = {BLUE, BLACK, RED, YELLOW}; uint8_t i; DDRB = 0xff; /* Enable output on all of the B pins */ PORTB = 0x00; /* Set them all to 0v */ while(1){ /* main loop here */ for ( i=0; i<=3; i++ ){ /* step through the colors clockwise */ PORTB = clockwise[i]; _delay_ms(delay); } for ( i=3; i>=0; i-- ){ /* step through the colors ccw */ PORTB = clockwise[i]; _delay_ms(delay); } }}
See the racy video for the back-and-forthing.
Downloads
I Never Half-step, Because I'm Not a Half-stepper...
Quest lyric aside, half-stepping your motor is where it's at. You get more peak current, more instantaneous torque, and twice the angular resolution.
Half-stepping in a nutshell: Instead of Blue, Black, Red, Yellow, you drive the motor with Blue, Blue+Black, Black, Black+Red, Red, Red+Yellow, Yellow, Yellow+Blue. The upshot is that for half the time you're engaging both magnets at once.
And during the times that both sets are engaged, the motor points halfway between the two, shrinking the angle between "steps" and making the motor turn more smoothly. Can you tell from the video? I'm not sure...
Now the part of the code that does the half-stepping looks like this:
The first PORTB command sets a single pole to positive and all the rest to negative. Then it waits. Then the second PORTB command sets a second pole (on the other winding) to positive, engaging both windings for 1.4x the torque (and 2x the current).
A full program listing is attached below. Two arrays are now defined (clockwise, counterclockwise) and both have 5 elements each to allow for the i+1 entry in the halfStepping function.
Half-stepping in a nutshell: Instead of Blue, Black, Red, Yellow, you drive the motor with Blue, Blue+Black, Black, Black+Red, Red, Red+Yellow, Yellow, Yellow+Blue. The upshot is that for half the time you're engaging both magnets at once.
And during the times that both sets are engaged, the motor points halfway between the two, shrinking the angle between "steps" and making the motor turn more smoothly. Can you tell from the video? I'm not sure...
Now the part of the code that does the half-stepping looks like this:
void halfStepping(uint16_t delay, uint8_t direction[]){ uint8_t i; for ( i=0; i<=3; i++ ){ PORTB = direction[i]; /* single-coil part */ _delay_ms(delay); PORTB |= direction[i+1]; /* add in half-step */ _delay_ms(delay); }}
The first PORTB command sets a single pole to positive and all the rest to negative. Then it waits. Then the second PORTB command sets a second pole (on the other winding) to positive, engaging both windings for 1.4x the torque (and 2x the current).
A full program listing is attached below. Two arrays are now defined (clockwise, counterclockwise) and both have 5 elements each to allow for the i+1 entry in the halfStepping function.
Add a Motor Driver
So far so good.
Only problem is that the motor doesn't seem to have all that much torque, which could be due to the fact that the microprocessor will only put out ~50mA per pin. The obvious next step would be to hook it up to a motor driver to supply it with more juice.
But then a little thinkin': I'm only driving it with 5v, and the coil-winding resistance is ~125 ohms. Which means that the motor's only drawing 40mA per pin, and it should be driven just fine by the (beefy!) AVR chip.
So to get more voltage driving the motor, I hooked it up to a SN754410 H-bridge chip. The circuit is pretty simple. Each pin from the AVR goes to an input, and the corresponding output pins go to the motor. The chip needs 5v for the logic section, and can take a lot more voltage in the motor section.
Running it on 11.25v (three 3.6v batteries) helped a bit. Noticeably more torque to my finger, but it's still not a powerhouse. Not bad for a motor which is smaller than a nickel, though. And now the circuit's become a general-purpose bipolar stepper motor driver.
Added Nov 29: Ran the motor last night at 12v for a while and it started to get hot. I'm not sure if it was a resonant frequency problem or if it was simply too much current for the windings. Either way, be a bit careful if you're driving this little motor with bigger voltages.
Only problem is that the motor doesn't seem to have all that much torque, which could be due to the fact that the microprocessor will only put out ~50mA per pin. The obvious next step would be to hook it up to a motor driver to supply it with more juice.
But then a little thinkin': I'm only driving it with 5v, and the coil-winding resistance is ~125 ohms. Which means that the motor's only drawing 40mA per pin, and it should be driven just fine by the (beefy!) AVR chip.
So to get more voltage driving the motor, I hooked it up to a SN754410 H-bridge chip. The circuit is pretty simple. Each pin from the AVR goes to an input, and the corresponding output pins go to the motor. The chip needs 5v for the logic section, and can take a lot more voltage in the motor section.
Running it on 11.25v (three 3.6v batteries) helped a bit. Noticeably more torque to my finger, but it's still not a powerhouse. Not bad for a motor which is smaller than a nickel, though. And now the circuit's become a general-purpose bipolar stepper motor driver.
Added Nov 29: Ran the motor last night at 12v for a while and it started to get hot. I'm not sure if it was a resonant frequency problem or if it was simply too much current for the windings. Either way, be a bit careful if you're driving this little motor with bigger voltages.
The End
So what did I learn? Driving a stepper motor with an AVR (and an H-bridge chip) is pretty easy, even in the "fancy" half-stepping mode.
Not sure what I'll do with the little stepper motors just yet, though. Any suggestions?
Not sure what I'll do with the little stepper motors just yet, though. Any suggestions?