Skip to content

Commit

Permalink
add yield() to mA_DC()
Browse files Browse the repository at this point in the history
  • Loading branch information
RobTillaart committed Jan 11, 2024
1 parent 5b73115 commit d1b711a
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 21 deletions.
14 changes: 8 additions & 6 deletions ACS712.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// FILE: ACS712.cpp
// AUTHOR: Rob Tillaart, Pete Thompson
// VERSION: 0.3.8
// VERSION: 0.3.9
// DATE: 2020-08-02
// PURPOSE: ACS712 library - current measurement
// URL: https://github.com/RobTillaart/ACS712
Expand Down Expand Up @@ -81,8 +81,8 @@ float ACS712::mA_AC(float frequency, uint16_t cycles)
uint16_t samples = 0;
uint16_t zeros = 0;

int _min, _max;
_min = _max = _analogRead(_pin);
int minimum, maximum;
minimum = maximum = _analogRead(_pin);

// find minimum and maximum and count the zero-level "percentage"
uint32_t start = micros();
Expand All @@ -95,12 +95,12 @@ float ACS712::mA_AC(float frequency, uint16_t cycles)
value = (value + _analogRead(_pin))/2;
}
// determine extremes
if (value < _min) _min = value;
else if (value > _max) _max = value;
if (value < minimum) minimum = value;
else if (value > maximum) maximum = value;
// count zeros
if (abs(value - _midPoint) <= zeroLevel ) zeros++;
}
int peak2peak = _max - _min;
int peak2peak = maximum - minimum;

// automatic determine _formFactor / crest factor
float D = 0;
Expand Down Expand Up @@ -179,6 +179,8 @@ float ACS712::mA_DC(uint16_t cycles)
{
value = (value + _analogRead(_pin))/2;
}
// for RTOS
if (i % 2 == 1) yield();
sum += (value - _midPoint);
}
float mA = sum * _mAPerStep;
Expand Down
20 changes: 14 additions & 6 deletions ACS712.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// FILE: ACS712.h
// AUTHOR: Rob Tillaart, Pete Thompson
// VERSION: 0.3.8
// VERSION: 0.3.9
// DATE: 2020-08-02
// PURPOSE: ACS712 library - current measurement
// URL: https://github.com/RobTillaart/ACS712
Expand All @@ -14,7 +14,7 @@
#include "Arduino.h"


#define ACS712_LIB_VERSION (F("0.3.8"))
#define ACS712_LIB_VERSION (F("0.3.9"))


// ACS712_FF_SINUS == 1.0/sqrt(2) == 0.5 * sqrt(2)
Expand Down Expand Up @@ -42,23 +42,31 @@ class ACS712
// 30A 66.0
ACS712(uint8_t analogPin, float volts = 5.0, uint16_t maxADC = 1023, float mVperAmpere = 100);

// returns mA peak2peak current.
// returns mA peak2peak current.
// blocks ~20-21 ms per cycle to sample a whole 50 or 60 Hz period.
// does NOT call yield() as that would disrupt measurement
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.
// blocks ~20-21 ms per cycle to sample a whole 50 or 60 Hz period.
// works with peak2peak level and (crest) Form Factor.
// lower frequencies block longer.
// does NOT call yield() as that would disrupt measurement
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.
// blocks 20-21 ms per cycle to sample a whole 50 or 60 Hz period.
// works with sampling.
// lower frequencies block longer.
// does NOT call yield() as that would disrupt measurement
float mA_AC_sampling(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1);


// returns mA
// blocks < 1 ms
// blocks < 1 ms (depending on # samples and ADC used)
// does call yield() for RTOS.
float mA_DC(uint16_t samples = 1);


Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).


## [0.3.9] - 2024-01-11
- add yield() in multiple reads to better support RTOS
- update readme.md (empty compatibility table)
- minor edits


## [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).
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020-2023 Rob Tillaart
Copyright (c) 2020-2024 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
Expand Down
57 changes: 53 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ could be obtained with such an ADC. It triggered the experimental supporting
of external ADC's with this library.


#### Calibration and accuracy

The library has no means to calibrate the output or use an offset.
However sort of calibrating can relatively easy be done by using
the MultiMap library.
MultiMap approaches a non-linear mapping by multiple linear mappings.

See https://github.com/RobTillaart/MultiMap.


#### Tests

The library is at least confirmed to work with the following boards:
Expand All @@ -91,12 +101,25 @@ Please let me know of other working platforms / processors (and failing ones!).
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.
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


Devices that could be compatible:

| | ACS720 | ACS724 | ACS725 | ACS732 | ACS733| ACS758 | ACS772 | ACS773 | ACS780 | ACS781 |
|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|
| tested | | | #44 | | | | | | | |


| | ACS37002 | ACS37003 | ACS71240 | ACS3761X | ACS37800 | ACS72981 |
|:------:|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:|
| tested | | | | | | |


If you have tested a compatible sensor, please share your experiences.
(can be done by opening an issue to update documentation)

Expand Down Expand Up @@ -151,6 +174,7 @@ This function is intended for signals with unknown Form Factor.
- **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.
- 0.3.9 calls yield() every 3 analogRead's to support RTOS (a bit).


#### mA_AC_sampling performance trick.
Expand Down Expand Up @@ -342,15 +366,24 @@ ACS.setADC(NULL, 5.0, 1023);
- example ACS712_20_DC_external_ADC.ino
- https://github.com/RobTillaart/ACS712/issues/31

- example ACS712_ESP32_external_ADC.ino
- https://github.com/RobTillaart/ACS712/issues/46


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.

To 'catch' the peaks well enough one needs at least 2 samples per millisecond (2000 sps)
for a 60 Hz signal. That gives 34 samples for 360 degrees => 10.6 degrees, which
results in a max deviation of 5.3 degrees from peak => max 0.5% off.

As a 50 Hz signal is a bit slower, 2000 sps would give 40 samples for => 9 degrees,
which results in a max deviation of 4.5 degrees from peak => max 0.4% off.


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()**.
doing **mA-AC()**. It will get an accuracy around ~2%.

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()**.
Expand Down Expand Up @@ -419,6 +452,22 @@ Schema with PULL-UP.
The library does not support this "extreme values" detection.


## RTOS

The library can be used in an RTOS environment, however a few functions of this
library are blocking for relative long times.

In version 0.3.9 the **mA_DC()** calls **yield()** between every three calls of analogRead.
This is done both for the external and intern ADC to prevent blocking of other threads.

For the **mA_AC()** and **mA_peak2peak()** a call to yield() is not desirable
as the samples are all needed to make a decent measurement.
For the applications that need proper scheduling one should put the sampling of the
INA226 at least for **AC** in a separate thread.

There is no RTOS example. If you have and willing to share you are welcome.


## ESPhome

For people who want to use this library for ESPhome, there exists a wrapper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// PURPOSE: demo to measure mA DC with external ADC
// URL: https://github.com/RobTillaart/ACS712

// see also ACS712_ESP32_external_ADC.ino

// use with Arduino Serial Plotter

#include "ACS712.h"
Expand Down Expand Up @@ -43,7 +45,7 @@ void loop()
}

// wrapper needed for external analogRead()
// as casting behavior is undefined between different function signatures.
// as casting behaviour is undefined between different function signatures.
uint16_t testADC(uint8_t p)
{
// simulation
Expand Down
28 changes: 28 additions & 0 deletions examples/ACS712_ESP32_external_ADC/.arduino-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:

packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json

compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
# - uno
# - due
# - zero
# - leonardo
# - m4
- esp32
# - esp8266
# - mega2560
# - rpipico

77 changes: 77 additions & 0 deletions examples/ACS712_ESP32_external_ADC/ACS712_ESP32_external_ADC.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// FILE: ACS712_ESP32_external_ADC.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo to measure mA DC with external ADC
// URL: https://github.com/RobTillaart/ACS712

// see also ACS712_20_DC_external_ADC.ino

#include <Arduino.h>
#include <ACS712.h>
#include <ADS1X15.h>


// I2C config
#define ADS1015_ADDRESS 0x48
#define ADS1015_SCL 22 // default SCL ESP32
#define ADS1015_SDA 21 // default SDA ESP32

// ADS1x15 config
#define SENSOR_ACS712_ADSPIN 1


// explicit params for demo
ADS1015 ads1015(ADS1015_ADDRESS, &Wire); // ADS1015 == 12 bit


// SENSOR_ACS712_ADSPIN sets pin 1 of the ADS1015, 5.0 volt, 4095 = 12 bit, 100 = mVperAmpere
ACS712 ACS(SENSOR_ACS712_ADSPIN, 5.0, 4095, 100);


// ACS712 ADC WRAPPER FOR ADS1015 Note: uses only one direction.
uint16_t readADS1015(uint8_t pin)
{
uint16_t ADS_raw = ads1015.readADC(pin);
Serial.print("ADS_raw: ");
Serial.println(ADS_raw);
return ADS_raw;
}


///////////////////////////////////////////////////////////////

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


// ESP32 set wire pins explicitly
Wire.begin(ADS1015_SDA, ADS1015_SCL);
Wire.setClock(400000);


// initialize ADS1015, if fail => report
if (ads1015.begin() == false)
{
Serial.println("ADS1x15 not found. Check wires and pins. Reboot.");
while(1);
}

// set up the external ADC for the ACS712
ACS.setADC(readADS1015, 5.0, 4095);
}


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


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

0 comments on commit d1b711a

Please sign in to comment.