RobTillaart / ACS712

Arduino library for ACS Current Sensor - 5A, 20A, 30A
MIT License
129 stars 35 forks source link

I2C ADC #31

Closed DJLevel3 closed 1 year ago

DJLevel3 commented 1 year ago

Is there any plan to support I2C ADCs such as an ADS1115?

I want to use this library to measure current from a step-down CT (I'm measuring some seriously large currents) and with an Arduino's built-in ADC I won't get the resolution I need. I want to use an ADS1115 board (such as https://a.co/d/4EJSIGC) but I don't see any functionality of the sort in this library. I'll see if I can find a way to get it to work, and if I do I'll update here, but if not is it a possibility for a dev to add this feature?

Thanks!

RobTillaart commented 1 year ago

Hi, Plans exist but no time at the moment as other tasks have my priority.

This is what I have in mind

Lib for the ADS1115 is available and stable. https://github.com/RobTillaart/ADS1X15 Other libs like the mcp-adc are also stable and much faster. https://github.com/RobTillaart/MCP_ADC

What need to be done is create a function pointer that takes analogRead() as default argument and which can be overridden by another function that wraps the ADS1115 call. The pin parameter can be interpreted as one of the 4 channels.

There need to be a *setADC((int read)(int pin))** function to do the work. (Something like that,) and a variable that holds the function pointer. That latter should be used where now analogRead() is called.

Did extend this ACS lib once with an ADCsimulator to do some math testing in a similar way and that worked well. So there is some evidence this will work

RobTillaart commented 1 year ago

Will give it some thoughts coming days, as it is an intriguing question If you can create a PR according to the flow I propose it might be merged into it.

(Problem is that the Arduino build-CI is broken so automatic testing is almost zero)

RobTillaart commented 1 year ago

proof of concept for function pointer (will be added as example to ADS1x15 lib in future)

Give it a try

//    FILE: ADS_pointerToFunction.ino
//  AUTHOR: Rob Tillaart
//    DATE: 2023-01-14
// PURPOSE: replace internal ADC with external ADC by using pointer to function
//     URL: https://github.com/RobTillaart/ADS1X15

#include "Arduino.h"
#include "ADS1X15.h"

//  adjust address if needed
ADS1115 ADS(0x48);  

//  pointer to ADC function
int (*readADC)(uint8_t);  

void setup() 
{
  Serial.begin(115200);
  while(!Serial);
  Serial.println(__FILE__);

  ADS.begin();  //  use defaults

  readADC = analogRead;  //  start with internal 
}

void loop()
{
  delay(500);
  int x = readADC(1);
  Serial.println(x);
  if (millis() > 5000) readADC = wrapper;
}

//  wrapper takes care of optional casting
int wrapper(uint8_t x)
{
  return ADS.readADC(x);
}

// -- END OF FILE --
RobTillaart commented 1 year ago

@DJLevel3 Created a develop branch with setADC() function to replace the internal ADC with an external one.

Be sure to adjust the parameters of the constructor to the ADC used These might become parameters of setADC() too.

See the example ACS712_20_DC_external_ADC.ino how to wrap the external ADC in a function that can be passed to setADC(). Similar as the sketch above.

Alternative is to make a cast in the call of setADC() directly.

Please give it a try and let me know if it works.

RobTillaart commented 1 year ago

Done additional tests,

What is missing is a function to reset to the internal ADC.


Alternative is to make a cast in the call of setADC() directly.

This gives problems and it appears not possible See - https://stackoverflow.com/questions/559581/casting-a-function-pointer-to-another-type

DJLevel3 commented 1 year ago

Might be a good idea to just use #define and #ifdef to swap out a function at compile time, no?

RobTillaart commented 1 year ago

Might be a good idea to just use #define and #ifdef to swap out a function at compile time, no?

That will work too, one need to add a guard to prevent double defines and to be able to overrule it command line. The setADC will still be useful to easily set the parameters.

The way i'm after makes it possible to change ADC runtime. That would allow different ADC's to be used. Think of a 16 bit slow for very precise measurements incl low currents and a 8 bit fast for larger currents.

RobTillaart commented 1 year ago

Merged the setADC() so you can runtime change the ADC used on any platform. Besides setting an external ADC of choice runtime one can (in theory)