loading

Major corrections and additions made 9/9/2014

See the new and improved 2015 version at http://www.green-trust.org/jmc

For my off-grid Ham Radio and Solar projects, I needed a way to measure volts, amps, watts, amp hours and watt hours. There's a couple of commercial products that can do this, but not with the flexibility I wanted. I designed a Arduino micro-controller based solution that is very extensible. Right now it monitors the above values of attached gear, and I'm thinking about adding web monitoring and a sd card for data collection. Well, let's get started.

Step 1: Voltage Divider

UPDATE 9/9/2014 !

The Arduino can accept up to 5v on a analog input. Our voltage can range as high as 20vdc in certain situations (open circuit pv voltage), so we designed a voltage divider that would provide 5v at 20v battery voltage, and less at various lower voltages. See http://en.wikipedia.org/wiki/Voltage_divider for more information on Voltage Dividers.

First we visit our friendly Voltage Divider Calculator. I input 20v as the input, 5v as the output, and 10k for R2 (experiment with <10k resistors till you get a likely pair). This calculates a R1 of 30K.

R1 = 30k Ohms

R2 = 10k Ohms

Vout = (R2 / (R1 + R2)) * Vin

Vout = (10000 / (30000 + 10000)) * 20v

Vout = (10000 / 40000) * 20v

Vout = .25 * 20v

Vout = 5v

Ratio = Vin / Vout

Ratio = 4

Because the Arduino has a 10-bit ADC, it outputs 0-1023 (1024 steps) for a 0-5v input. That's 0.00488v / step.

With a Voltage Divider with R1 = 30k Ohm and R2 = 10k Ohm, A 12v battery would calculate as follows:

12v / Ratio = 3v on the A4 pin.

3v / .00488 = 615 (ADC Reading - round up)

so A4 pin Voltage = .00488 * ADC reading (615 in this case), or 3.00 volts.

Then battery voltage = A4 pin voltage * Ratio (3 * 4 = 12)

The code to read that value is as follows:

ADCVal = analogRead(batMonPin); // read the voltage on the divider on pin A4
pinVoltage = ADCVal * 0.00488; // Calculate the voltage on the A/D pin
// A reading of 1 for the A/D = 0.00488mV
// if we multiply the A/D reading by 0.00488 then
// we get the voltage on the pin.

batteryVoltage = pinVoltage * Ratio; // Use the Ratio calculated for the voltage divider
// to calculate the battery voltage, Ratio = Vin / Vout



More details at http://arduinotronics.blogspot.com/2012/04/voltage-monitor.html

UPDATE:

Improved voltage reading circuit and sketch at AC Volt Meter (works with DC as well). Rock solid voltage measurement, and very accurate.

Step 2: Current Monitoring

The next step is to track the current being consumed by a load, or produced by a source. We are using a ACS715 Hall Effect sensor to track the current being passed.

Update! ACS714 Bidirectional current sensor now being deployed. This will enable a battery "gas gauge" for "AH IN - AH OUT = AMP Remaining" type monitoring.http://www.hacktronics.com/Sensors/Current-Sensor-30-to-30-Amp/flypage.tpl.html

Update! ACS712 5amp sensor project at 
http://arduinotronics.blogspot.com/2014/01/volt-amp-watt-hour-meter-shield.html

// read the analog in value:
  sensorValue = analogRead(analogInPin);           
  // convert to milli amps
  outputValue = (((long)sensorValue * 5000 / 1024) - 500 ) * 1000 / 133;
amps = (float) outputValue / 1000;

More details at http://arduinotronics.blogspot.com/2012/04/monitoring-power-consumption-with.html

Step 3: Math Alert!

To calculate watt (volts * amps), amp hours (amps * hours), and watt hours (watts * hours) requires tracking the time component, and performing a bit of math:

float watts = amps * batteryVoltage;

sample = sample + 1;

msec = millis();

time = (float) msec / 1000.0;

totalCharge = totalCharge + amps;

averageAmps = totalCharge / sample;

ampSeconds = averageAmps*time;

ampHours = ampSeconds/3600;

wattHours = batteryVoltage * ampHours;

Step 4: Serial Output

We can now output the results of the calculations to the serial port using the following code:


Serial.print("Volts = " );
Serial.print(batteryVoltage);
Serial.print("\t Current (amps) = ");
Serial.print(amps);
Serial.print("\t Power (Watts) = ");
Serial.print(watts);

Serial.print("\t Time (hours) = ");
Serial.print(time/3600);

Serial.print("\t Amp Hours (ah) = ");
Serial.print(ampHours);
Serial.print("\t Watt Hours (wh) = ");
Serial.println(wattHours);

Step 5: LCD Display

Keeping a computer connected all the time is inconvenient, so I added a 4 line lcd display to the project.

lcd.setCursor(0,0);
lcd.print(batteryVoltage);
lcd.print(" V ");
lcd.print(amps);
lcd.print(" A ");

lcd.setCursor(0,1);
lcd.print(watts);
lcd.print(" W ");
lcd.print(time/3600);
lcd.print(" H ");

lcd.setCursor(0,2);
lcd.print(ampHours);
lcd.print(" Ah ");
lcd.print(wattHours);
lcd.print(" Wh ");

Step 6: Source Code

All the code, schematics, and photo's along with discussion is available at http://tech.groups.yahoo.com/group/arduinohome/files/volt%20amp%20watt%20hour%20meter/ and http://forum.pololu.com/viewtopic.php?f=3&t=5415


#include

/* This sketch describes how to connect a ACS715 Current Sense Carrier
(http://www.pololu.com/catalog/product/1186) to the Arduino,
and read current flowing through the sensor.

*/

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

/*

Vcc on carrier board to Arduino +5v
GND on carrier board to Arduino GND
OUT on carrier board to Arduino A0



Insert the power lugs into the loads positive lead circuit,
arrow on carrier board points to load, other lug connects to
power supply positive

Voltage Divider

9k Ohm from + to A4
3k Ohm from A4 to Gnd


*/


int Vin = 20;

int Vout = 5;

int ratio = Vin / Vout; // Calculated from Vin / Vout

int batMonPin = A4; // input pin for the voltage divider
int ADCVal = 0; // variable for the A/D value
float pinVoltage = 0; // variable to hold the calculated voltage
float batteryVoltage = 0;

int analogInPin = A0; // Analog input pin that the carrier board OUT is connected to
int sensorValue = 0; // value read from the carrier board
int outputValue = 0; // output in milliamps
unsigned long msec = 0;
float time = 0.0;
int sample = 0;
float totalCharge = 0.0;
float averageAmps = 0.0;
float ampSeconds = 0.0;
float ampHours = 0.0;
float wattHours = 0.0;
float amps = 0.0;

int R1 = 9000; // Resistance of R1 in ohms
int R2 = 3000; // Resistance of R2 in ohms

int ratio = 0; // Calculated from Vin / Vout

void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
lcd.begin(20, 4);
}

void loop() {

int sampleADCVal = 0;
int avgADCVal = 0;
int sampleAmpVal = 0;
int avgSAV = 0;

for (int x = 0; x < 10; x++){ // run through loop 10x

// read the analog in value:
sensorValue = analogRead(analogInPin);
sampleAmpVal = sampleAmpVal + sensorValue; // add samples together

ADCVal = analogRead(batMonPin); // read the voltage on the divider
sampleADCVal = sampleADCVal + ADCVal; // add samples together

delay (10); // let ADC settle before next sample

}

avgSAV = sampleAmpVal / 10;

// convert to milli amps
outputValue = (((long)avgSAV * 5000 / 1024) - 500 ) * 1000 / 133;

/* sensor outputs about 100 at rest.
Analog read produces a value of 0-1023, equating to 0v to 5v.
"((long)sensorValue * 5000 / 1024)" is the voltage on the sensor's output in millivolts.
There's a 500mv offset to subtract.
The unit produces 133mv per amp of current, so
divide by 0.133 to convert mv to ma

*/


avgADCVal = sampleADCVal / 10; //divide by 10 (number of samples) to get a steady reading

pinVoltage = avgBVal * .00488; // Calculate the voltage on the A/D pin
/* A reading of 1 for the A/D = 0.0048mV
if we multiply the A/D reading by 0.00488 then
we get the voltage on the pin.



Also, depending on wiring and
where voltage is being read, under
heavy loads voltage displayed can be
well under voltage at supply. monitor
at load or supply and decide.
*/


batteryVoltage = pinVoltage * ratio; // Use the ratio calculated for the voltage divider
// to calculate the battery voltage


amps = (float) outputValue / 1000;
float watts = amps * batteryVoltage;

Serial.print("Volts = " );
Serial.print(batteryVoltage);
Serial.print("\t Current (amps) = ");
Serial.print(amps);
Serial.print("\t Power (Watts) = ");
Serial.print(watts);


sample = sample + 1;

msec = millis();



time = (float) msec / 1000.0;

totalCharge = totalCharge + amps;

averageAmps = totalCharge / sample;

ampSeconds = averageAmps*time;

ampHours = ampSeconds/3600;

wattHours = batteryVoltage * ampHours;





Serial.print("\t Time (hours) = ");
Serial.print(time/3600);

Serial.print("\t Amp Hours (ah) = ");
Serial.print(ampHours);
Serial.print("\t Watt Hours (wh) = ");
Serial.println(wattHours);


lcd.setCursor(0,0);
lcd.print(batteryVoltage);
lcd.print(" V ");
lcd.print(amps);
lcd.print(" A ");

lcd.setCursor(0,1);
lcd.print(watts);
lcd.print(" W ");
lcd.print(time/3600);
lcd.print(" H ");

lcd.setCursor(0,2);
lcd.print(ampHours);
lcd.print(" Ah ");
lcd.print(wattHours);
lcd.print(" Wh ");

lcd.setCursor(0,3);
lcd.print(ratio, 5);
lcd.print(" ");
lcd.print(avgBVal);

// wait 10 milliseconds before the next loop
// for the analog-to-digital converter to settle
// after the last reading:
delay(10);
}

Step 7: Future Expansion

Some of my ideas for expanding this project were along the lines of communications, like wifi or ethernet, with onboard webserver or attaching to Pachube / Cosm / Xively (https://xively.com/), a sd card for data logging, and today I had the idea of adding a low voltage disconnect to protect the battery from excessive discharge. I also designed a hybrid relay, which eliminates heating of the MOSFET Switch, and arcing of the relay contacts. I'll develop the code for this item shortly.

The hybrid relay enables spinoffs like dump load controllers for wind turbines, and load shedding for multi stage power downs or controlled power usage based on battery voltage or load priority.

Step 8: Protoboard

We have moved the current and voltage sensor off the solderless breadboard, and onto a Radio Shack proto board. This is more sturdy and "permanent".

Step 9: Web Based Interface With Database Back End

Currently working on a new web based front end, and a database back end. This will allow you to monitor your system remotely with a computer or smartphone, and see historical usage data. Stay tuned, coming very soon!

<p>Hi does the schematic diagram work for ac measurement? and also what changes in code will I do? hoping for your reply thanks :)</p>
<p>Hi, Could I contact you? Is it possible to do a device like yours but it can measure 5 Amps?</p>
very possible.<br><br>greentrust@gmail.com
The solar panel only produces what the load asks for (up to the limit of the panel and sun input). no load, no production.
<p>how to measure the solar power generated from solar panel instead of power consumption of a dc motor?</p>
what you measure depends on where you place your current sensor. place the current sensor in series with the solar panel, you then measure current drawn from the panel.
<p>when i connect the dc motor load to the panel, i only manage to measure the power consumed by the dc motor. anyway i can measure to solar panel POWER output instead?</p><p>if no load is connect, i'm merely measuring the Isc and Voc which does not represent the solar panel POWER OUTPUT i guess?</p>
dude, you rock. I was searching for this all over net.
<p>any progress on that webserver?</p>
<p>hello, can this be used in ac power source? thanks for your reply. :)</p>
Yes, with a different sensor, say a ACS714 or a CT.
thanks! I will try to do this since a kilowatt-hour meter is very expensive. I hope I don't blow up my arduino while working on ac source. ?
<p>Never supply high voltage to an arduino. Use a 9vdc adapter and a voltage divider to get voltages under 5vdc.</p>
<p>yes, will keep that in mind. btw, i am planning to measure the power consumption of my phone charger as it charges my phone. is it possible to do that? does your schematic works the same with an ACS714? thanks for your reply. :)</p>
<p>The schematic is similar (see datasheets), but the code would be different.</p>
thanks a lot! this would really help me ?
<p>Got your code working on OLED</p><p>Thanks </p>
<p>Hii</p><p>I'm making a device that can be connected to house electricity meters to measure current and power consumed over a short period of time (say 10 s.). Will this device work fine for the project? <br>Does this measures current/voltage continuously ?</p>
This device is designed for DC (solar, wind, off grid). I'm working on one now for ac.
<p>But isn't ACS714/715 capable of measuring AC Current values?</p>
<p>The acs714 can be used for ac or dc. the acs715 is dc only. For off grid solar dc applications, I actually prefer shunts, and for ac, I prefer current transducers.</p>
Another question, I noticed you used a voltage divider, what if I want to use a 5v regulator to supply, the arduino, will it work? if it will work do I have to add it to the code? if yes how do I do it?<br>thanks
using the same supply to measure voltage as well as power the arduino can cause measurement errors. Use a dc to dc converter off the original supply and all should be well. This one would work well -&nbsp;<a href="http://amzn.to/1UvrCWJ" rel="nofollow">http://amzn.to/1UvrCWJ</a>
Thank you so much for ur response. but my question goes this way.. what if I get an external 12v power supply and connect it to a 5v regulator (7805) do I have to add it to the code? if yes, how do I do it. cos I noticed that u added the voltage divider to the code. pls correct me if I'm wrong.<br>thanks
<p>the voltage divider is for measuring an input. unrelated to powering the arduino. you can build a voltage regualtor to power the arduino, and it has nothing to do with code.</p>
will arduino uno work for this project?
Absolutely.
<p>hello, can u put a clear schematic of ACS715 Hall Effect sensor so that we can build it since we can't buy it</p>
https://www.pololu.com/picture/view/0J1315
<p>just curious.</p><p>you call R1 30k and R2 10k yet the schem shows 9k and 3k ?</p><p>There is quite a difference and I just wondered which one was correct before I attempt this one.</p><p>I would like to use this with a 7 seg display for my boat battery (12V) and have already made a sketch for it but before I hook it up I want to be sure I am not going to fry anything.</p><p>Also am going to use a 3.3v pro mini so thinking that I should swap out the 5v (Vout) for 3.3 ??</p>
with a 12v input, R1=30k and r2 = 10k or r1 = 9k and r2 = 3k both return 3v. It's the same thing. I prefer using higher values to reduce power consumption. for your app R1= 120k, and r2=25k will return 2.931v at 17v input. should be good. http://www.raltron.com/cust/tools/voltage_divider.asp
<p>using this code we can calculate ah accurately only if battery is completly drained before connecting it to arduino.. This code will not be able to find the pre stored ah in the battery... can any one tell how to find the ah of battery exactly..</p>
<p>This code measures the consumed ah, not the ah stored in a battery. The only way to tell the capacity left in the battery is as you mention, periodically drain it, then refill it. </p>
<p>Hi, when I copied your source code and tried to compile it, there is error:</p><p>&quot;diymeter:58: error: redefinition of 'int ratio'<br><br> int ratio = 0; // Calculated from Vin / Vout<br><br> ^<br><br>diymeter:36: error: 'int ratio' previously declared here<br><br> int ratio = Vin / Vout; // Calculated from Vin / Vout<br><br> ^<br><br>C:\Users\Arek\Desktop\diymeter\diymeter.ino: In function 'void loop()':<br><br>diymeter:103: error: 'avgBVal' was not declared in this scope<br><br> pinVoltage = avgBVal * .00488; // Calculate the voltage on the A/D pin<br><br> ^<br><br>exit status 1<br>redefinition of 'int ratio' &quot;</p><p>Why is it so?</p>
<p>I'm trying to understand before I go buy this for my wind turbine project. Also, is the Uno good for this project?</p><p>In the calculation of current, I am a little confused. I need to put this in my paper so I need to fully understand it. </p><p>Does the sensor rest at 100 sensor value at 0V=0A? And where does the 1A = 133mV come from? Is it from the datasheet?</p><p>Can you please see what I'm wrong in the below?</p><p>5000mv = 30000mA, ratio is 1:6</p><p>ACS715OutputVoltage = (SensorValue - 100)* 5000/1024</p><p>Current = ACS715Voltage * 6</p>
<p>dear all,</p><p>where the formula below come from?</p><p>// convert to milli amps<br> outputValue = (((long)sensorValue * 5000 / 1024) - 500 ) * 1000 / 133;<br> amps = (float) outputValue / 1000;</p><p>some one can explain to me about those formula and the meaning of value 5000, 500, 133 ???</p>
I finished my project.<br> <br> First, depends on model, the current sensor would have different current range. They used ACS715 in this instructable:<br> <br> From datasheet <strong>(remember different model has different value)</strong>, its input current is 0-30A, and it outputs&nbsp;133mV/A,<br> <br> with &quot;Zero Current Output Voltage = Vcc * 0.1,<br> Vcc is supply voltage = 5V<br> so the current sensor should output 500mV at 0A.<br> <br> You should already know (from voltmeter part) arduino only reads 0-5000mV, with 1024 steps. So:<br> ((long)sensorValue * 5000 / 1024) is the voltage the arduino reads.<br> <br> minus the zeroing 500mv<br> <br> divide 133mV, times 1A = the current the sensor reads.<br> <br> <br>
<p>dear all,</p><p>where the formula below come from?</p><p>// convert to milli amps<br> outputValue = (((long)sensorValue * 5000 / 1024) - 500 ) * 1000 / 133;<br> amps = (float) outputValue / 1000;</p><p>some one can explain to me about those formula and the meaning of value 5000, 500, 133 ???</p>
<p>dear all,</p><p>where the formula below come from?</p><p>// convert to milli amps<br> outputValue = (((long)sensorValue * 5000 / 1024) - 500 ) * 1000 / 133;<br> amps = (float) outputValue / 1000;</p><p>some one can explain to me about those formula and the meaning of value 5000, 500, 133 ???</p>
well - i've now managed to bodge together some logging code using the adafruit SD card shield <br> <br>but - i'm troubled by non zero outputs when there's no voltage or current on the inputs - display is showing approx 15 volts and just under 15 amps when they should both be zero <br> <br>confused
I'm now unsure if i am seeing the fully updated code here as it as shown here will give inaccurate results if used with the ACS714 <br> <br>The bi-directional ACS714 output is centered on 2.5v - so zero current flow gives 2.5v - and not the 500mv as mentioned here and within the supplied code <br> <br>Also, the output of the ACS714 is 66mv/A rather than 133mV/A as mentioned here and within the supplied code <br> <br>hope this helps someone from having a confusing couple of hours as I have just experienced <br> <br>
This instructable is for the unidirectional acs715. I have not published a instructable for the acs714 as of yet.
<p>how about ACS712?</p><p>I missunderstand between readings of voltage divider and ACS712 sensor,</p><p>would you explain to me about ACS712 function on your project? (detail please)</p><p>thank you before,</p><p>best regards</p>
<p>the acs is a current sensor. the voltage divider is the voltage sensor.</p>
unplugging the SD card resolves the non zero volts - but i'm seeing 2.5v from the current sensor (to gnd) even when it's output pin isnt connected
Floating inputs won't be zero unless connected to ground through a resistor.
<p>good , pls. how resistor i must use to input voltage max 50v ? </p>
http://www.raltron.com/cust/tools/voltage_divider.asp says that R1 = 252k and R2 = 28k would be good values.
<p>thanks :)</p>
I have a strange problem...i duplicated your protoboard circuit (ammeter and voltage divider), and it served to work as expected. I then thought it should be easy to add an lm7805 voltage regulator to power the arduino from the measured voltage, and connected 7805's Vin to the voltage divider's input voltage, 7805's GND and Vout to the 4pin header's GND and VCC. Powered up, everything looks great so far... then i reconnected a small load to the hall sensor, and the arduino blacked out. Remove the load, it comes on and works again. Why is this happening and how might i correct it?

About This Instructable

356,988views

510favorites

License:

Bio: Professionally, I'm an IT Engineer (Executive Level) and Electronics Tech. I'm a Amateur Radio Operator (KK4HFJ). I lived off grid, with Solar (PV ... More »
More by sspence:DIY I2C LCD Display with Inputs Raspberry Pi & the Neo 6M GPS Earthquake / Vibration Sensor 
Add instructable to: