Skip to content

Commit 07e6239

Browse files
committed
Add readPowerFactor
1 parent d75ad89 commit 07e6239

File tree

4 files changed

+178
-11
lines changed

4 files changed

+178
-11
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
Library for the Allegro MicroSystems ACS37800 power monitor IC
3+
By: Paul Clark
4+
SparkFun Electronics
5+
Date: December 4th, 2021
6+
License: please see LICENSE.md for details
7+
8+
Feel like supporting our work? Buy a board from SparkFun!
9+
https://www.sparkfun.com/products/17873
10+
*/
11+
12+
#include "SparkFun_ACS37800_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_ACS37800
13+
#include <Wire.h>
14+
15+
ACS37800 mySensor; //Create an object of the ACS37800 class
16+
17+
void setup()
18+
{
19+
Serial.begin(115200);
20+
Serial.println(F("ACS37800 Example"));
21+
22+
Wire.begin();
23+
24+
//mySensor.enableDebugging(); // Uncomment this line to print useful debug messages to Serial
25+
26+
//Initialize sensor using default I2C address
27+
if (mySensor.begin() == false)
28+
{
29+
Serial.print(F("ACS37800 not detected. Check connections and I2C address. Freezing..."));
30+
while (1)
31+
; // Do nothing more
32+
}
33+
34+
// From the ACS37800 datasheet:
35+
// CONFIGURING THE DEVICE FOR AC APPLICATIONS : DYNAMIC CALCULATION OF N
36+
// Set bypass_n_en = 0 (default). This setting enables the device to
37+
// dynamically calculate N based off the voltage zero crossings.
38+
mySensor.setBypassNenable(false, true); // Disable bypass_n in shadow memory and eeprom
39+
40+
// We need to connect the LO pin to the 'low' side of the AC source.
41+
// So we need to set the divider resistance to 4M Ohms (instead of 2M).
42+
mySensor.setDividerRes(4000000);
43+
}
44+
45+
void loop()
46+
{
47+
float volts = 0.0;
48+
float amps = 0.0;
49+
50+
mySensor.readRMS(&volts, &amps); // Read the RMS voltage and current
51+
Serial.print(F("Volts: "));
52+
Serial.print(volts, 2);
53+
Serial.print(F(" Amps: "));
54+
Serial.println(amps, 2);
55+
56+
float pactive = 0.0;
57+
float preactive = 0.0;
58+
59+
mySensor.readPowerActiveReactive(&pactive, &preactive); // Read the active and reactive power
60+
Serial.print(F("Power: Active (W): "));
61+
Serial.print(pactive, 2);
62+
Serial.print(F(" Reactive (VAR): "));
63+
Serial.println(preactive, 2);
64+
65+
float papparent = 0.0;
66+
float pfactor = 0.0;
67+
bool posangle = 0;
68+
bool pospf = 0;
69+
70+
mySensor.readPowerFactor(&papparent, &pfactor, &posangle, &pospf); // Read the apparent power and the power factor
71+
Serial.print(F("Power: Apparent (VA): "));
72+
Serial.print(papparent, 2);
73+
Serial.print(F(" Power Factor: "));
74+
Serial.print(pfactor, 2);
75+
if (posangle)
76+
Serial.print(F(" Lagging"));
77+
else
78+
Serial.print(F(" Leading"));
79+
if (pospf)
80+
Serial.println(F(" Consumed"));
81+
else
82+
Serial.println(F(" Generated"));
83+
84+
delay(250);
85+
}

keywords.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ setBypassNenable KEYWORD2
4040
getBypassNenable KEYWORD2
4141
getCurrentCoarseGain KEYWORD2
4242
readRMS KEYWORD2
43-
readRMSActiveReactive KEYWORD2
43+
readPowerActiveReactive KEYWORD2
44+
readPowerFactor
4445
readInstantaneous KEYWORD2
4546
readErrorFlags KEYWORD2
4647
setSenseRes KEYWORD2

src/SparkFun_ACS37800_Arduino_Library.cpp

+89-9
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ ACS37800ERR ACS37800::readRMS(float *vRMS, float *iRMS)
592592
}
593593

594594
// Read volatile register 0x21. Return the pactive and pimag.
595-
ACS37800ERR ACS37800::readRMSActiveReactive(float *pActive, float *pReactive)
595+
ACS37800ERR ACS37800::readPowerActiveReactive(float *pActive, float *pReactive)
596596
{
597597
ACS37800_REGISTER_21_t store;
598598
ACS37800ERR error = readRegister(&store.data.all, ACS37800_REGISTER_VOLATILE_21); // Read register 21
@@ -601,7 +601,7 @@ ACS37800ERR ACS37800::readRMSActiveReactive(float *pActive, float *pReactive)
601601
{
602602
if (_printDebug == true)
603603
{
604-
_debugPort->print(F("readRMSActiveReactive: readRegister (21) returned: "));
604+
_debugPort->print(F("readPowerActiveReactive: readRegister (21) returned: "));
605605
_debugPort->println(error);
606606
}
607607
return (error); // Bail
@@ -628,9 +628,9 @@ ACS37800ERR ACS37800::readRMSActiveReactive(float *pActive, float *pReactive)
628628
float power = (float)signedUnsigned.Signed;
629629
if (_printDebug == true)
630630
{
631-
_debugPort->print(F("readRMSActiveReactive: pactive: 0x"));
631+
_debugPort->print(F("readPowerActiveReactive: pactive: 0x"));
632632
_debugPort->println(signedUnsigned.unSigned, HEX);
633-
_debugPort->print(F("readRMSActiveReactive: pactive (LSB, before correction) is "));
633+
_debugPort->print(F("readPowerActiveReactive: pactive (LSB, before correction) is "));
634634
_debugPort->println(power);
635635
}
636636
float LSBpermW = 3.08; // LSB per mW
@@ -643,12 +643,12 @@ ACS37800ERR ACS37800::readRMSActiveReactive(float *pActive, float *pReactive)
643643
power /= 1000; // Convert from mW to W
644644
if (_printDebug == true)
645645
{
646-
_debugPort->print(F("readRMSActiveReactive: pactive (W, after correction) is "));
646+
_debugPort->print(F("readPowerActiveReactive: pactive (W, after correction) is "));
647647
_debugPort->println(power);
648648
}
649649
*pActive = power;
650650

651-
// Extract pimag. Convert to Watts
651+
// Extract pimag. Convert to VAR
652652
// Note: datasheet says:
653653
// "Reactive power output. This field is an unsigned 16-bit fixed
654654
// point number with 16 fractional bits, where MaxPow = 0.704. To
@@ -661,9 +661,9 @@ ACS37800ERR ACS37800::readRMSActiveReactive(float *pActive, float *pReactive)
661661
power = (float)store.data.bits.pimag;
662662
if (_printDebug == true)
663663
{
664-
_debugPort->print(F("readRMSActiveReactive: pimag: 0x"));
664+
_debugPort->print(F("readPowerActiveReactive: pimag: 0x"));
665665
_debugPort->println(store.data.bits.pimag, HEX);
666-
_debugPort->print(F("readRMSActiveReactive: pimag (LSB, before correction) is "));
666+
_debugPort->print(F("readPowerActiveReactive: pimag (LSB, before correction) is "));
667667
_debugPort->println(power);
668668
}
669669
float LSBpermVAR = 6.15; // LSB per mVAR
@@ -675,14 +675,94 @@ ACS37800ERR ACS37800::readRMSActiveReactive(float *pActive, float *pReactive)
675675
power /= 1000; // Convert from mVAR to VAR
676676
if (_printDebug == true)
677677
{
678-
_debugPort->print(F("readRMSActiveReactive: pimag (VAR, after correction) is "));
678+
_debugPort->print(F("readPowerActiveReactive: pimag (VAR, after correction) is "));
679679
_debugPort->println(power);
680680
}
681681
*pReactive = power;
682682

683683
return (error);
684684
}
685685

686+
// Read volatile register 0x22. Return the apparent power, power factor, leading / lagging, generated / consumed
687+
ACS37800ERR ACS37800::readPowerFactor(float *pApparent, float *pFactor, bool *posangle, bool *pospf)
688+
{
689+
ACS37800_REGISTER_22_t store;
690+
ACS37800ERR error = readRegister(&store.data.all, ACS37800_REGISTER_VOLATILE_22); // Read register 22
691+
692+
if (error != ACS37800_SUCCESS)
693+
{
694+
if (_printDebug == true)
695+
{
696+
_debugPort->print(F("readPowerFactor: readRegister (22) returned: "));
697+
_debugPort->println(error);
698+
}
699+
return (error); // Bail
700+
}
701+
702+
// Extract papparent. Convert to VA
703+
// Note: datasheet says:
704+
// "Apparent power output magnitude. This field is an unsigned
705+
// 16-bit fixed point number with 16 fractional bits, where MaxPow
706+
// = 0.704. To convert the value (input power) to line power, divide
707+
// the input power by the RSENSE and RISO voltage divider ratio
708+
// using actual resistor values."
709+
// Datasheet also says:
710+
// "6.15 LSB/mVA for the 30A version and 2.05 LSB/mVA for the 90A version"
711+
712+
float power = (float)store.data.bits.papparent;
713+
if (_printDebug == true)
714+
{
715+
_debugPort->print(F("readPowerFactor: papparent: 0x"));
716+
_debugPort->println(store.data.bits.papparent, HEX);
717+
_debugPort->print(F("readPowerFactor: papparent (LSB, before correction) is "));
718+
_debugPort->println(power);
719+
}
720+
float LSBpermVA = 6.15; // LSB per mVA
721+
LSBpermVA *= 30.0 / _currentSensingRange; // Correct for sensor version
722+
power /= LSBpermVA; //Convert from codes to mVA
723+
//Correct for the voltage divider: (RISO1 + RISO2 + RSENSE) / RSENSE
724+
//Or: (RISO1 + RISO2 + RISO3 + RISO4 + RSENSE) / RSENSE
725+
float resistorMultiplier = (_dividerResistance + _senseResistance) / _senseResistance;
726+
power *= resistorMultiplier;
727+
power /= 1000; // Convert from mVAR to VAR
728+
if (_printDebug == true)
729+
{
730+
_debugPort->print(F("readPowerFactor: papparent (VA, after correction) is "));
731+
_debugPort->println(power);
732+
}
733+
*pApparent = power;
734+
735+
// Extract power factor
736+
// Datasheet says:
737+
// "Power factor output. This field is a signed 11-bit fixed point number
738+
// with 10 fractional bits. It ranges from –1 to ~1 with a step
739+
// size of 2^-10."
740+
741+
union
742+
{
743+
int16_t Signed;
744+
uint16_t unSigned;
745+
} signedUnsigned; // Avoid any ambiguity when casting to signed int
746+
747+
signedUnsigned.unSigned = store.data.bits.pfactor << 5; // Move 11-bit number into 16-bits (signed)
748+
749+
float pfactor = (float)signedUnsigned.Signed / 32768.0; // Convert to +/- 1
750+
if (_printDebug == true)
751+
{
752+
_debugPort->print(F("readPowerFactor: pfactor: 0x"));
753+
_debugPort->println(store.data.bits.pfactor, HEX);
754+
_debugPort->print(F("readPowerFactor: pfactor is "));
755+
_debugPort->println(pfactor);
756+
}
757+
*pFactor = pfactor;
758+
759+
// Extract posangle and pospf
760+
*posangle = store.data.bits.posangle & 0x1;
761+
*pospf = store.data.bits.pospf & 0x1;
762+
763+
return (error);
764+
}
765+
686766
// Read volatile registers 0x2A and 0x2C. Return the vInst (Volts), iInst (Amps) and pInst (VAR).
687767
ACS37800ERR ACS37800::readInstantaneous(float *vInst, float *iInst, float *pInst)
688768
{

src/SparkFun_ACS37800_Arduino_Library.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,8 @@ class ACS37800
411411

412412
//Basic methods for accessing the volatile registers
413413
ACS37800ERR readRMS(float *vRMS, float *iRMS); // Read volatile register 0x20. Return the vRMS and iRMS.
414-
ACS37800ERR readRMSActiveReactive(float *pActive, float *pReactive); // Read volatile register 0x21. Return the pactive and pimag (reactive)
414+
ACS37800ERR readPowerActiveReactive(float *pActive, float *pReactive); // Read volatile register 0x21. Return the pactive and pimag (reactive)
415+
ACS37800ERR readPowerFactor(float *pApparent, float *pFactor, bool *posangle, bool *pospf); // Read volatile register 0x22. Return the apparent power, power factor, leading / lagging, generated / consumed
415416
ACS37800ERR readInstantaneous(float *vInst, float *iInst, float *pInst); // Read volatile registers 0x2A and 0x2C. Return the vInst, iInst and pInst.
416417
ACS37800ERR readErrorFlags(ACS37800_REGISTER_2D_t *errorFlags); // Read volatile register 0x2D. Return its contents in errorFlags.
417418

0 commit comments

Comments
 (0)