1

For an battery driven application I want to measure the Vcc (using an Atmega 32u4). That is my code:

int readBandGap() {
  ADMUX = (B01 << REFS0)    // VCC
        | (0 << ADLAR)      // right-adjusted result
        | (B011110 << MUX0) // 1.1V
        ;
  // switch off any ADC conversion
  ADCSRA &= ~(1 << ADEN);
  // enable ADC
  ADCSRA |= 1 << ADEN;
  // start ADC
  ADCSRA |= 1 << ADSC;
  // wait until finished
  while (bit_is_set(ADCSRA, ADSC));
  // first read low, then high!
  uint8_t low = ADCL;
  uint8_t high = ADCH;
  // switch off any ADC conversion
  ADCSRA &= ~(1 << ADEN);
  return (high << 8) | low;
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  int value = readBandGap();
  float vcc = 1.1 * 1023 / value;
  Serial.print(value);
  Serial.print("  ");
  Serial.println(vcc);

  delay(1000);
}

My Olimexino 32u4 board has the ability to switch the voltage between 5V and 3.3V. There are two strange things:

  1. the first measurement is always significantly different than the later measurements

  2. with 5V I'm getting 450, followed by ~367; with 3.3V I'm getting 422, followed by ~395. I would have expected a higher Vcc resulting in a lower measured value (bandgap should be measured compared to Vcc).

Any ideas what is wrong with my approach?

  • I have known good Vcc measuring code here: hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino - You might like to compare it with your code - especially the bit that delays to allow Vref to settle. – Majenko Sep 26 '15 at 10:54
  • I've tried that code now and readVcc always reports ~1100, no matter whether I'm using 3.3 or 5V. Maybe for the 32u4 some different flags have to be used. – Thomas S. Sep 26 '15 at 12:58
  • Given that code was written for the 328P with fewer ADC inputs, yes, you probably need to adjust the MUX settings to get the right channel. – Majenko Sep 26 '15 at 13:25
1

The bandgap voltage reference needs some time to stabilize, after you enable it. See http://jeelabs.org/2012/05/12/improved-vcc-measurement/

Doing 3 dummy measurements, gives it enough time to do that.

| improve this answer | |
0

After tweaking a lot, I've now have found following code to work quite good.

float readVcc() {
  ADMUX = (B01 << REFS0)    // VCC
        | (0 << ADLAR)      // right-adjusted result
        | (B011110 << MUX0) // 1.1V
        ;
  // enable ADC
  ADCSRA |= (1 << ADEN);
  // seems necessary
  delay(2);
  // start ADC
  ADCSRA |= 1 << ADSC;
  // wait until finished
  while (bit_is_set(ADCSRA, ADSC));
  // first read low, then high!
  long value = ADCL;
  value |= ADCH << 8;
  return 1.1 / value * 1023;
}
| improve this answer | |

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.