diff --git a/ACS712.cpp b/ACS712.cpp index 4d1023a..fb8dba7 100644 --- a/ACS712.cpp +++ b/ACS712.cpp @@ -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 @@ -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(); @@ -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; @@ -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; diff --git a/ACS712.h b/ACS712.h index d343715..272b043 100644 --- a/ACS712.h +++ b/ACS712.h @@ -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 @@ -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) @@ -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); diff --git a/CHANGELOG.md b/CHANGELOG.md index c5a938a..9f16961 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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). diff --git a/LICENSE b/LICENSE index 42604f3..18dfaaf 100644 --- a/LICENSE +++ b/LICENSE @@ -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 diff --git a/README.md b/README.md index 3c1f8aa..ffc3d8a 100644 --- a/README.md +++ b/README.md @@ -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: @@ -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) @@ -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. @@ -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()**. @@ -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 diff --git a/examples/ACS712_20_DC_external_ADC/ACS712_20_DC_external_ADC.ino b/examples/ACS712_20_DC_external_ADC/ACS712_20_DC_external_ADC.ino index 55e4f4a..8c2c4b7 100644 --- a/examples/ACS712_20_DC_external_ADC/ACS712_20_DC_external_ADC.ino +++ b/examples/ACS712_20_DC_external_ADC/ACS712_20_DC_external_ADC.ino @@ -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" @@ -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 diff --git a/examples/ACS712_ESP32_external_ADC/.arduino-ci.yml b/examples/ACS712_ESP32_external_ADC/.arduino-ci.yml new file mode 100644 index 0000000..e1c447b --- /dev/null +++ b/examples/ACS712_ESP32_external_ADC/.arduino-ci.yml @@ -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 + diff --git a/examples/ACS712_ESP32_external_ADC/ACS712_ESP32_external_ADC.ino b/examples/ACS712_ESP32_external_ADC/ACS712_ESP32_external_ADC.ino new file mode 100644 index 0000000..b979c93 --- /dev/null +++ b/examples/ACS712_ESP32_external_ADC/ACS712_ESP32_external_ADC.ino @@ -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 +#include +#include + + +// 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 -- diff --git a/library.json b/library.json index 2972f3f..6380823 100644 --- a/library.json +++ b/library.json @@ -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": "*", diff --git a/library.properties b/library.properties index 76178de..aebbd43 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ACS712 -version=0.3.8 +version=0.3.9 author=Rob Tillaart , Pete Thompson maintainer=Rob Tillaart sentence=ACS712 library for Arduino.