LowPowerLab Forum

Hardware support => Moteino => Topic started by: john k2ox on January 04, 2014, 10:35:37 PM

Title: Battery Voltage Monitoring
Post by: john k2ox on January 04, 2014, 10:35:37 PM
There was mention on the forum about using Moteino to measure its own battery supply voltage.  As already mentioned you can use a two resistor voltage divider and connect it to an analog pin.  The down side of this is that it always drains power from the battery.

Also mentioned was a solution using a transistor to turn the pwr off to the divider.  There was a concern about the number of parts/complexity.  An additional Moteino I/O pin is needed to turn the xstr on/off too.

If you decide you want to monitor your battery and not increase battery drain try this.  Take your two resistor divider and instead of connecting the bottom resistor to ground connect it to a digital I/O pin.

When you want to read the voltage set the pin for output and set it low.  After you get your analog voltage reading, set the pin to input (high impedance).

If you are crafty you can probably use a pin that is now dedicated for a single task.  For instance, say you have an I/O pin dedicated as a chip select line.  Maybe it's for external ram or the data input for a digital temperature chip.  Look at your circuit if you've run short on pins, I bet you'll figure out a way to 'code' multiplex a pin.



Title: Re: Battery Voltage Monitoring
Post by: Felix on January 04, 2014, 10:41:13 PM
Great idea, I'll consider this mod for the PowerShield!
Perhaps I could add a jumper to allow between direct GND and a digital pin, the default being a pin.
Title: Re: Battery Voltage Monitoring
Post by: john k2ox on January 04, 2014, 10:56:27 PM
Cool.

News Flash.   New thought.

Lets say your current design requires a pull-up resistor for some perpheral device.  For example, if I remember correctly, the DSxxxx one wire devices need a 4700 ohm pull-up.  Instead of using one resistor, use two: whos sum equals 4700 ohms and whos ratio gives the desired voltage division.

This only costs you one additional resistor and an analog pin without an additional digital pin.
Title: Re: Battery Voltage Monitoring
Post by: Felix on January 05, 2014, 07:57:36 AM
I was planning on using much higher ohm values like 470k and 1Meg rather than 4.7k.
And my feeling is it might confuse some people if I try to document how that works :)
Title: Re: Battery Voltage Monitoring
Post by: LazyGlen on January 05, 2014, 10:22:17 AM
I did a little searching last night and found some references to "Arduino's secret volt meter"
Code and brief here: http://code.google.com/p/tinkerit/wiki/SecretVoltmeter (http://code.google.com/p/tinkerit/wiki/SecretVoltmeter)

I've put this into my TemperatureGateway code and it appears to work. I realize that this is measuring on the processor side of the regulator and therefore will only start to sag after the battery voltage drops below what the regulator needs to maintain it's rated output. For pin constrained designs it might be sufficient.

LG
Title: Re: Battery Voltage Monitoring
Post by: Felix on January 05, 2014, 07:20:39 PM
I used the same thing in the voltage monitor for the mailbox notifier. Except I ran the battery voltage through a voltage divider to scale the battery voltage below the 3.3v operating range of the Moteino.
Title: Re: Battery Voltage Monitoring
Post by: KanyonKris on January 06, 2014, 06:19:05 PM
john k2ox,

I had this same idea, to use an IO pin to switch the battery voltage divider on and off. When I discussed it with a co-worker who has done a lot of work with ATmegas he thought the over-voltage protection diodes on the IO might provide a path to ground so it wouldn't really shut off. Have you actually wired up a divider and tested this?
Title: Re: Battery Voltage Monitoring
Post by: jbeale on January 06, 2014, 08:08:23 PM
If your battery voltage is less than one diode-drop above your CPU operating voltage, switching off the divider using an I/O pin set to "input" will work. If the battery voltage is higher than that, the difference will appear across your divider, just as you say, with the associated current draw. 

If you use a large value resistor like 470k it's not going to be too much battery drain, maybe a few microamps ?  With that high an imput impedance, you might also need to add a capacitor from the ADC to ground to make the ADC reading valid, though.

All this is just theory- I haven't tried it.
Title: Re: Battery Voltage Monitoring
Post by: john k2ox on January 06, 2014, 09:40:14 PM
All true, in this case, you get to choose your compromise.    ;)
Title: Re: Battery Voltage Monitoring
Post by: SvendP on January 08, 2014, 11:45:46 AM
Hi there, first post here  :)

I have tested it with 2 x 1Mohm resistors and a 100nF capacitor, work like a charm. I was going for higher values of resistors, but didn't have some.
Have a look at: http://jeelabs.org/2013/05/16/measuring-the-battery-without-draining-it/ there it's done 10Mohm and still works.
 
Title: Re: Battery Voltage Monitoring
Post by: GaryP on January 08, 2014, 12:15:28 PM
Just starting out myself. 

I went with the Felix's 10M ohm and 470K with 0.1 uF cap from the Mail Box project and this is working well.   am using 2 or 3 batteries AAA batteries with a mix of rechargeables and alkalines for a test.  I just needed to do a measurement of the battery V and then put a suitable adjustment figure in the Battery Voltage calculation in the sketch.

The sketch I am using is based on the openenergymonitor project's emonTH sensor as it has a rather useful testing function as to whether you have added a DHT 11/22 sensor and/or a DS18B20.  I have tried starting with one form of sensor and adding the other and the change was picked up just fine.  A bit of tweaking with the pin allocations and pointing to plain the plain old Jeelib library was all it needed to get running on a Moteino

http://wiki.openenergymonitor.org/index.php?title=EmonTH#DS18B20_Temperature_Sensor for more info on the emonTH
Title: Re: Battery Voltage Monitoring
Post by: LazyGlen on January 16, 2014, 09:47:38 AM
I was at what my Wife and Daughters are now calling my "Arduino-Anonymous meeting" this week where the topic of battery monitoring came up. One of the attendees sent out a link to an analysis he wrote up which details the current drain associated with different methods.

http://fettricks.blogspot.com/2014/01/reducing-voltage-divider-load-to-extend.html (http://fettricks.blogspot.com/2014/01/reducing-voltage-divider-load-to-extend.html)

LG

PS - I plugged Moteino's while I was there.
Title: Re: Battery Voltage Monitoring
Post by: Felix on January 16, 2014, 09:55:53 AM
Arduino-Anonymous, ha!
Interesting, thanks!
Title: Re: Battery Voltage Monitoring
Post by: NixHydra on February 14, 2014, 06:36:12 AM
Guys,

You might find this link of some interest, considering the subject matter of this thread.

http://jeelabs.net/boards/6/topics/2934?page=3

cheers,
Title: Re: Battery Voltage Monitoring
Post by: john k2ox on March 15, 2014, 10:56:49 AM
A no hardware/current drain added solution.  http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ (http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/)
Title: Re: Battery Voltage Monitoring
Post by: NixHydra on March 18, 2014, 05:24:28 AM
Just an observation concerning the "secret Arduino voltmeter" stuff. Works really well if wanting to see how rock-solid the Vcc supply is but really isn't that helpful as far as battery depletion is concerned. Please see attachment. Parameters being monitored on node 111 are , Vcc, battery voltage, LDR (di-urnal cycle), temp, humdity, wireless module temperature, wireless module power level setting and RSSI.

cheers,

Title: Re: Battery Voltage Monitoring
Post by: Felix on March 18, 2014, 06:59:58 AM
Right, it's a secret voltmeter of .. itself.
Title: Re: Battery Voltage Monitoring
Post by: Spexx on March 18, 2014, 09:18:30 AM
If I understand it correct, I could use for battery sensing the Aref pin if the supply voltage is not more than 5V. But on higher voltages, e.g. with a 9V battery, this won't work. I could use a voltage divider, but this would drain all the time a little bit power from the battery.

As described in the link in post #11, probably the best would be to use a P-FET, which can disable the voltage divider. Does anyone has tested this? I'm thinking about to implement this to the Moteino board. I have tried to find a P-FET at Digikey, but I'm not so familar with FETs and I don't know which one to choose. I think I need one with a logic level, which can be used with a 3.3V voltage?
Can anyone help me to find a suitable SMD P-FET at Digikey?
Title: Re: Battery Voltage Monitoring
Post by: A on March 18, 2014, 01:35:48 PM
Can anyone help me to find a suitable SMD P-FET at Digikey?

I used a Diodes Incorporated DMG3415U-7 (http://www.digikey.com/product-search/en?x=19&y=14&lang=en&site=us&KeyWords=+DMG3415U-7) on my Weather Shield project (http://lowpowerlab.com/forum/index.php/topic,236.msg1954.html#msg1954) for this purpose and while I haven't done extensive testing, simple on and off testing shows things are working as expected.

Another option to consider (and what I used a footprint/schematic symbol for on my board) is the BSS84.
Title: Re: Battery Voltage Monitoring
Post by: Felix on March 18, 2014, 11:12:42 PM
Looking on digikey I see these have a rather high Rds: http://www.digikey.com/product-search/en/discrete-semiconductor-products/fets-arrays/1377094?k=bss84
Would you not want to reduce that to a minimum?
High density FETs with low Rds are more expensive though, so a little hard to justify that plus an extra DIO just to turn on/off a voltage monitor circuit.
In my opinion the simple multi mega ohm resistors+0.1uF cap solution works quite well and the leak current is very small compared to other stuff you might be doing.
Title: Re: Battery Voltage Monitoring
Post by: NixHydra on March 19, 2014, 07:32:45 AM
Hi Spexx,

If you have a look at reply#13 of this thread, you should find a link which describes just the application you were referring to. This uses a cheap as chips, BSH203 PFET and a BC547 transistor, plus a couple of resistors. Draws probably nanoampere levels when switched off, as opposed to the 11 microamperes when the divider is switched on. May be it will be of some help to you?

Felix, maybe it's just me but I tried that JeeLab's 10Mohm, 4M7ohm, 0.1 uF cap trick and when I tried checking the divider voltage as a 10 digit integer value, I found too big an error for my comfort zone. Pity because I would really have liked to get that divider current down low. That's why I ended up using a 110kohm, 220kohm divider for my little Moteino Shield v1.1. Whether the 0.1uF cap was installed made no difference. As I said, maybe it's just me!

cheers,
Title: Re: Battery Voltage Monitoring
Post by: Felix on March 19, 2014, 07:38:37 PM
I would go with 1meg+470k, that seems to be quite stable and consistent values.
Title: Re: Battery Voltage Monitoring
Post by: Spexx on March 20, 2014, 04:30:07 PM
I have done some simple tests with the voltage divider and measured the current with a multimeter. With 1M + 470k I have an additionally power drain of 3µA in case of using a power supply with 5V (7µA in power down  without the voltage divider and 10µA with it)... So I would say nearly nothing :)

 In a short test the values were relative stable, so I think you are right, this would be the easiest way of measure the voltage. I have also tested it with 2x 10M and I don't see any big differences to the measured values. The current drain was in this case only ~0,5µA.
Title: Re: Battery Voltage Monitoring
Post by: ColinR on August 26, 2014, 04:30:03 PM
Very interesting topic.

For reference, a 9V battery with 1.47M will dissipate approximately 6uA. For a typical 9V battery (550mAh), this gives about 10.25yrs battery life. In other words, not a big deal.

Colin
Title: Re: Battery Voltage Monitoring
Post by: oric_dan on August 26, 2014, 04:52:50 PM
One thing to keep in mind is that Atmel recommends using rather "low" value source resistances on the ADC channels. From section 24.6 of the mega328 d/s:

"The ADC is optimized for analog signals with an output impedance of approximately 10 k or less. If such a source is used, the sampling time will be negligible. If a source with higher impedance is used, the sampling time will depend on how long time the source needs to charge the S/H capacitor, with (which, duh!) can vary widely. The user is recommended to only use low impedance sources with slowly varying signals, since this minimizes the required charge transfer (time) to the S/H capacitor".

The source resistance of your voltage dividers will be the 2 Rs in parallel.

However, I think you can still use large R-values as long as you are certain to tie an external cap, like 100nF, on the ADC pin. Then, this will easily transfer the necessary charge current into the S/H cap.
Title: Re: Battery Voltage Monitoring
Post by: ColinR on August 26, 2014, 04:57:11 PM
This is good information. A key phrase there is 'slowly varying'. The time constant is, in essence, infinite, as the thing sits at a relatively constant voltage forever as it discharges. It will reach steady-state, as far as we are concerned.

Colin
Title: Re: Battery Voltage Monitoring
Post by: Charly86 on August 27, 2014, 04:39:20 AM
You're right hi resitor not recommended by Atmel but as this is battery, level is very stable and you can add 100nF cap's on // of the bottom resitor to stabilize voltage without any problem, this is what I'm doing.

By the way, I found extremly more reliable and accurate results doing ADC conversion into Lownoise mode and doing 8 samples and average the value. This is also true for any ADC conversion (NTC, Luminosity, .. whatever) and I'm doing this for any ADC sensor reading

Here is sample and working code (using LowPower library for sleep mode)

Code: [Select]

volatile uint8_t  adc_irq_cnt;

/* ======================================================================
Function: Interrupt routine for ADC
Purpose : Fired when ADC interrupt occured (mainly end of conversion)
Input   :
Output  :
Comments: Used by readADCLowNoise
====================================================================== */
ISR(ADC_vect) 
{
  // Increment ADC sample count
  // will check after wake up
  adc_irq_cnt++;
}

/* ======================================================================
Function: readADCLowNoise
Purpose : Read Analog Value with reducing noise for more accuracy
Input   : true return the average value, false return only the sum
Output  : average value read
Comments: hard coded to read 8 samples each time
          ADMUX Channel must have been set before this call
====================================================================== */
uint16_t readADCLowNoise(bool average)
{
  uint8_t low, high;
  uint16_t sum = 0;
 
  // Start 1st Conversion, but ignore it, can be hazardous
  ADCSRA |= _BV(ADSC);
 
  // as we will enter into deep sleep mode, flush serial to avoid
  // data loss or corrupted
  Serial.flush();

  // wait for first dummy conversion
  while (bit_is_set(ADCSRA,ADSC));

  // Initialize ADC sample counter
  adc_irq_cnt = 0;

  // Want to have an interrupt when the conversion is done
  ADCSRA |= _BV( ADIE );
 
  // Loop thru samples
  do
  {
    // Enable Noise Reduction Sleep Mode
    set_sleep_mode( SLEEP_MODE_ADC );
    sleep_enable();

    // Wait until 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();
    }
    while (bit_is_set(ADCSRA,ADSC));

    // No more sleeping
    sleep_disable();
    // Enable interrupts
    sei();
   
    // read low first
    low  = ADCL;
    high = ADCH;
   
    // Sum the total
    sum += ((high << 8) | low);
   
  }
  // Hard coded to read 8 samples
  while (adc_irq_cnt<8);
 
  // No more interrupts needed for this
  ADCSRA &= ~ _BV( ADIE );
 
  // Return the average divided by 8 (8 samples) if asked
  return ( average ? sum >> 3 : sum );
 
}

/* ======================================================================
Function: readVcc
Purpose : Read and Calculate V powered, the Voltage on Arduino VCC pin
Input   : -
Output  : value readed in mV
Comments: ADC Channel input is modified
====================================================================== */
uint16_t readVcc()
{
  uint16_t value;
 
  // Read 1.1V reference against AVcc
  // REFS1 REFS0          --> 0 1, AVcc external 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);

  // Take care, changing reference from VCC to 1.1V bandgap can take some time, this is due
  // to the fact that the capacitor on aref pin need to discharge or to charge
  delay(10); 

  // read value
  value = readADCLowNoise(true);
 
  // Vcc reference in millivolts
  // can be adjusted 1100L if 1V1 reference but has tolerance of 10% so you can measure it
  // and change it there, or better use it as parameter
  return ( (( 1023L * 1100L) / value) );
}

Full code and sketch available at https://github.com/hallard/RFM12B_arssi (https://github.com/hallard/RFM12B_arssi) under example RFM12B_Struct_node_arssi
Title: Re: Battery Voltage Monitoring
Post by: Antony on August 27, 2014, 09:37:40 AM
As a real-world use case, I've been using the voltage reader circuit described in Felix's mailbox mote for nearly three weeks. The same 9v battery also runs an anemometer AD amplifier circuit which has it's own variability of power consumption and complicates battery-life expectations. I calculated I'd get 5 weeks, but I just had to change the battery. From voltage logs, it appeared that once the battery dropped below 7.5v, power consumption increased non-linearly. I had not accounted for the non-linearity, and I guess that is where I lost at least some of the estimated time.
Title: Re: Battery Voltage Monitoring
Post by: Felix on August 27, 2014, 10:37:02 AM
I have been using that circuit (1M+470K+0.1uF) for many different projects. But to put this to rest, the mailbox notifier can run at least 6 months on it from both a 9V and a Lipo.
Title: Re: Battery Voltage Monitoring
Post by: oric_dan on August 27, 2014, 01:05:57 PM
The external R and internal S/H capacitor form a basic RC charging circuit, so if R is too large the cap will charge slowly, and will take a long time to "settle" at an accurate voltage reading. That's what the d/s is saying. This will be more of a problem when quickly switching between multiple ADC channels, as the S/H cap needs to be recharged  from the previous channel value, and settle at the new channel value.  This is also why 'unterminated' ADC channels will show a non-zero reading, as you're really measuring residual charge on the S/H cap from a previous reading.

Having the 100nF on the pin allows the S/H cap to quickly pull the necessary charge.
Title: Re: Battery Voltage Monitoring
Post by: Felix on August 27, 2014, 01:29:50 PM
Unterminated ADC channels will show a bogus low value reading even if you wave your hand around the board ;)
Title: Re: Battery Voltage Monitoring
Post by: Charly86 on August 27, 2014, 06:42:44 PM
Sure, and don't forget to trash 1st reading also  ;)
Title: Re: Battery Voltage Monitoring
Post by: Kitsibas on October 11, 2014, 03:01:35 PM
Hi,

i try to build battery voltage monitor using the P-FET element. i connected all like i read on this blog entry: http://fettricks.blogspot.com/2014/01/reducing-voltage-divider-load-to-extend.html

it dont work :) but I do not know if I have the correct element. i use: http://datasheet.octopart.com/IRF9Z34N-International-Rectifier-datasheet-7830620.pdf

It is good? if not could you give me correct one.

Thanks
Title: Re: Battery Voltage Monitoring
Post by: dave_sausages on August 30, 2016, 08:00:03 PM
I know this thread has been silent for a while, but I thought I'd chime in as I'm sure people will will still be using the ideas in this thread.

Regarding the original post:
There was mention on the forum about using Moteino to measure its own battery supply voltage.  As already mentioned you can use a two resistor voltage divider and connect it to an analog pin.  The down side of this is that it always drains power from the battery.

Also mentioned was a solution using a transistor to turn the pwr off to the divider.  There was a concern about the number of parts/complexity.  An additional Moteino I/O pin is needed to turn the xstr on/off too.

If you decide you want to monitor your battery and not increase battery drain try this.  Take your two resistor divider and instead of connecting the bottom resistor to ground connect it to a digital I/O pin.

When you want to read the voltage set the pin for output and set it low.  After you get your analog voltage reading, set the pin to input (high impedance).

If you are crafty you can probably use a pin that is now dedicated for a single task.  For instance, say you have an I/O pin dedicated as a chip select line.  Maybe it's for external ram or the data input for a digital temperature chip.  Look at your circuit if you've run short on pins, I bet you'll figure out a way to 'code' multiplex a pin.

Am I correct in thinking that if the Digital Pin (ground of voltage divider) goes high impedance, then the Analogue Pin that is measuring the voltage will see the full voltage being supplied to the battery connection of the voltage divider? And as the ATmega's have protection diodes that short to ground if more than vcc + 0.5v is applied to them, then it will connect to ground anyway?

Just wanted to help out any future people looking for simple voltage measuring options with no wasted current.
Title: Re: Battery Voltage Monitoring
Post by: TomWS on August 30, 2016, 08:29:11 PM
I know this thread has been silent for a while, but I thought I'd chime in as I'm sure people will will still be using the ideas in this thread.

Regarding the original post:
There was mention on the forum about using Moteino to measure its own battery supply voltage.  As already mentioned you can use a two resistor voltage divider and connect it to an analog pin.  The down side of this is that it always drains power from the battery.

Also mentioned was a solution using a transistor to turn the pwr off to the divider.  There was a concern about the number of parts/complexity.  An additional Moteino I/O pin is needed to turn the xstr on/off too.

If you decide you want to monitor your battery and not increase battery drain try this.  Take your two resistor divider and instead of connecting the bottom resistor to ground connect it to a digital I/O pin.

When you want to read the voltage set the pin for output and set it low.  After you get your analog voltage reading, set the pin to input (high impedance).

If you are crafty you can probably use a pin that is now dedicated for a single task.  For instance, say you have an I/O pin dedicated as a chip select line.  Maybe it's for external ram or the data input for a digital temperature chip.  Look at your circuit if you've run short on pins, I bet you'll figure out a way to 'code' multiplex a pin.

Am I correct in thinking that if the Digital Pin (ground of voltage divider) goes high impedance, then the Analogue Pin that is measuring the voltage will see the full voltage being supplied to the battery connection of the voltage divider? And as the ATmega's have protection diodes that short to ground if more than vcc + 0.5v is applied to them, then it will connect to ground anyway?

Just wanted to help out any future people looking for simple voltage measuring options with no wasted current.
The resistor divider described in the original post would, when the digital pin is high, cause the voltage on the analog pin to be divided between VBat and VCC (ATMega328P)  power supply.  If this causes the pin voltage to go 0.5V above VCC then you've exceeded the Absolute Maximum ratings of the device (Section 29.1).   It would also reverse bias the output pin, but, if it's still configured as an output then this probably won't be an issue.  If it's High Impedance, then this would definitely exceed the maximum on two pins (Digital control and Analog input).  Whether this causes a problem or simply 'leaks' current is going to be determined by the internal transistor design of the device.  IMO (and experience), the Absolute Maximum ratings exist for a reason and shouldn't be trifled with.

Load switches are cheap and small.   On a breadboard you can probably get away with a lot of, uh, 'flexibility'.  On a mote you depend on, Mother Nature makes sure you don't mess with her...

Tom
Title: Re: Battery Voltage Monitoring
Post by: dave_sausages on September 15, 2016, 07:57:41 PM
So I used a standard /2 voltage divider on all my nodes to measure the battery voltage, and all is well with reading the voltage. Except I'm currently chasing my tail on one of my Arduino Pro Mini nodes that communicates to my Moteino via bluetooth. When the voltage reported drops below 3.68 volts, the node stops functioning.

****edit****

Aha! I've worked it out. it does not stop functioning at 3.68 volts.....that's just the lowest point at which the voltage divider gives an accurate and or useful reading.

You see my pro-mini has a 3.3v regulator on it and I've measured a 350mv drop on it. So below about 3.7 battery volts, the regulator output and battery voltage fall by the same amount....meaning that the ADC never sees a change because the ratio of battery to 3.3v feed is the same!

So how can I get around this? Can I use the secret inbuilt voltage sense in the 328p? And switch to that when the input voltage to the 328p drops below 3.3v?

Title: Re: Battery Voltage Monitoring
Post by: TomWS on September 15, 2016, 09:56:29 PM
So I used a standard /2 voltage divider on all my nodes to measure the battery voltage, and all is well with reading the voltage. Except I'm currently chasing my tail on one of my Arduino Pro Mini nodes that communicates to my Moteino via bluetooth. When the voltage reported drops below 3.68 volts, the node stops functioning.

****edit****

Aha! I've worked it out. it does not stop functioning at 3.68 volts.....that's just the lowest point at which the voltage divider gives an accurate and or useful reading.

You see my pro-mini has a 3.3v regulator on it and I've measured a 350mv drop on it. So below about 3.7 battery volts, the regulator output and battery voltage fall by the same amount....meaning that the ADC never sees a change because the ratio of battery to 3.3v feed is the same!

So how can I get around this? Can I use the secret inbuilt voltage sense in the 328p? And switch to that when the input voltage to the 328p drops below 3.3v?
Battery voltage measurements should be made against the 1.1V reference voltage so that they are not a ratio of VCC but referenced to an absolute voltage.  There are plenty of references around this forum on the Web for this technique.

Tom
Title: Re: Battery Voltage Monitoring
Post by: dave_sausages on September 15, 2016, 10:32:40 PM
So I used a standard /2 voltage divider on all my nodes to measure the battery voltage, and all is well with reading the voltage. Except I'm currently chasing my tail on one of my Arduino Pro Mini nodes that communicates to my Moteino via bluetooth. When the voltage reported drops below 3.68 volts, the node stops functioning.

****edit****

Aha! I've worked it out. it does not stop functioning at 3.68 volts.....that's just the lowest point at which the voltage divider gives an accurate and or useful reading.

You see my pro-mini has a 3.3v regulator on it and I've measured a 350mv drop on it. So below about 3.7 battery volts, the regulator output and battery voltage fall by the same amount....meaning that the ADC never sees a change because the ratio of battery to 3.3v feed is the same!

So how can I get around this? Can I use the secret inbuilt voltage sense in the 328p? And switch to that when the input voltage to the 328p drops below 3.3v?
Battery voltage measurements should be made against the 1.1V reference voltage so that they are not a ratio of VCC but referenced to an absolute voltage.  There are plenty of references around this forum on the Web for this technique.

Tom

I see, so I should change my voltage divider so the Arduino input never goes above 1.1v? And then configure my ADC to use the 1.1v reference instead of the vcc?
Title: Re: Battery Voltage Monitoring
Post by: TomWS on September 16, 2016, 07:44:46 AM
I see, so I should change my voltage divider so the Arduino input never goes above 1.1v? And then configure my ADC to use the 1.1v reference instead of the vcc?
That's one way. 

Another way is to measure 1.1V in relation to VCC as your reference and this will tell you exactly what the processor's VCC voltage is (see many examples of reading VCC).  Then, knowing this value, measure your incoming voltage still using VCC as the reference, but scale the result to the REAL VCC value, not some 'assumed' VCC value. 

Tom
Title: Re: Battery Voltage Monitoring
Post by: WhiteHare on September 19, 2016, 01:34:56 PM
@dave_sausages
Here's code to do it:
https://lowpowerlab.com/forum/moteino/accurate-moteino-battery-voltage-monitoring/msg13026/#msg13026
Title: Re: Battery Voltage Monitoring
Post by: SupaJah on February 27, 2018, 07:45:22 PM
Hi. I hope some of you guys are still around to help me with this.

I have tried the battery voltage monitoring technique described in the opening post without any success on an ATMega328p running at 1Mhz. Instead of connecting R2 of the voltage divider directly to GND, R2 is connected to D12 and set low just before reading the battery voltage. The analogRead function always returns the maximum, 1024. Initially, I thought it was the sketch looping too fast, so I introduced a 10 ms delay after the analogRead function so that D12 can be properly 'grounded' before the battery voltage is read but that still didn't work.

My voltage divider circuit resembles this: Vin(3v) -- 1M(R1) -- A1 (Vo) -- 300K(R2) -- D12

D12 is the BATTERY_ENABLE_PIN.
My AnalogRefence is set to INTERNAL(1.1v).

Here's the code:
Code: [Select]
    pinMode(BATTERY_ENABLE_PIN, OUTPUT);
    digitalWrite(BATTERY_ENABLE_PIN, LOW);
    voltage = analogRead(A1);
    delay(10);
    pinMode(BATTERY_ENABLE_PIN, INPUT);

BTW, the battery monitor works if R2(300K) is connected directly to GND. Problem is when it is connected to D12, to save energy consumed by the divider as described above.
Title: Re: Battery Voltage Monitoring
Post by: TomWS on February 27, 2018, 09:18:39 PM
I'm not sure why you're doing it the way you're doing it if the input voltage <= VCC of the ATmega chip.  You can just read the input voltage directly in this case.  However, given your question, I think you should move the delay BEFORE the analogRead() call.  This will give the voltage time to settle on the input prior to reading it.

What are you trying to read?  If it is the ATmega's power supply voltage, there are already a ton of routines posted on this forum that do that AND you don't need any resistors!  Search the forum for "readVCC".  I'm sure you'll find something useful (probably a lot of crap too, but ignore that).

Tom
Title: Re: Battery Voltage Monitoring
Post by: SupaJah on March 01, 2018, 07:44:21 AM
Thanks for the reply @TomWs. I didn't realise that the Vcc of the ATmega328p could be measured without a potential divider circuit. Since your reply, I have tried a readVcc function which works well, except the result seems to be about 9.7% off when I verify it against my multimeter reading. But a little calibration takes care of that.
Title: Re: Battery Voltage Monitoring
Post by: TomWS on March 01, 2018, 09:19:01 AM
I have tried a readVcc function which works well, except the result seems to be about 9.7% off when I verify it against my multimeter reading. But a little calibration takes care of that.
The 1.1V reference is not perfect but it should produce better accuracy than this.  It may be that you need a bit more settling time between setting your ADC MUX and taking the reading.  Taking two readings, back to back and using the second one also helps, but this is mostly if you're taking an external reading from a high impedance source.

Here is what I've found in my collection of goodies...
Code: [Select]
unsigned int readVcc() {
  unsigned long result;
  byte saveADMUX;
 
  saveADMUX = ADMUX;
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    ADMUX = _BV(MUX3) | _BV(MUX2);
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif

  #if defined(__AVR_ATmega2560__)
    /****
    it took me a while to figure-out the problem, but on MEGA 2560, immediately after analogRead(A8), ADCL started returning zero.
    So every attempt to read from A8-A16 on Arduino MEGA will damage the functionality of readVcc().
    I've resolved the problem by adding:
    ADCSRB = 0;
    just before
    delay(20);
    **********************************/

    ADCSRB = 0;
  #endif

  delay(20); // Wait for Vref to settle (this can probably be shortened a bit)
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
  uint8_t high = ADCH; // unlocks both

  result = (high<<8) | low;
  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 (because...= 3300*1023/3 since 1.1 is exactly 1/3 of 3.3V)

  ADMUX = saveADMUX;  // restore the MUX to previous setting

  return result; // Vcc in millivolts
}


Title: Re: Battery Voltage Monitoring
Post by: perky on March 01, 2018, 02:12:41 PM
I suspect it's not just the settling time, you'd need to slow the ADC clock right down so that the sample and hold window is large enough to allow the high impedance source to charge the S&H capacitor. Just allowing a longer settling time on the pin isn't enough.

Mark.
Title: Re: Battery Voltage Monitoring
Post by: TomWS on March 01, 2018, 05:59:34 PM
I suspect it's not just the settling time, you'd need to slow the ADC clock right down so that the sample and hold window is large enough to allow the high impedance source to charge the S&H capacitor. Just allowing a longer settling time on the pin isn't enough.

Mark.
Wanna bet?   ;)

The MUX will charge the SH Cap as soon as the MUX is changed if there is no conversion underway.  The charge in this case is a function of the source impedance and the setup time of the MUX.  Once the conversion is underway, the source is actually disconnected from the S&H cap one clock period after SC.

Another time related factor, however, is the effect of any filter capacitor on AREF if the reference voltage is changed.  If you're reading VCC, however, then this is the default reference and the AREF voltage should be stable.

Tom
Title: Re: Battery Voltage Monitoring
Post by: perky on March 02, 2018, 07:20:43 AM
I've been labouring under the misapprehension that there was a 2 clock sample window! It appears I may have got confused with continuous sampling mode in the past. You're completely right, thanks Tom for pointing it out ;)

Mark.
Title: Re: Battery Voltage Monitoring
Post by: TomWS on March 02, 2018, 08:01:55 AM
You're completely right, thanks Tom for pointing it out ;)
Dang!  I was hoping to make my retirement fortune off this bet!
Good working with you, Mark!
Tom