12V battery meter with Arduino MEGA

Hi Everybody,

I was searching for hours for proper solution and finally decided to make my version and post here.
Before blowing up my board, I would highly appreciate, if somebody can spend some time and check the goodness of the below code and schematic:

So I have a 4 cell LiFePO4 battery with max. 12.8 V charging voltage and 10.7 V cut-off, connected to MEGA Vin pin.
Goal: measure the battery charged state in % as accurate as possible.
For this purpose I'm planning a voltage divider and use the internal reference voltage for accurate measuring.

void loop() {
  analogReference(INTERNAL2V56);   // set the reference voltage level from 5V to 2.56V
  for (int i=0; i<8; i++) analogRead(A0);   // just burn some ADC readings after reference change
  ADCvalue = analogRead(A0);            // read the divided battery voltage on analog pin # 0
  analogReference(DEFAULT);            // set back the reference voltage level to normal 5V
  A0volt = 2.56 * ADCvalue / 1023       // convert digital signal to voltage.
//  You might measure the Ref voltage separately, because not always 2.56V !!! (put delay(60000); 1 min. after above 'for' loop) and hard-code the reference voltage.
  R1 = 9978.9;                            // ohm (measured with DMM; near to 10k);
  R2 = 50128.2;                          // ohm (measured with DMM; near to 50k);
  Vin = A0volt * (R1 + R2) / R1;       // calculate the actual batter supply voltage
  percentage = 100 * (Vin - 10.7) / (12.8 - 10.7);
  Serial.print("Battery level [%]: "); Serial.println(percentage);
  delay(1000);
}

The wiring:

schematics.jpg

Thank You !

schematics.jpg

Three notes on accurate:

A0volt = 2.56 * ADCvalue / 1023       // convert digital signal to voltage.

Should have 1024

Just don't use floats. Just do the calculation in mV.

Battery percentage is nowhere near liniear with voltage. So the percentage calculation is flawed.

Think this should give you more than accurate enough results:

const unsigned long BatRs[] = {50128, 9979}; // as long as they have the same unit
const unsigned long BatVref = 2560; //mV
const unsigned long BatResolution = 1024;
const unsigned long BatRatio = ((BatRs[0] + BatRs[1]) * BatVref) / BatRs[1];

void setup(){
  analogReference(INTERNAL2V56);   // set the reference voltage level from 5V to 2.56V
  //for (int i=0; i<8; i++) analogRead(A0);   // just burn some ADC readings after reference change
  delay(10);
}

void loop() {
  unsigned int adcValue = analogRead(A0);            // read the divided battery voltage on analog pin # 0
  
  //analogReference(DEFAULT);            // set back the reference voltage level to normal 5V 
  //WHY?
  
  //A0volt = 2.56 * ADCvalue / 1023       // convert digital signal to voltage.
  
  unsigned int batVoltage = adcValue * BatRatio / BatResolution;
  Serial.print("Batery voltage: [mV]: ");
  Serial.println(batVoltage);
  byte percentage = 100 * (batVoltage - 10.7) / (12.8 - 10.7);
  Serial.print("Battery level [%]: ");
  Serial.println(percentage);
  delay(1000);
}

Although I didn't test it so may contain a bug

The resistor values of 10k and 50k are good.
You have to be careful when you have a loose wire with 12V. If that wire drops on the Arduino board, then the board is broken. If you accidentally shortcut the 50k resistor, then the board is broken.

Do you really need to switch between 2.56V and 5V reference ?
Can you just select the 2.56 reference in setup() ?

Switching the voltage reference might influence the first read value. I would use a delay(10) and single analogRead().

After setting the 2.56 voltage reference, you could measure the voltage off the AREF pin. Use that value in the sketch instead of 2.56. You might need a little more tuning in the sketch.

If you keep the board always at room temperature, then the 2.56V voltage reference is good. If you put the board in freezing cold, then it changes.

There is always some noise. When using the average of a few samples, it is possible to get rid of the noise.
It is even possible to use the noise to increase the accuracy.
I have a different opinion as septillion about integers and float. I use the analogRead() as integer, but once I calculate the result with a possible higher accuracy then I use float: averageRead.ino.

Ow, one thing I forgot, add a cap (100nF ceramic will do) to the output of the voltage divider. Arduino doesn't like to measure high impedance (top of my head >50k). Cap will add impedance without draining the battery.

Dear All,

first of all thank You very much for your time and continuous help spent in this topic.
I summarized the feedbacks for future use/other users (lesson learned :-).

I made a function from the scrip, so it can be called when the robot in operating. (If it will be below limit (let say 10%) the rover can stop or search for better solar conditions (solar panel is on the roof of the rover).)
In the script I set back the REF voltage from 2.56V to 5.0 V, because it will cause later issues in other part of the full program (not listed here).
I used standard resistor 50k -> 51k.

const unsigned long BatRs[] = {51028, 9979};    // as long as they have the same unit
const unsigned long BatVref = 2560;            //mV ; this must be measured on the AREF pin accurately with DMM 
					//after initiating 'analogReference(INTERNAL2V56);' and change here.
const unsigned long BatResolution = 1024;
const unsigned long BatRatio = ((BatRs[0] + BatRs[1]) * BatVref) / BatRs[1];
const float batVolt_Max = 12.8;
const float batVolt_Min = 10.7;
#define BatVolt_pin = 0;     //Anlaoge pin # A0


void BattVoltage() {
	
  analogReference(INTERNAL2V56);   // set the reference voltage level from 5V to 2.56V
  for (int i=0; i<8; i++) analogRead(BatVolt_pin);   // just burn some ADC readings after reference change
  delay(10);
  // delay(60000)    // 1 min delay only one time to have time
		     // to measure the voltage on AREF pin with DMM.
  unsigned int adcValue = analogRead(BatVolt_pin);      // read the divided battery voltage on analog pin # 0
  
  analogReference(DEFAULT);                 // set back the reference voltage level to normal 5V 
  for (int i=0; i<8; i++) analogRead(BatVolt_pin);      // so later in the main/full program no trouble
  delay(10);
  
  unsigned int batVoltage = adcValue * BatRatio / BatResolution;
  Serial.print("Batery voltage: [mV]: ");  Serial.println(batVoltage);
  byte percentage = 100 * (batVoltage - batVolt_Min) / (batVolt_Max - batVolt_Min);
  Serial.print("Battery level [%]: ");  Serial.println(percentage);
  return percentage;
}

If there is some improvement point still left, kindly share with us.

Thank You for Your support in advance !

schematics updated.jpg

I think it is okay. I prefer floats more than septillion I guess.

Did you know that the 32-bit single float precision library for the AVR boards (Arduino Uno and Mega) is one of the most optimized pieces of code there is ? It is super fast and it is fully according to the IEEE standard. Divisions are slow, but divisions with integers are also slow.

When reading an analog value in such a situation (or with a LDR and so on), then taking the average of 5 samples already gives a good improvement.

To measure the real voltage of the 2.56V, you could make an empty sketch with only setting the voltage reference.

void setup()
{
  analogReference( INTERNAL2V56);
}

void loop()
{
}

Do you have a good multimeter to tune the calculation ?

Dear Koepel,

Thank You for the quick feedback.
I didn't know.
The empty sketch and the averaging are very good ideas! :wink:
I have bench top type DMM to measure the 2.56V ref..
I updated the script:

const unsigned long BatRs[] = {51028, 9979};    // as long as they have the same unit
const unsigned long BatVref = 2560;            //mV ; this must be measured on the AREF pin accurately with DMM 
											//after initiating 'analogReference(INTERNAL2V56);' and change here.
const unsigned long BatResolution = 1024;
const unsigned long BatRatio = ((BatRs[0] + BatRs[1]) * BatVref) / BatRs[1];
const unsigned long batVolt_Max = 12.8;
const unsigned long batVolt_Min = 10.7;
#define BatVolt_pin = 0;            //Analog pin # A0
int batVoltage = 0;

void BattVoltage() {
	
  analogReference(INTERNAL2V56);   // set the reference voltage level from 5V to 2.56V
  for (int i=0; i<8; i++) analogRead(BatVolt_pin);   // just burn some ADC readings after reference change
  delay(10);
  
  unsigned int adcValue = analogRead(BatVolt_pin);      // read the divided battery voltage on analog pin # 0
   
  // take the average of 5 readings:
  for (j = 0; j < 5; j++)  {
    batVoltage += = adcValue * BatRatio / BatResolution;
    delay(10);
  }
  batVoltage = batVoltage / 5; 
 
  analogReference(DEFAULT);                             // set back the reference voltage level to normal 5V 
  for (int i=0; i<8; i++) analogRead(BatVolt_pin);      // so later in the main/full program
  delay(10);		                                // it will not cause any trouble
    
  Serial.print("Batery voltage [mV]: ");  Serial.println(batVoltage);
  byte percentage = 100 * (batVoltage - batVolt_Min) / (batVolt_Max - batVolt_Min);
  Serial.print("Battery level [%]: ");  Serial.println(percentage);
  return percentage;
}

Another way to calibrate the system would be to:

  • Apply known (aka measure it) battery voltage
  • just print the raw ADC value (or do a little average)

Now the calibrated value for 'BatRatio' is simply:

BatRatio = Vbat * 1024 / adcValue
With Vbat in mV.

This will make 'BatRs' and 'BatVref' obsolete.

For the sketch, just drop

for (int i=0; i<8; i++) analogRead(BatVolt_pin);

You already have the small delay. I think this delay can even be shorter.

And especially in the average I would reduce the delay(). 50ms is already pretty blocking.

And two point about the battery percentage:

a) You have an error in the calculation. Or, at least in the values used. Vbat is in mV, so 'batVolt_Max' and 'batVolt_Min' need to be as well

b) The percentage value will not give you a real indication. Battery capacity is not at all lineair with voltage. So now it will probably drop very quick, hover around a certain value most of the time and at the end drop quickly again.

Example of a discharge curve:

And do yourself (and especially future-self) a favor, pick a single naming convention and stick with it. I use camelCase as is tradition with Arduino, and in this case I used UpperCamelCase to indicate constants. With 'batVolt_Max' you mix camelCase and underscores which makes it harder to remember how to write a variable name. Was it 'batVoltMax'? 'bat_Volt_max'? 'bat_voltMax'? If you stick to a convention you just know how to write it.

Thank You for the guidance for septilion and pointing out the major discrepancies. The modified script:

const unsigned long BatRs[] = {51028, 9979};    // as long as they have the same unit
const unsigned long BatVref = 2560;            //mV ; this must be measured on the AREF pin accurately with DMM
					//after initiating 'analogReference(INTERNAL2V56);' and change here.
const unsigned long BatResolution = 1024;
const unsigned long BatRatio = ((BatRs[0] + BatRs[1]) * BatVref) / BatRs[1];
const float BatVoltMax = 12800;		//mV
const float BatVoltMin = 10700;		//mV
int BatVoltPin = 0;     //Anlaoge pin # A0


void battVoltage() {
	
  analogReference(INTERNAL2V56);   // set the reference voltage level from 5V to 2.56V
  for (int i=0; i<8; i++) analogRead(BatVoltPin);   // just burn some ADC readings after reference change
  delay(2);

  unsigned int adcValue = analogRead(BatVoltPin);      // read the divided battery voltage on analog pin # 0
 
  analogReference(DEFAULT);                 // set back the reference voltage level to normal 5V
  for (int i=0; i<8; i++) analogRead(BatVoltPin);      // so later in the main/full program no trouble
  delay(2);
 
  unsigned int batVoltage = adcValue * BatRatio / BatResolution;
  Serial.print("Batery voltage: [mV]: ");  Serial.println(batVoltage);
  byte percentage = 100 * (batVoltage - BatVoltMin) / (BatVoltMax - BatVoltMin);  //to be replaced
  Serial.print("Battery level [%]: ");  Serial.println(percentage);    // with regression func.
  return percentage;
}

I modified for reference measurement this code as well:

int value;
void setup()
{
 analogReference(INTERNAL2V56);
 value = analogRead(0);    //The effect of analogReference() call doesn't take place till the next call to analogRead()
}

void loop()
{
}

This is giving on MEGA AREF's pin with DMM 2.465 V, instead of 2.560 V.
So row#2 to be modified to: const unsigned long BatVref = 2465; //mV

Regarding point b): This is a major obstacle and the note is absolutely correct.
I think for more accurate calculation the following steps are required:

  • I have to get the characteristic of the battery.
  • Guess the average discharging current and calculate C.
  • Split the selected curve in three section and approximate the curve with some functions.
  • Calculate the capacity (%).
  • The above is valid on a certain temperature !

Just on more thing regarding BatResolution = 1024;
If I connect 5V out from UNO to same UNO analog A0 and run this code:

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

void loop()
{
Serial.println(analogRead(0));
}

I got 1023, so 5V == 1023
I think const unsigned long BatResolution = 1024; to be changed to
const unsigned long BatResolution = 1023;

steger:
I think const unsigned long BatResolution = 1024; to be changed to
const unsigned long BatResolution = 1023;

O no, you opened a box of spiders. This has been a long discussion. The final answer by Nick Gammon is here: Gammon Forum : Electronics : Microprocessors : ADC conversion on the Arduino (analogRead).

In short: The ADC has 1024 steps. It can measure 0V, but it can not measure 5V. The 5V would be the 1025th step. The division factor must therefor be 1024. That is the range of the ADC and the range is required for the calculation.
When you apply 5V to the analog input, then you are already one step too high for the ADC.
The voltage range is still exactly 5V.

Example: suppose the 5V is exactly 5.000000V. If you read a value of 1023, that means you measure 1023/1024 * 5V. That is correct, that is the level one step below 5V. At 5V there is one step overvoltage.

Note: When the analogReference() is set to 1.1V, then the ADC can measure between 0V and 1.1V and everything between 1.1 and 5V returns 1023. That is okay, nothing will be damaged.

Did you check my averageRead.ino in a previous post ? I already mentioned there the 1024 and the half-a-bit and I also mentioned Nick Gammon's page.

@steger Close but no sigar.

Small changes:

const unsigned long BatRs[] = {51028, 9979};    // as long as they have the same unit
const unsigned long BatVref = 2465;            //mV ; this must be measured on the AREF pin accurately with DMM
 //after initiating 'analogReference(INTERNAL2V56);' and change here.
const unsigned long BatResolution = 1024;
const unsigned long BatRatio = ((BatRs[0] + BatRs[1]) * BatVref) / BatRs[1];
const unsigned long BatVoltMax = 12800; //mV
const unsigned long BatVoltMin = 10700; //mV
const byte BatVoltPin = A0;     //Analog pin # A0


void battVoltage() {
  analogReference(INTERNAL2V56);   // set the reference voltage level from 5V to 2.56V
  //for (int i=0; i<8; i++) analogRead(BatVoltPin);   // just burn some ADC readings after reference change
  delay(2);

  unsigned int adcValue = analogRead(BatVoltPin);      // read the divided battery voltage on analog pin # 0
 
  analogReference(DEFAULT);                 // set back the reference voltage level to normal 5V
  //for (int i=0; i<8; i++) analogRead(BatVoltPin);      // so later in the main/full program no trouble
  delay(2);
 
  unsigned int batVoltage = adcValue * BatRatio / BatResolution;
  Serial.print("Battery voltage: [mV]: ");  
  Serial.println(batVoltage);
  byte percentage = 100 * (batVoltage - BatVoltMin) / (BatVoltMax - BatVoltMin);  //to be replaced
  Serial.print("Battery level [%]: ");  
  Serial.println(percentage);    // with regression func.
  //return percentage; //return type is void so not allowed
}

Did you also note the easier way to calibrate it in a single measurement?

Koepel:
O no, you opened a box of spiders.

Hehe, my thought exactly :smiley:

@Koepel
Can of worms indeed; I tried (unsuccessfully) to explain this in a way with which no-one could argue. Guess I underestimated arduinoers.

The "academically" correct conversion is range * (n +0.5) / 1024

but ..

the 0.5 is less than the accuracy of the converter - so lets forget it.

and .. yes lets work in millivolts AND integers - because some will take 2560mV * 7 / 1024

and get 17.500 - which is nonsense.

@steger

Why do you keep changing the analog reference?
Do you NEED to measure something against the DEFAULT?

void battVoltage() {
	
  analogReference(INTERNAL2V56);   // set the reference voltage level from 5V to 2.56V
  analogRead(BatVoltPin);   // you only need one
  delay(2);

  unsigned int adcValue = analogRead(BatVoltPin);      // read the divided battery voltage on analog pin # 0
 
  // analogReference(DEFAULT);                 // set back the reference voltage level to normal 5V  WHY?
  for (int i=0; i<8; i++)  analogRead(BatVoltPin);     //and put the result WHERE? This is doing nothing.

  delay(2);
 
  unsigned int batVoltage = adcValue * BatRatio / BatResolution;
  Serial.print("Batery voltage: [mV]: ");  Serial.println(batVoltage);
  byte percentage = 100 * (batVoltage - BatVoltMin) / (BatVoltMax - BatVoltMin);  //to be replaced
  Serial.print("Battery level [%]: ");  Serial.println(percentage);    // with regression func.
  return percentage;
}

I dont think using an array here is productive in code, basically just confusing.
As they are constants just give them names - no indication of what they are even in the comment.

const unsigned long BatRs[] = {51028, 9979};    // as long as they have the same unit
const unsigned long BatVref = 2465;            //mV ; this must be measured on the AREF pin accurately 
const unsigned long BatResolution = 1024;
const unsigned long BatRatio = ((BatRs[0] + BatRs[1]) * BatVref) / BatRs[1];

@septillion

  //return percentage; //return type is void so not allowed

would it make more sense to declare percentage AND function type as integer?

Dear johnerrington,

thank You very much for Your feedback.
Yes, I need the to measure something against the DEFAULT later on. (The function will be called later if some button is pressed.) I just kept it like this (no harm) and info for others, how to set back, but if somebody would like to use only this script it can be commented out of course to avoid any confusion.

I updated the script with the proposal of Koepel dated 7th of Jan. Thank You for the advise Koepel ! Highly appreciated ! :wink:

const unsigned long BatRs[] = {51028, 9979};    // as long as they have the same unit
const unsigned long BatVref = 2560;            //mV ; this must be measured on the AREF pin accurately with DMM 
											//after initiating 'analogReference(INTERNAL2V56);' and change here.
const unsigned long BatResolution = 1024;
const unsigned long BatRatio = ((BatRs[0] + BatRs[1]) * BatVref) / BatRs[1];
const unsigned long BatVoltMax = 13500; //mV
const unsigned long BatVoltMin = 10400; //mV
#define BatVolt_pin = 0;     //Anlaoge pin # A0
const int nSamples = 1000;   // Usually from 5 to 10000

byte BattVoltage() {
  analogReference(INTERNAL2V56);   // set the reference voltage level from 5V to 2.56V

  // unsigned int adcValue = analogRead(BatVoltPin);      // read the divided battery voltage on analog pin # 0
  // unsigned int batVoltage = (adcValue + 0.5) * BatRatio / BatResolution; // add them up
  // take the average of few readings for better accuracy:
  // https://gist.github.com/Koepel/f7d625a6e5c0481fc4c7a9c530c643ef   :
  unsigned int adcValue = averageRead(BatVolt_pin);  // read the average of the divided battery voltage on analog pin # 0
  unsigned int batVoltage = adcValue * BatRatio / BatResolution;
 
 Serial.print("Batery voltage [mV]: ");  Serial.println(batVoltage);
  byte percentage = 100 * (batVoltage - batVolt_Min) / (batVolt_Max - batVolt_Min);  // to be improved
  Serial.print("Battery level [%]: ");  Serial.println(percentage);
  return percentage;
}


float averageRead(int pin)
{
  unsigned long total = 0;
  for( int i=0; i < nSamples; i++)
  {
    total += (unsigned long) analogRead(pin);
  }
  total += nSamples / 2;   // add half a bit
  return(float(total) / float(nSamples));
}

Now bigger issue is the characteristic of the batteries, which are depending on the discharge rate[C-Rate] & temperature. So this formula to be improved::
byte percentage = 100 * (batVoltage - BatVoltMin) / (BatVoltMax - BatVoltMin);
As improvement, I have to measure the temperature on the battery (or inside :wink: ) and current supply from the battery to the full circuit and the function itself:
f% = f(batVoltage, Tbattery, Crate)
Crate = Isupply [A] / NominalCapacityBattery [Ah]
As a starter I thought this schematics:

LiFePO4 charastersitic_C.jpg

LiFePO4 charastersitic_Temp.jpg

LiFePO4 charastersitic_C.jpg

LiFePO4 charastersitic_Temp.jpg

I need the to measure something against the DEFAULT later on.

WHY?

It makes no sense to measure against two different references.
While the "INTERNAL" reference is not too bad, if calibrated, the "DEFAULT" is not reliable at all.

My recommendation would be to use a better EXTERNAL voltage reference as described here
for all your measurements, then you can expect consistency and accuracy.

You can choose an external reference to suit your measurement range and so get better accuracy and precision.

The ACS712 requires indeed the DEFAULT voltage reference of 5V, because it does not output a voltage, it outputs a certain fraction of the 5V.
steger, those ACS712 modules are very inaccurate. Assume they are 20% inaccurate as a start. Maybe it can be improved later.

Thanks @Koepel, I didnt spot that.
In which case would it be sensible to calibrate the default against the internal reference using the "magic voltmeter" and do everything with the default reference - assuming Vcc is stable?

johnerrington:
In which case would it be sensible to calibrate the default against the internal reference using the "magic voltmeter" and do everything with the default reference - assuming Vcc is stable?

That is possible, but changing the reference voltage is made for this situation. Since there is a 100nF at AREF, some time is needed and the first ADC value might not be valid.
The 5V is probably not really stable. It will be less stable than the internal reference.

With a Arduino Mega 2560 board + Ethernet shield I switch the reference voltage all the time, and I also run the "magic voltmeter" all the time. Returning to normal after the "magic voltmeter" took more effort. I had to increase the delay to 20ms and do more than one dummy analogRead(). I made a mistake in my project. I put everything on a prototype shield and now the current to the Mega+Ethernet causes a offset to my voltage measurements. That is because R2 of the voltage divider is connected to the GND on the prototype shield. The offset is only 6mV, but it is noticeable.

@steger Again, did you notice the easy calibrate option :wink:

float averageRead(int pin)

Why is that float so damn tempting :wink: Keep it integer :slight_smile:

#define BatVolt_pin = 0;     //Anlaoge pin # A0

What's wrong with a type ave integer!?

I would still wait a bit for the ref to settle after changing it. Now you include the settling into the averaging.

byte BattVoltage() {
[...]
return percentage;

Seems rather confusing to me :wink:

Also, try
to
keep
the
indentation
in check

And about percentage. Yeah, you can take temperature and current all in consideration, but do you really need to now it that accurate in that many situation? I can tell you, most consumer electronics does not bother. And are you actually downing that much current? And do you expect it to set in the freezing cold?

const unsigned long BatRs[] = {51028, 9979};    // as long as they have the same unit
const unsigned long BatVref = 2560;            //mV ; this must be measured on the AREF pin accurately with DMM
											//after initiating 'analogReference(INTERNAL2V56);' and change here.
const unsigned long BatResolution = 1024;
const unsigned long BatRatio = ((BatRs[0] + BatRs[1]) * BatVref) / BatRs[1];
const unsigned long BatVoltMax = 13500; //mV
const unsigned long BatVoltMin = 10400; //mV
const byte BatVoltPin = A0;     //Analog pin # A0
const unsigned int NrSamples = 1000;   // Usually from 5 to 10000

byte batteryPercentage() {
  analogReference(INTERNAL2V56);   // set the reference voltage level from 5V to 2.56V
  delay(2); //I would still wait for it to settle in

  // unsigned int adcValue = analogRead(BatVoltPin);      // read the divided battery voltage on analog pin # 0
  // unsigned int batVoltage = (adcValue + 0.5) * BatRatio / BatResolution; // add them up
  // take the average of few readings for better accuracy:
  // https://gist.github.com/Koepel/f7d625a6e5c0481fc4c7a9c530c643ef   :
  unsigned int adcValue = averageRead(BatVoltPin);  // read the average of the divided battery voltage on analog pin # 0
  analogReference(DEFAULT); //switch back for later use
  unsigned int batVoltage = adcValue * BatRatio / BatResolution;
 
  Serial.print("Batery voltage [mV]: "); 
  Serial.println(batVoltage);
  byte percentage = 100 * (batVoltage - batVolt_Min) / (batVolt_Max - batVolt_Min);  // to be improved
  Serial.print("Battery level [%]: ");  //<= statement ends, next line please!
  Serial.println(percentage);
  
  
  return percentage;
}


unsigned int averageRead(byte pin){
  unsigned long total = 0;
  for(unsigned int i = 0; i < NrSamples; i++)
  {
    total += analogRead(pin);
  }
  total += nSamples / 2;   // add half a bit
  return (total / NrSamples);
}

I prefer calculations in the source code with numbers that are in real units (liters, meters, volt, ampere, kPa, kg, and so on).
With float calculations there is no trouble with overflow or divisions, it is just as fast (maybe 50% slower, that's peanuts) and most important: the source code is more readable.
Using the 10-bit ADC value for a calculation with 32-bit single precision float is just fine. Nothing bad will happen.

septillion, my averageRead() function is supposed to return a float. That is the whole point of that function. It uses noise to get a little more information than the 10-bit from the ADC.

Don't sink, stay float :wink:

steger, when Arduino users disagree and both solutions are good, then you can pick what seems best for you :smiley: