# amp | watt hour meter

I’ve built a voltage and current monitor using a ACS715 from Pololu. I’m calculating hours using millis, and total amp hours consumed. millis is a unsigned long, but I’d like to see hours in operation in a format like 1.25 hours, not jumps from 0 - 1 - 2 etc. Photo’s, schematics etc. posted at http://tech.groups.yahoo.com/group/arduinohome/.

``````/* 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.

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

arrow on carrier board points to load, other lug connects to
power supply positive

*/
int batMonPin = A4;    // input pin for the voltage divider
int batVal = 0;       // variable for the A/D value
float pinVoltage = 0; // variable to hold the calculated voltage
float batteryVoltage = 0;
float ratio = 3.2;  // Change this to match the MEASURED ration of the circuit
int sensorValue = 0;        // value read from the carrier board
int outputValue = 0;        // output in milliamps
unsigned long time = 0;
int sample = 0;
float totalAmps = 0.0;
float averageAmps = 0.0;
unsigned long hours = 0;
float ampHours = 0.0;

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

void loop() {

// increment sample counter

sample = ++sample;

time = millis();

// convert to milli amps
outputValue = (((long)sensorValue * 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

*/

pinVoltage = batVal * 0.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.   */

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

// print the results to the serial monitor:
Serial.print("Voltage = " );
Serial.print(batteryVoltage);
Serial.print("\t Current (ma) = ");
Serial.print(outputValue);
Serial.print("\t Power (Watts) = ");
float amps = outputValue / 1000.0;
float watts = amps * batteryVoltage;
Serial.print(watts);

totalAmps = totalAmps + amps;

averageAmps = totalAmps / sample;

hours = time/3600000;

ampHours = averageAmps * hours;

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

Serial.print("\t Energy (ah) = ");
Serial.println(ampHours);

// wait 10 milliseconds before the next loop
// for the analog-to-digital converter to settle
delay(10);
}
`````` but I’d like to see hours in operation in a format like 1.25 hours, not jumps from 0 - 1 - 2 etc.

It’s your code. You are free to do that. You don’t need our permission.

Could you be any less helpful? An idea on how to do that, or even a suggestion on some other improvement would have been more appropriate.

Could you be any less helpful?

I could try.

An idea on how to do that

You have hour as an integer, so storing 1.25 in that is not going to work. You want some resolution on time that is less than 1 hour. You need to define what that resolution is. If it is 1/4 hour, then you need to keep track of minutes, not hours. When you need to know how much time has elapsed, you divide minutes by 60 to get hours. You then subtract 60 times the number of hours to get the remainder. Multiply that value by 4 to get quarter hours.

If the time that you have measured is 78 minutes, that's 1 hour and 18 minutes, or 1 hour, 1 quarter hour and 3 minutes. Ignore the minutes. You can decide to round or truncate as you see fit. You might want 85 minutes to be 1 hour and 1 quarter hour or 1 hour and 2 quarter hours.

Oops, that was not being less helpful. I'll try harder in the future.

even a suggestion on some other improvement would have been more appropriate.

You asked a specific question. "Can I do this?" I answered that question. You did not ask how to do it, or for a review of the code, so I didn't answer those unasked questions.

``````  sample = ++sample;
``````
``````++sample;
``````

is equivalent to

``````sample = sample + 1;
``````

So, your code is equivalent to

``````sample = sample = sample + 1;
``````

A bit of redundancy there, no?

Start by converting the time into minutes.
Divide by 60 to get the hours.
Modulus divide by 60 to get the minutes.
The total time (as a float) would be hours plus (type casted to float) minutes divided by 60.

I’d calculate the charge more directly - at each sample point multiply the current by the time since the last sample, this gives an estimate of the charge that has flowed in this sample period. Add that to the totalCharge variable (you wrongly call this totalAmps).

The ampere-hours value is totalCharge/3600.0 since 1Ah = 3600C.

Thanks for the help. Got it working the way I wanted it. See attached:

``````/* 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.

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

arrow on carrier board points to load, other lug connects to
power supply positive

*/
int batMonPin = A4;    // input pin for the voltage divider
int batVal = 0;       // variable for the A/D value
float pinVoltage = 0; // variable to hold the calculated voltage
float batteryVoltage = 0;
float ratio = 3.2;  // Change this to match the MEASURED ration of the circuit
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;
unsigned long hours = 0;
unsigned long minutes = 0;
float ampHours = 0.0;
float wattHours = 0.0;
float amps = 0.0;

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

void loop() {

// convert to milli amps
outputValue = (((long)sensorValue * 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

*/

pinVoltage = batVal * 0.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.

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

// print the results to the serial monitor:
amps = (float) outputValue / 1000;

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

float watts = amps * batteryVoltage;
Serial.print(watts);

sample = sample + 1;

msec = millis();

totalCharge = totalCharge + amps;

minutes = msec/1000/60;

time = (float) minutes / 60;

ampHours = totalCharge/time;

averageAmps = totalCharge / sample;

ampHours = averageAmps*time;

wattHours = batteryVoltage * ampHours;

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

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

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

New updates, including LCD, and improved voltage divider fixing an impedance mismatch. Also showcased on http://www.instructables.com/id/DIY-Amp-Hour-Meter-Arduino/

``````#include <LiquidCrystal.h>

/* 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

arrow on carrier board points to load, other lug connects to
power supply positive

*/
int batMonPin = A4;    // input pin for the voltage divider
int batVal = 0;       // variable for the A/D value
float pinVoltage = 0; // variable to hold the calculated voltage
float batteryVoltage = 0;
float ratio = 2.4;  // Change this to match the MEASURED ration of the circuit, 12k R1 and 5k R2
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;

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

void loop() {

// convert to milli amps
outputValue = (((long)sensorValue * 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

*/

pinVoltage = batVal * 0.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.

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 ");

// wait 10 milliseconds before the next loop
// for the analog-to-digital converter to settle 