7. Using the Trimmer Pot for Motor Control

The following sample program uses the motor control 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/328’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 and 3pi, the user trimpot can be optionally jumpered
	// to ADC7 using a blue shorting block; the Orangutan and 3pi ship 
	// 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 ATmegaxx8 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 ranges 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;
}