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

430 lines
9.4 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
2023-01-15 14:39:54 -05:00
// VERSION: 0.3.4
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
2023-01-03 14:19:20 -05:00
// URL: https://github.com/RobTillaart/ACS712
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-28 03:44:41 -04:00
// CONSTRUCTOR
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
{
2022-09-01 05:19:21 -04:00
_pin = analogPin;
2023-01-15 14:39:54 -05:00
_mVperAmpere = mVperAmpere;
_formFactor = ACS712_FF_SINUS;
_noisemV = ACS712_DEFAULT_NOISE; // 21mV according to datasheet
// set in setADC()
// keep it here until after experimental.
2022-10-10 06:21:13 -04:00
_maxADC = maxADC;
2022-09-01 05:19:21 -04:00
_mVperStep = 1000.0 * volts / maxADC; // 1x 1000 for V -> mV
_mAPerStep = 1000.0 * _mVperStep / _mVperAmpere;
_midPoint = maxADC / 2;
2023-01-15 14:39:54 -05:00
// default ADC is internal.
setADC(_internalAnalog, volts, maxADC);
2020-03-19 10:16:52 -04:00
}
2021-06-24 08:41:36 -04:00
2022-08-28 03:44:41 -04:00
// MEASUREMENTS
2022-09-01 05:19:21 -04:00
float ACS712::mA_peak2peak(float frequency, uint16_t cycles)
{
uint16_t period = round(1000000UL / frequency);
if (cycles == 0) cycles = 1;
float sum = 0;
2022-10-10 06:21:13 -04:00
2022-09-01 05:19:21 -04:00
for (uint16_t i = 0; i < cycles; i++)
{
int minimum, maximum;
// Better than using midPoint
2023-01-15 14:39:54 -05:00
minimum = maximum = _readADC(_pin);
2022-09-01 05:19:21 -04:00
// find minimum and maximum
uint32_t start = micros();
2023-01-15 14:39:54 -05:00
while (micros() - start < period) // UNO ~180 samples...
2022-09-01 05:19:21 -04:00
{
2023-01-15 14:39:54 -05:00
int value = _readADC(_pin);
2022-10-10 06:21:13 -04:00
if (_suppresNoise) // average 2 samples.
{
2023-01-15 14:39:54 -05:00
value = (value + _readADC(_pin))/2;
2022-10-10 06:21:13 -04:00
}
2022-09-01 05:19:21 -04:00
// determine extremes
2022-10-10 06:21:13 -04:00
if (value < minimum) minimum = value;
else if (value > maximum) maximum = value;
2022-09-01 05:19:21 -04:00
}
sum += (maximum - minimum);
}
2022-10-10 06:21:13 -04:00
float peak2peak = sum * _mAPerStep;
if (cycles > 1) peak2peak /= cycles;
2022-09-01 05:19:21 -04:00
return peak2peak;
}
float ACS712::mA_AC(float frequency, uint16_t cycles)
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
2022-08-28 03:44:41 -04:00
if (cycles == 0) cycles = 1;
float sum = 0;
2021-01-29 06:31:58 -05:00
2022-09-01 05:19:21 -04:00
// remove 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
2022-08-28 03:44:41 -04:00
for (uint16_t i = 0; i < cycles; i++)
2021-01-29 06:31:58 -05:00
{
2022-08-28 03:44:41 -04:00
uint16_t samples = 0;
uint16_t zeros = 0;
2020-11-27 05:10:47 -05:00
2022-08-28 03:44:41 -04:00
int _min, _max;
2023-01-15 14:39:54 -05:00
_min = _max = _readADC(_pin);
2022-08-28 03:44:41 -04:00
// find minimum and maximum and count the zero-level "percentage"
uint32_t start = micros();
while (micros() - start < period) // UNO ~180 samples...
{
samples++;
2023-01-15 14:39:54 -05:00
int value = _readADC(_pin);
2022-10-10 06:21:13 -04:00
if (_suppresNoise) // average 2 samples.
{
2023-01-15 14:39:54 -05:00
value = (value + _readADC(_pin))/2;
2022-10-10 06:21:13 -04:00
}
2022-08-28 03:44:41 -04:00
// determine extremes
2022-10-10 06:21:13 -04:00
if (value < _min) _min = value;
else if (value > _max) _max = value;
2022-08-28 03:44:41 -04:00
// count zeros
2022-10-10 06:21:13 -04:00
if (abs(value - _midPoint) <= zeroLevel ) zeros++;
2022-08-28 03:44:41 -04:00
}
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;
2021-01-29 06:31:58 -05:00
}
2022-10-10 06:21:13 -04:00
float mA = 0.5 * sum * _mAPerStep;
if (cycles > 1) mA /= cycles;
2020-11-27 05:10:47 -05:00
2022-09-01 05:19:21 -04:00
return mA;
2020-03-19 10:16:52 -04:00
}
2021-06-24 08:41:36 -04:00
2022-08-28 03:44:41 -04:00
float ACS712::mA_AC_sampling(float frequency, uint16_t cycles)
2020-03-19 10:16:52 -04:00
{
2022-08-28 03:44:41 -04:00
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++;
2023-01-15 14:39:54 -05:00
int value = _readADC(_pin);
2022-10-10 06:21:13 -04:00
if (_suppresNoise) // average 2 samples.
{
2023-01-15 14:39:54 -05:00
value = (value + _readADC(_pin))/2;
2022-10-10 06:21:13 -04:00
}
float current = value - _midPoint;
2022-08-28 03:44:41 -04:00
sumSquared += (current * current);
2022-11-21 14:44:08 -05:00
// not adding noise squared might be more correct for small currents.
2022-08-28 03:44:41 -04:00
// if (abs(current) > noiseLevel)
2022-10-10 06:21:13 -04:00
// {
2022-08-28 03:44:41 -04:00
// sumSquared += (current * current);
// }
}
sum += sqrt(sumSquared / samples);
}
2022-10-10 06:21:13 -04:00
float mA = sum * _mAPerStep;
if (cycles > 1) mA /= cycles;
2022-08-28 03:44:41 -04:00
return mA;
}
2022-09-01 05:19:21 -04:00
float ACS712::mA_DC(uint16_t cycles)
2022-08-28 03:44:41 -04:00
{
// read at least twice to stabilize the ADC
2023-01-15 14:39:54 -05:00
_readADC(_pin);
2022-08-28 03:44:41 -04:00
if (cycles == 0) cycles = 1;
float sum = 0;
for (uint16_t i = 0; i < cycles; i++)
{
2023-01-15 14:39:54 -05:00
int value = _readADC(_pin);
2022-10-10 06:21:13 -04:00
if (_suppresNoise) // average 2 samples.
{
2023-01-15 14:39:54 -05:00
value = (value + _readADC(_pin))/2;
2022-10-10 06:21:13 -04:00
}
sum += (value - _midPoint);
2022-08-28 03:44:41 -04:00
}
2022-10-10 06:21:13 -04:00
float mA = sum * _mAPerStep;
if (cycles > 1) mA /= cycles;
2022-09-01 05:19:21 -04:00
return mA;
2020-03-19 10:16:52 -04:00
}
2021-06-24 08:41:36 -04:00
2022-08-28 03:44:41 -04:00
// CALIBRATION MIDPOINT
2022-09-01 05:19:21 -04:00
uint16_t ACS712::setMidPoint(uint16_t midPoint)
2022-08-28 03:44:41 -04:00
{
2022-11-21 14:44:08 -05:00
if (midPoint <= _maxADC) _midPoint = (int) midPoint;
2022-09-01 05:19:21 -04:00
return _midPoint;
2022-08-28 03:44:41 -04:00
};
uint16_t ACS712::getMidPoint()
{
return _midPoint;
};
2022-09-01 05:19:21 -04:00
uint16_t ACS712::incMidPoint()
2022-08-28 03:44:41 -04:00
{
2022-11-21 14:44:08 -05:00
if (_midPoint < (int)(_maxADC)) _midPoint += 1;
2022-09-01 05:19:21 -04:00
return _midPoint;
2022-08-28 03:44:41 -04:00
};
2022-09-01 05:19:21 -04:00
uint16_t ACS712::decMidPoint()
2022-08-28 03:44:41 -04:00
{
2022-10-10 06:21:13 -04:00
if (_midPoint > 0) _midPoint -= 1;
2022-09-01 05:19:21 -04:00
return _midPoint;
2022-08-28 03:44:41 -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-09-01 05:19:21 -04:00
uint16_t ACS712::autoMidPoint(float frequency, uint16_t cycles)
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
2022-08-28 03:44:41 -04:00
if (cycles == 0) cycles = 1;
uint32_t total = 0;
for (uint16_t i = 0; i < cycles; i++)
2021-06-24 08:41:36 -04:00
{
2022-08-28 03:44:41 -04:00
uint32_t subTotal = 0;
uint32_t samples = 0;
uint32_t start = micros();
while (micros() - start < twoPeriods)
{
2023-01-15 14:39:54 -05:00
uint16_t reading = _readADC(_pin);
2022-08-28 03:44:41 -04:00
subTotal += reading;
samples++;
2022-10-10 06:21:13 -04:00
// Delaying prevents overflow
// since we'll perform a maximum of 40,000 reads @ 50 Hz.
2022-08-28 03:44:41 -04:00
delayMicroseconds(1);
}
2022-10-10 06:21:13 -04:00
total += (subTotal / samples);
2020-11-27 05:10:47 -05:00
}
2022-08-28 03:44:41 -04:00
_midPoint = total / cycles;
2022-09-01 05:19:21 -04:00
return _midPoint;
2020-11-27 05:10:47 -05:00
}
2021-06-24 08:41:36 -04:00
2022-10-10 06:21:13 -04:00
uint16_t ACS712::resetMidPoint()
{
_midPoint = _maxADC / 2;
return _midPoint;
};
2022-08-28 03:44:41 -04:00
// CALIBRATION FORM FACTOR
void ACS712::setFormFactor(float formFactor)
{
_formFactor = formFactor;
};
2022-09-01 05:19:21 -04:00
2022-08-28 03:44:41 -04:00
float ACS712::getFormFactor()
{
return _formFactor;
};
// CALIBRATION NOISE
// noise defaults 21 datasheet
void ACS712::setNoisemV(uint8_t noisemV)
{
_noisemV = noisemV;
};
2022-09-01 05:19:21 -04:00
2022-08-28 03:44:41 -04:00
uint8_t ACS712::getNoisemV()
{
return _noisemV;
};
2022-10-10 06:21:13 -04:00
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;
}
2022-08-28 03:44:41 -04:00
// CALIBRATION mV PER AMP
// Adjusting resolution AC and DC
void ACS712::setmVperAmp(float mVperAmpere)
{
_mVperAmpere = mVperAmpere;
2022-09-01 05:19:21 -04:00
_mAPerStep = 1000.0 * _mVperStep / _mVperAmpere;
2022-08-28 03:44:41 -04:00
};
2022-09-01 05:19:21 -04:00
2022-08-28 03:44:41 -04:00
float ACS712::getmVperAmp()
{
return _mVperAmpere;
};
2022-09-01 05:19:21 -04:00
float ACS712::getmAPerStep()
{
return _mAPerStep;
};
2022-08-28 03:44:41 -04:00
float ACS712::getAmperePerStep()
{
2022-09-01 05:19:21 -04:00
return _mAPerStep * 0.001;
2022-08-28 03:44:41 -04:00
};
2022-09-01 05:19:21 -04:00
// FREQUENCY DETECTION
2021-12-01 08:20:22 -05:00
// 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;
2023-01-15 14:39:54 -05:00
maximum = minimum = _readADC(_pin);
2021-12-01 08:20:22 -05:00
// 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
{
2023-01-15 14:39:54 -05:00
int value = _readADC(_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();
2022-10-10 06:21:13 -04:00
// casting to int to keep compiler happy.
2023-01-15 14:39:54 -05:00
while ((int(_readADC(_pin)) > Q1) && ((micros() - start) < timeOut));
while ((int(_readADC(_pin)) <= Q3) && ((micros() - start) < timeOut));
2021-12-01 08:20:22 -05:00
start = micros();
for (int i = 0; i < 10; i++)
{
2023-01-15 14:39:54 -05:00
while ((int(_readADC(_pin)) > Q1) && ((micros() - start) < timeOut));
while ((int(_readADC(_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;
}
2022-09-01 05:19:21 -04:00
// timing for FREQUENCY DETECTION
2022-08-28 03:44:41 -04:00
void ACS712::setMicrosAdjust(float factor)
{
_microsAdjust = factor;
};
2022-09-01 05:19:21 -04:00
2022-08-28 03:44:41 -04:00
float ACS712::getMicrosAdjust()
{
return _microsAdjust;
};
2021-12-01 08:20:22 -05:00
2022-09-01 05:19:21 -04:00
// DEBUG
uint16_t ACS712::getMinimum(uint16_t milliSeconds)
{
2023-01-15 14:39:54 -05:00
uint16_t minimum = _readADC(_pin);
2022-09-01 05:19:21 -04:00
// find minimum
uint32_t start = millis();
while (millis() - start < milliSeconds)
{
2023-01-15 14:39:54 -05:00
uint16_t value = _readADC(_pin);
2022-09-01 05:19:21 -04:00
if (value < minimum) minimum = value;
}
return minimum;
}
uint16_t ACS712::getMaximum(uint16_t milliSeconds)
{
2023-01-15 14:39:54 -05:00
uint16_t maximum = _readADC(_pin);
2022-09-01 05:19:21 -04:00
// find minimum
uint32_t start = millis();
while (millis() - start < milliSeconds)
{
2023-01-15 14:39:54 -05:00
uint16_t value = _readADC(_pin);
2022-09-01 05:19:21 -04:00
if (value > maximum) maximum = value;
}
return maximum;
}
2023-01-15 14:39:54 -05:00
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;
}
2021-06-24 08:41:36 -04:00
// -- END OF FILE --
2021-12-01 08:20:22 -05:00