0.3.5 ACS712

This commit is contained in:
rob tillaart 2023-01-18 13:43:31 +01:00
parent cac33b7d86
commit aceae77552
6 changed files with 145 additions and 103 deletions

View File

@ -1,7 +1,7 @@
//
// FILE: ACS712.cpp
// AUTHOR: Rob Tillaart, Pete Thompson
// VERSION: 0.3.4
// VERSION: 0.3.5
// DATE: 2020-08-02
// PURPOSE: ACS712 library - current measurement
// URL: https://github.com/RobTillaart/ACS712
@ -26,7 +26,7 @@ ACS712::ACS712(uint8_t analogPin, float volts, uint16_t maxADC, float mVperAmper
_midPoint = maxADC / 2;
// default ADC is internal.
setADC(_internalAnalog, volts, maxADC);
setADC(NULL, volts, maxADC);
}
@ -42,16 +42,16 @@ float ACS712::mA_peak2peak(float frequency, uint16_t cycles)
{
int minimum, maximum;
// Better than using midPoint
minimum = maximum = _readADC(_pin);
minimum = maximum = _analogRead(_pin);
// find minimum and maximum
uint32_t start = micros();
while (micros() - start < period) // UNO ~180 samples...
{
int value = _readADC(_pin);
int value = _analogRead(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + _readADC(_pin))/2;
value = (value + _analogRead(_pin))/2;
}
// determine extremes
if (value < minimum) minimum = value;
@ -82,17 +82,17 @@ float ACS712::mA_AC(float frequency, uint16_t cycles)
uint16_t zeros = 0;
int _min, _max;
_min = _max = _readADC(_pin);
_min = _max = _analogRead(_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 = _readADC(_pin);
int value = _analogRead(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + _readADC(_pin))/2;
value = (value + _analogRead(_pin))/2;
}
// determine extremes
if (value < _min) _min = value;
@ -144,10 +144,10 @@ float ACS712::mA_AC_sampling(float frequency, uint16_t cycles)
while (micros() - start < period)
{
samples++;
int value = _readADC(_pin);
int value = _analogRead(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + _readADC(_pin))/2;
value = (value + _analogRead(_pin))/2;
}
float current = value - _midPoint;
sumSquared += (current * current);
@ -169,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
_readADC(_pin);
_analogRead(_pin);
if (cycles == 0) cycles = 1;
float sum = 0;
for (uint16_t i = 0; i < cycles; i++)
{
int value = _readADC(_pin);
int value = _analogRead(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + _readADC(_pin))/2;
value = (value + _analogRead(_pin))/2;
}
sum += (value - _midPoint);
}
@ -233,7 +233,7 @@ uint16_t ACS712::autoMidPoint(float frequency, uint16_t cycles)
uint32_t start = micros();
while (micros() - start < twoPeriods)
{
uint16_t reading = _readADC(_pin);
uint16_t reading = _analogRead(_pin);
subTotal += reading;
samples++;
// Delaying prevents overflow
@ -329,14 +329,14 @@ float ACS712::detectFrequency(float minimalFrequency)
{
int maximum = 0;
int minimum = 0;
maximum = minimum = _readADC(_pin);
maximum = minimum = _analogRead(_pin);
// determine maxima
uint32_t timeOut = round(1000000.0 / minimalFrequency);
uint32_t start = micros();
while (micros() - start < timeOut)
{
int value = _readADC(_pin);
int value = _analogRead(_pin);
if (value > maximum) maximum = value;
if (value < minimum) minimum = value;
}
@ -352,13 +352,13 @@ float ACS712::detectFrequency(float minimalFrequency)
timeOut *= 10;
start = micros();
// casting to int to keep compiler happy.
while ((int(_readADC(_pin)) > Q1) && ((micros() - start) < timeOut));
while ((int(_readADC(_pin)) <= Q3) && ((micros() - start) < timeOut));
while ((int(_analogRead(_pin)) > Q1) && ((micros() - start) < timeOut));
while ((int(_analogRead(_pin)) <= Q3) && ((micros() - start) < timeOut));
start = micros();
for (int i = 0; i < 10; i++)
{
while ((int(_readADC(_pin)) > Q1) && ((micros() - start) < timeOut));
while ((int(_readADC(_pin)) <= Q3) && ((micros() - start) < timeOut));
while ((int(_analogRead(_pin)) > Q1) && ((micros() - start) < timeOut));
while ((int(_analogRead(_pin)) <= Q3) && ((micros() - start) < timeOut));
}
uint32_t stop = micros();
@ -386,13 +386,13 @@ float ACS712::getMicrosAdjust()
// DEBUG
uint16_t ACS712::getMinimum(uint16_t milliSeconds)
{
uint16_t minimum = _readADC(_pin);
uint16_t minimum = _analogRead(_pin);
// find minimum
uint32_t start = millis();
while (millis() - start < milliSeconds)
{
uint16_t value = _readADC(_pin);
uint16_t value = _analogRead(_pin);
if (value < minimum) minimum = value;
}
return minimum;
@ -401,13 +401,13 @@ uint16_t ACS712::getMinimum(uint16_t milliSeconds)
uint16_t ACS712::getMaximum(uint16_t milliSeconds)
{
uint16_t maximum = _readADC(_pin);
uint16_t maximum = _analogRead(_pin);
// find minimum
uint32_t start = millis();
while (millis() - start < milliSeconds)
{
uint16_t value = _readADC(_pin);
uint16_t value = _analogRead(_pin);
if (value > maximum) maximum = value;
}
return maximum;
@ -425,5 +425,17 @@ void ACS712::setADC(uint16_t (* f)(uint8_t), float volts, uint16_t maxADC)
}
//////////////////////////////////////////////////////////////////////
//
// PRIVATE
//
uint16_t ACS712::_analogRead(uint8_t pin)
{
// if extern ADC is defined use it.
if (_readADC != NULL) return _readADC(pin);
return analogRead(pin);
}
// -- END OF FILE --

View File

@ -2,7 +2,7 @@
//
// FILE: ACS712.h
// AUTHOR: Rob Tillaart, Pete Thompson
// VERSION: 0.3.4
// VERSION: 0.3.5
// DATE: 2020-08-02
// PURPOSE: ACS712 library - current measurement
// URL: https://github.com/RobTillaart/ACS712
@ -13,7 +13,7 @@
#include "Arduino.h"
#define ACS712_LIB_VERSION (F("0.3.4"))
#define ACS712_LIB_VERSION (F("0.3.5"))
// ACS712_FF_SINUS == 1.0/sqrt(2) == 0.5 * sqrt(2)
@ -123,16 +123,10 @@ class ACS712
// EXPERIMENTAL 0.3.4
// supports up to 16 bits ADC.
uint16_t (* _readADC)(uint8_t);
uint16_t _analogRead(uint8_t pin);
};
// wrapper for internal analogRead()
// solves platform specific casting.
static uint16_t _internalAnalog(uint8_t pin)
{
return analogRead(pin);
}
// -- END OF FILE --

View File

@ -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.5] - 2023-01-18
- fix #33 failing build => issue 345 created @ arduino-ci
- redo **setADC()**
- allows reset to internal **analogRead()** too now.
- update README.md
## [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

View File

@ -21,7 +21,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/ACS712.git"
},
"version": "0.3.4",
"version": "0.3.5",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=ACS712
version=0.3.4
version=0.3.5
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

@ -275,21 +275,55 @@ 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:
- **void setADC(uint16_t (\*)(uint8_t), float volts, uint16_t maxADC)** sets the ADC function and the parameters of the used ADC.
The library uses the internal **analogRead()** as default.
Be sure to set the parameters of the ADC correctly.
The easiest way to implement an external ADC is to make a wrapper function as casting for
function pointer is a no go area.
```cpp
static uint16_t _internalAnalog(uint8_t pin)
// set to external ADC - 5 volts 12 bits
ACS.setADC(myAnalogRead, 5.0, 4096);
...
uint16_t myAnalogRead(uint8_t pin)
{
return analogRead(pin);
return MCP.read(pin); // assuming MCP is ADC object.
}
```
Be sure to set the parameters of the constructor correctly.
To reset to the internal ADC use **NULL** as function pointer.
Be sure to set the parameters of the ADC correctly.
```cpp
// reset to internal ADC - 5 volts 10 bits
ACS.setADC(NULL, 5.0, 1023);
```
- example ACS712_20_DC_external_ADC.ino
- https://github.com/RobTillaart/ACS712/issues/31
Note that the use of an external ADC should meet certain performance requirements,
especially for measuring **ma-AC()**.
To 'catch' the peaks well enough one needs at least 2 samples per millisecond
for a 60 Hz signal.
The 16 bit I2C **ADS1115** in continuous mode gives max 0.8 samples per millisecond.
This will work perfect for high resolution **mA-DC()** but is not fast enough for
doing **mA-AC()**.
The SPI based **MCP3202** ao can do up to 100 samples per millisecond at 12 bit.
These ADC's are perfect both **mA-DC()** and **mA-AC()**.
- https://github.com/RobTillaart/ADS1X15
- https://github.com/RobTillaart/MCP_ADC
## Voltage divider
As per issue #15 in which an ACS712 was connected via a voltage divider to the ADC of an ESP32.
@ -332,7 +366,8 @@ To detect that the ACS712 is disconnected from the ADC one could connect the
analog pin via a pull-down to GND. A pull-up to VCC is also possible.
Choose the solution that fits your project best. (Think safety).
**mA_DC()** and **mA_AC_sampling()** will report HIGH values (Out of range) when the ACS712 is disconnected.
**mA_DC()** and **mA_AC_sampling()** will report HIGH values (Out of range) when
the ACS712 is disconnected.
The other - peak2peak based functions - will see this as zero current (min == max).
Schema with PULL-UP.
@ -362,32 +397,23 @@ The examples show the basic working of the functions.
#### Should - 0.3.x
- investigate noise suppression #21 (0.3.1 and later)
#### Could
- merge **mA_AC()** and **mA_AC_sampling()** into one. (0.4.0)
- or remove - depreciate - the worst one
- investigate blocking calls:
- **mA_AC()** blocks for about 20 ms at 50 Hz.
This might affect task scheduling on a ESP32. Needs to be investigated.
Probably need a separate thread that wakes up when new analogRead is available?
- RTOS specific class?
- **detectFrequency(float)** blocks pretty long.
- other set functions also a range check?
- split the readme.md in multiple documents?
- which?
#### Won't
#### Could
- merge **mA_AC()** and **mA_AC_sampling()** into one. (0.4.0)
- or remove - depreciate - the worst one
- add range check to (all) set functions?
#### Won't (unless requested)
- external analogue read support? separate class!
- after this one stabilized.
- ACS712X class with external ADC ( 16 or even 24 bit)
- keep interface alike?
- are these fast enough for e.g. 60 Hz (100 samples in 16 millis?)
- **ADS1115** in continuous mode ==> 0.8 samples per millisecond at 16 bit Ideal for **mA-DC()**
- **MCP3202** SPI interface ==> up to 100 samples per millisecond !! at 12 bit. Perfect.
- investigate support for micro-Amperes. **ACS.uA_DC()**
- need a very stable voltage
- needs a 24 bit ADC
@ -400,4 +426,8 @@ The examples show the basic working of the functions.
- midPoint can be a float so it can be set more exact.
- extra precision is max half bit = smaller than noise?
- math will be slower during sampling (UNO)
- split the readme.md in multiple documents?
- which?
- setADC() to support > 16 bit?
- uint32_t performance penalty?