ACS712 not accurate

I use ESP32 and ACS712 5A, but the readings I get are fluctuating and inaccurate... here is the program I use. please help me where is the mistake. Thank You

#define def_frequency 50

uint16_t adc = 4095;
uint16_t cycle = 1;
uint8_t ACSpin = 32;
uint8_t noisemV = 21;
int midPoint;

float ACS_resolution = 185.0;
float maxVolt = 3.30;
float formFactor = (1.0 / sqrt(2));
float mVperStep;
float mAperStep;

bool suppresNoise = false;

void setup() {
  Serial.begin(115200);
  delay(100);
  ACS712_init(maxVolt, adc, ACS_resolution);
  autoMidpoint(def_frequency, cycle);
  Serial.println("ACS Ready.....");
  delay(2000);
}

void loop() {
  float average = 0;
  uint32_t start_time = millis();
  for (int i = 0; i < 100; i++) {
    average += readACS(def_frequency,cycle);
  }
  float mA = average / 100.0;
  float mAmps = mA - 130.0;
  uint32_t duration = millis() - start_time;
  Serial.print("Time: ");
  Serial.print(duration);
  Serial.print("  mA: ");
  Serial.println(mAmps);
  delay(1000);
}

void ACS712_init(float volts, uint16_t maxADC, float mVperAmpere) {
  //  set in setADC()
  //  keep it here until after experimental.
  mVperStep   = 1000.0 * volts / maxADC;  //  1x 1000 for V -> mV
  mAperStep   = 1000.0 * mVperStep / mVperAmpere;
  midPoint    = maxADC / 2;
}

uint16_t autoMidpoint(float frequency, uint16_t cycles) {
  uint16_t twoPeriods = round(2000000UL / frequency);
  if (cycles == 0) cycles = 1;
  uint32_t total = 0;
  for (uint16_t i = 0; i < cycles; i++)
  {
    uint32_t subTotal = 0;
    uint32_t samples  = 0;
    uint32_t time_start    = micros();
    while (micros() - time_start < twoPeriods)
    {
      uint16_t reading = analogRead(ACSpin);
      subTotal += reading;
      samples++;
      //  Delaying prevents overflow
      //  since we'll perform a maximum of 40,000 reads @ 50 Hz.
      delayMicroseconds(1);
    }
    total += (subTotal / samples);
  }
  midPoint = (total + (cycles / 2)) / cycles; //  rounding.
  return midPoint;
}

float readACS(float frequency, uint16_t cycles) {
  uint16_t period  = round(1000000UL / frequency);

  if (cycles == 0) cycles = 1;
  float sum = 0;

  //  remove float operation from loop.
  uint16_t zeroLevel = round(noisemV / mVperStep);

  for (uint16_t i = 0; i < cycles; i++)
  {
    uint16_t samples = 0;
    uint16_t zeros   = 0;

    int minimum, maximum;
    minimum = maximum = analogRead(ACSpin);

    //  find minimum and maximum and count the zero-level "percentage"
    uint32_t time_start = micros();
    while (micros() - time_start < period)  // UNO ~180 samples...
    {
      samples++;
      int adc_value = analogRead(ACSpin);
      if (suppresNoise)  //  average 2 samples.
      {
        adc_value = (adc_value + analogRead(ACSpin)) / 2;
      }
      //  determine extremes
      if (adc_value < minimum) minimum = adc_value;
      else if (adc_value > maximum) maximum = adc_value;
      //  count zeros
      if (abs(adc_value - midPoint) <= zeroLevel ) zeros++;
    }
    int peak2peak = maximum - minimum;

    //  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;
  }
  float mA = 0.5 * sum * mAperStep;
  if (cycles > 1) mA /= cycles;

  return mA;
}

The mistake is that you are using an ACS712 with an ESP32.

The ACS712 is a ratiometric 5volt-only sensor,
which should be used with a 5volt-logic ratiometric A/D (like an Uno).

The ESP32 is a 3.3volt-logic MCU with an absolute (voltage) A/D.

Very hard to get a stable offset (midpoint) and span with that combination.

For mains AC you should look at a current transformer.
Also note that an ACS712 (and the board it's mounted on) is not safe for 230AC.
Leo..

1 Like

yes, I know that.. esp32 has 3.3V A/D
in the acs712 datasheet, it has a zero value of 2.5 volts, can I manipulate the program in the esp32 to still be able to read the acs712?
the current that I read is not up to 2A, in the datasheet the acs712 5A has a linearity of 185mV, if what I read is a maximum of 2A, it means that the analog reading of the esp32 is a maximum of 2.87 Volts... is there something wrong with my understanding? please correct, thank you

More correct, the output has a zero current voltage of VCC/2.
So that 2.5volt is only correct if the ACS supply is 5.0 volt

That 185mV/A gain is also supply dependent, and only valid if the supply is 5.0volt

Start by powering the ACS with a stable 5.0 volt, not just from the USB supply pin of the ESP.
Leo..

1 Like

i was supply the ACS from Hi-Link power supply 220 VAC to 5 VDC, so supply in ACS not from usb pin of the ESP
but result still fluctuative and inaccurate if compare with ampere meter

Why don't you try the ACS712 library

https://docs.espressif.com/projects/esp-idf/en/v4.4/esp32/api-reference/peripherals/adc.html

I've tried it but the results are the same, fluctuating and inaccurate if I compare it with an ampere meter

It will be inaccurate untill you calibrate everything but there should not be any fluctuations if the sensor is wired correctly and you set up your code correctly.
Did you try the ACS712_20_AC_average.ino example?

Yes, I've tried it, but it's still fluctuating with quite a large error
is the current I read too small? When the power is off, my ammeter reads 12mA, and when it's on it's 253mA. whereas in this ACS library program, when the power is off it fluctuates from 0 - 77 mA

Show us a wiring diagram and maybe we can see whats wrong.

C8 1nF, C9 100nF
VCC i can choose 5V or 3V3, but i try 3V3 ACS isn't working so i use 5V
Vout to GPIO 32

Hi, @irwnnyuda

Can you post some images of your project?
So we can see your component layout.

Is your project on a PCB?

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

So you made your own PCB and are not using a ACS712 module, is that correct?
If yes, can you show the board layout?

What is the load?


This is the PCB in my project. the load is a 12V led strip. So at the end there is a 12V 5A power supply which is used to supply the LED, I control the RGBW LED with PWM via the L298 driver, for controlling the RGBW LED there is no problem, the problem is only in the current reading. there are several sensors in it, namely ZMPT, ACS712, LDR, RTC and PIR

Then the ACS712 is the wrong choice. You should be using an INA219/229 etc.
They are designed to work with 3.3volt processors.

Note that PWM current can vary a lot, and must be averaged.
Why a lossy L298 for a LED strip. A single mosfet should be much better there.
Leo..

I use an ACS712 to measure the AC current, so the output will be on the power meter to estimate electricity costs.
isn't INA219/229 for DC current? sorry if my knowledge is lacking.
I use L298 because it needs 4 MOSFETs to control the red, green, blue and white led strip

Yes, the INA is for low voltage measurements.
You could have a good estimate of mains power usage by measuring the LED current.

So you accept the 1-4volt dropout that this ancient H-bridge motor has.
LEDs won't reach max brightness with bjt-based drivers.
Leo..

Hi, @irwnnyuda

Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Can you please links to data/specs of the LED strip.

Your 712 is measuring the AC MAINS current?

Did you design the PCBs?

Thanks.. Tom.. :smiley: :+1: :coffee: :australia: