Hi,
I've been using 4 moteinos nodes monitoring temperature / humidity / luminosity across the house for 4 months now. They were powered with 9V batteries and I wanted to switch to lipos and report the battery voltage to my raspberry Pi.
I thought it was easy :
* I redirected Vin through a voltage divider with two 22kΩ resistor (and with a very small capacitor) to my current board (my max Vin voltage is 4.2V so half the voltage is enough).
* Connected A6 to my resistor divider
* I modified my program to add :
pinMode(A6, INPUT);
unsigned int vin = analogRead(A6);
float bat = vin * (3246 / 1024) * 2;
my 3.3V is a little low (3,246 V), I checked it with my voltmeter and with the readVcc() function I copied from this forum.
When I connect my moteino to my laptop (so USB powered), my calculation give me 4,7V, the voltmeter shows 5.05V
When powering the moteino with my Lipo battery again there is a difference between my program and the voltmeter.
What did I miss ?
Thanks in advance.
Quote from: WhiteHare on September 22, 2015, 04:56:39 PM
Well, definitely divide by 1023, not 1024.
However, why even go there? What's wrong with using readvcc, which you already have?
@vlad59, I think WhiteHare is suggesting using readVcc to arrive at the first multiplier and then calculate your result as follows:
pinMode(A6, INPUT); // this is unnecessary as this will be power on default and the analogRead will also put it in analog input mode
uint16_t
realVcc,
vin;
// first read realVcc
realVcc = readVcc();
// now read vin
vin = analogRead(A6);
// now calculate the result, note that using float values will consume more time and processing power, but here it is...
// note that the early terms are converted to float just to ensure that you don't get truncation and,
// as a general rule it's advisable to divide after your multiplications (if integer math was used you'd lose a LOT of precision otherwise)
float bat = ((float)vin * realVcc * 2.0)/1023.0;
Let us know how it works out.
Tom
@WhiteHare
ReadVcc only give the value of the 3.3V, I want the value before the regulator (to be sure my lipo never goes below 3.5V). Unless I'm mistaken of course.
My voltmeter is between VIN and GND (directly on the moteino)
@TomWS
I also tried after posting to cast the value read into float that didn't help.
I'll try your code tonight. I'll also check the value of my resistors.
Thanks you both for your help.
@TomWS
Victory ! Your code is working fine, there was a loss of precision in my code. I guess that dividing at the end did the trick.
Thanks a lot.
@WhiteHare
About only reading VCC (using readVcc). I've not read the specs of the moteino's regulator recently but, I don't know how I would be able to detect the difference between a lipo charged at 3.7V (completely normal) VS a lipo charged at 3.5V (needs a recharge very soon).
My lipo power the moteino using the embedded regulator (pin VIN / GND). I don't have a choice because, a fully charged lipo can go up to 4.2V and damage the moteino so I need the regulator.
The voltage divisor is also connected directly to the lipo, Pin A6 is connected the mid point of my divider.
English is not my main language, I admit I don't understand completely what you mean.
Quote from: vlad59 on September 23, 2015, 03:44:01 PM
@TomWS
Victory ! Your code is working fine, there was a loss of precision in my code. I guess that dividing at the end did the trick.
Thanks a lot.
Great! Glad to hear it! I suspect, however, that the bulk of the accuracy comes from using the existing VCC reading as one of the terms in the equation (rather than a constant). I'll do this in my code when I really care about the accuracy of an ADC reading since the reading is typically proportional to the VCC value.
Tom
@Vlad59, are you using the battery as a 'backup' or a primary power source?
The reason I ask is that the resistor divider you are using is a fairly high load on a battery power source. You mentioned that you also have a capacitor in your divider. If the capacitor is at least 0.1uF and is connected between the center point on your divider and ground, then you can increase your resistor values by at least two orders of magnitude, for example, 2.2MegOhm, rather than 22K Ohm. This will significantly reduce the load on your battery without affecting the accuracy.
Tom
Hi TomWS,
For now all my sensors are unpowered when my Moteino is sleeping (I use a NPN transistor connected to the arduino to control that) I was thinking of using the same trick for my battery monitor but you're right that's easier, I only got to find a bigger cap (mine is lower at the moment).
Thanks again for the advice
Quote from: vlad59 on September 25, 2015, 11:20:14 AM
Hi TomWS,
For now all my sensors are unpowered when my Moteino is sleeping (I use a NPN transistor connected to the arduino to control that) I was thinking of using the same trick for my battery monitor but you're right that's easier, I only got to find a bigger cap (mine is lower at the moment).
Thanks again for the advice
Unfortunately, you won't be able to use an NPN transistor to disable the voltage divider because this will leave the analog input pin pulled to VIN. And, as others have found out, most other switching arrangements are overly complicated.
If your cap is too small, you can use a trick to work around that. If you do two sequential analogReads from the same port, the second one will be accurate. (I'll credit @gregcope for reminding me of this).
Tom
@TomWS
I finally used 2 1MOhm resistor and a bigger cap and that work fine.
@all
To avoid wasting time / RAM, I finally replace the floating point operation with a full int approximation :
uint16_t readVin() {
uint32_t vin = 0;
vin = analogRead(A6);
vin *= vcc;
vin >>= 8;
return vin;
}
vcc is the output of ReadVcc halved (right shift one time) to avoid overflowing the 32 bits integer. I found out that reading VCC only one time a day is enough so the value is cached.
The overall approximation is good enough for my use case (~ 0.05 V), it's also way faster (the division was really slow).
You can have almost have a one line function, I splitted it to make it easier to read.
Great! I'm glad you found a way to optimize for your needs. You will learn a lot as you experiment like this and have the benefit of having something truly customized for you.
Good job!
Tom