/******************************************************************************
 Title:    ADC -> PWM
 Author:   rue_mohr
 Date:     Aug 19 2005
 Software: AVR-GCC 3.3 
 Hardware: atmega32
  
     speed input PA0 (analog, 0 to 5V input)
     
     forward pwm PD7 -> BLI
     reverse pwm PB3 -> BHI   
     dir         PB0 -> ALI
                 +5V -> AHI
                 
what this should do:
when you turn the pot one way, the motor shoudl go forward, at a variable speed
when you turn the pot the other way, the motor shoudl go backward, at a variable speed
center is stopped, goes up as you get away from center
    
*******************************************************************************/
#include<avr/io.h>

#define Forward            1
#define Reverse            0

#define OUTPUT             1
#define INPUT              0

void pwm_init( );
void adc_init( );
int  Analog  ( uint8_t n);
void SetPWM  ( uint8_t channel, uint8_t value) ;
void SetDir  ( uint8_t dir );
void SetSpeed ( int Speed );


int main (void)  {
 
  DDRA = (INPUT << PA0 | INPUT << PA1 |INPUT << PA2 |INPUT << PA3 |INPUT << PA4 |INPUT << PA5 |INPUT << PA6 |INPUT << PA7);
  DDRB = (OUTPUT << PB0 | INPUT << PB1 |INPUT << PB2 |OUTPUT << PB3 |INPUT << PB4 |INPUT << PB5 |INPUT << PB6 |INPUT << PB7);
  DDRC = (INPUT << PC0 | INPUT << PC1 |INPUT << PC2 |INPUT << PC3 |INPUT << PC4 |INPUT << PC5 |INPUT << PC6 |INPUT << PC7);
  DDRD = (INPUT << PD0 | INPUT << PD1 |INPUT << PD2 |INPUT << PD3 |INPUT << PD4 |INPUT << PD5 |INPUT << PD6 |OUTPUT << PD7);        
  
  adc_init();          
  pwm_init();
  
  while(1) {
    SetSpeed ( ( Analog(0) / 2.0 ) - 256 ); 
  }
  
}
    
//------------------------| FUNCTIONS |------------------------

void SetSpeed ( int Speed ) {

  if (Speed > 0) {
      SetPWM( 0, 0);     // make sure one side is stopped
      SetDir( Forward ); // set direction
      SetPWM( 1, Speed); // set other side
    } else {
      SetPWM( 1, 0);
      SetDir( Reverse );
      SetPWM( 0, -Speed);
    }
}

void SetDir  (  uint8_t dir ) {

   if (dir == 0) {
     PORTB |= 0x03;
   } else {
     PORTB &= (~0x03);
   }
}


void SetPWM( uint8_t channel, uint8_t value) {
   if (channel == 0)   
      OCR0 = value;
   if (channel == 1)   
      OCR2 = value;
}

void adc_init() {
  // Activate ADC with Prescaler 
  ADCSRA =  1 << ADEN  |
            0 << ADSC  |
            0 << ADATE |
            0 << ADIF  |
            0 << ADIE  |
            1 << ADPS2 |  /* divide by 128 for 16Mhz */
            1 << ADPS1 |
            1 << ADPS0 ;
}

void pwm_init() {
  // clear pwm levels
  OCR0 = 0; 
  OCR2 = 0;
  
  // set up WGM, clock, and mode for timer 0
  TCCR0 = 0 << FOC0  | 
          1 << WGM00 | /* fast pwm */
          1 << COM01 | /* inverted */
          0 << COM00 | /*   this bit 1 for inverted, 0 for normal  */
          1 << WGM01 | /* fast pwm */
          1 << CS02  | /* prescale by 1024 */
          0 << CS01  |
          1 << CS00  ;
  
  // set up WGM, clock, and mode for timer 2
  TCCR2 = 0 << FOC2  | 
          1 << WGM20 |
          1 << COM21 |
          0 << COM20 | /*   this bit 1 for inverted, 0 for normal  */
          1 << WGM21 |
          1 << CS22  |
          0 << CS21  |
          1 << CS20  ;
  
 }


int Analog ( uint8_t n ) {

    // Select pin ADC0 using MUX
    ADMUX = n & 7;
    
    //Start conversion
    ADCSRA |= _BV(ADSC);
    
    // wait until converstion completed
    while (ADCSRA & _BV(ADSC) ) {}
    
    // get converted value
    return ADC;  
}



