Page 1 of 1

Beyond The Arduino 3 - Guessing Game

Posted: Fri May 29, 2015 8:13 pm
by robralston
A crude experiment "sort of" illustrates one of the concepts in the Guessing Game code, the need to set the ADC clock prescaler.

A ten turn pot used for RV1 (Figure 8 Guessing Game Schematic) with the wiper to pin PC0, with this voltage measured by a voltmeter and set to 2.50 volts and used for the set value. Then, changing the pot to approximately 3.2 volts and slowly backing it down, guessing frequently, both LEDs flash for a correct answer around 2.7 volts. Same thing but coming up from about 1.8 volts, a voltage of about 2.3 volts gets in the correct range.

These results are repeatable, within about 10 - 15 mV.

However, if that single line of code is commented out so the ADC clock is 16 MHz, then every single guess is correct, even when the pot is rotated fully to either end of its range, i.e. 0 or 5V for a guess against the 2.5V setting. If the set value is ground or Vcc, even then any guess is always right.

I don't know what noisy ADC value is being saved for the set and for the guess but I assumed that they would sometimes be different, and the guess would be either too high or too low. Maybe I did't try enough times?

Nevertheless, it is clear that the ADC clock must be slowed down.

Code: Select all

 ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);   //Clock Prescaler: 128, allow for accurate (>50kHz <200kHz) sampling with 16MHz system clock 

Re: Beyond The Arduino 3 - Guessing Game

Posted: Sat May 30, 2015 6:21 am
by aretallack
Thanks, Robert, for sharing. It's interesting to see an experiment that validates the info on the datasheet.

I don't know enough of the details of the innards of the ATmega328, but I do know that the ADC uses a "sample and hold" circuit - this "grabs" the input voltage, and then keeps it at a steady level in order to perform the successive approximation against that fixed value. Otherwise, the value could change resulting in an invalid ADC conversion. A typical sample-and-hold circuit charges up a capacitor to store the input voltage. I guess that if the ADC runs too fast, the capacitor in the sample-and-hold circuit won't have enough time to charge up, and therefore return the same reading each time it is run.

The datasheet mentions that the sampling accuracy falls off if the ADC runs at more than 200kHz - it would be interesting to see exactly how badly the accuracy deteriorates as one increases speed above 200kHz. I guess we'd need to work with a known input value, and then write out the ADC values over the UART.


Re: Beyond The Arduino 3 - Guessing Game

Posted: Mon Jun 01, 2015 10:13 pm
by robralston
Andrew, thanks for the suggestion of outputting the ADC values over the UART.

This was easy to do using the Serial Thermometer code. Changed the ADC_init routine from a single line loading the ADC prescaler bits to three lines so it was easy to comment/uncomment to generate the ADC Prescaler Selection Table 24-5 (page 250 of Atmel-8271I-AVR- ATmega-Datasheet_10/2014). I wonder if there is a typo in the table so that if the prescaler bits were all 0, the Division Factor would be 1 rather than, as printed, 2 ?? The only other change was to use the three lines included for debugging in the getTemp routine.

Used the code to measure 3 ADC input values: Gnd, Vcc (measured as 5.02 volts, sourced from USB), and Vcc/2 from a 100k - 100k voltage divider (measured as 2.49 volts). Recorded 10 values for each input. The results were repeatable. Below, where 2 ADC values are written, this was not a range, but 2 discrete values.

Clearly, with a prescale of 1 or 2 the ADC results would be useless. However, the readings were already looking good with a prescale of 4 although I would still use the prescale of 128 in an actual application.

With a prescale of 1 or 2, the values when PC0 was grounded came in as either 991 or 1023, nothing in between. This was repeatable and seems quite odd.

(The results below are shown as BBcode since I cannot figure out how to input a table, and still have my fingers crossed that it will come out OK.).

Code: Select all

ADPS bits: 000 Div Factor: 1	Vcc = 1023	Vcc/2 = 1023	     Gnd = 991 or 1023
ADSP bits: 001 Div Factor: 2	Vcc = 1023	Vcc/2 = 1023	     Gnd = 991 or 1023
ADSP bits: 010 Div Factor: 4	Vcc = 1023	Vcc/2 = 508, 509	 Gnd = 0
ADSP bits: 011 Div Factor: 8	Vcc = 1023	Vcc/2 = 508	      Gnd = 0
ADSP bits: 100 Div Factor: 16  Vcc = 1023	Vcc/2 = 508, 509	 Gnd = 0
ADSP bits: 101 Div Factor: 32  Vcc = 1023	Vcc/2 = 508, 509	 Gnd = 0
ADSP bits: 110 Div Factor: 64  Vcc = 1023	Vcc/2 = 508, 509	 Gnd = 0
ADSP bits: 111 Div Factor: 128 Vcc = 1023	Vcc/2 = 508, 509	 Gnd = 0

Changed your code from:  ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);  to:

ADCSRA |= (1<<ADPS2);
ADCSRA |= (1<<ADPS1);
ADCSRA |= (1<<ADPS0);

Re: Beyond The Arduino 3 - Guessing Game

Posted: Mon Jun 01, 2015 11:47 pm
by aretallack
Thanks Robert. An interesting experiment! The BBCode came out fine. Why don't you mail this through to the editor, it may be useful to other readers in the letters or Q&A.

Thanks for taking the time to do this and for sharing!