I am trying to write a sketch that measures the bandgap voltage as precise as possible, and writes the value to the eeprom for future reference
I want to use a 2.5v reference ic on AREF
for those dropping in on this discussion - please read up on the matter - a good starting point is this thread:
http://arduino.cc/forum/index.php/topic,38119.0.html
My code is heavely based on the previous work of Coding Badly, and RetroLefty
My problem is - the code using the sleep mode to produce better results seems to reset the analogreference to internal - where I would like to use an external reference, using a LM336 2v5 (an affordable 2.5 volt reference ic)
my code:
// use reference 2,47v on AREF to measure the bandgap voltage
#include <avr/sleep.h>
ISR(ADC_vect)
{
}
// This performs an A/D conversion using the current ADMUX settings. You must set ADMUX before calling this function.
int rawAnalogReadWithSleep( void )
{
// Generate an interrupt when the conversion is finished
ADCSRA |= _BV( ADIE );
// Enable Noise Reduction Sleep Mode
set_sleep_mode( SLEEP_MODE_ADC );
sleep_enable();
// Any interrupt will wake the processor including the millis interrupt so we have to...
// Loop until the conversion is finished
do
{
// The following line of code is only important on the second pass. For the first pass it has no effect.
// Ensure interrupts are enabled before sleeping
sei();
// Sleep (MUST be called immediately after sei)
sleep_cpu();
// Checking the conversion status has to be done with interrupts disabled to avoid a race condition
// Disable interrupts so the while below is performed without interruption
cli();
}
// Conversion finished? If not, loop.
while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
// No more sleeping
sleep_disable();
// Enable interrupts
sei();
// The Arduino core does not expect an interrupt when a conversion completes so turn interrupts off
ADCSRA &= ~ _BV( ADIE );
// Return the conversion result
return( ADC );
}
int bandgapRead(byte us =250) // returns raw measurement of bandgap with aref = 2,47v
{
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // For mega boards
// const long InternalReferenceVoltage = 1100L; // Adjust this value to your boards specific internal BG voltage x1000
// REFS1 REFS0 --> 0 1, AVcc internal ref. -Selects AVcc reference
// MUX4 MUX3 MUX2 MUX1 MUX0 --> 11110 1.1V (VBG) -Selects channel 30, bandgap voltage, to measure
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR)| (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#elif defined(__AVR_ATmega8__) // Atmega8 has a 1.3V bandgap. UNTESTED!!! // http://forums.adafruit.com/viewtopic.php?f=25&t=12547
// const long InternalReferenceVoltage = 1300L; // Adjust this value to your boards specific internal BG voltage x1000
// REFS1 REFS0 --> 0 1, AVcc internal ref. -Selects AVcc external reference
// MUX3 MUX2 MUX1 MUX0 --> 1110 1.1V (VBG) -Selects channel 14, bandgap voltage, to measure
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#else // For 168/328 boards
// const long InternalReferenceVoltage = 1100L; // Adjust this value to your boards specific internal BG voltage x1000
// REFS1 REFS0 --> 0 1, AVcc internal ref. -Selects AVcc external reference
// MUX3 MUX2 MUX1 MUX0 --> 1110 1.1V (VBG) -Selects channel 14, bandgap voltage, to measure
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#endif
delay(us); // Let mux settle a little to get a more stable A/D conversion
// Start a conversion
// ADCSRA |= _BV( ADSC );
// Wait for it to complete
// while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
// Scale the value
// return ((InternalReferenceVoltage * 1023L) / ADC); // calculates for straight line value
return (rawAnalogReadWithSleep());
}
void setup() {
// initialize the serial port
Serial.begin(9600);
pinMode(10, OUTPUT); // set the digital pin as output:
digitalWrite (10, HIGH);
pinMode (9, OUTPUT); // quick and dirty - make pin9 a gnd - for easy led connection when using pin10
digitalWrite(9, LOW);
analogReference (EXTERNAL);
delay (200);
pinMode (A5, INPUT);
int dummy = analogRead (A5); // dummyread
delay (10000); // measuring the AREF pin produces a nice 2.47v during this delay
// but as soon as we try and measure the bandgap voltage
// analogreference seems to revert to internal
digitalWrite (10, LOW);
}
void loop()
{
Serial.println (bandgapRead());
delay(200);
}
In case someone has a atmega8, please verify if the bandgap voltage is indeed 1.3v ?
Thank you all for your contributions