Go Down

### Topic: amp | watt hour meter (Read 7262 times)previous topic - next topic

#### sspence65

##### May 05, 2012, 03:07 pmLast Edit: May 12, 2012, 10:52 pm by Steve Spence - KK4HFJ Reason: 1
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/.

Code: [Select]
`/* 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 +5vGND on carrier board to Arduino GNDOUT on carrier board to Arduino A0Insert the power lugs into the loads positive lead circuit, arrow on carrier board points to load, other lug connects to power supply positive*/int batMonPin = A4;    // input pin for the voltage dividerint batVal = 0;       // variable for the A/D valuefloat pinVoltage = 0; // variable to hold the calculated voltagefloat batteryVoltage = 0;float ratio = 3.2;  // Change this to match the MEASURED ration of the circuitint analogInPin = A0;  // Analog input pin that the carrier board OUT is connected toint sensorValue = 0;        // value read from the carrier boardint outputValue = 0;        // output in milliampsunsigned 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();        // read the analog in value:  sensorValue = analogRead(analogInPin);              // 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, sodivide by 0.133 to convert mv to ma          */    batVal = analogRead(batMonPin);    // read the voltage on the divider  pinVoltage = batVal * 0.00488;       /*  Calculate the voltage on the A/D pinA reading of 1 for the A/D = 0.0048mVif 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  // after the last reading:  delay(10);                     }`
Steve Spence - ET/AT/R&D KK4HFJ

#### PaulS

#1
##### May 05, 2012, 03:30 pm
Quote
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.

#### sspence65

#2
##### May 05, 2012, 03:39 pm
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.
Steve Spence - ET/AT/R&D KK4HFJ

#### PaulS

#3
##### May 05, 2012, 03:57 pm
Quote
Could you be any less helpful?

I could try.

Quote
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.

Quote
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.

#### PaulS

#4
##### May 05, 2012, 03:59 pm
Code: [Select]
`  sample = ++sample;`
Code: [Select]
`++sample;`
is equivalent to
Code: [Select]
`sample = sample + 1;`
So, your code is equivalent to
Code: [Select]
`sample = sample = sample + 1;`
A bit of redundancy there, no?

#### Arrch

#5
##### May 05, 2012, 04:09 pm
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.

#### MarkT

#6
##### May 05, 2012, 04:41 pm
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.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

#### sspence65

#7
##### May 05, 2012, 08:46 pmLast Edit: May 05, 2012, 09:48 pm by Steve Spence - KK4HFJ Reason: 1
Thanks for the help. Got it working the way I wanted it. See attached:

Code: [Select]
`/* 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 +5vGND on carrier board to Arduino GNDOUT on carrier board to Arduino A0Insert the power lugs into the loads positive lead circuit, arrow on carrier board points to load, other lug connects to power supply positive*/int batMonPin = A4;    // input pin for the voltage dividerint batVal = 0;       // variable for the A/D valuefloat pinVoltage = 0; // variable to hold the calculated voltagefloat batteryVoltage = 0;float ratio = 3.2;  // Change this to match the MEASURED ration of the circuitint analogInPin = A0;  // Analog input pin that the carrier board OUT is connected toint sensorValue = 0;        // value read from the carrier boardint outputValue = 0;        // output in milliampsunsigned 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() {        // read the analog in value:  sensorValue = analogRead(analogInPin);              // 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, sodivide by 0.133 to convert mv to ma          */    batVal = analogRead(batMonPin);    // read the voltage on the divider  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  // after the last reading:  delay(10);                     }`
Steve Spence - ET/AT/R&D KK4HFJ

#### sspence65

#8
##### May 12, 2012, 10:51 pm
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/

Code: [Select]
`#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 +5vGND on carrier board to Arduino GNDOUT on carrier board to Arduino A0Insert the power lugs into the loads positive lead circuit, arrow on carrier board points to load, other lug connects to power supply positive*/int batMonPin = A4;    // input pin for the voltage dividerint batVal = 0;       // variable for the A/D valuefloat pinVoltage = 0; // variable to hold the calculated voltagefloat batteryVoltage = 0;float ratio = 2.4;  // Change this to match the MEASURED ration of the circuit, 12k R1 and 5k R2int analogInPin = A0;  // Analog input pin that the carrier board OUT is connected toint sensorValue = 0;        // value read from the carrier boardint outputValue = 0;        // output in milliampsunsigned 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() {        // read the analog in value:  sensorValue = analogRead(analogInPin);              // 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, sodivide by 0.133 to convert mv to ma          */     batVal = analogRead(batMonPin);    // read the voltage on the divider   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  // after the last reading:  delay(10);                     }`
Steve Spence - ET/AT/R&D KK4HFJ

#### sspence65

#9
##### May 16, 2012, 08:07 pmLast Edit: May 16, 2012, 08:10 pm by Steve Spence - KK4HFJ Reason: 1
I just received the ACS714 bidirectional hall effect sensor from Pololu. I'll be modifying the project to watch ah in and ah out, with a peukert calculation, for estimated capacity remaining.

I'm adding a low voltage disconnect circuit with a hybrid relay (eliminates MOSFET heating and relay arcing) to protect the battery from excessive discharge. When sketch starts, the MOSFET is enabled, then the relay. Upon voltage drop below predermined value, the relay drops, then the MOSFET. Use a SSR for an AC Load. Full instructable at http://www.instructables.com/id/DIY-Amp-Hour-Meter-Arduino/.
Steve Spence - ET/AT/R&D KK4HFJ

Go Up