Measure AC & DC Currents with Arduino and ACS758 Sensor

This post shows how to measure AC & DC currents using Arduino uno board and ACS758 hall effect current sensor with Ture RMS/average calculations.
A 1602 LCD connected to the Arduino board is used to display current values, the Arduino also sends the same values to the Laptop which can be viewed using serial monitor.
A pushbutton connected to the Arduino board is used to choose between AC and DC currents.

Hints:
No warranty is provided with this project, so do it at your own risk!
A part of project circuit may be subjected to high voltage which is very harmful to human body, so be-careful!

Abbreviations:
AC: Alternating Current
DC: Direct Current
TRMS: True Root Mean Square
ADC: Analog-to-Digital Converter
CT: Current Transformer
LDO Regulator: Low Dropout Regulator
PCB: Printed Circuit Board
DIY: Do It Yourself

Interfacing Arduino with ACS758 ACS770 AC/DC current sensor hardware circuit

About ACS758 current sensor:
The ACS758 family from Allegro™ is an integrated circuit (IC) which is specifically designed for current measurement with frequency upto 120kHz. It’s a hall-effect-based current sensor with 100µΩ current conductor. This device generates a voltage that is proportional to the current passing through it where the generated voltage is galvanically isolated from the passing current. This means at all times, high power circuit is isolated from low power circuit.

The ACS758 family consists of many versions with different current ratings: 50A, 100A, 150A and 200A. Some versions are bidirectional sensors and the others are unidirectional. Bidirectional means that the sensor can be used to measure current flow in both directions, they are most used with AC loads (it may be used also with DC loads). Unidirectional means the sensor can sense current flow in one direction only, this type is suitable for DC loads.

In this project I’m going to use bidirectional sensor with rated DC current of 200A, its full name is: ACS758ECB-200B. Since this device is bidirectional, it allows us to measure AC and DC currents with typical sensitivity of 10mV/A.
However, other ACS758 versions may also be used in this project, such as ACS758ECB-50B which has a typical sensitivity of 40mV/A.
ACS770 is a newer version of hall-effect based current sensors, it’s recommended by the manufacturer to use it instead of the ACS758!

When the ACS758ECB-200B is powered by single supply source with 5V and when the primary current is zero, then the output of the device is 2.5V (it’s just VCC/2), this voltage called: quiescent output voltage ( VIOUT(Q) ).
When a dual supply is used with ±2.5V the quiescent output voltage should be zero with respect to circuit ground.
With a supply of 5V (single or dual) the typical device sensitivity is 10mV/A. The sensitivity as defined in device datasheet is the change in device output in response to a 1 A change through the primary conductor. For example when a single supply is used and with primary current of 5 Amps then the device output is: VIOUT(Q) + 5 x 10mV = 2.5 + 0.05 = 2.550V.

Measure AC & DC currents with Arduino and ACS758 sensor circuit:
Project circuit diagram is shown below (click on the image for better view).

Arduino ACS758 AC/DC current measurement circuit ACS770

Note that in the circuit there is 1 ground only which is the same as Arduino board ground (GND).
The Arduino uno board is represented by U8.
For circuit resistors, a low tolerance resistors should be used, let’s say 1% or lower, lower tolerance yields better accuracy!

As shown in circuit schematic, the ACS758 current sensor is connected between the AC/DC source and the load. Instead of the ACS758 other similar devices may also be used, for example ACS770.
The voltage source may be AC or DC according to the connected load.

Hardware required:
This is a summary of circuit required parts (circuit schematic diagram may contain some component parameters not mentioned below).

  • Arduino Uno or equivalent board such as Arduino Nano
  • ACS758 Hall-effect current sensor (U1)   —> details
  • 2 x OPA2191 op amp (U2, U7)   —> details
  • MCP1501-20 buffered voltage reference (U9)   —> details
  • TS5A23166 dual analog switch (U6)   —> details
  • LT1761-SD LDO regulator (U5)   —> details
  • LT1964-SD LDO negative regulator (U4)   —> details
  • B0505S-2W isolated DC-DC converter (U3)
  • 1602 LCD screen
  • 4 x 1N4184 diode (D1, D2, D3, D4)
  • 180k resistor (R8)
  • 3 x 20k resistor (R9, R16, R17)
  • 2 x 18k resistor (R2, R10)
  • 2 x 16k resistor (R5, R6)
  • 4 x 15k resistor (R3, R4, R11, R13)
  • 2 x 12k resistor (R5, R6)
  • 4 x 10k resistor (R15, R19, R20, R21)
  • 330 Ohm resistor (R24)
  • 3 x 100 Ohm resistor (R1, R7, R18)
  • 10 Ohm resistor (R22)
  • 10k variable resistor (R23)
  • 5 x 10 µF capacitor (C5, C8, C9, C14, C15)
  • 2 x 2.2 µF capacitor (C18, C19)
  • 10 x 0.1 µF capacitor (C1, C2, C4, C6, C7, C10, C11, C12, C13, C17)
  • 2 x 10 nF capacitor (C3, C16)
  • Pushbutton (S1)
  • Breadboard
  • Jumper wires

Circuit description:
The ACS758 current sensor is noted in the circuit schematic above as U1. It is supplied with bipolar source of ±2.5V. I used a bipolar power supply in order to easily amplify the ACS758 sensor output signal using operational amplifier circuit U2.

At rated current of +200A the voltage output of the ACS758 sensor is +2V and at current of -200A the output voltage is -2V (always with respect to circuit GND).

The output of the ACS758 is connected to a RC filter (R1 and C3) which removes any high frequency noise and then connected to OPA2191 operational amplifier U2.
The OPA2191 from Texas Instruments contains 2 independent op amps in one package. The first op amp is used as a voltage follower in order to properly buffer the ACS758 sensor output voltage.

The output of the voltage follower is connected to another op amp circuit which mainly consists of the second op amp of OPA2191 U2. This amplifier circuit has variable gain that can be digitally controlled by the Arduino board, the available gains are: 10, 1 and 0.5.
The Arduino automatically sets the gain of the amplifier, let’s say, when the output signal voltage of the ACS758 is very low then the gain should be 10, and when the output signal voltage is high the gain should be 0.5.

To easily control the amplifier gain I used TS5A23166 analog switch from Texas Instruments. This analog switch has an ON resistance of 0.9 Ohm which can be ignored when it is compared with 20k or 18k. A single chip of the TS5A23166 consists of two analog switches.
The first switch is closed (NO1 is connected to COM1) by sending a logic high to IN1 pin, and the second switch is closed (NO2 is connected to COM2) by sending a logic high to IN2 pin.
The digital control signals IN1 and IN2 are sent from pins 3 and 4 of the Arduino uno board, respectively.

With the two switches open, the gain of the inverting amplifier is equal to: 180k/18k = 10. When switch S1 closed the gain becomes: (180k // 20k)/18k = 18k/18k = 1. If both switches are closed then the gain is: (180k // 20k // 18k)/18k = 9k/18k = 0.5 .

ACS758 current sensor (U1), OPA2191 op amp (U2) and TS5A23166 (U6) are supplied with bipolar power supply with +2.5V and -2.5V. A bipolar supply allows me to easily amplify or attenuate the output voltage of the ACS758 current sensor using the op amp circuit described above.

I used LT1761-SD LDO regulator (U5) from Analog Devices to get approximately +2.5V, the input voltage of this regulator is 5V and it comes from the Arduino board, I chose R13 and R14 (connected to ADJ pin) respectively with values 15k and 16k to get an output of +2.5V (voltage output equation in LT1761 datasheet).

In the other hand, I used LT1964-SD LDO negative regulator (U4) also from Analog Devices to get approximately -2.5V, the input voltage of this regulator is -5V. I chose R11 and R12 (connected to ADJ pin) respectively with values 15k and 16k to get an output of -2.5V (voltage output equation in LT1964 datasheet).
However, to get -5V I used B0505S-2W isolated DC/DC converter (U3). The input as well as the output of this small module is 5V, with the input isolated from the output.
By connecting B0505S-2W output positive pin to circuit GND we get -5V on its negative pin (with respect to circuit GND). The negative voltage is then used to feed the LT1964-SD regulator.
The B0505S-2W input supply (5V) is from the Arduino board.

Since we are working with alternating current (& DC positive and negative currents) then a part of ACS758 sensor output signal waveform may be negative. The Arduino ADC module can’t read analog negative voltages and we need to shift all the waveform to the positive side, this means we have to add a dc offset to the signal produced by the OPA2191 (U2) without affecting the gain again.

For that I used another amplifier circuit which firstly filters the signal and secondly adds a dc offset of 1.024V. The main component is another OPA2191 (U7) where just 1 op amp is used. It is supplied with 5V from the Arduino board (pin 8 of U7 is connected to Arduino 5V pin, and pin 4 of U7 is connected to any of Arduino GND pins).
This circuit has a gain of 1 and dc offset of 1.024V.

The low pass filter removes any high frequency harmonics and other noise. The cutoff frequency can be calculated as follows:
f = 1/(2 x π x R x C) = 3.12KHz
Where: R = R15 // R16 // R17 + R18 = 5.1k Ohm
C is C16 = 10nF

To prevent cross-talk between the used and the unused op amps of OPA2191 U7, the unused op amp inverting input is connected to GND and the non-inverting input to 2.048V voltage reference.
I choose to use OPA2191 because it does have many nice features such as: low offset voltage (±5µV), low noise (15 nV/√Hz at 1 kHz), low offset voltage drift: (±0.1 μV/°C) …

I used the MCP1501-20 (U9) from Microchip Technology to get a precise voltage of 2.048V which is then used as a positive voltage reference for the Arduino microcontroller ADC module. The MCP1501-20 is also supplied from the Arduino board with 5V. Its output is filtered and connected to the Arduino AREF pin.

The 1602 LCD screen (2 rows and 16 columns) is used to display the value of the current that flows through the ACS758 sensor (load current), it is connected to the Arduino board as follows:
RS —> Arduino digital pin 5
E   —> Arduino digital pin 6
D4 —> Arduino digital pin 7
D5 —> Arduino digital pin 8
D6 —> Arduino digital pin 9
D7 —> Arduino digital pin 10
VSS, RW, D0, D1, D2, D3 and K are connected to GND,
VEE to the 10k Ohms variable resistor (or potentiometer) output,
VDD to Arduino 5V and A to Arduino 5V through 330 ohm resistor.

VEE pin is used to control the contrast of the LCD. A (anode) and K (cathode) are the back light LED pins.

The pushbutton which is connected to Arduino digital pin 2 is used to choose between 3 current types: AC, DC or AC+DC.
With the Arduino code below and when AC type is selected, the Arduino calculates TRMS value of the AC current flows through the ACS758 sensor, any DC current will not be included in the results.
Alternatively, when DC type is selected, the Arduino calculates average (mean) value of the current applied to the ACS758 sensor.
However, when AC+DC type is selected, the Arduino calculates TRMS value of the current that passes through the ACS758 sensor where the DC component is included in calculations.

Measure AC & DC currents with Arduino and ACS758 sensor code:
Project code is the one below, it was tested with Arduino UNO board.
This Arduino code calculates RMS values for AC and AC+DC currents, and average (mean) values for DC current. The user can switch between the 3 current calculation modes using the pushbutton connected to Arduino digital pin 3, the default current type is AC (at startup).

Simply the average (mean or DC offset) value in discrete-time is the sum of all sample values divided by number of samples:

mean value equation

And the RMS value in discrete-time can be calculated using the following equation:

RMS value equation

The Arduino uno board microcontroller (ATmega328P) contains a 10-bit ADC module, the positive voltage reference is 2.048V means that a 2.048V is digitally represented by 1023 and 0V is represented by 0 (1 digit for every 2mV).

To get more precise and higher resolution readings, I wrote a simple code to use what’s known as oversampling and decimation technique to add another 2 bits to the 10 bits of the ADC. This gives us a total of useful 12-bit words.

Firstly, I declared an array of 256 elements named r_array , it is used to store reading samples which are used later to calculate average (dc offset) and RMS values.
With oversampling of 2 bits, we’ve to do 16 analog readings for each element of the ‘r_array’ variable. These readings are summed and divided by 4, where 16 = 4² and 4 = 2² and this ² is number of oversampling bits.

Oversampling code is located in a void function named get_smaples() which is used to fill sample array r_array by doing a total of 4096 (16 x 256) successive ADC readings.

Programming hints:
At startup, the Arduino MCU executes an auto calibration code, so before powering the Arduino make sure that there’s no current flows through the ACS758 sensor, otherwise results of DC and AC+DC current calculations may not be accurate, auto calibration has no effect on AC calculations.

I added the auto calibration code to read and record the whole circuit offset voltages which is for example caused by: unsymetrical bipolar supply (±2.5V), ACS758 offset, op amps offset …
The auto calibration code saves the default DC offset values for the 3 gains (10, 1 and 0.5) to a float array of 3 elements, it’s named as: dc_offset[3] .

The Arduino automatically switches between the three gain choices (10, 1 and 0.5) whenever RMS or average voltage applied to analog channel 0 exceeds 500mV, or goes down under 50mV if the gain is 1 and 250mV if the gain is 0.5.

Load current ranges with respect to gain are as follows:

Gain Load current range (A)
10 < 5
1 5 – 50
0.5 > 50

Functions used in the Arduino code:
void current_type_set(): selection of current type AC, DC or AC+DC is made by pressing the pushbutton connected to digital pin 2. When pressed, the Arduino immediately executes an interrupt routine and then in the loop() function a variable named current_type is incremented which is later used to distinguish between the 3 current types.

void gain_set(uint8_t g): this function is used to change circuit gain according to g.

void get_smaples(): this function fills the sample array mentioned above with 256 12-bit of data.

bool debounce (): used to debounce the pushbutton connected to Arduino digital pin 2. Returns true if OK and false if error.

Full Arduino code:

The following video shows my DIY circuit for this project, I used a clamp meter from UNI-T company (UT219DS) in order to test the accuracy of my circuit.
Note that some wires connecting the Arduino uno and the DIY PCB are soldered on the back of the two boards, this removes small voltages & noise caused by poor connections between jumper wires and Arduino board female header pins.

Related Projects:

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.