Hi all.......
I'm trying to control a dc motor to spin an aluminum disc at an exact speed using by varying its PWM duty cycle. The disc has 32 holes punched in it, with a IR LED/phototransistor pair making a beautiful square wave as the disc rotates.
Now, I'm trying to use this feedback to control the speed of the motor. I want the square wave from the rotary encoder to be 500Hz. Below is my first attempt at writing the control algorithm, but it doesn't work. The PWM duty cycle starts at 100%, but decrements every time a hole goes past the encoder, and resets back to 100% when it reaches 0%.
If someone could take a look and offer suggestions, I'd really appreciate it!
Thanks!
#include#include #include #include #include typedef uint8_t byte; typedef uint16_t word; #define aByte(bit) (1 << bit) // byte with bit set #define IRLedPin PA1 #define photoTransistorPin PA0 #define motorPin PB2 #define setPortAPinForOutput(pin) (DDRA |= aByte(pin)) #define setPortAPin(pin) (PORTA |= aByte(pin)) #define clearPortAPin(pin) (PORTA &= ~(aByte(pin))) #define setPortBPinForOutput(pin) (DDRB |= aByte(pin)) #define setPortBPin(pin) (PORTB |= aByte(pin)) #define clearPortBPin(pin) (PORTB &= ~(aByte(pin))) volatile byte overflows; #define desiredTicksPerInterrupt 5000 ISR(PCINT0_vect) { /* if timer's not running zero timer start it with app. prescaler (/8 i think; (20000000/8)/200 holes per second gives 12,500 max clock ticks between holes at slowest speed we care about, well within range of the 16-bit timer) if timer is running stop it decide whether running too fast or too slow, or if overflow happened, just max out pwm adjust pwm freq Want 500 holes per second So we want (20000000/8)/500 = 5000 clock ticks between interrupts. */ if(TCCR1B == 0x00 && !(PINA & (1 << photoTransistorPin))) //If timer is stopped and it was a falling edge { overflows = 0; //Reset overflows counter TCNT1 = 0x0000; //Reset timer TCCR1B = _BV(CS11); //Start timer with /8 prescaler } else if (!(PINA & (1 << photoTransistorPin))){ // If the timer isn't stopped... TCCR1B = ~_BV(CS11); //Stop timer. if (overflows > 0) //If overfow happened... { OCR0A = 0xFF; //Max out PWM. } else { //If it didn't... if(TCNT1 > desiredTicksPerInterrupt) { if(OCR0A + 1 <= 0xFF) { OCR0A++; //turn up the duty cycle } } if(TCNT1 < desiredTicksPerInterrupt) { OCR0A--; //turn down the duty cycle } } } } ISR(TIM1_OVF_vect) { overflows++; //increment overflows counter when an overflow happens } int main(void) { //set clock divider to /1 CLKPR = (1 << CLKPCE); CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0); setPortAPinForOutput(IRLedPin); setPortAPin(IRLedPin); setPortBPinForOutput(motorPin); TCCR0A = _BV(COM0A1) | _BV(WGM00); //Toggle OC0A on Compare Match, Set WGM00 for Phase Correct PWM TCCR0B = _BV(CS00); //Start clock, no prescaler OCR0A = 0xFF; //Start at 100% duty cycle for spin-up GIMSK = _BV(PCIE0); //Enable pin change interrupt 0 PCMSK0 = _BV(PCINT0); //Enable pin change interrupt on PA0 sei(); //Enable interrupts for(;;){ } return 0; /* never reached */ }