In the previous project I built a circuit that can be used to measure AC and DC currents with a good accuracy over a wide range from 0 to 200A DC, this circuit is based on Arduino UNO board and Allegro ACS758 hall-effect current sensor.
In this project I’m going to use the same Arduino board and current sensor to measure AC and DC currents with minimum required components. 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
PCB: Printed Circuit Board
DIY: Do It Yourself
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) ).
With a supply of 5V, 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.
Electric current measurement using Arduino and ACS758 sensor:
Project circuit diagram is shown below (click on the image for better view).
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 U2.
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 (U2)
- ACS758 Hall-effect current sensor (U1) —> details
- 1602 LCD screen
- 10k variable resistor (R2)
- 100 Ohm resistor (R1)
- 330 Ohm resistor (R3)
- 0.1 uF capacitor (C1)
- 10 nF capacitor (C2)
- Pushbutton (S1)
- Breadboard
- Jumper wires
Circuit description:
The ACS758 current sensor is noted in the circuit schematic above as U1. It is supplied with voltage of 5V which comes from the Arduino board.
At rated current of +200A the voltage output of the ACS758 sensor is 4.5V ( VIOUT(Q) + 200 x 10mV = 4.5V ) and at current of -200A the output voltage is 0.5V ( VIOUT(Q) – 200 x 10mV = 0.5V ).
The output of the ACS758 is connected to a RC filter (R1 and C1) that removes any high frequency noise and then directly to Arduino analog channel 2.
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 3
E —> Arduino digital pin 4
D4 —> Arduino digital pin 5
D5 —> Arduino digital pin 6
D6 —> Arduino digital pin 7
D7 —> Arduino digital pin 8
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 (offset) is included in calculations.
Electric current measurement using Arduino and ACS758 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 2, 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:
And the RMS value in discrete-time can be calculated using the following equation:
The Arduino uno board microcontroller (ATmega328P) contains a 10-bit ADC module, in this project the positive voltage reference of the ADC module is the same as Arduino VCC (about 5 volts).
The ATmega328P MCU also contains a bandgap voltage reference of 1.1V. This internal voltage reference helps getting more accurate voltage values applied to any analog channel rather than the Arduino VCC (because we don’t know the exact value of VCC).
The philosophy is, first get the digital representation number of the internal voltage reference and then read the analog channel A2 voltage, for both readings VCC is used as positive reference of the ADC module. We can extract the analog voltage applied to A2 channel by multiplying the digital representation number of A2 voltage by the ratio of actual internal reference voltage (1.1V) and the digital representation number of the internal reference voltage.
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 save circuit default offset voltage that is mainly caused by the ACS758 sensor. The auto-calibrated DC offset value is saved to a float variable named: dc_offset.
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, it 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | /************************************************************************ * * AC & DC Electric current measurement using Arduino and Allegro ACS758 * hall-effect based current sensor - 2nd Project. * Calculated current values are printed on 1602 LCD screen and serial monitor. * This is a free software with NO WARRANTY - Use it at your own risk! * http://simple-circuit.com/ * ************************************************************************/ #include <LiquidCrystal.h> // include Arduino LCD library // LCD module connections (RS, E, D4, D5, D6, D7) LiquidCrystal lcd(3, 4, 5, 6, 7, 8); #define REF_VOLTAGE 1100.0 // internal bandgap reference voltage, in millivolts #define ACS758_SENS 10 // ACS758 sensitivity = 10mV/A (for ACS758-200B version) #define CUR_SEL 2 // current type select pushbutton pin // define current type #define AC 0 // AC current #define DC 1 // DC current #define AC_DC 2 // AC+DC current (AC current with DC offset) // variables byte current_type = AC; // current type according to previous 3 definitions const uint16_t n = 256; // number of samples float _array[n]; // sample array with 'n' elements float dc_offset; // auto-calibration dc offset void setup(void) { Serial.begin(9600); pinMode (CUR_SEL, INPUT_PULLUP); lcd.begin(16, 2); // set up the LCD's number of columns and rows // ADC configuration ADMUX |= (1 << REFS0) ; // set ADC +ive vlotage reference to AVCC // ADC auto triggering is enabled, ADC clock division factor set to 128 (ADC clock = 125kHz) ADCSRA |= (1 << ADATE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // do auto-calibration to the circuit (no current should flow through the ACS758 sensor) ADMUX |= (1 << MUX1) ; // select analog channel 2 (A2) as input to ADC dc_offset = 0; get_smaples(); for (uint16_t j = 0; j < n; j++) dc_offset += _array[j]; dc_offset /= n; attachInterrupt( digitalPinToInterrupt(CUR_SEL), current_type_set, FALLING ); // interrupt enable } volatile bool button = 0; // variable for CUR_SEL button press // set current type: AC, DC or AC+DC void current_type_set() { button = 1; detachInterrupt( digitalPinToInterrupt(CUR_SEL) ); // interrupt disable loop(); } // button debounce function bool debounce () { byte count = 0; for(byte i = 0; i < 5; i++) { if ( !digitalRead(CUR_SEL) ) count++; delay(10); } if(count > 2) return 1; else return 0; } // analog data acquisition function void get_smaples() { // clear sample array for (uint16_t i = 0; i < n; i++) _array[i] = 0.0; ADCSRA |= (1 << ADEN) | (1 << ADSC) ; // enable ADC module and start converion (free running mode) // ignore the first reading while ( (ADCSRA & (1 << ADIF)) == 0 ); // wait for ADIF to be set (conversion complete) ADCSRA = ADCSRA; // reset ADIF flag bit // fill samples array with 12-bit data (add another 2 bits using oversampling technique) for (uint16_t i = 0; i < n; i++) { for (uint16_t j = 0; j < 16; j++) { while ( (ADCSRA & (1 << ADIF)) == 0 ); // wait for ADIF to be set (conversion complete) ADCSRA |= (1 << ADIF); // reset ADIF bit by writing 1 to it _array[i] += ADCW; } } ADCSRA &= ~((1 << ADEN) | (1 << ADSC)) ; // stop conversion and disable ADC module, reset ADIF bit also for (uint16_t i = 0; i < n; i++) _array[i] /= 4.0; } // main loop function void loop() { if (button) { // if current type button is pressed button = 0; if ( debounce() ) { current_type++; if (current_type > 2) current_type = 0; } attachInterrupt( digitalPinToInterrupt(CUR_SEL), current_type_set, FALLING ); // interrupt enable return; } // get digital representation of the internal bangap reference voltage float bgref_voltage = 0; // Arduino internal reference voltage variable ADMUX |= (1 << MUX3) | (1 << MUX2) | (1 << MUX1); // select internal bandgap refernce as input to ADC get_smaples(); // get samples for (uint16_t i = 0; i < n; i++) bgref_voltage += _array[i] ; bgref_voltage /= n; // average value // read ACS758 output voltage float acs758_voltage = 0; // ACS758 sensor output voltage variable ADMUX &= ~( (1 << MUX3) | (1 << MUX2) ) ; // select analog channel 2 (A2) as input to ADC get_smaples(); if ( current_type == AC || current_type == AC_DC ) { // AC or AC+DC type float _offset = 0; if ( current_type == AC ) { // AC signal for (uint16_t i = 0; i < n; i++) // caculate signal average value (dc offset) _offset += _array[i]; _offset = _offset / n; } else // AC+DC signal _offset = dc_offset; // the dc offset is the pre-calibrated one // calculate signal RMS value (digital representation) for (uint16_t i = 0; i < n; i++) acs758_voltage += sq( _array[i] - _offset ); acs758_voltage = acs758_voltage / n; acs758_voltage = sqrt(acs758_voltage); } else { // DC type for (uint16_t i = 0; i < n; i++) acs758_voltage += _array[i] - dc_offset ; // remove the pre-calibrated DC offset acs758_voltage /= n; // average value } // calculate actual ACS758 sensor output voltage acs758_voltage = acs758_voltage * REF_VOLTAGE / bgref_voltage ; // now we can calculate current passing through the ACS758 sensor (in amps) float acs758_current = acs758_voltage / ACS758_SENS ; // print data on the LCD and serial monitor lcd.setCursor(0, 0); if ( current_type == AC ) { lcd.print( "AC Current = "); Serial.print( "AC Current = "); } else if ( current_type == DC ) { lcd.print( "DC Current = "); Serial.print( "DC Current = "); } else { lcd.print( "AC+DC Current = "); Serial.print( "AC+DC Current = "); } lcd.setCursor(0, 1); if ( acs758_current < -0.01) { lcd.print('-'); Serial.print('-'); } acs758_current = abs(acs758_current); char _buffer[9]; if(acs758_current < 10.0) // if current < 10.0 Amps sprintf( _buffer, "%1u.%02u A ", (uint8_t)acs758_current, (uint8_t)(acs758_current * 100) % 100 ); else if (acs758_current < 100.0) // if 10.0 <= current < 100.0 Amps sprintf( _buffer, "%2u.%02u A ", (uint8_t)acs758_current, (uint8_t)(acs758_current * 100) % 100 ); else // current is >= 100.0 Amps sprintf( _buffer, "%3u.%02u A", (uint8_t)acs758_current, (uint8_t)(acs758_current * 100) % 100 ); lcd.print(_buffer); Serial.println( _buffer ); Serial.println(); } // end of 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:
Measure AC & DC Currents with Arduino and ACS758 Sensor
Interfacing Arduino with Current Transformer – AC Current Measurement
AC Current Measurement using Arduino and Current Transformer
Isolated AC Voltage Measurement with Arduino and AMC1301 Amplifier
can we use the same for upto 10A current measurments and esp32?
Hey there, (don’t know your name already),
within the article about a simple current meter with an Arduino
August 17, 2021
Version “Current_simple”:
Electric Current Measurement Using Arduino and ACS758 Sensor
http://simple-circuit.com/interface-arduino-allegro-acs758-current-sensor-ac-dc/
In the component list it seems that the capacitor C2 (10nF) is missing and the C1 has the wrong value compared to the schematic.
Please check and correct.
Anyway, your articles are very helpful for electronic hoppyists!
best regards
Herbert
Yes you’re right, thank you so much!