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 3k for R2 (experiment with <10k resistors till you get a likely pair). This calculates a R1 of 9K. Try to keep the values as close to, but under 10k Ohms as possible.
R1 = 9k Ohms
R2 = 3k Ohms
Vout = (R1 / (R1 + R2)) * Vin
Vout = (9000 / (9000 + 3000)) * 20v
Vout = (9000 / 12000) * 20v
Vout = .75 * 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 = 9k Ohm and R2 = 3k 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
Improved voltage reading circuit and sketch at AC Volt Meter (works with DC as well). Rock solid voltage measurement, and very accurate.