first commit

This commit is contained in:
Jérôme Delacotte
2025-03-06 11:15:32 +01:00
commit 7b30d6e298
5276 changed files with 2108927 additions and 0 deletions

454
libraries/ACS712/ACS712.cpp Normal file
View File

@@ -0,0 +1,454 @@
//
// FILE: ACS712.cpp
// AUTHOR: Rob Tillaart, Pete Thompson
// VERSION: 0.3.8
// DATE: 2020-08-02
// PURPOSE: ACS712 library - current measurement
// URL: https://github.com/RobTillaart/ACS712
#include "ACS712.h"
// CONSTRUCTOR
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
_mAPerStep = 1000.0 * _mVperStep / _mVperAmpere;
_midPoint = maxADC / 2;
// default ADC is internal.
setADC(NULL, volts, maxADC);
}
// MEASUREMENTS
float ACS712::mA_peak2peak(float frequency, uint16_t cycles)
{
uint16_t period = round(1000000UL / frequency);
if (cycles == 0) cycles = 1;
float sum = 0;
for (uint16_t i = 0; i < cycles; i++)
{
int minimum, maximum;
// Better than using midPoint
minimum = maximum = _analogRead(_pin);
// find minimum and maximum
uint32_t start = micros();
while (micros() - start < period) // UNO ~180 samples...
{
int value = _analogRead(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + _analogRead(_pin))/2;
}
// determine extremes
if (value < minimum) minimum = value;
else if (value > maximum) maximum = value;
}
sum += (maximum - minimum);
}
float peak2peak = sum * _mAPerStep;
if (cycles > 1) peak2peak /= cycles;
return peak2peak;
}
float ACS712::mA_AC(float frequency, uint16_t cycles)
{
uint16_t period = round(1000000UL / frequency);
if (cycles == 0) cycles = 1;
float sum = 0;
// remove float operation from loop.
uint16_t zeroLevel = round(_noisemV/_mVperStep);
for (uint16_t i = 0; i < cycles; i++)
{
uint16_t samples = 0;
uint16_t zeros = 0;
int _min, _max;
_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 = _analogRead(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + _analogRead(_pin))/2;
}
// determine extremes
if (value < _min) _min = value;
else if (value > _max) _max = value;
// count zeros
if (abs(value - _midPoint) <= zeroLevel ) zeros++;
}
int peak2peak = _max - _min;
// automatic determine _formFactor / crest factor
float D = 0;
float FF = 0;
if (zeros > samples * 0.025) // more than 2% zero's
{
D = 1.0 - (1.0 * zeros) / samples; // % SAMPLES NONE ZERO
FF = sqrt(D) * _formFactor; // ASSUME NON ZERO PART ~ SINUS
}
else // # zeros is small => D --> 1 --> sqrt(D) --> 1
{
FF = _formFactor;
}
// value could be partially pre-calculated: C = 1000.0 * 0.5 * _mVperStep / _mVperAmpere;
// return 1000.0 * 0.5 * peak2peak * _mVperStep * _formFactor / _mVperAmpere);
sum += peak2peak * FF;
}
float mA = 0.5 * sum * _mAPerStep;
if (cycles > 1) mA /= cycles;
return mA;
}
float ACS712::mA_AC_sampling(float frequency, uint16_t cycles)
{
uint32_t period = round(1000000UL / frequency);
if (cycles == 0) cycles = 1;
float sum = 0;
// float noiseLevel = _noisemV/_mVperStep;
for (uint16_t i = 0; i < cycles; i++)
{
uint16_t samples = 0;
float sumSquared = 0;
uint32_t start = micros();
while (micros() - start < period)
{
samples++;
int value = _analogRead(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + _analogRead(_pin))/2;
}
float current = value - _midPoint;
sumSquared += (current * current);
// not adding noise squared might be more correct for small currents.
// if (abs(current) > noiseLevel)
// {
// sumSquared += (current * current);
// }
}
sum += sqrt(sumSquared / samples);
}
float mA = sum * _mAPerStep;
if (cycles > 1) mA /= cycles;
return mA;
}
float ACS712::mA_DC(uint16_t cycles)
{
// read at least twice to stabilize the ADC
_analogRead(_pin);
if (cycles == 0) cycles = 1;
float sum = 0;
for (uint16_t i = 0; i < cycles; i++)
{
int value = _analogRead(_pin);
if (_suppresNoise) // average 2 samples.
{
value = (value + _analogRead(_pin))/2;
}
sum += (value - _midPoint);
}
float mA = sum * _mAPerStep;
if (cycles > 1) mA /= cycles;
return mA;
}
// CALIBRATION MIDPOINT
uint16_t ACS712::setMidPoint(uint16_t midPoint)
{
if (midPoint <= _maxADC) _midPoint = (int) midPoint;
return _midPoint;
};
uint16_t ACS712::getMidPoint()
{
return _midPoint;
};
uint16_t ACS712::incMidPoint()
{
if (_midPoint < (int)(_maxADC)) _midPoint += 1;
return _midPoint;
};
uint16_t ACS712::decMidPoint()
{
if (_midPoint > 0) _midPoint -= 1;
return _midPoint;
};
// configure by sampling for 2 cycles of AC
// Also works for DC as long as no current flowing
// note this is blocking!
uint16_t ACS712::autoMidPoint(float frequency, uint16_t cycles)
{
uint16_t twoPeriods = round(2000000UL / frequency);
if (cycles == 0) cycles = 1;
uint32_t total = 0;
for (uint16_t i = 0; i < cycles; i++)
{
uint32_t subTotal = 0;
uint32_t samples = 0;
uint32_t start = micros();
while (micros() - start < twoPeriods)
{
uint16_t reading = _analogRead(_pin);
subTotal += reading;
samples++;
// Delaying prevents overflow
// since we'll perform a maximum of 40,000 reads @ 50 Hz.
delayMicroseconds(1);
}
total += (subTotal / samples);
}
_midPoint = (total + (cycles/2))/ cycles; // rounding.
return _midPoint;
}
uint16_t ACS712::autoMidPointDC(uint16_t cycles)
{
if (cycles == 0) cycles = 1;
uint32_t total = 0;
for (uint16_t i = 0; i < cycles; i++)
{
total += analogRead(_pin);
}
_midPoint = (total + (cycles/2))/ cycles; // rounding.
return _midPoint;
}
uint16_t ACS712::resetMidPoint()
{
_midPoint = _maxADC / 2;
return _midPoint;
};
// CALIBRATION FORM FACTOR
void ACS712::setFormFactor(float formFactor)
{
_formFactor = formFactor;
};
float ACS712::getFormFactor()
{
return _formFactor;
};
// CALIBRATION NOISE
// noise defaults 21 datasheet
void ACS712::setNoisemV(uint8_t noisemV)
{
_noisemV = noisemV;
};
uint8_t ACS712::getNoisemV()
{
return _noisemV;
};
float ACS712::mVNoiseLevel(float frequency, uint16_t cycles)
{
float mA = mA_peak2peak(frequency, cycles);
// divide by 2 as the level is half of the peak to peak range
return mA * _mVperAmpere * 0.001 / 2;
}
void ACS712::suppressNoise(bool flag)
{
_suppresNoise = flag;
}
// CALIBRATION mV PER AMP
// Adjusting resolution AC and DC
void ACS712::setmVperAmp(float mVperAmpere)
{
_mVperAmpere = mVperAmpere;
_mAPerStep = 1000.0 * _mVperStep / _mVperAmpere;
};
float ACS712::getmVperAmp()
{
return _mVperAmpere;
};
float ACS712::getmAPerStep()
{
return _mAPerStep;
};
float ACS712::getAmperePerStep()
{
return _mAPerStep * 0.001;
};
// FREQUENCY DETECTION
// uses oversampling and averaging to minimize variation
// blocks for substantial amount of time, depending on minimalFrequency
float ACS712::detectFrequency(float minimalFrequency)
{
int maximum = 0;
int minimum = 0;
maximum = minimum = _analogRead(_pin);
// determine maxima
uint32_t timeOut = round(1000000.0 / minimalFrequency);
uint32_t start = micros();
while (micros() - start < timeOut)
{
int value = _analogRead(_pin);
if (value > maximum) maximum = value;
if (value < minimum) minimum = value;
}
// calculate quarter points
// using quarter points is less noise prone than using one single midpoint
int Q1 = (3 * minimum + maximum ) / 4;
int Q3 = (minimum + 3 * maximum ) / 4;
// 10x passing Quantile points
// wait for the right moment to start
// to prevent endless loop a timeout is checked.
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));
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));
}
uint32_t stop = micros();
// calculate frequency
float wavelength = stop - start;
float frequency = 1e7 / wavelength;
if (_microsAdjust != 1.0) frequency *= _microsAdjust;
return frequency;
}
// timing for FREQUENCY DETECTION
void ACS712::setMicrosAdjust(float factor)
{
_microsAdjust = factor;
};
float ACS712::getMicrosAdjust()
{
return _microsAdjust;
};
// DEBUG
uint16_t ACS712::getMinimum(uint16_t milliSeconds)
{
uint16_t minimum = _analogRead(_pin);
// find minimum
uint32_t start = millis();
while (millis() - start < milliSeconds)
{
uint16_t value = _analogRead(_pin);
if (value < minimum) minimum = value;
}
return minimum;
}
uint16_t ACS712::getMaximum(uint16_t milliSeconds)
{
uint16_t maximum = _analogRead(_pin);
// find maximum
uint32_t start = millis();
while (millis() - start < milliSeconds)
{
uint16_t value = _analogRead(_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;
}
//////////////////////////////////////////////////////////////////////
//
// PRIVATE
//
uint16_t ACS712::_analogRead(uint8_t pin)
{
// if external ADC is defined use it.
if (_readADC != NULL) return _readADC(pin);
return analogRead(pin);
}
// -- END OF FILE --

138
libraries/ACS712/ACS712.h Normal file
View File

@@ -0,0 +1,138 @@
#pragma once
//
// FILE: ACS712.h
// AUTHOR: Rob Tillaart, Pete Thompson
// VERSION: 0.3.8
// DATE: 2020-08-02
// PURPOSE: ACS712 library - current measurement
// URL: https://github.com/RobTillaart/ACS712
//
// Tested with a RobotDyn ACS712 20A breakout + UNO.
//
#include "Arduino.h"
#define ACS712_LIB_VERSION (F("0.3.8"))
// 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))
#define ACS712_FF_SAWTOOTH (1.0/sqrt(3))
#define ACS712_DEFAULT_FREQ 50
#define ACS712_DEFAULT_NOISE 21
class ACS712
{
public:
// NOTE:
// One can quite precisely tune the value of the sensor
// (1) the milliVolt per Ampere and
// (2) the volts parameter.
//
// TYPE mV per Ampere
// 5A 185.0
// 20A 100.0
// 30A 66.0
ACS712(uint8_t analogPin, float volts = 5.0, uint16_t maxADC = 1023, float mVperAmpere = 100);
// returns mA peak2peak current.
float mA_peak2peak(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1);
// returns mA
// blocks 20-21 ms to sample a whole 50 or 60 Hz period.
// works with peak2peak level and (crest) Form Factor.
// lower frequencies block longer.
float mA_AC(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1);
// returns mA
// blocks 20-21 ms to sample a whole 50 or 60 Hz period.
// works with sampling.
// lower frequencies block longer.
float mA_AC_sampling(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1);
// returns mA
// blocks < 1 ms
float mA_DC(uint16_t samples = 1);
// midPoint functions
// set reference point (raw ADC) for both DC and AC
uint16_t setMidPoint(uint16_t midPoint);
uint16_t getMidPoint();
uint16_t incMidPoint();
uint16_t decMidPoint();
// Auto midPoint, assuming zero DC current or any AC current
// For DC current set the frequency to 1000 or so to reduce blocking.
uint16_t autoMidPoint(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1);
// Auto midPoint, dedicated for zero DC current (much faster ==> less blocking)
uint16_t autoMidPointDC(uint16_t cycles = 1);
// resets to half maxADC
uint16_t resetMidPoint();
// Form Factor is also known as crest factor;
// affects mA_AC() only, default sinus.
void setFormFactor(float formFactor = ACS712_FF_SINUS);
float getFormFactor();
// noise defaults 21 datasheet
void setNoisemV(uint8_t noisemV = ACS712_DEFAULT_NOISE);
uint8_t getNoisemV();
// enable/disable noiseSuppression for this measurement as needed.
float mVNoiseLevel(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1); // uses mA_peak2peak()
void suppressNoise(bool flag);
// Adjusting resolution AC and DC
void setmVperAmp(float mVperAmpere);
float getmVperAmp();
float getmAPerStep();
float getAmperePerStep();
// Frequency detection.
// the minimal frequency determines the time to sample.
float detectFrequency(float minimalFrequency = 40);
void setMicrosAdjust(float factor = 1.0);
float getMicrosAdjust();
// DEBUG
uint16_t getMinimum(uint16_t milliSeconds = 20);
uint16_t getMaximum(uint16_t milliSeconds = 20);
// EXPERIMENTAL 0.3.4
// function returning 16 bit max, with pin or channel as parameter
void setADC(uint16_t (*)(uint8_t), float volts, uint16_t maxADC);
private:
uint8_t _pin;
uint16_t _maxADC;
float _mVperStep;
float _formFactor; // peak2peak -> RMS
float _mVperAmpere;
float _mAPerStep;
int _midPoint;
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);
uint16_t _analogRead(uint8_t pin);
};
// -- END OF FILE --

View File

@@ -0,0 +1,121 @@
# Change Log ACS712
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.3.8] - 2023-09-19
- add badges to readme.md
- minor edits
## [0.3.7] - 2023-05-20
- add example **estimateMidPointAC.ino** #37
- update readme.md (sampling trick #38).
- minor edits.
## [0.3.6] - 2023-04-19
- add **autoMidPointDC(cycles)** see issue #35
- add rounding to **autoMidPoint()**
- update README.md
## [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
- add example
- add URL in .h .cpp
## [0.3.2] - 2022-11-18
- fix #26 revert data type \_midPoint to int
- Add CHANGELOG.md
## [0.3.1 2022-09-xx
- add float mVNoiseLevel(frequency, cycles)
- add void suppressNoise(bool flag) - experimental suppression by averaging two samples.
- update readme.md
- improve midPoint functions
- add resetMidPoint()
- add RP2040 pico in build-ci
## [0.3.0] - 2022-09-01
- return midPoint value in MP functions.
- float return type for mA() functions
- add float mA_peak2peak(freq, cycles)
- add debug getMinimum(), getmaximum();
- update Readme.md
----
## [0.2.8] - 2022-08-19 prepare for 0.3.0
- Fix #21 FormFactor
- add mA_AC_sampling() as method to determine
- current when FormFactor is unknown.
- added float _AmperePerStep cached value.
- added getAmperePerStep();
- moved several functions to .cpp
- improve documentation
## [0.2.7] - 2022-08-10
- change mVperAmp to float
- add ACS712_FF_SAWTOOTH
- update readme.md + unit test + minor edits
## [0.2.6] - 2021-12-09
- update readme.md
- update license
## [0.2.5] - 2021-12-03
- add timeout to detectFrequency()
## [0.2.4] - 2021-11-22
- add experimental detectFrequency()
## [0.2.3] - 2021-10-15
- change frequencies to float, for optimal tuning.
- update build CI
- update readme.md
## [0.2.2] - 2021-06-23
- support for more frequencies
## [0.2.1] - 2020-12-06
- Add Arduino-CI + unit test
- update readme
- refactor
## [0.2.0] - 2020-08-02
- Add autoMidPoint()
----
## [0.1.4] - 2020-08-02
- Allow for faster processors
## [0.1.3] - 2020-05-27
- fix library.json
## [0.1.2] - 2020-03-21
- automatic form factor test
## [0.1.1] - 2020-03-18
- first release version
## [0.1.0] - 2020-03-17
- initial version

21
libraries/ACS712/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020-2023 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

498
libraries/ACS712/README.md Normal file
View File

@@ -0,0 +1,498 @@
[![Arduino CI](https://github.com/RobTillaart/ACS712/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/ACS712/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/ACS712/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/ACS712/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/ACS712/actions/workflows/jsoncheck.yml)
[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/ACS712.svg)](https://github.com/RobTillaart/ACS712/issues)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/ACS712/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/ACS712.svg?maxAge=3600)](https://github.com/RobTillaart/ACS712/releases)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/ACS712.svg)](https://registry.platformio.org/libraries/robtillaart/ACS712)
# ACS712
Library for the ACS712 Current Sensor - 5A, 20A, 30A and compatibles.
## Description
The ACS712 is a chip to measure current, both AC or DC. The chip has an
analogue output that provides a voltage that is linear with the current.
The ACS712 library supports only a built in ADC by means of **analogRead()**.
However since 0.3.4 there is an experimental **setADC()**.
The library has 4 core functions:
- **float mA_peak2peak(frequency = 50, cycles = 1)**
- **float mA_DC(cycles = 1)**
- **float mA_AC(frequency = 50, cycles = 1)**
- **float mA_AC_sampling(frequency = 50, cycles = 1)**
The parameter cycles is used to measure multiple cycles and average them.
To measure DC current a single **analogRead()** with conversion math is
sufficient to get a value.
To stabilize the signal **analogRead()** is called at least twice.
To measure AC current **a blocking loop for 20 milliseconds** (50 Hz, 1 cycle)
is run to determine the peak to peak value which is converted to the RMS value.
To convert the peak2peak value to RMS one need the so called crest or form factor.
This factor depends heavily on the signal form, hence its name.
For a perfect sinus the value is sqrt(2)/2 == 1/sqrt(2).
See **Form factor** below.
For a 60 Hz environment the blocking is ~16.7 milliseconds, still pretty long.
The **mA_AC_sampling()** calculates the average of the sumSquared of many measurements.
This function should be used when the form factor is not known.
Note to make precise measurements, the power supply of both the ACS712 and the ADC of
the processor should be as stable as possible.
That improves the stability of the midpoint and minimizes the noise.
#### Resolution
| Sensor | mVperA | LSB 10bit | LSB 12bit | LSB 16bit |
|:---------|:--------:|:-----------:|:-----------:|:-----------:|
| 5 A | 185 | 26.4 mA | 6.6 mA | 0.41 mA |
| 20 A | 100 | 48.9 mA | 12.2 mA | 0.76 mA |
| 30 A | 66 | 74.1 mA | 18.5 mA | 1.16 mA |
```cpp
getmAPerStep();
mA LSB = (5000 mV / maxADC) / mVperA * 1000.0;
mA LSB = (1000 * 5000 mV) / (maxADC * mVperA);
```
Although no 16 bit ADC built in are known, it indicates what resolution
could be obtained with such an ADC. It triggered the experimental supporting
of external ADC's with this library.
#### Tests
The library is at least confirmed to work with the following boards:
| Device | Voltage | ADC steps | Notes |
|:-------------|:-------:|:---------:|:--------|
| Arduino UNO | 5.0V | 1024 | tested with RobotDyn ACS712 20 A breakout.
| Arduino UNO | 5.0V | 1024 | tested with Open-Smart ACS712 5 A breakout.
| Arduino NANO | 5.0V | 1024 | #18
| ESP32 | 3.3V | 4096 | #15
| Promicro | 5.0V | 1024 | #15
Please let me know of other working platforms / processors (and failing ones!).
## Compatibles
Robodyn has a breakout for the ACS758 - 50 A. - See resolution below.
This sensor has versions up to 200 Amps, so use with care!
Allegromicro offers a lot of different current sensors that might be compatible.
These include bidirectional and unidirectional ones.
The unidirectional seem to be for DC only.
https://www.allegromicro.com/en/products/sense/current-sensor-ics/current-sensors-innovations
If you have tested a compatible sensor, please share your experiences.
(can be done by opening an issue to update documentation)
#### Resolution ACS758
Not tested, but looks compatible - same formula as above
| Sensor | mVperA | LSB 10bit | LSB 12bit | LSB 16bit | directional |
|:---------|:--------:|:-----------:|:-----------:|:-----------:|:-------------:|
| 50 A | 40 | 122.2 mA | 30.5 mA | 1.91 mA | bi |
| 50 A | 60 | 81.5 mA | 20.3 mA | 1.27 mA | uni |
| 100 A | 20 | 244.4 mA | 61.0 mA | 3.81 mA | bi |
| 100 A | 40 | 122.2 mA | 30.5 mA | 1.91 mA | uni |
| 150 A | 13.3 | 367.5 mA | 91.8 mA | 5.74 mA | bi |
| 150 A | 26.7 | 183.1 mA | 45.7 mA | 2.86 mA | uni |
| 200 A | 10 | 488.8 mA | 122.1 mA | 7.63 mA | bi |
| 200 A | 20 | 244.4 mA | 61.0 mA | 3.81 mA | uni |
## Interface
```cpp
#include ACS712.h
```
#### Base
- **ACS712(uint8_t analogPin, float volts = 5.0, uint16_t maxADC = 1023, float mVperAmpere = 100)** constructor.
It defaults a 20 A type sensor, which is defined by the default value of mVperAmpere. See table below.
Volts is the voltage used by the (Arduino) internal ADC. maxADC is the maximum output of the internal ADC.
The defaults are based upon an Arduino UNO, 10 bits ADC.
These two ADC parameters are needed to calculate the voltage output of the ACS712 sensor.
- **float mA_peak2peak(float frequency = 50, uint16_t cycles = 1)** blocks ~21 ms to sample a whole 50 or 60 Hz period.
Returns the peak to peak current, can be used to determine form factor.
The **mA_peak2peak()** can also be used to measure on a zero current line
to get an indication of the lowest detectable current.
Finally this function is used internally to detect the noiseLevel in mV on a zero current line.
- **float mA_AC(float frequency = 50, uint16_t cycles = 1)** blocks ~21 ms to sample a whole 50 or 60 Hz period.
Note that a lower frequency, or more cycles, will increase the blocking period.
The function returns the AC current in mA.
Its working is based upon multiplying the peak2peak value by the FormFactor which must be known and set.
- 0.2.2 frequencies other integer values than 50 and 60 are supported.
- 0.2.3 floating point frequencies are supported to tune even better.
- 0.2.8 the parameter cycles allow to average over a number of cycles.
- **float mA_AC_sampling(float frequency = 50, uint16_t cycles = 1)** blocks ~21 ms to sample a whole period.
The function returns the AC current in mA. (Note it returns a float).
Its working is based upon sampling a full period and take the square root of the average sumSquared.
This function is intended for signals with unknown Form Factor.
- 0.2.8 the parameter cycles allow to average over a number of cycles.
- **float mA_DC(uint16_t samples = 1)** blocks < 1 ms (Arduino UNO) as it calls **analogRead()** twice.
A negative value indicates the current flows in the opposite direction.
- 0.2.8 the parameter samples allow to average over a number of samples.
#### mA_AC_sampling performance trick.
A trick to sample faster is to set the frequency to 2 times the actual frequency so to 100 or 120 Hz.
This results in sampling only half a period and the same current will be measured.
Advantage is that the function only blocks for ~10 ms @ 50Hz (8.5 @ 60Hz).
The drawback is about 4x as many variation.
So only use if the performance (or less blocking) is needed.
In a similar way one can increase the accuracy (reducing the variation)
by setting the frequency a factor 2 lower (25 and 30 Hz).
Drawback is a far longer blocking time.
Use with care!
See - https://github.com/RobTillaart/ACS712/issues/38
#### Midpoint
The midpoint is the (raw) zero-reference for all current measurements.
It is defined in steps of the ADC and is typical around half the **maxADC** value defined
in the constructor. So for a 10 bit ADC a number between 500..525 is most likely.
Since 0.3.0 all midpoint functions return the actual midPoint.
- **uint16_t setMidPoint(uint16_t midPoint)** sets midpoint for the ADC conversion.
Parameter must be between 0 and maxADC/2, otherwise midpoint is not changed.
- **uint16_t getMidPoint()** read the value set / determined.
- **uint16_t incMidPoint()** manual increase midpoint, e.g. useful in an interactive application.
Will not increase if midpoint equals maxADC.
- **uint16_t decMidPoint()** manual decrease midpoint.
Will not decrease if midpoint equals 0.
- **uint16_t resetMidPoint()** resets the midpoint to the initial value of maxADC / 2 as in the constructor.
- **uint16_t autoMidPointDC(uint16_t cycles = 1)** Auto midPoint for DC only.
Assuming zero DC current. To reduce the noise cycles must be increased even up to 100.
This method is typically much faster for DC than the **autoMidPoint(freq, cycles)**
for the same number of cycles. (See issue #35)
- **uint16_t autoMidPoint(float frequency = 50, uint16_t cycles = 1)** Auto midPoint, for any AC current or zero DC current.
For DC one can use a high frequency e.g. 1000 Hz to reduce the time blocking.
The function takes the average of many measurements during one or more full cycles.
Note the function therefore blocks for at least 2 periods which is about
40 ms for 50 Hz.
By increasing the number of cycles the function averages even more measurements,
possibly resulting in a better midPoint. Idea is that noise will average out.
This function is mandatory for measuring AC.
- 0.2.2 frequencies other than 50 and 60 are supported.
- 0.2.8 the parameter cycles allow to average over a number of cycles.
Since version 0.3.0 there is another way to determine the midPoint.
One can use the two debug functions.
(milliseconds > 20 to get at least a full cycle)
- **uint16_t getMinimum(uint16_t milliSeconds = 20)**
- **uint16_t getMaximum(uint16_t milliSeconds = 20)**
and take the average of these two values. In code:
```cpp
uint16_t midpoint = ACS.setMidPoint(ACS.getMinimum(20)/2 + ACS.getMaximum(20)/ 2);
```
See - ACS712_20_AC_midPoint_compare.ino
The ACS712 has a midPoint level that is specified as 0.5 \* VCC.
So **autoMidPoint()** can help to detect voltage deviations for the ACS712.
The library does not support this yet.
#### Form factor
The form factor is also known as the **crest factor**.
It is only used for signals measured with **mA_AC()**.
- **void setFormFactor(float formFactor = ACS712_FF_SINUS)** manually sets the form factor.
Must typical be between 0.0 and 1.0, see constants below.
- **float getFormFactor()** returns current form factor.
The library has a number of predefined form factors:
| definition | value | approx | notes |
|:---------------------|:----------------|:--------:|:----------|
| ACS712_FF_SQUARE | 1.0 | 1.000 |
| ACS712_FF_SINUS | 1.0 / sqrt(2) | 0.707 | default |
| ACS712_FF_TRIANGLE | 1.0 / sqrt(3) | 0.577 |
| ACS712_FF_SAWTOOTH | 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.
Please let me know if other crest factors need to be added.
Since version 0.3.0 the form factor can be determined by
```cpp
float formFactor = 2.0 * mA_AC_sampling() / ACS.mA_peak2peak();
```
See - ACS712_20_determine_form_factor.ino
#### Noise
Default = 21 mV (datasheet)
- **void setNoisemV(uint8_t noisemV = 21)** sets the noise level,
is used to determine zero level e.g. in the AC measurements with **mA_AC()**.
- **uint8_t getNoisemV()** returns the set value.
- **float mVNoiseLevel(float frequency, uint16_t cycles)** determines the mV of noise.
Measurement should be taken when there is no AC/DC current or a constant DC current.
The level will give a (not quantified yet) indication of the accuracy of the measurements.
A first order indication can be made by comparing it to voltage / 2 of the constructor.
Noise on the signal can be reduced by using a low pass (RC) filter.
Version 0.3.1 includes experimental code to take two sample and average them.
The idea is that ```((3 + 5)/2)^2 < (3^2 + 5^2)/2```
In theory this should suppress noise levels however more investigation in
software noise detection and suppression is needed.
- **void suppressNoise(bool flag)** experimental noise suppression.
#### mV per Ampere
Used for both for AC and DC measurements.
Its value is defined in the constructor and depends on type sensor used.
These functions allow to adjust this setting run-time.
- **void setmVperAmp(float mVperAmpere)** sets the milliVolt per Ampere measured.
- **float getmVperAmp()** returns the set value.
Typical values see "Resolution" section above, and the "voltage divider" section below.
#### Frequency detection
Experimental functionality for AC signal only!
- **float detectFrequency(float minimalFrequency = 40)** Detect the frequency of the AC signal.
- **void setMicrosAdjust(float factor = 1.0)** adjusts the timing of micros in **detectFrequency()**.
Values are typical around 1.0 ± 1%
- **float getMicrosAdjust()** returns the set factor.
The minimum frequency of 40 Hz is used to sample for enough time to find the minimum and maximum
for 50 and 60 Hz signals.
Thereafter the signal is sampled 10 cycles to minimize the variation of the frequency.
The **microsAdjust()** is to adjust the timing of **micros()**.
This function is only useful if one has a good reference source like a calibrated function generator
to find the factor to adjust.
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 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
// set to external ADC - 5 volts 12 bits
ACS.setADC(myAnalogRead, 5.0, 4096);
...
uint16_t myAnalogRead(uint8_t pin)
{
return MCP.read(pin); // assuming MCP is ADC object.
}
```
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.
Schema
```
ACS712 ----[ R1 ]----o----[ R2 ]---- GND
|
|
ADC of processor
```
The voltage divider gave an error of about a factor 2 as all voltages were divided,
including the "offset" from the **midPoint** zero current level.
By adjusting the mV per Ampere with **setmVperAmp(float mva)** the readings can be corrected
for this "voltage divider effect".
#### Examples:
For a 20 A type sensor, 100 mV/A would be the normal value.
After using a voltage divider one need to adjust the mVperAmp.
| R1 (ACS) | R2 (GND) | voltage factor | mVperAmp corrected |
|:--------:|:---------:|:-------------------------------:|:-----------------------:|
| 10200 | 4745 | 4745 / (10200 + 4745) = 0.3175 | 100 \* 0.3175 = 31.75 |
| 4745 | 10200 | 10200 / (10200 + 4745) = 0.6825 | 100 \* 0.6825 = 68.25 |
| 10200 | 9800 | 9800 / (10200 + 9800) = 0.4900 | 100 \* 0.4900 = 49.00 |
**Note:** setting the midPoint correctly is also needed when using a voltage divider.
## Disconnect detection
(to be tested)
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.
The other - peak2peak based functions - will see this as zero current (min == max).
Schema with PULL-UP.
```
ACS712 OUT
|
|
VCC ----[ R1 ]----o R1 = 1 M ohm.
|
|
ADC of processor
```
The library does not support this "extreme values" detection.
## ESPhome
For people who want to use this library for ESPhome, there exists a wrapper
class for this ACS712 library.
- https://github.com/marianomd/acs712-esphome
As I do not have ESPhome know how, please share your experiences.
This can be done by an issue.
## Operation
The examples show the basic working of the functions.
## Future
#### Must
- test more
- other than the 20A module
- 5, 10, 30, 50 ...
- need to buy extra hardware
#### Should - 0.3.x
- investigate **estimateMidPoint(confidence)** See issue #35
- is less blocking by spreading the sampling over many calls.
returning a confidence level.
- investigate noise suppression #21 (0.3.1 and later)
- 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?
- investigate **detectFrequency(float)** blocks pretty long.
#### 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?
- add unit test for **autoMidPointDC()** (needed?)
- **setMidPoint()**
- Q: could midpoint be set beyond maxADC? is there any use case?
#### Won't (unless requested)
- investigate support for micro-Amperes. **ACS.uA_DC()**
- need a very stable voltage
- needs a 24 bit ADC
- default noise is already ~21mV...
- => not feasible in normal setup.
- Should the FormFactor not be just a parameter of **mA_AC()**
it is the only function using it. ==> No unnecessary breaking API
- should cycles be an uint8_t ?
- No, uint16 allows averaging in minutes range uint8_t just ~5 seconds
- 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?
## Support
If you appreciate my libraries, you can support the development and maintenance.
Improve the quality of the libraries by providing issues and Pull Requests, or
donate through PayPal or GitHub sponsors.
Thank you,

View File

@@ -0,0 +1,70 @@
//
// FILE: ACS712_20_AC.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo AC measurement with point to point
// URL: https://github.com/RobTillaart/ACS712
#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);
uint32_t start, stop;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("ACS712_LIB_VERSION: ");
Serial.println(ACS712_LIB_VERSION);
// use simulation
ACS.setADC(signal, 5, 1024);
ACS.autoMidPoint();
Serial.print("MidPoint: ");
Serial.print(ACS.getMidPoint());
Serial.print(". Noise mV: ");
Serial.println(ACS.getNoisemV());
}
void loop()
{
delay(100);
start = micros();
// int mA = ACS.mA_AC();
int mA = ACS.mA_AC_sampling();
stop = micros();
Serial.print("mA: ");
Serial.print(mA);
Serial.print(". Form factor: ");
Serial.print(ACS.getFormFactor());
Serial.print(" time: ");
Serial.println(stop - start);
delay(5000);
}
// simulated 50 Hz signal
uint16_t signal(uint8_t p)
{
return 512 + 400 * sin((micros() % 1000000) * (TWO_PI * 50 / 1e6));
}
// -- END OF FILE --

View File

@@ -0,0 +1,58 @@
//
// FILE: ACS712_20_AC_DEMO.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo to set the mVperAmpere and Form FActor.
// URL: https://github.com/RobTillaart/ACS712
#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.autoMidPoint();
}
void loop()
{
int mA = ACS.mA_AC();
Serial.println(mA);
if (Serial.available() > 0)
{
char c = Serial.read();
if (c == '*') ACS.setmVperAmp(ACS.getmVperAmp() + 1);
if (c == '/') ACS.setmVperAmp(ACS.getmVperAmp() - 1);
Serial.print("mVperAmp:\t");
Serial.println(ACS.getmVperAmp());
if (c == '+') ACS.setFormFactor(ACS.getFormFactor() * 1.05);
if (c == '-') ACS.setFormFactor(ACS.getFormFactor() / 1.05);
Serial.print("formFactor:\t");
Serial.println(ACS.getFormFactor());
}
delay(1000);
}
// -- END OF FILE --

View File

@@ -0,0 +1,52 @@
//
// FILE: ACS712_20_AC_SAMPLING_DEMO.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo to sample AC current and set mVPerAmpere
// URL: https://github.com/RobTillaart/ACS712
#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.autoMidPoint();
}
void loop()
{
float mA = ACS.mA_AC_sampling();
Serial.println(mA, 1);
while (Serial.available() > 0)
{
char c = Serial.read();
if (c == '*') ACS.setmVperAmp(ACS.getmVperAmp() + 1);
if (c == '/') ACS.setmVperAmp(ACS.getmVperAmp() - 1);
Serial.print("mVperAmp:\t");
Serial.println(ACS.getmVperAmp());
}
delay(250);
}
// -- END OF FILE --

View File

@@ -0,0 +1,59 @@
//
// FILE: ACS712_20_AC_average.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo AC measurement with point to point + averaging
// URL: https://github.com/RobTillaart/ACS712
#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.autoMidPoint();
Serial.print("MidPoint: ");
Serial.println(ACS.getMidPoint());
Serial.print("Noise mV: ");
Serial.println(ACS.getNoisemV());
}
void loop()
{
float average = 0;
uint32_t start = millis();
for (int i = 0; i < 100; i++)
{
// select sppropriate function
// average += ACS.mA_AC_sampling();
average += ACS.mA_AC();
}
float mA = average / 100.0;
uint32_t duration = millis() - start;
Serial.print("Time: ");
Serial.print(duration);
Serial.print(" mA: ");
Serial.println(mA);
delay(1000);
}
// -- END OF FILE --

View File

@@ -0,0 +1,50 @@
//
// FILE: ACS712_20_AC_compare.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo AC measurement comparison
// URL: https://github.com/RobTillaart/ACS712
#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.autoMidPoint();
Serial.print("MidPoint: ");
Serial.print(ACS.getMidPoint());
Serial.print(". Noise mV: ");
Serial.println(ACS.getNoisemV());
}
void loop()
{
int m1 = ACS.mA_AC();
float m2 = ACS.mA_AC_sampling();
Serial.print("mA:\t");
Serial.print(m1);
Serial.print("\t\t");
Serial.println(m2);
delay(1000);
}
// -- END OF FILE --

View File

@@ -0,0 +1,64 @@
//
// FILE: ACS712_20_AC_low_pass.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo AC measurement with point to point with low pass filter
// URL: https://github.com/RobTillaart/ACS712
#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, 185);
// ESP 32 example (might requires resistors to step down the logic voltage)
// ACS712 ACS(25, 3.3, 4095, 185);
float value = 0;
float weight = 0.2;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("ACS712_LIB_VERSION: ");
Serial.println(ACS712_LIB_VERSION);
ACS.autoMidPoint();
Serial.print("MidPoint: ");
Serial.println(ACS.getMidPoint());
Serial.print("Noise mV: ");
Serial.println(ACS.getNoisemV());
Serial.print("Amp/Step: ");
Serial.println(ACS.getAmperePerStep(), 4);
value = ACS.mA_AC(); // get good initial value
}
void loop()
{
// select sppropriate function
float mA = ACS.mA_AC_sampling();
// float mA = ACS.mA_AC();
value += weight * (mA - value); // low pass filtering
Serial.print("weight: ");
Serial.print(weight);
Serial.print(" value: ");
Serial.print(value, 0);
Serial.print(" mA: ");
Serial.print(mA);
Serial.println();
delay(1000);
}
// -- END OF FILE --

View File

@@ -0,0 +1,54 @@
//
// FILE: ACS712_20_AC_midPoint_compare.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo to compare different midPoint methods.
// URL: https://github.com/RobTillaart/ACS712
#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.println();
Serial.print("ACS712_LIB_VERSION: ");
Serial.println(ACS712_LIB_VERSION);
Serial.println("Compare different midPoint methods.\n");
Serial.print("Default: \t");
Serial.println(ACS.getMidPoint());
Serial.print("AutoMP: \t");
Serial.println(ACS.autoMidPoint());
uint16_t average = (ACS.getMinimum(20) + ACS.getMaximum(20)) / 2;
ACS.setMidPoint(average);
Serial.print("Average: \t");
Serial.println(average);
Serial.println();
Serial.println("\ndone...");
}
void loop()
{
delay(1000);
}
// -- END OF FILE --

View File

@@ -0,0 +1,74 @@
//
// FILE: ACS712_20_AC_midPoint_performance.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo to compare different midPoint methods.
// URL: https://github.com/RobTillaart/ACS712
#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);
uint32_t start, stop;
float mp = 0;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.println();
Serial.print("ACS712_LIB_VERSION: ");
Serial.println(ACS712_LIB_VERSION);
Serial.println("Compare different midPoint methods.\n");
start = micros();
mp = ACS.getMidPoint();
stop = micros();
Serial.print("Default: \t");
Serial.print(mp);
Serial.print("\t");
Serial.println(stop - start);
delay(10);
start = micros();
mp = ACS.autoMidPoint();
stop = micros();
Serial.print("AutoMP: \t");
Serial.print(mp);
Serial.print("\t");
Serial.println(stop - start);
delay(10);
start = micros();
uint16_t average = (ACS.getMinimum(20) + ACS.getMaximum(20)) / 2;
stop = micros();
Serial.print("Average: \t");
Serial.print(average);
Serial.print("\t");
Serial.println(stop - start);
delay(10);
Serial.println("\ndone...");
}
void loop()
{
delay(1000);
}
// -- END OF FILE --

View File

@@ -0,0 +1,66 @@
//
// FILE: ACS712_20_AC_simulation.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo AC measurement with point to point
// URL: https://github.com/RobTillaart/ACS712
#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);
uint32_t start, stop;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("ACS712_LIB_VERSION: ");
Serial.println(ACS712_LIB_VERSION);
// select simulated signal
ACS.setADC(signal, 5, 1024);
ACS.autoMidPoint();
Serial.print("MidPoint: ");
Serial.print(ACS.getMidPoint());
Serial.print(". Noise mV: ");
Serial.println(ACS.getNoisemV());
}
void loop()
{
delay(100);
start = micros();
// int mA = ACS.mA_AC();
int mA = ACS.mA_AC_sampling(50);
stop = micros();
Serial.print("mA: ");
Serial.print(mA);
Serial.print(" time: ");
Serial.println(stop - start);
delay(5000);
}
// simulation.
uint16_t signal(uint8_t p)
{
return round(512 + 400 * sin((micros() % 1000000) * (TWO_PI * 50 / 1e6)));
}
// -- END OF FILE --

View File

@@ -0,0 +1,73 @@
//
// FILE: ACS712_20_AC_suppress_noise.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo AC measurement with point to point
// URL: https://github.com/RobTillaart/ACS712
#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.autoMidPoint();
Serial.print("MidPoint: ");
Serial.print(ACS.getMidPoint());
Serial.print(". Noise mV: ");
Serial.println(ACS.getNoisemV());
}
void loop()
{
ACS.suppressNoise(false);
Serial.println("\nFALSE");
for (int i = 0; i < 4; i++)
{
Serial.print(ACS.mA_AC());
Serial.print("\t");
Serial.print(ACS.mA_AC_sampling());
Serial.print("\t");
Serial.print(ACS.mA_peak2peak());
Serial.print("\t");
Serial.println();
delay(1000);
}
ACS.suppressNoise(true);
Serial.println("\nTRUE");
for (int i = 0; i < 4; i++)
{
Serial.print(ACS.mA_AC());
Serial.print("\t");
Serial.print(ACS.mA_AC_sampling());
Serial.print("\t");
Serial.print(ACS.mA_peak2peak());
Serial.print("\t");
Serial.println();
delay(1000);
}
}
// -- END OF FILE --

View File

@@ -0,0 +1,44 @@
//
// FILE: ACS712_20_DC.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo to measure mA DC
// 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.autoMidPoint();
// Serial.println(ACS.getMidPoint());
}
void loop()
{
int mA = ACS.mA_DC();
Serial.println(mA);
delay(100);
}
// -- END OF FILE --

View File

@@ -0,0 +1,56 @@
//
// FILE: ACS712_20_DC_DEMO.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo to set the midPoint and the mVperAmpere.
// URL: https://github.com/RobTillaart/ACS712
#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.autoMidPoint();
}
void loop()
{
int mA = ACS.mA_DC();
Serial.println(mA);
if (Serial.available() > 0)
{
char c = Serial.read();
if (c == '+') ACS.incMidPoint();
if (c == '-') ACS.decMidPoint();
if (c == '0') ACS.setMidPoint(512);
Serial.println(ACS.getMidPoint());
if (c == '*') ACS.setmVperAmp(ACS.getmVperAmp() * 1.05);
if (c == '/') ACS.setmVperAmp(ACS.getmVperAmp() / 1.05);
Serial.println(ACS.getmVperAmp());
}
delay(1000);
}
// -- END OF FILE --

View File

@@ -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 --

View File

@@ -0,0 +1,55 @@
//
// FILE: ACS712_20_determine_form_factor.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo to determine form factor
// URL: https://github.com/RobTillaart/ACS712
#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);
int i = 0;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("ACS712_LIB_VERSION: ");
Serial.println(ACS712_LIB_VERSION);
ACS.autoMidPoint();
}
void loop()
{
Serial.println("\n\nAC \tP2P \tCREST");
for (int i = 0; i < 10; i++)
{
float mA_1 = ACS.mA_AC_sampling();
float mA_2 = ACS.mA_peak2peak();
float crest = 2.0 * mA_1 / mA_2;
Serial.print(mA_1);
Serial.print("\t");
Serial.print(mA_2);
Serial.print("\t");
Serial.println(crest, 4);
delay(100);
}
delay(100);
}
// -- END OF FILE --

View File

@@ -0,0 +1,47 @@
//
// FILE: ACS712_20_mV_noise_level.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo AC measurement with point to point
// URL: https://github.com/RobTillaart/ACS712
#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);
}
void loop()
{
ACS.autoMidPoint();
Serial.println();
Serial.print(" MidPoint: ");
Serial.println(ACS.getMidPoint());
Serial.print("Config Noise mV: ");
Serial.println(ACS.getNoisemV());
Serial.print("Detect Noise mV: ");
Serial.println(ACS.mVNoiseLevel(), 1);
delay(2000);
}
// -- END OF FILE --

View File

@@ -0,0 +1,90 @@
//
// FILE: ACS712_20_AC.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo AC measurement with point to point
// URL: https://github.com/RobTillaart/ACS712
///////////////////////////////////////////////////////////////////
//
// DISPLAY
//
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
#define BL_OFF 0
#define BL_ON 1
#define DISPLAY_ADDR 0x3F // check
LiquidCrystal_I2C lcd(DISPLAY_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
uint32_t lastDisplay = 0;
#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, 185);
// 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);
lcd.begin(16, 2);
lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
lcd.setBacklight(BL_ON);
lcd.clear();
ACS.autoMidPoint();
}
void loop()
{
lcd.clear();
float f1 = ACS.mA_AC();
float f2 = ACS.mA_AC_sampling();
lcd.setCursor(0, 0);
lcd.print("mA: ");
lcd.print(f1, 1);
lcd.setCursor(10, 0);
lcd.print(f2, 1);
lcd.setCursor(0, 1);
lcd.print("FF: ");
lcd.print(f1 / f2);
delay(1000);
}
// -- END OF FILE --

View File

@@ -0,0 +1,54 @@
//
// FILE: ACS712_autoMidPointDC.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo detect DC midpoint.
// URL: https://github.com/RobTillaart/ACS712
#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);
uint32_t start, stop;
uint16_t midPoint = 0;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("ACS712_LIB_VERSION: ");
Serial.println(ACS712_LIB_VERSION);
delay(10);
// might be different 1 cycle or 100.
start = micros();
midPoint = ACS.autoMidPointDC(1);
stop = micros();
Serial.println("ACS.autoMidPointDC()");
Serial.print("us:\t");
Serial.println(stop - start);
Serial.print("MP 1:\t");
Serial.println(midPoint);
midPoint = ACS.autoMidPointDC(100);
Serial.print("MP 100:\t");
Serial.println(midPoint);
}
void loop()
{
}
// -- END OF FILE --

View File

@@ -0,0 +1,49 @@
//
// FILE: ACS712_detectFrequency.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo detect frequency + timing indication.
// URL: https://github.com/RobTillaart/ACS712
#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);
uint32_t start, stop;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.print("ACS712_LIB_VERSION: ");
Serial.println(ACS712_LIB_VERSION);
}
void loop()
{
// e.g. detect 50 or 60 Hz sinus signal
// blocks on bad signals.
start = micros();
float frequency = ACS.detectFrequency(45);
stop = micros();
Serial.print(stop - start);
Serial.print("\t");
Serial.println(frequency, 1);
delay(100);
}
// -- END OF FILE --

View File

@@ -0,0 +1,55 @@
// FILE: RMS_by_sampling.ino
// AUTHOR: Rob Tillaart
// DATE: 2022-08-15
// PURPOSE: demo RMS by sampling for AC current
// URL: https://github.com/RobTillaart/ACS712
//
// stand alone sketch to be used with a ACS712
#include "Arduino.h"
// #include "printHelpers.h"
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
}
void loop()
{
// 50 Hz, Arduino UNO, 20A ACS
float current = mA_AC_sampling(50, 5000.0 / 1023, 100, A0);
Serial.println(current);
delay(1000);
}
float mA_AC_sampling(float frequency, float mVperStep, float mVperAmpere, uint8_t analogPin)
{
uint16_t midpoint = 511;
uint32_t period = round(1000000UL / frequency);
uint16_t samples = 0;
float sumSquared = 0;
uint32_t start = micros();
while (micros() - start < period)
{
samples++;
float current = analogRead(analogPin) - midpoint;
sumSquared += (current * current);
}
// Serial.print(scieng(sumSquared, 1, 3));
// Serial.print("\t");
// Serial.print(samples);
// Serial.print("\t");
float AmperePerStep = mVperStep / mVperAmpere;
float RMS = sqrt(sumSquared / samples) * AmperePerStep;
return RMS * 1000.0; // mA
}
// -- END OF FILE --

View File

@@ -0,0 +1,89 @@
// FILE: estimateMidPointAC.ino
// AUTHOR: Rob Tillaart
// PURPOSE: experimental
// URL: https://github.com/RobTillaart/ACS712/issues/37
//
// Estimates the midpoint by taking many (short-blocking) samples
// instead of many samples in a long blocking period.
// The function adjusts the confidence (or quality) of the midpoint
// depending on the value read.
// This code is experimental and meant to investigate a non-blocking
// way to find the midPoint for the ACS712 when measuring AC currents.
//
// It will not be included in the library
//
// Use with care.
#include "Arduino.h"
uint32_t start, stop;
int _pin = A0;
uint32_t count = 0;
volatile uint16_t mp;
float conf = 0;
uint16_t estimateMidPointAC(float &confidence, bool reset = false)
{
static bool _firstCall = true;
static float _minimum, _maximum, _confidence;
int value = analogRead(_pin);
if (_firstCall || reset)
{
_firstCall = false;
_minimum = _maximum = value;
_confidence = 0;
confidence = _confidence;
return _minimum;
}
if (value > _maximum)
{
_maximum = value;
_confidence /= 2;
}
else if (value < _minimum)
{
_minimum = value;
_confidence /= 2;
}
else if (_confidence < 100)
{
_confidence += 1;
}
confidence = _confidence;
return (_minimum + _maximum) / 2;
}
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
}
void loop()
{
count++;
start = micros();
mp = estimateMidPointAC(conf, true);
stop = micros();
Serial.print(millis());
Serial.print("\t");
Serial.print(count);
Serial.print("\t");
Serial.print(conf);
Serial.print("\t");
Serial.print(mp);
Serial.print("\t");
Serial.print(stop - start);
Serial.println();
delay(random(100));
}
// -- END OF FILE --

View File

@@ -0,0 +1,53 @@
# Syntax Colouring Map For ACS712
# Data types (KEYWORD1)
ACS712 KEYWORD1
# Methods and Functions (KEYWORD2)
mA_peak2peak KEYWORD2
mA_AC KEYWORD2
mA_DC KEYWORD2
mA_AC_sampling KEYWORD2
setMidPoint KEYWORD2
getMidPoint KEYWORD2
incMidPoint KEYWORD2
decMidPoint KEYWORD2
resetMidPoint KEYWORD2
autoMidPoint KEYWORD2
autoMidPointDC KEYWORD2
setFormFactor KEYWORD2
getFormFactor KEYWORD2
setNoisemV KEYWORD2
getNoisemV KEYWORD2
mVNoiseLevel KEYWORD2
suppressNoise KEYWORD2
setmVperAmp KEYWORD2
getmVperAmp KEYWORD2
getmAPerStep KEYWORD2
getAmperePerStep KEYWORD2
detectFrequency KEYWORD2
setMicrosAdjust KEYWORD2
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
ACS712_FF_SAWTOOTH LITERAL1
ACS712_DEFAULT_FREQ LITERAL1
ACS712_DEFAULT_NOISE LITERAL1

View File

@@ -0,0 +1,29 @@
{
"name": "ACS712",
"keywords": "ACS712, Current, 5A, 20A, 30A",
"description": "ACS712 library for Arduino. ",
"authors":
[
{
"name": "Rob Tillaart",
"email": "Rob.Tillaart@gmail.com",
"maintainer": true
},
{
"name": "Pete Thompson",
"email": "pete.thompson@yahoo.com",
"maintainer": false
}
],
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/ACS712.git"
},
"version": "0.3.8",
"license": "MIT",
"frameworks": "*",
"platforms": "*",
"headers": "ACS712.h"
}

View File

@@ -0,0 +1,11 @@
name=ACS712
version=0.3.8
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.
paragraph=Current measurement, tested with RobotDyn ACDC 20A Module.
category=Signal Input/Output
url=https://github.com/RobTillaart/ACS712
architectures=*
includes=ACS712.h
depends=

View File

@@ -0,0 +1,215 @@
//
// FILE: unit_test_001.cpp
// AUTHOR: Rob Tillaart
// DATE: 2020-12-06
// PURPOSE: unit tests for the ACS712 current sensor
// https://github.com/RobTillaart/ACS712
// https://www.adafruit.com/product/2857
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
//
// supported assertions
// ----------------------------
// assertEqual(expected, actual)
// assertNotEqual(expected, actual)
// assertLess(expected, actual)
// assertMore(expected, actual)
// assertLessOrEqual(expected, actual)
// assertMoreOrEqual(expected, actual)
// assertTrue(actual)
// assertFalse(actual)
// assertNull(actual)
#include <ArduinoUnitTests.h>
#include "Arduino.h"
#include "ACS712.h"
#define A0 0
unittest_setup()
{
fprintf(stderr, "ACS712_LIB_VERSION: %s\n", (char *) ACS712_LIB_VERSION);
}
unittest_teardown()
{
}
unittest(test_constants)
{
assertEqualFloat(1.0/sqrt(2), ACS712_FF_SINUS, 0.001);
assertEqualFloat(1.0, ACS712_FF_SQUARE, 0.001);
assertEqualFloat(1.0/sqrt(3), ACS712_FF_TRIANGLE, 0.001);
assertEqualFloat(1.0/sqrt(3), ACS712_FF_SAWTOOTH, 0.001);
assertEqual(21, ACS712_DEFAULT_NOISE);
assertEqual(50, ACS712_DEFAULT_FREQ);
}
unittest(test_mA_DC)
{
GodmodeState* state = GODMODE();
state->reset();
// 0 == A0
ACS712 ACS(0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
// assertEqual(0, ACS.mA_AC(50));
// assertEqual(0, ACS.mA_AC(60));
int future[12] = {0, 0, 100, 100, 200, 200, 511, 511, 900, 900, 1023, 1023};
state->analogPin[0].fromArray(future, 12);
assertEqualFloat(-24975.6, ACS.mA_DC(), 1);
assertEqualFloat(-20088.0, ACS.mA_DC(), 1);
assertEqualFloat(-15200.4, ACS.mA_DC(), 1);
assertEqualFloat(0.0, ACS.mA_DC(), 1);
assertEqualFloat( 19012.7, ACS.mA_DC(), 1);
assertEqualFloat( 25024.4, ACS.mA_DC(), 1);
}
unittest(test_mA_AC)
{
ACS712 ACS(A0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
// loop with micros and a lot of analogReads - not possible
// assertEqual(0, ACS.mA_AC(50));
// assertEqual(0, ACS.mA_AC(60));
assertEqual(1, 1);
}
unittest(test_mA_AC_samples)
{
ACS712 ACS(A0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
// loop with micros and a lot (150?) of analogReads - not possible
// assertEqual(0, ACS.mA_AC_samples(50));
// assertEqual(0, ACS.mA_AC_samples(60));
assertEqual(1, 1);
}
unittest(test_midPoint)
{
ACS712 ACS(A0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
// loop with micros and a lot of analogReads - not possible
// ACS.autoMidPoint(50);
// uint16_t amp50 = ACS.getMidPoint();
// assertEqual(0, amp50);
//
// ACS.autoMidPoint(60);
// uint16_t amp60 = ACS.getMidPoint();
// assertEqual(0, amp60);
uint16_t amp = ACS.getMidPoint();
assertEqual(511, amp);
ACS.setMidPoint(1000);
amp = ACS.getMidPoint();
assertEqual(1000, amp);
ACS.incMidPoint();
amp = ACS.getMidPoint();
assertEqual(1001, amp);
ACS.decMidPoint();
amp = ACS.getMidPoint();
assertEqual(1000, amp);
ACS.decMidPoint();
amp = ACS.getMidPoint();
assertEqual(999, amp);
ACS.resetMidPoint();
amp = ACS.getMidPoint();
assertEqual(511, amp);
// test range ends
ACS.setMidPoint(1023);
amp = ACS.incMidPoint();
assertEqual(1023, amp);
ACS.setMidPoint(0);
amp = ACS.decMidPoint();
assertEqual(0, amp);
}
unittest(test_formFactor)
{
ACS712 ACS(A0, 5.0, 1023, 100);
// default 0.5 * sqrt(2)
float ff = ACS.getFormFactor();
float eff = 0.5 * sqrt(2);
float delta = abs(eff - ff);
assertMoreOrEqual(0.0001, delta);
ACS.setFormFactor(0.8);
ff = ACS.getFormFactor();
eff = 0.8;
delta = abs(eff - ff);
assertMoreOrEqual(0.0001, delta);
}
unittest(test_Noise)
{
ACS712 ACS(A0, 5.0, 1023, 100);
int nmv = ACS.getNoisemV();
assertEqual(21, nmv); // default value..
ACS.setNoisemV(100);
nmv = ACS.getNoisemV();
assertEqual(100, nmv);
}
unittest(test_mVperAmp)
{
ACS712 ACS(A0, 5.0, 1023, 100);
float mpa = ACS.getmVperAmp();
assertEqualFloat(100, mpa, 0.001); // default value..
float mva = 25.0;
while (mva < 200)
{
ACS.setmVperAmp(mva);
mpa = ACS.getmVperAmp();
assertEqualFloat(mva, mpa, 0.001);
mva += 24.8; // just a bit random adjustments
}
}
unittest(test_AmperePerStep)
{
ACS712 ACS(A0, 5.0, 1023, 100);
float aps = ACS.getAmperePerStep();
assertEqualFloat(0.047885, aps, 0.001);
float mva = 25.0;
while (mva < 200)
{
ACS.setmVperAmp(mva);
aps = ACS.getAmperePerStep();
assertEqualFloat(5000.0/1023/mva, aps, 0.001);
mva += 24;
}
}
unittest_main()
// -- END OF FILE --