Control Stepper Motor - using PWM and timer2

Hello Members,
I hope this is the correct forum for this question.
I found the code sample below using timer2 somewhere in the Arduino forums.
I am using an Arduino Uno and a DVR8825 stepper driver chip (from Pololu).
The code below does what it describes - the motor speeds up, slows down, etc.

I would like to use the same concept (setting bits in registers, etc) to do the following:
press button, start the motor (at some selected speed) - motor moves slider until slider hits limit switch.
Motor either reverses, runs for 3 steps (in microstep mode - m0 = 1, m1 =0, m2 = 1) and stops, ready to run in
opposite direction. OR motor stops, reverse direction,starts and runs for 3 steps (in microstep mode - m0 = 1, m1 =0, m2 = 1) and stops, ready to run in opposite direction, runs in opposite direction, hits limit switch, etc.

The motor seems to take the direction change "on the fly" without stopping ok. I have implented the above functionality using the Adafruit MotorShield V2, but would like to use the DVR8825 since it has higer current capability.

I have tried a variation of the code below - moving the OCR2A,B code out of the loop function, and into a
motor run function, but have not figured out how to count steps when set in the 1/32 step mode (slowest for the DVR8825, dependent on the PWM freq, etc.)

Any tips will be helpful. I can attach my bad code if desired.

Thanks,
ewholz

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--;
}

That seems a very complicated way to get a stepper motor to work. Try this simple demo code - it should be easy to understand.

// testing a stepper motor with a Pololu A4988 driver board or equivalent
// on an Uno the onboard led will flash with each step
// as posted on Arduino Forum at http://forum.arduino.cc/index.php?topic=208905.0

byte directionPin = 6;
byte stepPin = 5;
int numberOfSteps = 100;
byte ledPin = 13;
int pulseWidthMicros = 20;  // microseconds
int millisbetweenSteps = 25; // milliseconds


void setup() 
{ 

  Serial.begin(9600);
  Serial.println("Starting StepperTest");
  digitalWrite(ledPin, LOW);
  
  delay(2000);

  pinMode(directionPin, OUTPUT);
  pinMode(stepPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  
 
  digitalWrite(directionPin, HIGH);
  for(int n = 0; n < numberOfSteps; n++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(pulseWidthMicros);
    digitalWrite(stepPin, LOW);
    
    delay(millisbetweenSteps);
    
    digitalWrite(ledPin, !digitalRead(ledPin));
  }
  
  delay(3000);
  

  digitalWrite(directionPin, LOW);
  for(int n = 0; n < numberOfSteps; n++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(pulseWidthMicros);
    digitalWrite(stepPin, LOW);
    
    delay(millisbetweenSteps);
    
    digitalWrite(ledPin, !digitalRead(ledPin));
  }
  
}

void loop() 
{ 

}

Another thing to consider is using the AccelStepper library.

I just realised this is essentially the same question as in your other Thread. Don't waste our time by double posting - keep everything in one place.

...R

Hello Robin2
You are correct the code is tricky. But fun (I like to do things the HARD way XD.
I will try your sample - and see how it works.
Thanks again, I appreciate the information and help.

ewholz

sorry for the double post., I was not sure if I should post in the "Programming" area - or the "Motors, etc" area.
I will try to be more careful in future.

thanks ,

ewholz

ewholz:
sorry for the double post., I was not sure if I should post in the "Programming" area - or the "Motors, etc" area.

Where is less important than keeping things together. If you click Report to Moderator in this post (mine, not yours) you can ask the moderator to merge this back with the other Thread.

...R