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);
}
| Provided by website-hit-counters.com . |