2

I need to monitor a battery plugged to an ATmega running on standalone mode.

I use the "ATmega on a breadboard (8 MHz internal clock)" bootloader. More info here

When the ATmega is powered with 5V the sketch outputs good values : arround 5100 mV.

But when I power it with 3.3V the sketch gives strange values : arround 178619 mV.

Here is my code Inspired from here

void setup() 
{ 
  Serial.begin(9600);
  Serial.println(F("Internal Voltage Sensor"));
}

void loop() 
{ 
  Serial.println( readVcc()); 
  delay(1000); 
} 

long readVcc() 
{
  long voltage=0;
  uint8_t wADC;

  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  ADCSRA |= _BV(ADEN);  // enable the ADC

  delay(20); // Wait for Vref to settle

  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  // Reading register "ADCW" takes care of how to read ADCL first and ADCH then.
  wADC = ADCW;

  voltage = 11253000L / wADC; // Calculate Vcc (in mV); 1125.3 = 1.1*1023*1000
  return voltage; // Vcc in millivolts
}

I don't understand what's going on. The returned value with Vcc=3.3V should be lower than with VCC=5V. Something like 3300 mV !

  • Try adding some more Serial.printlns to you code. E.g. Serial.println(wADC); – Gerben Jan 13 '18 at 10:59
  • 2
    ADCL is the lower byte, ADCH is the higher byte, and the must be read ADCL first and then ADCH. The ADCW tells the compiler to read the two bytes in the right order. Using ADCW is of course easier, and even better, because it can't go wrong... unless you try to put 16 bits of ADCW into a byte and throw away the higher byte. Make wADC a uint16_t. – Jot Jan 13 '18 at 11:42
2

Thanks for your answers! Jot gave the solution: wADC must be a uint16_t.

Here is the corrected code :

void setup() 
{ 
  Serial.begin(9600);
  Serial.println(F("Internal Voltage Sensor"));
}

void loop() 
{ 
  Serial.println(readVcc()); 
  delay(1000); 
} 

long readVcc() 
{
  long voltage=0;
  uint16_t wADC;

  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  ADCSRA |= _BV(ADEN);  // enable the ADC

  delay(20); // Wait for Vref to settle

  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  // Reading register "ADCW" takes care of how to read ADCL first and ADCH then.
  wADC = ADCW;

  voltage = 1125300L / wADC; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return voltage; // Vcc in millivolts
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.