ACS711 Sensor

Hello,

I have been using the ACS711 hall effect current sensor to measure the current coming out of my battery with an arduino nano MCU. My issue seems to be a hardware issue where my Vout reading has so much noise and fluctuates between 4.01 V and 2.85 V when a load of just the arduino MCU and 15 inactive serial addressable LEDs (WS2812B). What could be causing this?? I am having this issue with 3 other modules of the ACS711.

The same MCU used to measure Vout is powered by the same battery I am looking to calculate the current of.

Here is the schematic of my project attached below:

Schematic_Final base model_2020-10-28_12-38-22.pdf (269.5 KB)

Here is my code :

long readVcc() 
{ long result; 
// Read 1.1V reference against AVcc 
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 
delay(2); // Wait for Vref to settle 
ADCSRA |= _BV(ADSC); // Convert 
while (bit_is_set(ADCSRA,ADSC)); 
result = ADCL; 
result |= ADCH<<8; 
result = 1126400L / result; // Back-calculate AVcc in mV 
return result; 
}

const int analogIn = A0;
int mVperAmp = 136; // from datasheet
int RawValue= 0;
double Voltage = 0;
double avgVoltage = 0;
double Amps = 0;

void setup() 
{ 
  Serial.begin(9600);
}

void loop() 
{ 
//  Serial.println( readVcc(), DEC );
  RawValue = analogRead(analogIn);
  Voltage = (((RawValue / 1023.0) * readVcc()) / 1000) ; // Gets you mV
  avgVoltage = (Voltage / 1.025)- 2.34; // magic 
  Amps = (( avgVoltage/ mVperAmp) * 1000)  ;
  Serial.print("A0 = " ); // shows pre-scaled value 
  Serial.print(RawValue); 
  Serial.print("\t V = "); // shows the voltage measured                                                                
  Serial.print(avgVoltage,2); // the '3' after voltage allows you to display 3 digits after decimal point
  Serial.print("\t Amps = "); // shows the voltage measured 
  Serial.println(Amps,2); // the '3' after voltage allows you to display 3 digits after decimal point
  delay(1000);
}

& this is what my output would look like when applying a load of 1 Ampere:

A0 = 524 V = 0.01 Amps = 0.04
A0 = 524 V = 0.01 Amps = 0.04
A0 = 523 V = 0.00 Amps = 0.01
A0 = 524 V = 0.01 Amps = 0.04
A0 = 523 V = 0.00 Amps = 0.01
A0 = 523 V = 0.00 Amps = 0.01
A0 = 510 V = -0.06 Amps = -0.42
A0 = 443 V = -0.36 Amps = -2.63
A0 = 505 V = -0.08 Amps = -0.59
A0 = 525 V = 0.01 Amps = 0.07
A0 = 474 V = -0.22 Amps = -1.61
A0 = 437 V = -0.38 Amps = -2.82
A0 = 491 V = -0.14 Amps = -1.05
A0 = 454 V = -0.31 Amps = -2.27
A0 = 524 V = 0.01 Amps = 0.04
A0 = 451 V = -0.32 Amps = -2.36
A0 = 460 V = -0.28 Amps = -2.07
A0 = 455 V = -0.31 Amps = -2.30
A0 = 524 V = 0.01 Amps = 0.04
A0 = 450 V = -0.33 Amps = -2.40
A0 = 499 V = -0.11 Amps = -0.78
A0 = 480 V = -0.19 Amps = -1.41
A0 = 467 V = -0.25 Amps = -1.84
A0 = 522 V = -0.00 Amps = -0.03
A0 = 509 V = -0.06 Amps = -0.46
A0 = 479 V = -0.21 Amps = -1.51
A0 = 521 V = -0.01 Amps = -0.06
A0 = 520 V = -0.01 Amps = -0.09
A0 = 440 V = -0.37 Amps = -2.73
A0 = 469 V = -0.24 Amps = -1.77
A0 = 520 V = -0.01 Amps = -0.09
A0 = 440 V = -0.37 Amps = -2.73
A0 = 523 V = 0.00 Amps = 0.01
A0 = 495 V = -0.13 Amps = -0.99
A0 = 448 V = -0.33 Amps = -2.46
A0 = 441 V = -0.37 Amps = -2.69
A0 = 438 V = -0.38 Amps = -2.79
A0 = 525 V = 0.01 Amps = 0.07
A0 = 466 V = -0.25 Amps = -1.87
A0 = 439 V = -0.38 Amps = -2.76

Hello.

We have multiple ACS711 current sensors, but based on the sensitivity you are using, it sounds like you are probably using product #2452 ACS711EX Current Sensor Carrier -15.5A to +15.5A.

What are you using as your 1A load? Could you post scope captures of the output of your ACS711 sensor? Have you tried removing it from the rest of your setup and measuring a simple known load?

By the way, I am not sure how you derived your equations for calculating the amperage and I did not verify if they are correct or not, but we have an equation for calculating the current under the “Using the sensor” section of the product page linked above that might be helpful.

Brandon

Hello,

Yes that is the module I am using, I apologize as I do no have access to an oscilloscope for my output readings. I am using a digital multimeter to verify my work.

I have used the equations mentioned in the “using the sensor” and it immensely improved my results. I am however using 5V as my VCC and I think my sensitivity is causing whatever degree of error shown in my serial monitor here. The formatted code is here:


#include <SD.h>
long readVcc() 
{ long result; 
// Read 1.1V reference against AVcc 
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 
delay(2); // Wait for Vref to settle 
ADCSRA |= _BV(ADSC); // Convert 
while (bit_is_set(ADCSRA,ADSC)); 
result = ADCL; 
result |= ADCH<<8; 
result = 1126400L / result; // Back-calculate AVcc in mV 
return result; 
}
File myFile;
const int analogIn = A1;
int mVperAmp = 136; // from datasheet
int RawValue= 0;
double Voltage = 0;
double avgVoltage = 0;
double Amps = 0;

void setup() 
{ 
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  delay(2000);  //afer reset Arduino, 2s to take out SD

  Serial.print("Initializing SD card...");
  if (!SD.begin(10)) {
    Serial.println("initialization failed!");
  }
  else
  {
    Serial.println("initialization done.");
  }
}

void loop() 
{ 
//  Serial.println( readVcc(), DEC );
  RawValue = analogRead(analogIn);
  Voltage = (((RawValue / 1023.0) * readVcc()) / 1000) ; // Gets you mV
  avgVoltage = (Voltage / 1.025); // magic 
  Amps = (( avgVoltage/ 4.6) * 36.7) -18.05 ;
  Serial.print("A0 = " ); // shows pre-scaled value 
  Serial.print(RawValue); 
  Serial.print("\t V = "); // shows the voltage measured                                                                
  Serial.print(avgVoltage,2); // the '3' after voltage allows you to display 3 digits after decimal point
  Serial.print("\t Amps = "); // shows the voltage measured 
  Serial.println(Amps,2); // the '3' after voltage allows you to display 3 digits after decimal point
  delay(1000);

  write_data(Amps);  //write data
}

void write_data(double amperage_input)
{

  myFile = SD.open("amp.csv", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    myFile.print("The current is: ");
    myFile.println(amperage_input);
    myFile.close();
    //Serial.println("Write file successful!"); //print out COM Port
  } else {
    //Serial.println("error opening test.txt");
  }
}

I find myself altering the 18.3 A value mentioned in the section for each ACS711EX current sensor I use. May you further explain how the equation was derived and what role the sensitivity would play in it so I can implement it into my code??

Thank you,
Ibrahim

The equation (which I have included below for reference) takes VCC into account, so it does not matter if you are using 3.3V or 5V.

i = 36.7*\frac{VOUT}{VCC} - 18.3

I do not understand where your avgVoltage calculation comes from, but that might be causing some error. Also, it looks like you have a function for reading VCC, so you might try using that instead of hard-coding it as 4.6:

Voltage = (RawValue / 1023.0) * readVcc() ; 

 Amps = (36.7 *(Voltage/readVcc())) -18.3 ;

Brandon

So I included the alterations you mentioned and here is my output with no load:

A0 = 512	 V = 2319.765	 Amps = 0.07
A0 = 510	 V = 2310.704	 Amps = -0.00
A0 = 510	 V = 2310.704	 Amps = -0.00
A0 = 511	 V = 2315.235	 Amps = 0.03
A0 = 510	 V = 2301.232	 Amps = -0.08
A0 = 509	 V = 2306.173	 Amps = -0.04
A0 = 511	 V = 2315.235	 Amps = 0.03
A0 = 509	 V = 2306.173	 Amps = -0.04
A0 = 511	 V = 2315.235	 Amps = 0.03
A0 = 511	 V = 2315.235	 Amps = 0.03
A0 = 511	 V = 2315.235	 Amps = 0.03
A0 = 511	 V = 2315.235	 Amps = 0.03
A0 = 510	 V = 2310.704	 Amps = -0.00
A0 = 510	 V = 2310.704	 Amps = -0.00
A0 = 511	 V = 2315.235	 Amps = 0.03
A0 = 511	 V = 2315.235	 Amps = 0.03
A0 = 511	 V = 2315.235	 Amps = 0.03
A0 = 511	 V = 2315.235	 Amps = 0.03
A0 = 510	 V = 2310.704	 Amps = -0.00

At a 1 ampere load with arduino MCU:

A0 = 474	 V = 2165.202	 Amps = -1.23
A0 = 474	 V = 2156.399	 Amps = -1.36
A0 = 471	 V = 2142.751	 Amps = -1.40
A0 = 474	 V = 2165.202	 Amps = -1.23
A0 = 475	 V = 2160.948	 Amps = -1.26
A0 = 471	 V = 2142.751	 Amps = -1.40
A0 = 474	 V = 2156.399	 Amps = -1.30
A0 = 476	 V = 2165.498	 Amps = -1.22
A0 = 476	 V = 2174.338	 Amps = -1.22
A0 = 475	 V = 2160.948	 Amps = -1.26
A0 = 474	 V = 2147.595	 Amps = -1.36
A0 = 473	 V = 2160.635	 Amps = -1.26
A0 = 475	 V = 2160.948	 Amps = -1.26
A0 = 471	 V = 2142.751	 Amps = -1.40
A0 = 474	 V = 2156.399	 Amps = -1.30
A0 = 474	 V = 2165.202	 Amps = -1.23
A0 = 475	 V = 2160.948	 Amps = -1.33
A0 = 474	 V = 2156.399	 Amps = -1.30
A0 = 475	 V = 2160.948	 Amps = -1.26
A0 = 474	 V = 2156.399	 Amps = -1.30
A0 = 474	 V = 2156.399	 Amps = -1.30
A0 = 473	 V = 2151.850	 Amps = -1.33
A0 = 476	 V = 2174.338	 Amps = -1.22
A0 = 474	 V = 2156.399	 Amps = -1.30
A0 = 473	 V = 2151.850	 Amps = -1.33
A0 = 475	 V = 2160.948	 Amps = -1.26

Here is my updated code:

#include <SD.h>
long readVcc() 
{ long result; 
// Read 1.1V reference against AVcc 
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 
delay(2); // Wait for Vref to settle 
ADCSRA |= _BV(ADSC); // Convert 
while (bit_is_set(ADCSRA,ADSC)); 
result = ADCL; 
result |= ADCH<<8; 
result = 1126400L / result; // Back-calculate AVcc in mV 
return result; 
}
File myFile;
const int analogIn = A1;
int mVperAmp = 136; // from datasheet
int RawValue= 0;
double Voltage = 0;
float Vcc;
double Amps = 0;

void setup() 
{ 
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  delay(2000);  //afer reset Arduino, 2s to take out SD

  Serial.print("Initializing SD card...");
  if (!SD.begin(10)) {
    Serial.println("initialization failed!");
  }
  else
  {
    Serial.println("initialization done.");
  }
}

void loop() 
{ 
//  Serial.println( readVcc(), DEC );
  RawValue = analogRead(analogIn);
  Voltage = (((RawValue / 1023.0) * readVcc())) ; // Gets you mV
  Amps = (( Voltage/ readVcc()) * 36.7) -18.3 ;
  Serial.print("A0 = " ); // shows pre-scaled value 
  Serial.print(RawValue); 
  Serial.print("\t V = "); // shows the voltage measured                                                                
  Serial.print(Voltage,3); // the '3' after voltage allows you to display 3 digits after decimal point
  Serial.print("\t Amps = "); // shows the voltage measured 
  Serial.println(Amps,2); // the '3' after voltage allows you to display 3 digits after decimal point
  delay(1000);

  write_data(Amps);  //write data
}

void write_data(double amperage_input)
{

  myFile = SD.open("amp.csv", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    myFile.print("The current is: ");
    myFile.println(amperage_input);
    myFile.close();
    //Serial.println("Write file successful!"); //print out COM Port
  } else {
    //Serial.println("error opening test.txt");
  }
}

Can I get more accuracy from the sensor and eliminate the noise seen in my values???

What are you using as your 1A load? How do you know it is only 1A, and how steady do you expect it to be? Are you measuring it with a multimeter to see what the draw actually is? You can get less noise in your measurements at the cost of response time by taking multiple measurements and averaging them together.

Brandon

Hello Brandon,

I am using a USB dummy load: https://www.amazon.ca/DROK-Detector-Electronic-Discharge-Resistance/dp/B00KLZHCEQ

It draws around 0.8 to 1.2 A depending on the power lost to heat. I was looking to take an average of my voltage, you however advised me against that, should I be taking an average of the Raw voltage, output voltage, VCC, or final current readings??

Best regards,
Ibrahim

Thank you for the additional information about your load.

I think you misunderstood what I was advising before; your avgVoltage variable before looked like it was just taking the voltage reading and dividing it by 1.025, instead of actually taking an average of multiple readings. It is probably best to average the raw readings, to save some overhead on computing the conversion to volts multiple times.

Brandon

Hello Brandon,

I have implemented what you suggested although I must admit that as I load the device, the readings are still off by 0.2 - 0.4A greater than the actual reading read by the multimeter.

Here is the code:

#include <SD.h>
long readVcc() 
{ long result; 
// Read 1.1V reference against AVcc 
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 
delay(2); // Wait for Vref to settle 
ADCSRA |= _BV(ADSC); // Convert 
while (bit_is_set(ADCSRA,ADSC)); 
result = ADCL; 
result |= ADCH<<8; 
result = 1126400L / result; // Back-calculate AVcc in mV 
return result; 
}
File myFile;
const int analogIn = A0;
int mVperAmp = 136; // from datasheet
int RawValue= 0;
double Voltage = 0;
float Vcc;
double Amps = 0;

const int numReadings = 10;
double readings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
int total = 0;                  // the running total
double average = 0;                // the average

void setup() 
{ 
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  delay(2000);  //afer reset Arduino, 2s to take out SD

  Serial.print("Initializing SD card...");
  if (!SD.begin(10)) {
    Serial.println("initialization failed!");
  }
  else
  {
    Serial.println("initialization done.");
  }
   for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}

void loop() 
{ 
  // subtract the last reading:
  total = total - readings[readIndex];
  // read from the sensor:
  readings[readIndex] = analogRead(analogIn);
  // add the reading to the total:
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;
 
  // if we're at the end of the array...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
 
  // calculate the average:
  average = total / numReadings;
//  Serial.println( readVcc(), DEC );
  RawValue = analogRead(analogIn);
  Voltage = (((average / 1023.0) * readVcc())) ; // Gets you mV
  Amps = (( Voltage/ readVcc()) * 36.7) -18.3 ;
//  RawValue = analogRead(analogIn);
//  Voltage = (((RawValue / 1023.0) * readVcc())) ; // Gets you mV
//  Amps = (( Voltage/ readVcc()) * 36.7) -18.3 ;
  Serial.print("A0 = " ); // shows pre-scaled value 
  Serial.print(RawValue); 
  Serial.print("\t V = "); // shows the voltage measured                                                                
  Serial.print(Voltage,3); // the '3' after voltage allows you to display 3 digits after decimal point
  Serial.print("\t Amps = "); // shows the voltage measured 
  Serial.println(Amps,2); // the '3' after voltage allows you to display 3 digits after decimal point
  delay(1000);

}

I have noticed that my Vout reading on my arduino is also off by around 0.1 V from the reading on digital multimeter. There are also some random spikes in current. Is there anything else I can do to help diagnose the problem?? Could my microcontroller’s ADC be the issue??

Thank you,
Ibrahim

Before trying to troubleshoot the random spikes you are seeing, are you sure they are not accurate and your system is just drawing current in bursts that your multimeter isn’t catching? Usually multimeters do a fair amount of processing and do not register spikes well when measuring in a continuous mode. Are you still using the same USB dummy load? A purely resistive load might be a better test since it should be fairly constant.

You might try performing an ADC reading on the internal GND channel in order to clear any voltage that might be leftover on the ADC from the previous measurement. (There are also other approaches that do about the same thing, such as taking multiple readings and discarding the first one.)

Brandon