GY-63_MS5611/libraries/ACS712/ACS712.cpp

169 lines
4.9 KiB
C++
Raw Normal View History

2020-03-19 10:16:52 -04:00
//
// FILE: ACS712.cpp
2020-11-27 05:10:47 -05:00
// AUTHOR: Rob Tillaart, Pete Thompson
2022-08-12 04:47:41 -04:00
// VERSION: 0.2.7
2020-11-27 05:10:47 -05:00
// DATE: 2020-08-02
2020-03-19 10:16:52 -04:00
// PURPOSE: ACS712 library - current measurement
//
2021-06-24 08:41:36 -04:00
// 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.
2021-10-16 05:40:09 -04:00
// 0.2.3 2021-10-15 changed frequencies to float, for optimal tuning.
// updated build CI, readme.md
2021-12-02 13:29:13 -05:00
// 0.2.4 2021-11-22 add experimental detectFrequency()
// 0.2.5 2021-12-03 add timeout to detectFrequency()
2021-12-09 09:42:38 -05:00
// 0.2.6 2021-12-09 update readme.md + license
2022-08-12 04:47:41 -04:00
// 0.2.7 2022-08-10 change mVperAmp to float
// add ACS712_FF_SAWTOOTH
// update readme.md + unit test + minor edits
2021-06-24 08:41:36 -04:00
2020-03-19 10:16:52 -04:00
#include "ACS712.h"
2021-06-24 08:41:36 -04:00
2022-08-12 04:47:41 -04:00
ACS712::ACS712(uint8_t analogPin, float volts, uint16_t maxADC, float mVperAmpere)
2020-03-19 10:16:52 -04:00
{
2021-01-29 06:31:58 -05:00
_pin = analogPin;
2022-08-12 04:47:41 -04:00
_mVperStep = 1000.0 * volts / maxADC; // 1x 1000 for V -> mV
_mVperAmpere = mVperAmpere;
2021-06-24 08:41:36 -04:00
_formFactor = ACS712_FF_SINUS;
2021-01-29 06:31:58 -05:00
_midPoint = maxADC / 2;
2022-08-12 04:47:41 -04:00
_noisemV = 21; // Noise is 21mV according to datasheet
2020-03-19 10:16:52 -04:00
}
2021-06-24 08:41:36 -04:00
2022-08-12 04:47:41 -04:00
int ACS712::mA_AC(float frequency)
2020-03-19 10:16:52 -04:00
{
2022-08-12 04:47:41 -04:00
uint16_t period = round(1000000UL / frequency);
2021-01-29 06:31:58 -05:00
uint16_t samples = 0;
2021-06-24 08:41:36 -04:00
uint16_t zeros = 0;
2021-01-29 06:31:58 -05:00
int _min, _max;
_min = _max = analogRead(_pin);
2021-10-16 05:40:09 -04:00
// remove expensive float operation from loop.
2022-08-12 04:47:41 -04:00
uint16_t zeroLevel = round(_noisemV/_mVperStep);
2021-06-24 08:41:36 -04:00
uint32_t start = micros();
2021-01-29 06:31:58 -05:00
while (micros() - start < period) // UNO ~180 samples...
{
samples++;
int val = analogRead(_pin);
2022-08-12 04:47:41 -04:00
// determine extremes
2021-01-29 06:31:58 -05:00
if (val < _min) _min = val;
2021-06-24 08:41:36 -04:00
else if (val > _max) _max = val;
2022-08-12 04:47:41 -04:00
// count zeros
2021-06-24 08:41:36 -04:00
if (abs(val - _midPoint) <= zeroLevel ) zeros++;
2021-01-29 06:31:58 -05:00
}
int point2point = (_max - _min);
2020-11-27 05:10:47 -05:00
2022-08-12 04:47:41 -04:00
// automatic determine _formFactor / crest factor
2021-01-29 06:31:58 -05:00
float D = 0;
float FF = 0;
2022-08-12 04:47:41 -04:00
// TODO uint32_t math? (zeros * 40) > samples
if (zeros > samples * 0.025) // more than 2% zero's
2021-01-29 06:31:58 -05:00
{
2022-08-12 04:47:41 -04:00
D = 1.0 - (1.0 * zeros) / samples; // % SAMPLES NONE ZERO
FF = sqrt(D) * ACS712_FF_SINUS; // ASSUME NON ZERO PART ~ SINUS
2021-01-29 06:31:58 -05:00
}
2022-08-12 04:47:41 -04:00
else // # zeros is small => D --> 1 --> sqrt(D) --> 1
2021-01-29 06:31:58 -05:00
{
2021-06-24 08:41:36 -04:00
FF = ACS712_FF_SINUS;
2021-01-29 06:31:58 -05:00
}
_formFactor = FF;
2020-11-27 05:10:47 -05:00
2022-08-12 04:47:41 -04:00
// value could be partially pre-calculated: C = 1000.0 * 0.5 * _mVperStep / _mVperAmpere;
// return 1000.0 * 0.5 * point2point * _mVperStep * _formFactor / _mVperAmpere);
float mA = (500.0 * point2point) * _mVperStep * _formFactor / _mVperAmpere;
return round(mA);
2020-03-19 10:16:52 -04:00
}
2021-06-24 08:41:36 -04:00
2020-03-19 10:16:52 -04:00
int ACS712::mA_DC()
{
2021-10-16 05:40:09 -04:00
// read twice to stabilize the ADC
2021-06-24 08:41:36 -04:00
analogRead(_pin);
int steps = analogRead(_pin) - _midPoint;
2022-08-12 04:47:41 -04:00
float mA = 1000.0 * steps * _mVperStep / _mVperAmpere;
return round(mA);
2020-03-19 10:16:52 -04:00
}
2021-06-24 08:41:36 -04:00
2021-10-16 05:40:09 -04:00
// configure by sampling for 2 cycles of AC
// Also works for DC as long as no current flowing
// note this is blocking!
2022-08-12 04:47:41 -04:00
void ACS712::autoMidPoint(float frequency)
2020-11-27 05:10:47 -05:00
{
2022-08-12 04:47:41 -04:00
uint16_t twoPeriods = round(2000000UL / frequency);
2021-06-24 08:41:36 -04:00
uint32_t total = 0;
2020-11-27 05:10:47 -05:00
uint32_t samples = 0;
2021-06-24 08:41:36 -04:00
uint32_t start = micros();
while (micros() - start < twoPeriods)
{
2020-11-27 05:10:47 -05:00
uint16_t reading = analogRead(_pin);
total += reading;
2022-08-12 04:47:41 -04:00
samples++;
// Delaying ensures we won't overflow since we'll perform a maximum of 40,000 reads
2020-11-27 05:10:47 -05:00
delayMicroseconds(1);
}
_midPoint = total / samples;
}
2021-06-24 08:41:36 -04:00
2021-12-01 08:20:22 -05:00
// Experimental frequency detection.
// uses oversampling and averaging to minimize variation
// blocks for substantial amount of time, depending on minimalFrequency
2021-12-02 13:29:13 -05:00
float ACS712::detectFrequency(float minimalFrequency)
2021-12-01 08:20:22 -05:00
{
2021-12-02 13:29:13 -05:00
int maximum = 0;
int minimum = 0;
2021-12-01 08:20:22 -05:00
maximum = minimum = analogRead(_pin);
// determine maxima
2021-12-02 13:29:13 -05:00
uint32_t timeOut = round(1000000.0 / minimalFrequency);
2021-12-01 08:20:22 -05:00
uint32_t start = micros();
2021-12-02 13:29:13 -05:00
while (micros() - start < timeOut)
2021-12-01 08:20:22 -05:00
{
2021-12-02 13:29:13 -05:00
int value = analogRead(_pin);
2021-12-01 08:20:22 -05:00
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
2021-12-02 13:29:13 -05:00
int Q1 = (3 * minimum + maximum ) / 4;
int Q3 = (minimum + 3 * maximum ) / 4;
2021-12-01 08:20:22 -05:00
2022-08-12 04:47:41 -04:00
// 10x passing Quantile points
// wait for the right moment to start
// to prevent endless loop a timeout is checked.
2021-12-02 13:29:13 -05:00
timeOut *= 10;
start = micros();
while ((analogRead(_pin) > Q1) && ((micros() - start) < timeOut));
while ((analogRead(_pin) <= Q3) && ((micros() - start) < timeOut));
2021-12-01 08:20:22 -05:00
start = micros();
for (int i = 0; i < 10; i++)
{
2021-12-02 13:29:13 -05:00
while ((analogRead(_pin) > Q1) && ((micros() - start) < timeOut));
while ((analogRead(_pin) <= Q3) && ((micros() - start) < timeOut));
2021-12-01 08:20:22 -05:00
}
uint32_t stop = micros();
// calculate frequency
float wavelength = stop - start;
float frequency = 1e7 / wavelength;
if (_microsAdjust != 1.0) frequency *= _microsAdjust;
return frequency;
}
2021-06-24 08:41:36 -04:00
// -- END OF FILE --
2021-12-01 08:20:22 -05:00