I've gotten so much help from this forum that I thought I might give something back in return.
I recently began tinkering with the Pololu DRV8825 stepper motor driver. It turns out to be a very nifty solution. Very clean and easy to write code for. Below is my test loop. Two things to note: 1) NO LIBRARIES!, and 2) NO INTERRUPTS!. Yup, by using the hardware PWM off Timer2, all one needs to do is set OCR2A and OCR2B and you get variable speed. Many thanks to Nick for the nifty solution to that problem. I got it off his website.
Now, this approach does have some downside. In exchange for the extreme simplicity of using the hardware PWM and the timer, one gives up the capability of gang-of-motors. That's fine for my project. I just need to drive two motors simultaneously. The equivalent use of Timer0 will take care of that. I'm not worried about millis() or micros(). Got my own cheap_delay().
So, anyway, here's the code.
/*
Using Timer 2. 1024 prescale, F_CPU/1024 divisor, 50% duty cycle:
[calculated]
base freq OCR2A OCR2B pulse width(ms) pin3 freq(Hz) RPM (@200 steps/rev)
--------- ----- ----- --------------- ------------- --------------------
61 255 127 8 61 18
120 129 64 4 120 36
240 64 32 2 240 72
480 32 15 1 489 144
--> 960 15 7 0.5 977 288 <--
| 1920 7 3 0.26 1954 576 |
| |
--> 960 seems to be about the limit of the 28BYG301 <----------
*/
// As currently configured, LOW on the direction pin is CCW.
// HIGH reverses to CW. Default to LOW for start.
int main( void )
{
int direction = 0; // 0 is LOW, 1 is HIGH.
// Setup the outputs: pin 3 for STEP, pin 4 for DIR. Per DVR8825 pinout.
DDRD |= (1 << 3); // Enable pin 3 for OUTPUT to step the DRV8825
DDRD |= (1 << 4); // Enable pin 4 for OUTPUT for step direction.
// Setup Timer2: fast PWM, clear OC2B on compare, 1024 prescale.
TCCR2A |= (1 << WGM20) | (1 << WGM21) | (1 << COM2B1 );
TCCR2B |= (1 << WGM22) | (1 << CS22 ) | (1 << CS21) | (1<< CS20);
while(1)
{
// Speed up.
for( int freq = 61; freq < 961; freq += 10 )
{
OCR2A = ((F_CPU / 1024) / freq) - 1;
OCR2B = ((OCR2A + 1) / 2) - 1;
cheap_delay( 100000 );
}
// Slow down.
for( int freq = 960; freq > 60; freq -= 10 )
{
OCR2A = ((F_CPU / 1024) / freq) - 1;
OCR2B = ((OCR2A + 1) / 2) - 1;
cheap_delay( 100000 );
}
// Reverse direction.
if( direction ) // Direction is HIGH (CW)
{
PORTD &= ~(1 << 4); // Set DIR pin LOW.
direction = 0; // Record for the next pass thru the test loop.
}
else // Direction is LOW (CCW)
{
PORTD |= (1 << 4 ); // Set DIR pin HIGH.
direction = 1; // Record for the next pass thru the test loop.
}
}
}
void cheap_delay( volatile unsigned long count )
{
while( count > 0 ) count--;
}