Reading incorrect DC current from Allegro ACS712 20A

Hello everyone and thank you for viewing my very first post.

I am attempting to implement the ACS712 to read the current coming out of my power supply. My voltage conversion is very close to that read with the multimeter so I assume my problem is in the current calculation. Below are the two codes I have tried. Both are formed mostly from code I found in this forum or elsewhere on the internet and the current scale of 100mA/V is taken from the datasheet attached.

The moving average is the most stable. It returns a steady 2.38V compared to the measured 2.356V from the multimeter. However, the measured current is 2.56A but the code returns a steady bounce between 1.18 and 1.22A. this is where I'm lost.

const int numReadings = 50;

int readings[numReadings];
int i = 0;
int total = 0;
int average = 0;

void setup() {
 
  Serial.begin(9600);
  pinMode(23, INPUT);
  for (int j = 0; j < numReadings; j++)
    readings[j] = 0;
}
 
void loop() {
  
    // subtract the last reading:
  total = total - readings[i];         
  // read from the sensor:  
  readings[i] = analogRead(23); 
  // add the reading to the total:
  total = total + readings[i];       
  // advance to the next position in the array:  
  i++;                    
  // if we're at the end of the array...
  if (i >= numReadings)              
    // ...wrap around to the beginning: 
    i = 0;                           
  // calculate the average:
  average = total / numReadings;         
  
  float voltage = (3.3*average)/1024;
  float current = abs((voltage - 2.5)/0.1);
  delay(300);
  Serial.print("average: ");
  Serial.println(average);
  Serial.print("voltage: ");
  Serial.println(voltage);
  Serial.print("current: ");  
  Serial.println(current);  
}

The weighted average works terribly and I can't figure out why. I assume it's something simple and I just need a fresh pair of eyes to see it. The formula came from this website:

http://www.tigoe.com/pcomp/code/arduinowiring/37/

The voltage, again, comes in about right (around 2.35V with some bouncing) but my current reading is now jumping from 7A to 15A and everything in between. Very strange when considering the current calculation is the same for both scripts.

const float weight = 0.95;
float lastEstimate = 0;


void setup() { 
  Serial.begin(9600);
}
 
void loop() {
  int input = analogRead(23);
  float voltage = input*3.3/1024.0;
  float currentEstimate = (weight*voltage) + (1.0 - weight)*lastEstimate;
  float current = abs((currentEstimate - 2.5)/0.01);
  Serial.print("input: ");
  Serial.println(input);
  Serial.print("voltage: ");
  Serial.println(voltage);
  Serial.print("current: ");  
  Serial.println(current);  
  lastEstimate = currentEstimate;
  delay(300);
}

I also attached the sensor schematic. I have a 2.2nF in place of the 1nF because I ran out and added a 4.7nF smoothing cap between A9 and GND.

I think I included all the necessary information, let me know if there's anything else I can provide. Thanks in advance!

ACS712-Datasheet.pdf (643 KB)

First, just so we are all straight, the sensitivity according to the datasheet is 100mV/A, not 100mA/V (assuming you have the +/-20A ACS712).

Your calculation for the current is correct, C = (V - 2.5)/(0.1V/A). For the steady 2.38V your code reported, the current is therefore -1.2A. Why do you think it should be 2.56A? Is this what you are measuring with your multimeter?

Also, the reason your current reading is bouncing around so much is because the current calculation divides the average voltage by a small number less than 1 (in this case 0.1). This division makes the current very sensitive to even small changes in average voltage. You should really apply the moving average to the current, not the voltage. Doing so will make sure the current reading is nice and smooth.

In your second piece of code, you have a small typo in your current calculation. If you look at where the current is calculated, you will see that you've accidentally divided by 0.01 instead of 0.1.

The first program has been around for a long time, but has a couple of very bad bugs. The average values from the first few readings (until the array index i reaches numReadings-1) are incorrectly calculated, because of the following line:

  average = total / numReadings;

As a result you should see the reported values vary substantially, until at least numReadings have been gathered. One fix would be to have the program wait until numReadings have been collected, before calculating and reporting averages.

Also, an int cannot contain a positive number larger than 32767, so 50 readings of about 600 or more will overflow the accumulation of "total". Reduce numReadings to about 20 to avoid this problem, or declare total to be a long integer.

You should never assume that a program you have downloaded works correctly, as very many of them don't.

Finally, rather than subtracting 2.5 V for the zero current offset, you should determine the ADC value that corresponds to zero current passing through the sensor, and subtract that number from the ADC reading.