ACS712-30 Problem

Hello Guys!

I ran into problems with ACS712-30A sensor... i bought it soldered on PCB with pre-assembled filter capacitator.
With no load across the sensor i'm getting this:

0.07 - Value in Amps
512 - ADC value from pin where sensor is connected
0.07
512
-0.00
513
-0.00
513
0.07
512
-0.00
512
-0.00
512
0.07
513
-0.00

it allways fluctuating like that, when i connect another sensor it fluctuate again, but with different values.
I'm using MEGA 2560 with this code:

//------------------------------------------------------------------------------------------------------
////////////////// READS AND AVERAGES THE ANALOG INPUTS (SOLRAR VOLTAGE,BATTERY VOLTAGE)////////////////
//------------------------------------------------------------------------------------------------------
int read_adc(int adc_parameter)
{

int sum = 0;
int sample ;
for (int i=0; i<AVG_NUM; i++)
{ // loop through reading raw adc values AVG_NUM number of times
sample = analogRead(adc_parameter); // read the input pin
sum += sample; // store sum for averaging
delayMicroseconds(50); // pauses for 50 microseconds
}
return(sum / AVG_NUM); // divide sum by AVG_NUM to get average and return it
}

//-------------------------------------------------------------------------------------------------------------
////////////////////////////////////READ THE DATA//////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------------------
void read_data(void)
{

charge_current = (read_adc(CURRENT_ADC)*.07402 -37.90);
Serial.println(charge_current);
Serial.println(read_adc(CURRENT_ADC));
delay(100);

Those are the parts of the code for reading, averaging and printing sensor values...

Regards!

I don't see the fluctuation, I see only the raw values of 512 and 513, that seems normal.

You posted only a small part of the sketch, so I have no idea what that is doing or if it is okay.

Hi!

Those are the values which represents amps, i copied this from serial console, i expect to be 0.00 when there is no current across the sensor? so i don't know why i'm getting those readings bellow.

0.07 A
0.07 A
-0.00 A
-0.00 A
0.07 A
-0.00 A
-0.00 A
0.07 A
-0.00 A

I pasted the most important part of my code, it needs to read, average and print in serial console readings from ACS sensor...

Best Regards!

You code raises questions: If AVG_NUM is too large, you get integer overflow; I'm not sure about the integer to float in the calculation.
You throw away the extra bits created by the averaging. When you would use that extra in the float calculation, you get more accuracy and perhaps also a more stable value.

Did you buy a module or the ACS712 chip ? The copper traces for the high current is almost rocket science. It is not easy to use the ACS712 chip with 30A and have an accurate result.

That is a 30A sensor. So a little jitter between 0.00 and 0.07 is almost nothing. That is 0.2%.

What are the raw values without averaging ? Do you have a lot of noise ?
When the sensor is near your computer or other electric device, it will get extra noise.

Peter_n:
You code raises questions: If AVG_NUM is too large, you get integer overflow; I'm not sure about the integer to float in the calculation.

I copied this code from instructables, my programming skills are weak... :smiley: do you have any idea what i need to change in code?

That is a 30A sensor. So a little jitter between 0.00 and 0.07 is almost nothing. That is 0.2%.

Ok, but why i'm getting negative number?

What are the raw values without averaging ? Do you have a lot of noise ?
When the sensor is near your computer or other electric device, it will get extra noise.

Didn't tested without averaging, i will give it a try now, hmm there is nothing near sensor, expect laptop, i tried to change the location of the sensor, but nothing happens...

Regards!

Okay, that might be the normal noise of the sensor itself.

The Arduino analogRead() returns a value of 0...1023 for a voltage of 0...5V.
The ACS712 has an output of 2.5V, because it can measure the current in both directions.

When the current is in one direction, the 2.5V is going up, and with current in the other direction, the 2.5V is going down. The caculation translates the 2.5V in 0 amps. So with a little noise, you can get negative values.

You are now using code with some "magical" number in it for the calculation. I prefer that you understand the code, so you can make changes to it when needed.
I prefer to calculate the voltage at the analog pin, and after that calculate the current. The ACS712 has a certain mV per A. That would fit nicely into a calculation.

I used this code to calculate current across the sensor:

Sensitivity is =66mV / A =0.066V/A

No test current through the output voltage is VCC / 2= 5/2=2.5

ADC count= (1024/5)* Vin

Vin=2.5+0.066*I (where I=current )

ADC count= 204.8(2.5+0.066I) =512+13.51I

=> 13.51*I = (ADC count-512)

=> I =(ADC count/13.51)- 512/13.51

Current (I) =0.07402*ADC -37.89

Is this correct?

dejanb:
it allways fluctuating like that, when i connect another sensor it fluctuate again, but with different values.

Yes, its a real device with noise. Fluctuating by only 1 LSB is actually very good for
a hall-sensor like this, since they are very noisy sensors in general.

If you have a 30A full-scale sensor you should expect at least 0.1A error, and more than
that in trimmable offset.

Reading the datasheet you'll see graphs explaining the fundamental limits to accuracy
in the device. Typically you need to calibrate each sensor's offset value and use
a low-pass anti-aliasing filter before sampling (or sample at a high rate and digitally
filter) to get good low-noise output at limited bandwidth.

If you want high bandwidth output then you have the noise, its fundamental.

If you intend to integrate the readings to keep track of total charge flowed then the
noise is irrelevant since integration will cancel it out leaving just signal (and offset
error).

Ok, thanks for clarification, i think that i will buy 100A shunt from ebay and go to try with it

Best Regards!

In very simple terms the minimum possible measured resolution is 1/512.

Note that the sensor measures +/- 30 amps so the full ADC span of 1024 bits actually covers -30 to +30 (60) amps

30 x 1 / 512 = 0.06 so getting a reading of 70 mA roughly equates to 1bit which may be expected if there is any signal noise

Many tears ago, as instrument engineers we used analogue instruments to measure variables and it was considered pretty good if you could read better than 1 or 2%. With a variable range of 0-10,000 this represented an acceptable resolution of +/- 100 units. Then along came digital instruments and suddenly operators expected displays to read absolute values within 1 digit ---- a physical impossibility if the variable was say 0-10,000

So, when you pump an analogue value into a digital system you must always consider resolution capability of the ADC and add onto that any measurement error including noise, drift etc etc

dejanb, so the magic numbers are not magic for you :slight_smile:
I prefer to do that calculation in the sketch itself, so everyone can see how it is calculated.
If you would see your own sketch again in a year, it would be nice to see in a glance what the sketch is doing.

Should I help with code for avaraging and float calculations, or are you going into a different direction with the shunt ?

Peter_n:
dejanb, so the magic numbers are not magic for you :slight_smile:
I prefer to do that calculation in the sketch itself, so everyone can see how it is calculated.
If you would see your own sketch again in a year, it would be nice to see in a glance what the sketch is doing.

Should I help with code for avaraging and float calculations, or are you going into a different direction with the shunt ?

Hello!

Help please! :slight_smile: let's try it again with ACS sensor, every sketch i tried didn't performed well, maybe it is because of my limited knowledge in this matter...

Regards!

Did you tell which board you have ?
I hope you have an Arduino Uno or Leonardo or something like that. In the sketch I assume that the ADC is 10-bits and the board runs at 5V.

I would like to return a voltage as float and keep the extra information that was gained by averaging.

// Read voltage from a certain analog pin.
// AVG_NUM can be up to 60, more does not fit into a unsigned integer.
#define AVG_NUM 20
float read_volt(int pin)
{
  unsigned int total = 0;               // start with zero, this is used for the total value.
  for (int i=0; i<AVG_NUM; i++) // loop through reading raw adc values AVG_NUM number of times 
  {                                                
    total += analogRead(pin);       // read the input pin 

    // The delay is arbitrary. 
    // It can be 0 to 20ms. 
    // Test for your own circuit what is best.
    delayMicroseconds(50);              // pauses for 50 microseconds 
  }
  // The voltage is raw_adc / 1023 * 5V and also divided by the amount of samples for average.
  // Convert every integer to float before calculating something.
  // This way, the extra bits gained by averaging are used in the calculation.
  float volt = (float) total / 1023.0 * 5.0 / (float) AVG_NUM;
  return(volt);
}

Converting the current can be done in the loop()
I prefer to explain every number and let the compiler or Arduino do the calculation.

const int currentPin = A0;

  // The ASC712-30 has 66mV/A
  // That is 1 amp for every 0.066V.
  // The middle of 2.5V is zero amps.
  float voltage = read_volt (currentPin);
  float amps = (voltage - 2.5) / 0.066;

My ACS712 is soldered in a circuit, so I tested it without that.
I don't know if my calculation is right, you have to check that.
Can you also check with a multimeter what the actual current is and if that matches the Arduino output ?

This is a full test sketch with A0 as analog input:

// Tested with Arduino 1.5.8 without ACS712-30

const int currentPin = A0;

void setup()			  
{
  Serial.begin(9600);
  Serial.println(F("Current Sketch"));
}

void loop()			  
{
  // The ASC712-30 has 66mV/A
  // That is 1 amp for every 0.066V.
  // The middle of 2.5V is zero amps.
  float voltage = read_volt (currentPin);
  float amps = (voltage - 2.5) / 0.066;

  Serial.println( amps);
  delay(500);
}


// Read voltage from a certain analog pin.
// AVG_NUM can be up to 60, more does not fit into a unsigned integer.
#define AVG_NUM 20
float read_volt(int pin)
{
  unsigned int total = 0;         // start with zero, this is used for the total value.
  for (int i=0; i<AVG_NUM; i++)   // loop through reading raw adc values AVG_NUM number of times 
  {                                                
    total += analogRead(pin);     // read the input pin 

    // The delay is arbitrary. 
    // It can be 0 to 20ms. 
    // Test for your own circuit what is best.
    delayMicroseconds(50);        // pauses for 50 microseconds 
  }
  // The voltage is raw_adc / 1023 * 5V and also divided by the amount of samples for average.
  // Convert every integer to float before calculating something.
  // This way, the extra bits gained by averaging are used in the calculation.
  float volt = (float) total / 1023.0 * 5.0 / (float) AVG_NUM;
  return(volt);
}

Try to increase the number of samples for the average to 5 or 60, and try to change that delay. It might not change anything, and sometimes it does help a little.

Hi'

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png or pdf?

Tom.... :slight_smile:

Peter_n:
Did you tell which board you have ?
I hope you have an Arduino Uno or Leonardo or something like that. In the sketch I assume that the ADC is 10-bits and the board runs at 5V.

I would like to return a voltage as float and keep the extra information that was gained by averaging.

// Read voltage from a certain analog pin.

// AVG_NUM can be up to 60, more does not fit into a unsigned integer.
#define AVG_NUM 20
float read_volt(int pin)
{
  unsigned int total = 0;              // start with zero, this is used for the total value.
  for (int i=0; i<AVG_NUM; i++) // loop through reading raw adc values AVG_NUM number of times
  {                                               
    total += analogRead(pin);      // read the input pin

// The delay is arbitrary.
    // It can be 0 to 20ms.
    // Test for your own circuit what is best.
    delayMicroseconds(50);              // pauses for 50 microseconds
  }
  // The voltage is raw_adc / 1023 * 5V and also divided by the amount of samples for average.
  // Convert every integer to float before calculating something.
  // This way, the extra bits gained by averaging are used in the calculation.
  float volt = (float) total / 1023.0 * 5.0 / (float) AVG_NUM;
  return(volt);
}




Converting the current can be done in the loop()
I prefer to explain every number and let the compiler or Arduino do the calculation.



const int currentPin = A0;

// The ASC712-30 has 66mV/A
  // That is 1 amp for every 0.066V.
  // The middle of 2.5V is zero amps.
  float voltage = read_volt (currentPin);
  float amps = (voltage - 2.5) / 0.066;




My ACS712 is soldered in a circuit, so I tested it without that.
I don't know if my calculation is right, you have to check that.
Can you also check with a multimeter what the actual current is and if that matches the Arduino output ?

This is a full test sketch with A0 as analog input:


// Tested with Arduino 1.5.8 without ACS712-30

const int currentPin = A0;

void setup()  
{
  Serial.begin(9600);
  Serial.println(F("Current Sketch"));
}

void loop()  
{
  // The ASC712-30 has 66mV/A
  // That is 1 amp for every 0.066V.
  // The middle of 2.5V is zero amps.
  float voltage = read_volt (currentPin);
  float amps = (voltage - 2.5) / 0.066;

Serial.println( amps);
  delay(500);
}

// Read voltage from a certain analog pin.
// AVG_NUM can be up to 60, more does not fit into a unsigned integer.
#define AVG_NUM 20
float read_volt(int pin)
{
  unsigned int total = 0;        // start with zero, this is used for the total value.
  for (int i=0; i<AVG_NUM; i++)  // loop through reading raw adc values AVG_NUM number of times
  {                                               
    total += analogRead(pin);    // read the input pin

// The delay is arbitrary.
    // It can be 0 to 20ms.
    // Test for your own circuit what is best.
    delayMicroseconds(50);        // pauses for 50 microseconds
  }
  // The voltage is raw_adc / 1023 * 5V and also divided by the amount of samples for average.
  // Convert every integer to float before calculating something.
  // This way, the extra bits gained by averaging are used in the calculation.
  float volt = (float) total / 1023.0 * 5.0 / (float) AVG_NUM;
  return(volt);
}




Try to increase the number of samples for the average to 5 or 60, and try to change that delay. It might not change anything, and sometimes it does help a little.

Hello

Thank You for the help and for a such comprehensive explanation!
I have Mega 2560 board. Tried your code and it works very well i increased AVG_NUM so the results are much steadier to read, without load i'm getting this:

0.08
0.10
0.10
0.10
0.08
0.09
0.08
0.08
0.10
0.09
0.09
0.11
0.10
0.10
0.09

I connected load of 100ma and tested with arduino, it matches almost identicaly as my digital multimeter!
Tomorow i will try some larger loads like 5-10A so i will see how it stands...

Best Regards!

Cool 8)
Since the average is 0.09A, the 2.5V seems te be not exactly in the middle. Perhaps it should be 2.506 V.

P.S.: You don't have to quote my post, it is already there. You can use the "Reply" button or the "Quick Reply" field.

Hello!

Sorry for delay, i had too much job, as always.... ::slight_smile:
I tried with higher current this evening, i attached 5A and 7A light bulbs, everything seems to be very good, i compared my DMM readings to ACS sensor readings, they re allmost identical...

Two more things:

Between arduino 5v and gnd there is 4.66V instead 5V, and withoud load, on the sensor out pin i measure 2.344V instead 2.5 V or similar....
What do you think of this?

Regards!

The ACS712 is a neat little chip but as you discovered it has its draw backs.
It might allready have been mentioned but you can increase the filter capacitance of the ACS712.
That will reduce the jitter but increase the rise time.

I got fairly good results with a 0.1µF capacitor (on pin 6), the circuit responts still fast enough within a fraction of a second and the jitter is recused to one bit resolition of the internal arduino resolution.
That way there is no need for software averaging.
The rise time will increase to about 300µS, that still is just 0,3 milliseconds.

As far as i know the chinese boards of ebay use all a 10nF filter capacitor.

The bad thing about this chip is, the output voltage is referenced to the supply voltage.
That means if you use the internal arduino voltage reference for the ADC that will increase the error quite a bit.
You have use the supply voltage of the arduino as the reference voltage.

Greetings,
Peter

dejanb:
Between arduino 5v and gnd there is 4.66V instead 5V, and withoud load, on the sensor out pin i measure 2.344V instead 2.5 V or similar....
What do you think of this?

That is not unusual and no problem, as long as you use the same "5V" as the reference for the ADC and arduino supply.
The output of the ACS712 will allways be "VCC dividet by 2".

Oif you measure VCC at 4,66 V you get:
4,66 / 2 = 2,33 V

And you measured the ACS712 outut at 2.34V, that is spot on as far as precision goes for this setup.

Hello friends!

Thanks for the help and explanation, i will try to change filter capacitator to see results!

Regards!