7. Using the Trimmer Pot for Motor Control

The following sample program uses the motor control macros and functions defined in Section 5 to drive the motors in response to the trimmer potentiometer position. Motors 1 and 2 transition linearly from full forward to stationary to full reverse as the potentiometer voltage varies from 0 to 5 V. This program uses the ATmega48/168’s analog-to-digital converter to determine the position of the potentiometer.

#include <avr/io.h>

int main()
{
    motors_init();

    // ***** ADC INITIALIZATION *****

    // On the Orangutan LV-168, the user trimpot can be optionally jumpered
    // to ADC7 using a blue shorting block; the Orangutan LV-168 ships 
    // with this shorting block in place (this shorting block is required
    // by this program).  On the Baby Orangutan, the trimpot is permanently 
    // connected to ADC7.

    ADCSRA = 0x87;        // bit 7 set: ADC enabled
                        // bit 6 clear: don't start conversion
                        // bit 5 clear: disable autotrigger
                        // bit 4: ADC interrupt flag
                        // bit 3 clear: disable ADC interrupt
                        // bits 0-2 set: ADC clock prescaler is 128

    ADMUX = 0x07;        // bit 7 and 6 clear: voltage ref is Vref pin
                        // bit 5 clear: right-adjust result (10-bit ADC)
                        // bit 4 not implemented
                        // bits 0-3: ADC channel (channel 7)

    while (1)            // loop forever
    {
        long sum = 0;
        unsigned int avg, i;

        // Here we accumulate 500 conversion results to get an average ADC.
        // According to the mega168 datasheet, it takes approximately 13
        // ADC clock cycles to perform a conversion.  We have configured
        // the ADC run at IO clock / 128 = 20 MHz / 128 = 156 kHz, which
        // means it has a conversion rate of around 10 kHz.  As a result,
        // it should take around 50 ms to accumulate 500 ADC samples.
        for (i = 0; i < 500; i++)
        {
            ADCSRA |= ( 1 << ADSC );           // start conversion
            while ( ADCSRA & ( 1 << ADSC ))    // wait while converting
                ;
            sum += ADC;     // add in conversion result
        }
        avg = sum / 500;    // compute the average ADC result

        // set motors based on trimpot position (middle value = motor speed 0)
        //  avg is a 10-bit value and hence will range from 0 to 1023
        if (avg <= 511)
        {
            M1_FORWARD((511 - avg) / 2);
            M2_FORWARD((511 - avg) / 2);
        }
        else
        {
            M1_REVERSE((avg - 512) / 2);
            M2_REVERSE((avg - 512) / 2);
        }
    }

    return 0;
}