Motor Control

The motor is controlled with an ATTiny13. We PWM the motor driver’s enable line, with an external speed control via an ADC.  Motor speed and direction are measured using a pair of photo-interrupters and a lego pulley to make a simple quadrature encoder.  The encoder is read with a little interrupt routine on the Tiny.  By watching the rising and falling edges of one output and testing the state of the other,we can determine direction and update a counter accordingly.  When the counter exceeds a set value we reverse!

Code after the break.

#define F_CPU 9600000UL
#include 
#include 
#include 

#define PWM PB0
#define DIRECTION PB1
#define QUAD_B PB2
#define QUAD_A PB3
#define SPEED_CONTROL PB4
#define LEFT 1
#define RIGHT 0

int i;
int direction;
int position;
int maxPosition;

int main(void)
{
  DDRB |= ((1 << PWM) | (1 << DIRECTION));
  
  TCCR0A |= ((1 << COM0A1) |      // Set up PWM
             (1 << COM0A0) |      // COM0A1 - COM0A0 (Set OC0A on 
             (1 << WGM01)  |      // Compare Match, clear OC0A at TOP)
             (1 << WGM00));       // WGM01 - WGM00 (set fast PWM)
  OCR0A   = 0;                    // initialize Output Compare 
                                  // Register A to 0
  TCCR0B |= (1 << CS01);          // Start timer at Fcpu / 256
  
                                  // Set up ADC
  ADCSRA |= (1 << ADEN) |         // Analog-Digital enable bit
            (1 << ADPS1) |        // set prescaler to 8 (clock/8)
            (1 << ADPS0);         // set prescaler to 8 (clock/8)
  
  ADMUX |=  (1 << ADLAR) |        // AD result store in (more 
                                  // significant bit in ADCH)
            (1 << MUX1);          // Choose AD input AD2 (BP 4)
  
                                  // Set up quadrature interrupt
  PCMSK |= (1 << QUAD_A);         // Pin change interrupt QUAD_A
  GIMSK |= (1 << PCIE);           // Enable pin change interrupts
  
  direction = LEFT;               // Init drive variables
  position = 0;
  maxPosition = 32;               // could be changed with a control
  
  sei();                          // Enable interrupts
  
  while(1)
  {                               // Read speed control pot
    ADCSRA |= (1 << ADEN);        // Analog-Digital enable bit
    ADCSRA |= (1 << ADSC);        // Discard first conversion
    while (ADCSRA & (1 << ADSC)); // wait until conversion is done
    ADCSRA |= (1 << ADSC);        // start single conversion
    while (ADCSRA & (1 << ADSC)); // wait until conversion is done
    ADCSRA &= ~(1 << ADEN);       // shut down the ADC
    OCR0A = ADCH;
    _delay_ms(50);
  }
}

ISR (PCINT0_vect)
{                                 // quadrature decoder
  if(PINB & (1 << QUAD_A))        // on the rising edge of A
    if(PINB & (1 << QUAD_B))      // if B is high...
      ++position;                 // ...we are going right
    else                          // if B is low...
      --position;                 // ...we are going left
  else                            // on the falling edge of A
    if(PINB & (1 << QUAD_B))      // if B is high...
      --position;                 // ...we are going left
    else                          // if B is low...
      ++position;                 // ...we are going right
      
  if(position < 0)                // switch directions at
    PORTB &= ~(1 << DIRECTION);   // position extremes
  else if(position > maxPosition)
    PORTB |= (1 << DIRECTION);
}
Comments (View)
blog comments powered by Disqus
hit counter
Provided by website-hit-counters.com .