0.2.2 ACS712

This commit is contained in:
rob tillaart 2021-06-24 14:41:36 +02:00
parent 3157f59bd2
commit 697f27f05a
11 changed files with 162 additions and 82 deletions

View File

@ -1,87 +1,98 @@
//
// FILE: ACS712.cpp
// AUTHOR: Rob Tillaart, Pete Thompson
// VERSION: 0.2.1
// VERSION: 0.2.2
// DATE: 2020-08-02
// PURPOSE: ACS712 library - current measurement
//
// HISTORY:
// 0.1.0 2020-03-17 initial version
// 0.1.1 2020-03-18 first release version
// 0.1.2 2020-03-21 automatic formfactor test
// 0.1.3 2020-05-27 fix library.json
// 0.1.4 2020-08-02 Allow for faster processors
// 0.2.0 2020-08-02 Add autoMidPoint
// 0.2.1 2020-12-06 Add arduino-CI + readme + unittest + refactor
// HISTORY:
// 0.1.0 2020-03-17 initial version
// 0.1.1 2020-03-18 first release version
// 0.1.2 2020-03-21 automatic form factor test
// 0.1.3 2020-05-27 fix library.json
// 0.1.4 2020-08-02 Allow for faster processors
// 0.2.0 2020-08-02 Add autoMidPoint
// 0.2.1 2020-12-06 Add Arduino-CI + readme + unit test + refactor
// 0.2.2 2021-06-23 support for more frequencies.
#include "ACS712.h"
ACS712::ACS712(uint8_t analogPin, float volts, uint16_t maxADC, uint8_t mVperA)
{
_pin = analogPin;
_mVpstep = 1000.0 * volts / maxADC; // 1x 1000 for V -> mV
_mVperAmpere = mVperA;
_formFactor = 0.70710678119; // 0.5 * sqrt(2); TODO: should be smaller in practice 0.5 ?
_formFactor = ACS712_FF_SINUS;
_midPoint = maxADC / 2;
_noisemV = 21; // Noise is 21mV according to datasheet
}
int ACS712::mA_AC(uint8_t freq)
{
uint32_t start = micros();
uint16_t period = ((freq == 60) ? 16670 : 20000);
uint16_t period = (1000000UL + freq/2) / freq;
uint16_t samples = 0;
uint16_t zeros = 0;
uint16_t zeros = 0;
int _min, _max;
_min = _max = analogRead(_pin);
// remove expensive float operation from loop.
uint16_t zeroLevel = round(_noisemV/_mVpstep);
uint32_t start = micros();
while (micros() - start < period) // UNO ~180 samples...
{
samples++;
int val = analogRead(_pin);
if (val < _min) _min = val;
if (val > _max) _max = val;
if (abs(val - _midPoint) <= (_noisemV/_mVpstep)) zeros++;
else if (val > _max) _max = val;
if (abs(val - _midPoint) <= zeroLevel ) zeros++;
}
int point2point = (_max - _min);
// automatic determine _formFactor / crest factor
float D = 0;
float FF = 0;
if (zeros > samples * 0.025)
if (zeros > samples * 0.025) // more than 2% zero's
{
D = 1.0 - (1.0 * zeros) / samples; // % SAMPLES NONE ZERO
FF = sqrt(D) * 0.5 * sqrt(2); // ASSUME NON ZERO PART ~ SINUS
D = 1.0 - (1.0 * zeros) / samples; // % SAMPLES NONE ZERO
FF = sqrt(D) * ACS712_FF_SINUS; // ASSUME NON ZERO PART ~ SINUS
}
else // # zeros is small => D --> 1 --> sqrt(D) --> 1
{
FF = 0.5 * sqrt(2);
FF = ACS712_FF_SINUS;
}
_formFactor = FF;
// math could be partially precalculated: C = 1000.0 * 0.5 * _mVpstep / _mVperAmpere;
// rounding?
return 1000.0 * 0.5 * point2point * _mVpstep * _formFactor / _mVperAmpere;
// value could be partially precalculated: C = 1000.0 * 0.5 * _mVpstep / _mVperAmpere;
// return 1000.0 * 0.5 * point2point * _mVpstep * _formFactor / _mVperAmpere);
return round( (500.0 * point2point) * _mVpstep * _formFactor / _mVperAmpere);
}
int ACS712::mA_DC()
{
// read twice to stabilize...
analogRead(_pin);
int steps = analogRead(_pin) - _midPoint;
return 1000.0 * steps * _mVpstep / _mVperAmpere;
// read twice to stabilize...
analogRead(_pin);
int steps = analogRead(_pin) - _midPoint;
return 1000.0 * steps * _mVpstep / _mVperAmpere;
}
// configure by sampling for 2 cycles of AC
// Also works for DC as long as no current flowing
void ACS712::autoMidPoint(uint8_t freq)
{
uint32_t start = micros();
uint16_t twoPeriods = ((freq == 60) ? 16670 : 20000) * 2;
uint32_t total = 0;
uint16_t twoPeriods = (2000000UL + freq/2) / freq;
uint32_t total = 0;
uint32_t samples = 0;
while (micros() - start < twoPeriods) {
uint32_t start = micros();
while (micros() - start < twoPeriods)
{
uint16_t reading = analogRead(_pin);
total += reading;
samples ++;
@ -91,4 +102,5 @@ void ACS712::autoMidPoint(uint8_t freq)
_midPoint = total / samples;
}
// END OF FILE
// -- END OF FILE --

View File

@ -2,7 +2,7 @@
//
// FILE: ACS712.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.1
// VERSION: 0.2.2
// DATE: 2020-08-02
// PURPOSE: ACS712 library - current measurement
//
@ -11,7 +11,13 @@
#include "Arduino.h"
#define ACS712_LIB_VERSION "0.2.1"
#define ACS712_LIB_VERSION (F("0.2.2"))
// ACS712_FF_SINUS == 1.0/sqrt(2) == 0.5 * sqrt(2)
// should be smaller in practice 0.5 ?
#define ACS712_FF_SINUS (1.0/sqrt(2))
#define ACS712_FF_SQUARE (1.0)
#define ACS712_FF_TRIANGLE (1.0/sqrt(3))
class ACS712
@ -28,14 +34,18 @@ class ACS712
// 30A 66
ACS712(uint8_t analogPin, float volts = 5.0, uint16_t maxADC = 1023, uint8_t mVperA = 100);
// returns mA
// blocks 20-21 ms to sample a whole 50 or 60 Hz period.
// lower frequencies block longer.
int mA_AC(uint8_t freq = 50);
// returns mA
// blocks < 1 ms
int mA_DC();
// midpoint ADC for DC only
inline void setMidPoint(uint16_t mp) { _midPoint = mp; };
inline uint16_t getMidPoint() { return _midPoint; };
@ -44,18 +54,23 @@ class ACS712
// Auto midPoint, assuming zero DC current or any AC current
void autoMidPoint(uint8_t freq = 50);
// also known as crest factor; affects AC only
inline void setFormFactor(float ff) { _formFactor = ff; };
// also known as crest factor; affects mA_AC() only
// default sinus.
inline void setFormFactor(float ff = ACS712_FF_SINUS) { _formFactor = ff; };
inline float getFormFactor() { return _formFactor; };
// noise
inline void setNoisemV(uint8_t noisemV) { _noisemV = noisemV; };
// noise defaults 21
inline void setNoisemV(uint8_t noisemV = 21) { _noisemV = noisemV; };
inline uint8_t getNoisemV() { return _noisemV; };
// AC and DC
inline void setmVperAmp(uint8_t mva) { _mVperAmpere = mva; };
inline uint8_t getmVperAmp() { return _mVperAmpere; };
private:
uint8_t _pin;
float _mVpstep; // millivolt per step
@ -65,4 +80,4 @@ class ACS712
uint8_t _noisemV;
};
// END OF FILE
// -- END OF FILE --

View File

@ -1,23 +1,24 @@
//
// FILE: ACS712_20_AC.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-03-18
// (c) : MIT
//
#include "ACS712.h"
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
// ACS712 5A uses 185 mV per A
// ACS712 20A uses 100 mV per A
// ACS712 30A uses 66 mV per A
ACS712 ACS(A0, 5.0, 1023, 100);
// ESP 32 example (requires resistors to step down the logic voltage)
//ACS712 ACS(25, 5.0, 4095, 185);
void setup()
{
Serial.begin(115200);
@ -30,6 +31,7 @@ void setup()
Serial.println(ACS.getNoisemV());
}
void loop()
{
int mA = ACS.mA_AC();
@ -39,4 +41,5 @@ void loop()
Serial.println(ACS.getFormFactor());
}
// END OF FILE
// -- END OF FILE --

View File

@ -1,23 +1,24 @@
//
// FILE: ACS712_20_AC_DEMO.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: demo to set midpoint and mVperAmpere for class.
// DATE: 2020-03-18
// (c) : MIT
//
#include "ACS712.h"
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
// ACS712 5A uses 185 mV per A
// ACS712 20A uses 100 mV per A
// ACS712 30A uses 66 mV per A
ACS712 ACS(A0, 5.0, 1023, 100);
// ESP 32 example (requires resistors to step down the logic voltage)
//ACS712 ACS(25, 5.0, 4095, 185);
void setup()
{
Serial.begin(115200);
@ -25,6 +26,7 @@ void setup()
ACS.autoMidPoint();
}
void loop()
{
int mA = ACS.mA_AC();
@ -47,4 +49,5 @@ void loop()
delay(1000);
}
// END OF FILE
// -- END OF FILE --

View File

@ -1,23 +1,24 @@
//
// FILE: ACS712_20_DC.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-03-18
// (c) : MIT
//
#include "ACS712.h"
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
// ACS712 5A uses 185 mV per A
// ACS712 20A uses 100 mV per A
// ACS712 30A uses 66 mV per A
ACS712 ACS(A0, 5.0, 1023, 100);
// ESP 32 example (requires resistors to step down the logic voltage)
//ACS712 ACS(25, 5.0, 4095, 185);
void setup()
{
Serial.begin(115200);
@ -25,10 +26,12 @@ void setup()
ACS.autoMidPoint();
}
void loop()
{
int mA = ACS.mA_DC();
Serial.println(mA);
}
// END OF FILE
// -- END OF FILE --

View File

@ -1,23 +1,24 @@
//
// FILE: ACS712_20_DC_DEMO.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo to set midpoint and mVperAmpere for class.
// DATE: 2020-03-18
// (c) : MIT
//
#include "ACS712.h"
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
// ACS712 5A uses 185 mV per A
// ACS712 20A uses 100 mV per A
// ACS712 30A uses 66 mV per A
ACS712 ACS(A0, 5.0, 1023, 100);
// ESP 32 example (requires resistors to step down the logic voltage)
//ACS712 ACS(25, 5.0, 4095, 185);
void setup()
{
Serial.begin(115200);
@ -25,6 +26,7 @@ void setup()
ACS.autoMidPoint();
}
void loop()
{
int mA = ACS.mA_DC();
@ -45,4 +47,5 @@ void loop()
delay(1000);
}
// END OF FILE
// -- END OF FILE --

View File

@ -1,23 +1,30 @@
# Syntax Coloring Map For ACS712
# Datatypes (KEYWORD1)
# Data types (KEYWORD1)
ACS712 KEYWORD1
# Methods and Functions (KEYWORD2)
mA_AC KEYWORD2
mA_DC KEYWORD2
setMidPoint KEYWORD2
getMidPoint KEYWORD2
incMidPoint KEYWORD2
decMidPoint KEYWORD2
setFormFactor KEYWORD2
getFormFactor KEYWORD2
setNoisemV KEYWORD2
getNoisemV KEYWORD2
setmVperAmp KEYWORD2
getmVperAmp KEYWORD2
# Constants (LITERAL1)
ACS712_LIB_VERSION LITERAL1
ACS712_FF_SINUS LITERAL1
ACS712_FF_SQUARE LITERAL1
ACS712_FF_TRIANGLE LITERAL1

View File

@ -19,9 +19,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/ACS712"
"url": "https://github.com/RobTillaart/ACS712.git"
},
"version": "0.2.1",
"version": "0.2.2",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*"

View File

@ -1,5 +1,5 @@
name=ACS712
version=0.2.1
version=0.2.2
author=Rob Tillaart <rob.tillaart@gmail.com>, Pete Thompson <pete.thompson@yahoo.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=ACS712 library for Arduino.

View File

@ -31,65 +31,94 @@ on the signal form. For a perfect sinus the value is sqrt(2)/2.
#### Base
- **ACS712(analogPin, volts = 5.0, maxADC = 1023, mVperA = 100)** constructor
- **mA_AC(freq = 50)** blocks ~21 ms to sample a whole 50 or 60 Hz period.
- **mA_DC()**
- **ACS712(analogPin, volts = 5.0, maxADC = 1023, mVperA = 100)** constructor. It defaults a 20 A type sensor, which is defined by the default value of mVperA. See below.
- **mA_AC(freq = 50)** blocks ~21 ms to sample a whole 50 or 60 Hz period. Since version 0.2.2 frequencies other than 50 and 60 are supported, the lower the frequency, the longer the blocking period.
- **mA_DC()** blocks < 1 ms as it just needs one analogue read.
| type sensor | mVperA | LSB 5V-10bit |
|:-------------|:------:|:------------:|
| 5 A | 185 | ~25 mA |
| 20 A | 100 | ~50 mA |
| 30 A | 66 | ~75 mA |
#### Midpoint
- **setMidPoint(mp)** sets midpoint ADC for DC only
- **autoMidPoint(uint8_t freq = 50)** Auto midPoint, assuming zero DC current or any AC current
- **getMidPoint()** read back setting
- **incMidPoint()** manual increase midpoint (manually)
- **decMidPoint()** manual decrease midpoint (manually)
- **setMidPoint(mp)** sets midpoint for the ADC
- **autoMidPoint(uint8_t freq = 50)** Auto midPoint, assuming zero DC current or any AC current. Note it will block for 2 periods. Since version 0.2.2 frequencies other than 50 and 60 are supported.
- **getMidPoint()** read back the value set / determined.
- **incMidPoint()** manual increase midpoint, e.g. useful to manually adjust the midPoint in an interactive application.
- **decMidPoint()** manual decrease midpoint
#### Formfactor
Also known as crest factor; affects AC only.
Default = 0.5 \* sqrt(2) = ~0.70710678...
Also known as crest factor; affects AC signals only.
- **setFormFactor(ff = ACS712_FF_SINUS)** manually sets form factor 0.0 .. 1.0,
- **getFormFactor()** returns current form factor
The library has a number of predefined form factors
| definition | value | approx | notes |
|:---------------------|:--------------|:------:|:--------|
| ACS712_FF_SINUS | 1.0 / sqrt(2) | 0.707 | default |
| ACS712_FF_SQUARE | 1.0 | 1.000 | |
| ACS712_FF_TRIANGLE | 1.0 / sqrt(3) | 0.577 | |
| | | | |
It is important to measure the current with a calibrated multimeter
and determine / verify the form factor of the signal. This can help
to improve the quality of your measurements.
- **setFormFactor(ff)** manually sets formfactor 0.0 .. 1.0
- **getFormFactor()** returns current formFactor
#### Noise
Default = 21 mV.
- **setNoisemV(noisemV)** set noise level
- **setNoisemV(noisemV = 21)** set noise level, is used to determine zero level e.g. in AC measurements.
- **getNoisemV()** returns set value
#### mV per Ampere
Both for AC and DC
Both for AC and DC. Is defined in the constructor and depends on
- **setmVperAmp(mva)** sets the milliVolt per Ampere measured.
- **getmVperAmp()** returns set value.
Typical values see constructor above.
## Test
The library is tested with the RobotDyn ACS712 20A breakout and an Arduino UNO.
The library is tested with the RobotDyn ACS712 20 A breakout and an Arduino UNO.
## Operation
With the constructor the parameters **volts** and **maxADC (steps)** of the ADC are set
together with the **milliVolt per Ampere** value. The last parameter can be adjusted
afterwards, e.g. to callibrate this value runtime. Note this parameter affects both
afterwards, e.g. to calibrate this value runtime. Note this parameter affects both
AC and DC measurements.
To callibrate the zero level for DC measurements, 5 functions are available to
To calibrate the zero level for DC measurements, 5 functions are available to
adjust the midPoint.
To callibrate the RMS value for AC measurements, 2 functions are available to
To calibrate the RMS value for AC measurements, 2 functions are available to
get and set the formFactor.
To callibrate the noise level (used for AC measurements), 2 functions are available to
To calibrate the noise level (used for AC measurements), 2 functions are available to
get and set the noise in mV.
The examples show the basic working of the functions.
## Future
- mA_AC blocks 20 ms so might affect taskscheduling on a ESP32.
This needs to be investigated.
- int point2point(uint8_t freq) function for AC. Is part of mA_AC() allready.
- mA_AC blocks 20 ms so might affect task scheduling on a ESP32.
This needs to be investigated. Probably need a separate thread that wakes up when new analogRead is available.
- int point2point(uint8_t freq) function for AC. Is part of mA_AC() already. Needs extra global variables?
- float frequency as parameter? Or detect zero crossing to start?
- external analogue read support? separate class?

View File

@ -1,7 +1,6 @@
//
// FILE: unit_test_001.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// DATE: 2020-12-06
// PURPOSE: unit tests for the SHT31 temperature and humidity sensor
// https://github.com/RobTillaart/SHT31
@ -69,6 +68,7 @@ unittest(test_mA_AC)
assertEqual(1, 1);
}
unittest(test_midPoint)
{
ACS712 ACS(A0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
@ -95,6 +95,7 @@ unittest(test_midPoint)
assertEqual(1000, amp);
}
unittest(test_formFactor)
{
ACS712 ACS(A0, 5.0, 1023, 100);
@ -112,6 +113,7 @@ unittest(test_formFactor)
assertMoreOrEqual(0.0001, delta);
}
unittest(test_Noise)
{
ACS712 ACS(A0, 5.0, 1023, 100);
@ -124,6 +126,7 @@ unittest(test_Noise)
assertEqual(100, nmv);
}
unittest(test_mVperAmp)
{
ACS712 ACS(A0, 5.0, 1023, 100);
@ -136,6 +139,8 @@ unittest(test_mVperAmp)
assertEqual(50, mpa);
}
unittest_main()
// --------
// -- END OF FILE --