Introduction: Arduino - Voltage and Current Measurement ACS712, ADS1015
How to make a circuit for voltage and current measurement using Arduino and ACS712, ADS1015. The ADS1015 is a 12-bit analog-to-digital converter. Equipped with i2c bus and 4 channels A0-4. What is very important is also have "Internal Low-Drift Voltage Reference", which significantly simplifies the construction of precision measuring systems. ACS712 is the circuit for measuring the current using a hall effect. My version measures current from -30A to 30A.
This article can also see here:
Step 1: Components
Step 2: Schematic
For testing I used a bulb in the diagram shown as R9. I used resistors R7 and R8 to make the voltage divider.
Step 3: Software
The following piece of code is responsible for the measurement at the 4 inputs of the ADC. The value "NUMBR_OF_SAMPLES" specifies the number of samples, in this case it is 20. After sampling, the average value of the measurements is calculated.
int16_t adc0, adc1, adc2, adc3; float avg0 = 0.0f; float avg1 = 0.0f; float avg2 = 0.0f; float avg3 = 0.0f; for(int i=0; i<NUMBR_OF_SAMPLES; i++){ adc0 = ads.readADC_SingleEnded(0); adc1 = ads.readADC_SingleEnded(1); adc2 = ads.readADC_SingleEnded(2); adc3 = ads.readADC_SingleEnded(3); avg0 += adc0; avg1 += adc1; avg2 += adc2; avg3 += adc3; delay( 10 ); } avg0 = avg0/(float)(NUMBR_OF_SAMPLES); avg1 = avg1/(float)(NUMBR_OF_SAMPLES); avg2 = avg2/(float)(NUMBR_OF_SAMPLES); avg3 = avg3/(float)(NUMBR_OF_SAMPLES);To calculate the voltage at ADS1015 inputs, you need to multiply the average value of the measurement by 3mV( 3.0f/1000.0f ).
Because at the AIN0 input I have a voltage divider, so I have to multiply it by 10.
Resistors are not perfect, that's why I multiply everything by 1.0805f.
float voltage0 = DIVISOR0 * (avg0 * 3.0f/1000.0f); float voltage1 = DIVISOR1 * (avg1 * 3.0f/1000.0f); float voltage2 = DIVISOR2 * (avg2 * 3.0f/1000.0f);To accurately calculate the current I have to measure the ACS712 power supply voltage. In the test, the whole
circuit is powered by USB, which is approximately 5V. In my case the voltage was 4.72V. This difference
is significant when measuring accurately.
float w = ( voltage2/5.0f ) * 0.066f; float i_cur = ((voltage2 / 2.0f) - voltage1) / w;To calculate power we multiply the voltage and current by itself.
float power = voltage0 * i_cur;Download source code: Arduino-voltage-and-current.ino
5 Comments
Question 3 years ago
Thanks for the design. I have hard time reading the text in the
schematic. Can you possible increase the resolution?
5 years ago
I know this is just a breadboard, proof-of-concept Instructable, but does the ADS1015 buy you anything? The arduino analog pins have 10-bit precision, so you can read down to around 0.05V and 0.06A. And you can increase the voltage precision by changing the voltage divider.
Reply 5 years ago
Thanks for the comment, that's a good question. The advantages of "ADS1015" are: 12-Bit Noise-Free Resolution, Internal Low-Drift Voltage Reference, I2C Bus, Wide Supply Range: 2.0 V to 5.5 V, Increase the number of pins.
Reply 5 years ago
A few things were puzzling me about this, and I think you have done a good job in this implementation and I have learned a few things from it. The main point is that the sensitivity is scaled by the ratio of Vcc to 5 volts. It is covered in the ACS712 datasheet under the heading "Ratiometry" which I had never checked before.
This means it is imperative, if you want accurate results, to measure Vcc and use it to scale not only the 0 current voltage, but also the sensitivity - which you have done. The implementations I have seen before did not do that.
It also means that if you are using the Arduino analog inputs, you still need to measure Vcc. You don't need it for the 0 current voltage adjustment, because the Arduino ADC is itself scaled to its own Vcc, and if the ACS712 and the Arduino share the same Vcc rail, they are automatically synchronised and the 0 current measurement will always be 512 (ie half of the full scale reading of 1024). However, because the sensitivity also needs to be scaled, it is necessary to measure Vcc to apply the correct sensitivity scaling.
To do this accurately requires the use of the Arduino 1V reference, and a voltage divider to bring the measured value within range.
As to the relative benefit of using the ADS1015 versus the Arduino, the least significant bit voltage on the Arduino is 4.88 mv (=5000/1024) which translates to 74mA. The ADS1015 is 3mV which translates to 45 mA. So it is not all that much better. But with the ADS1015 you also have the option of changing the scaling to 2mV/lsb which gives better accuracy of 30mA, and which can still just cover the full +-30 range of the ACS712. Yet another option with the ACS1015 is to use another input (I thiink it should be AIN3) set to Vcc/2 using a resistive divider, and do differential measurements between that and the ACS712. With that the sensitivity can be further increased to 1mV/lsb and 15mA, still without loss of the full +- 30A range., because it now exploits the full 12 bits of the ADC in hte ACS1015.
5 years ago
The circuit diagram shows you are using a voltage divider of 47 K to the measurement point, and 4K7 to ground below the ADC input, giving a nominal division ratio of 11 - quite close to your 10.805 factor. Did you get the 10.805 by calculation from measuring the resistors, or by observing the results compared to the mulimeter?
I would be interested to know how well the two track over the full voltage range.
The full scale range of the ADS1050 can be set to a variety of different values. The default setting is +-2.024 V according to the data sheet. Yet you have successfully measured the 5V rail (as 4.4V) so presumably the ADAFRUIT library changes the gain setting from the default to +-6.144 V. Is that correct? I could not see anything that changed that in your software, and the 6.144 gain setting is consistent with the 3mV per lsb that you are using.
All this means that your resolution is 33 mV per bit, although making 20 readings and averaging them gives you a fractional bit capability, maybe.