Skip to content

Commit

Permalink
add setADC() (#32)
Browse files Browse the repository at this point in the history
* add setADC() for external ADC
  • Loading branch information
RobTillaart authored Jan 15, 2023
1 parent 793130c commit fd01481
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 41 deletions.
71 changes: 44 additions & 27 deletions ACS712.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// FILE: ACS712.cpp
// AUTHOR: Rob Tillaart, Pete Thompson
// VERSION: 0.3.3
// VERSION: 0.3.4
// DATE: 2020-08-02
// PURPOSE: ACS712 library - current measurement
// URL: https://github.com/RobTillaart/ACS712
Expand All @@ -14,13 +14,19 @@
ACS712::ACS712(uint8_t analogPin, float volts, uint16_t maxADC, float mVperAmpere)
{
_pin = analogPin;
_mVperAmpere = mVperAmpere;
_formFactor = ACS712_FF_SINUS;
_noisemV = ACS712_DEFAULT_NOISE; // 21mV according to datasheet

// set in setADC()
// keep it here until after experimental.
_maxADC = maxADC;
_mVperStep = 1000.0 * volts / maxADC; // 1x 1000 for V -> mV
_mVperAmpere = mVperAmpere;
_mAPerStep = 1000.0 * _mVperStep / _mVperAmpere;
_formFactor = ACS712_FF_SINUS;
_midPoint = maxADC / 2;
_noisemV = ACS712_DEFAULT_NOISE; // 21mV according to datasheet

// default ADC is internal.
setADC(_internalAnalog, volts, maxADC);
}


Expand All @@ -36,16 +42,16 @@ float ACS712::mA_peak2peak(float frequency, uint16_t cycles)
{
int minimum, maximum;
// Better than using midPoint
minimum = maximum = analogRead(_pin);
minimum = maximum = _readADC(_pin);

// find minimum and maximum
uint32_t start = micros();
while (micros() - start < period) // UNO ~180 samples...
while (micros() - start < period) // UNO ~180 samples...
{
int value = analogRead(_pin);
int value = _readADC(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + analogRead(_pin))/2;
value = (value + _readADC(_pin))/2;
}
// determine extremes
if (value < minimum) minimum = value;
Expand Down Expand Up @@ -76,17 +82,17 @@ float ACS712::mA_AC(float frequency, uint16_t cycles)
uint16_t zeros = 0;

int _min, _max;
_min = _max = analogRead(_pin);
_min = _max = _readADC(_pin);

// find minimum and maximum and count the zero-level "percentage"
uint32_t start = micros();
while (micros() - start < period) // UNO ~180 samples...
{
samples++;
int value = analogRead(_pin);
int value = _readADC(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + analogRead(_pin))/2;
value = (value + _readADC(_pin))/2;
}
// determine extremes
if (value < _min) _min = value;
Expand Down Expand Up @@ -138,10 +144,10 @@ float ACS712::mA_AC_sampling(float frequency, uint16_t cycles)
while (micros() - start < period)
{
samples++;
int value = analogRead(_pin);
int value = _readADC(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + analogRead(_pin))/2;
value = (value + _readADC(_pin))/2;
}
float current = value - _midPoint;
sumSquared += (current * current);
Expand All @@ -163,15 +169,15 @@ float ACS712::mA_AC_sampling(float frequency, uint16_t cycles)
float ACS712::mA_DC(uint16_t cycles)
{
// read at least twice to stabilize the ADC
analogRead(_pin);
_readADC(_pin);
if (cycles == 0) cycles = 1;
float sum = 0;
for (uint16_t i = 0; i < cycles; i++)
{
int value = analogRead(_pin);
int value = _readADC(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + analogRead(_pin))/2;
value = (value + _readADC(_pin))/2;
}
sum += (value - _midPoint);
}
Expand Down Expand Up @@ -227,7 +233,7 @@ uint16_t ACS712::autoMidPoint(float frequency, uint16_t cycles)
uint32_t start = micros();
while (micros() - start < twoPeriods)
{
uint16_t reading = analogRead(_pin);
uint16_t reading = _readADC(_pin);
subTotal += reading;
samples++;
// Delaying prevents overflow
Expand Down Expand Up @@ -323,14 +329,14 @@ float ACS712::detectFrequency(float minimalFrequency)
{
int maximum = 0;
int minimum = 0;
maximum = minimum = analogRead(_pin);
maximum = minimum = _readADC(_pin);

// determine maxima
uint32_t timeOut = round(1000000.0 / minimalFrequency);
uint32_t start = micros();
while (micros() - start < timeOut)
{
int value = analogRead(_pin);
int value = _readADC(_pin);
if (value > maximum) maximum = value;
if (value < minimum) minimum = value;
}
Expand All @@ -346,13 +352,13 @@ float ACS712::detectFrequency(float minimalFrequency)
timeOut *= 10;
start = micros();
// casting to int to keep compiler happy.
while ((int(analogRead(_pin)) > Q1) && ((micros() - start) < timeOut));
while ((int(analogRead(_pin)) <= Q3) && ((micros() - start) < timeOut));
while ((int(_readADC(_pin)) > Q1) && ((micros() - start) < timeOut));
while ((int(_readADC(_pin)) <= Q3) && ((micros() - start) < timeOut));
start = micros();
for (int i = 0; i < 10; i++)
{
while ((int(analogRead(_pin)) > Q1) && ((micros() - start) < timeOut));
while ((int(analogRead(_pin)) <= Q3) && ((micros() - start) < timeOut));
while ((int(_readADC(_pin)) > Q1) && ((micros() - start) < timeOut));
while ((int(_readADC(_pin)) <= Q3) && ((micros() - start) < timeOut));
}
uint32_t stop = micros();

Expand Down Expand Up @@ -380,13 +386,13 @@ float ACS712::getMicrosAdjust()
// DEBUG
uint16_t ACS712::getMinimum(uint16_t milliSeconds)
{
uint16_t minimum = analogRead(_pin);
uint16_t minimum = _readADC(_pin);

// find minimum
uint32_t start = millis();
while (millis() - start < milliSeconds)
{
uint16_t value = analogRead(_pin);
uint16_t value = _readADC(_pin);
if (value < minimum) minimum = value;
}
return minimum;
Expand All @@ -395,18 +401,29 @@ uint16_t ACS712::getMinimum(uint16_t milliSeconds)

uint16_t ACS712::getMaximum(uint16_t milliSeconds)
{
uint16_t maximum = analogRead(_pin);
uint16_t maximum = _readADC(_pin);

// find minimum
uint32_t start = millis();
while (millis() - start < milliSeconds)
{
uint16_t value = analogRead(_pin);
uint16_t value = _readADC(_pin);
if (value > maximum) maximum = value;
}
return maximum;
}


void ACS712::setADC(uint16_t (* f)(uint8_t), float volts, uint16_t maxADC)
{
_readADC = f;

_maxADC = maxADC;
_mVperStep = 1000.0 * volts / maxADC; // 1x 1000 for V -> mV
_mAPerStep = 1000.0 * _mVperStep / _mVperAmpere;
_midPoint = maxADC / 2;
}


// -- END OF FILE --

25 changes: 16 additions & 9 deletions ACS712.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// FILE: ACS712.h
// AUTHOR: Rob Tillaart, Pete Thompson
// VERSION: 0.3.3
// VERSION: 0.3.4
// DATE: 2020-08-02
// PURPOSE: ACS712 library - current measurement
// URL: https://github.com/RobTillaart/ACS712
Expand All @@ -13,7 +13,7 @@

#include "Arduino.h"

#define ACS712_LIB_VERSION (F("0.3.3"))
#define ACS712_LIB_VERSION (F("0.3.4"))


// ACS712_FF_SINUS == 1.0/sqrt(2) == 0.5 * sqrt(2)
Expand Down Expand Up @@ -105,6 +105,9 @@ class ACS712
uint16_t getMaximum(uint16_t milliSeconds = 20);


// EXPERIMENTAL 0.3.4
void setADC(uint16_t (*)(uint8_t), float volts, uint16_t maxADC);

private:
uint8_t _pin;
uint16_t _maxADC;
Expand All @@ -116,16 +119,20 @@ class ACS712
uint8_t _noisemV;
float _microsAdjust = 1.0; // 0.9986
bool _suppresNoise = false;

// EXPERIMENTAL 0.3.4
// supports up to 16 bits ADC.
uint16_t (* _readADC)(uint8_t);
};


// simulate analogRead() - develop only -
// static int aRead(uint8_t pin)
// {
// float t = micros();
// float value = 515 + 50 * sin(t * PI / 180.0);
// return value;
// }
// wrapper for internal analogRead()
// solves platform specific casting.
static uint16_t _internalAnalog(uint8_t pin)
{
return analogRead(pin);
}


// -- END OF FILE --

10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).


## [0.3.3] - 2023-03-01
## [0.3.4] - 2023-01-14
- experimental
- add **void setADC()** to use an external ADC for measurements.
- add **static uint16_t internalAnalog(uint8_t p)** wrapping analogRead() - solves casting.
- add example ACS712_20_DC_external_ADC.ino


## [0.3.3] - 2023-01-03
- update GitHub actions
- update license
- add example
- add URL in .h .cpp


## [0.3.2] - 2022-11-18
- fix #26 revert data type \_midPoint to int
- Add CHANGELOG.md
Expand Down
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ float formFactor = 2.0 * mA_AC_sampling() / ACS.mA_peak2peak();
See - ACS712_20_determine_form_factor.ino



#### Noise

Default = 21 mV (datasheet)
Expand Down Expand Up @@ -274,6 +273,23 @@ Testing with my UNO I got a factor 0.9986.
Current version is experimental and not performance optimized.


#### setADC (experimental 0.3.4)

- **void setADC(uint16_t (\*)(uint8_t), float volts, uint16_t maxADC)** sets the ADC function and its parameters.
Defaults the internal **analogRead()** by this wrapper in ACS712.h:
```cpp
static uint16_t _internalAnalog(uint8_t pin)
{
return analogRead(pin);
}
```
Be sure to set the parameters of the constructor correctly.
- example ACS712_20_DC_external_ADC.ino
- https://github.com/RobTillaart/ACS712/issues/31
## Voltage divider
As per issue #15 in which an ACS712 was connected via a voltage divider to the ADC of an ESP32.
Expand Down
57 changes: 57 additions & 0 deletions examples/ACS712_20_DC_external_ADC/ACS712_20_DC_external_ADC.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// FILE: ACS712_20_DC_external_ADC.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo to measure mA DC with external ADC
// URL: https://github.com/RobTillaart/ACS712

// use with Arduino Serial Plotter

#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 (might requires resistors to step down the logic voltage)
// ACS712 ACS(25, 3.3, 4095, 185);


void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("ACS712_LIB_VERSION: ");
Serial.println(ACS712_LIB_VERSION);

ACS.setADC(testADC, 10, 1023);

// ACS.autoMidPoint();
// Serial.println(ACS.getMidPoint());
}


void loop()
{
int mA = ACS.mA_DC();
Serial.println(mA);
delay(1000);
}

// wrapper needed for external analogRead()
// as casting behavior is undefined between different function signatures.
uint16_t testADC(uint8_t p)
{
// simulation
return 600 + p;
// replace with an external ADC call.
// return ADS.readADC(p);
// return analogRead(p + 1); // use another internal ADC
}


// -- END OF FILE --
3 changes: 3 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ getMicrosAdjust KEYWORD2
getMinimum KEYWORD2
getMaximum KEYWORD2

setADC KEYWORD2


# Constants (LITERAL1)
ACS712_LIB_VERSION LITERAL1

ACS712_FF_SINUS LITERAL1
ACS712_FF_SQUARE LITERAL1
ACS712_FF_TRIANGLE LITERAL1
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/ACS712.git"
},
"version": "0.3.3",
"version": "0.3.4",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=ACS712
version=0.3.3
version=0.3.4
author=Rob Tillaart <[email protected]>, Pete Thompson <[email protected]>
maintainer=Rob Tillaart <[email protected]>
sentence=ACS712 library for Arduino.
Expand Down

0 comments on commit fd01481

Please sign in to comment.