Measuring Current with an ACS712
| Difficulty | Advanced |
|---|---|
| Category | Sensors |
| Supported boards | Arduino Uno R3 and compatible ATmega328P boards |
| Time needed | 60 minutes |
| Prerequisites | Using a Multimeter |
| Tested board | Not yet verified |
| Tested on | Not yet verified |
| Arduino IDE version | Not yet verified |
| Library | Not yet verified |
What it does
Every current flowing in a wire creates a magnetic field around it. An ACS712 has a short copper bar inside it and a Hall-effect sensor beside that bar, so it senses the field and reports the current as a voltage, without the measuring circuit touching the current-carrying one at all.
That isolation is the point. A shunt resistor puts your Arduino’s ground into the circuit being measured; this does not. The current path and the output are separated inside the chip.
It is how you build something that watches its own consumption, or notices a motor stalling, or logs how much a fridge draws over a day.
Safety, because this sits in the live path
This sensor is wired in series with the load, which means breaking the circuit and putting the module in the gap. Everything flowing to the load flows through that green terminal block.
This tutorial is for low-voltage DC only. A 12 V motor, a lamp, a battery charging a phone. That is what it is written for and what you should build.
On mains. The chip’s internal isolation is rated for a few kilovolts, which is why people reach for it to measure household appliances. The chip is not the problem. The problem is the module: a bare board with exposed screw terminals and no enclosure, in a circuit where one terminal is at mains potential. Touching that board while it is live would be dangerous, and so would a wire pulling loose inside it.
If you want to measure a mains appliance, use a commercial plug-in energy meter. They cost very little, they are enclosed and approved, and they tell you more. Everything in this page is about understanding, not about putting a bare board on a 230 V circuit.
Never run the load current through a breadboard. Breadboard contacts are rated for a fraction of an amp. The load wiring goes in the screw terminals, tightened properly, with thick enough cable for the current.
Before you begin
Required parts and tools
- An Arduino Uno or compatible board.
- One ACS712 module. This is Siratek product 5283.
- A low-voltage DC load and its own supply.
- A multimeter, to check the sensor against something you trust.
- Three jumper wires, and proper cable for the load side.
Which variant you have, and why it decides the code
The ACS712 is made in three ranges, and the sensitivity differs:
| Part | Range | Sensitivity |
|---|---|---|
| ACS712-05B | 5 A | 185 mV per amp |
| ACS712-20A | 20 A | 100 mV per amp |
| ACS712-30A | 30 A | 66 mV per amp |
The chip on the Siratek board is marked ACS712 ELC-20A, so the figure to use is 100 mV per amp.
Put the wrong number in and every reading is wrong by a fixed factor, with nothing to warn you. Read the marking on your own chip before trusting the code below.
The resolution problem, stated honestly
This is the limitation that disappoints people, and it is arithmetic rather than a fault.
An Uno’s analog input divides 5 V into 1024 steps, so one step is about 4.9 mV. At 100 mV per amp, one step is about 0.049 A, nearly fifty milliamps.
So the 20 A part cannot resolve better than roughly 50 mA, and real noise is several counts, which means the practical floor is somewhere around 100 to 200 mA. An LED drawing 20 mA is invisible to it. A phone charger at 0.5 A is barely distinguishable from nothing.
Three ways to live with this:
- Use it for what it is good at: amps, not milliamps. Motors, heaters, lamps, battery charging.
- Average heavily. Sixty-four readings instead of one turns a jittery number into a usable one.
- For small currents, use the 5 A variant, which is nearly twice as sensitive, or a shunt and an amplifier instead.
The output sits at half the supply
With no current flowing, the output is at VCC divided by two, about 2.5 V, which reads around
- Current one way pushes it up; current the other way pushes it down.
That is how it measures alternating current as well as direct. It is also why the zero point must be measured rather than assumed: the real figure is rarely exactly 512, it varies between modules, and it drifts a little with temperature.
Measure it at startup, with no current flowing, exactly as with the joystick.
The sensitivity is proportional to the supply. Power the module from a sagging 4.7 V rail and both the zero point and the volts-per-amp figure shift. For anything you care about, measure the 5 V rail with a meter and use the real value in the code.
Pin reference
| Pin or terminal | Connect to | Purpose | Notes |
|---|---|---|---|
VCC |
Uno 5V |
Power | Sensitivity scales with this |
GND |
Uno GND |
Ground | |
OUT |
Uno A0 |
Analog output | About 2.5 V at zero current |
| Terminal 1 | Supply positive | Current in | Load side |
| Terminal 2 | Load positive | Current out | Load side |
The load’s negative lead goes back to its own supply, not through the module.
Wiring steps
- Unplug the USB cable and disconnect the load supply.
GNDtoGND,VCCto5V,OUTtoA0.- Plug in the USB cable and run the first sketch. Check it reads near 512 with nothing in the terminals. This proves the Arduino side before any current exists.
- Unplug again.
- Break the positive lead between the supply and the load, and put the two cut ends into the two screw terminals.
- Tighten both properly and check no bare conductor shows.
- Plug in the USB cable, then connect the load supply.
Step 3 is the one that saves time. If the zero reading is wrong, nothing after it can be right.
Software and libraries
No library is required.
Minimal working example
// Siratek: find the zero point, with no current flowing.
const int sensorPin = A0;
void setup() {
Serial.begin(9600);
Serial.println("Siratek: nothing in the terminals. This should sit near 512.");
}
void loop() {
long total = 0;
for (int i = 0; i < 64; i++) {
total += analogRead(sensorPin);
delayMicroseconds(200);
}
Serial.print("raw average = ");
Serial.println(total / 64.0, 2);
delay(500);
}
Write that number down. It is your zero, and it is probably not 512.
Measuring direct current
// Siratek: DC current through an ACS712-20A.
const int sensorPin = A0;
// From the sketch above. Yours will differ.
const float zeroCount = 512.0;
// Measure your 5V rail with a meter and put the real figure here.
const float supplyVolts = 5.0;
// 100 mV per amp for the 20 A part. 185 for the 5 A, 66 for the 30 A.
const float mvPerAmp = 100.0;
float readAmps() {
long total = 0;
for (int i = 0; i < 64; i++) {
total += analogRead(sensorPin);
delayMicroseconds(200);
}
float average = total / 64.0;
float millivolts = (average - zeroCount) * (supplyVolts * 1000.0 / 1023.0);
return millivolts / mvPerAmp;
}
void setup() {
Serial.begin(9600);
Serial.println("Siratek: current meter ready.");
}
void loop() {
float amps = readAmps();
Serial.print(amps, 2);
Serial.println(" A");
delay(500);
}
Sixty-four samples is not caution, it is necessary. A single reading on this part wanders by several counts, which is over a tenth of an amp.
Check it against a multimeter. Put the meter in series as well, or measure the same load separately, and compare. If the two disagree by a constant factor, you have the wrong mvPerAmp. If they disagree by a constant offset, your zeroCount is wrong. The two faults look different, and that is how you tell them apart.
Alternating current needs a different approach
For AC, the average is zero: the current goes equally positive and negative, and the sketch above would report nothing.
What you want is the RMS value, which means sampling over at least one full cycle and taking the root mean square of the deviation from zero:
// Siratek: RMS current, sampled over about five cycles of 50 Hz.
float readAmpsRms() {
unsigned long start = millis();
double sumSquares = 0;
long samples = 0;
while (millis() - start < 100) { // 100 ms is five cycles at 50 Hz
float d = analogRead(sensorPin) - zeroCount;
sumSquares += d * d;
samples++;
}
float rmsCounts = sqrt(sumSquares / samples);
float millivolts = rmsCounts * (supplyVolts * 1000.0 / 1023.0);
return millivolts / mvPerAmp;
}
This is the same idea as measuring loudness with the sound sensor: a single sample of an alternating signal tells you nothing, and the information is in the spread.
Note that this measures current only, not power. Power needs voltage as well, and on an AC circuit it needs the phase between them. Multiplying this reading by 230 gives apparent power, not real power, and the two differ on anything with a motor in it.
And note again: do not put this board on a mains circuit. The sketch is here because the technique matters, and it applies equally to a low-voltage AC supply from a transformer.
Expected result
Around 512 with nothing connected, moving clearly when a load of an amp or more flows, and agreeing with a multimeter to within a few percent after calibration.
Switch the load off and on and watch the reading. A motor’s starting surge is clearly visible, and is often several times its running current, which is the most instructive thing this sensor shows you. It makes the warning in Powering Your Project concrete.
Troubleshooting
| Symptom | Likely cause | Check or fix |
|---|---|---|
| Reads about 512 with a load running | Load current not going through the terminals | The module goes in series |
| Reading has a constant offset | Zero point assumed | Measure it with nothing connected |
| Reading out by a constant factor | Wrong mvPerAmp |
Read the chip marking |
| Small currents invisible | Resolution is about 50 mA per count | Expected on the 20 A part |
| Reading jumps around | Single samples | Average sixty-four |
| Drifts as the room warms | Hall sensors are temperature sensitive | Re-zero when it matters |
| Changes when a motor starts elsewhere | Supply sagging changes the sensitivity | Measure the real rail voltage |
| AC reads zero | Averaging cancels it out | Use the RMS method |
| Numbers differ from a meter | Calibration, or the meter is in a different place | Compare carefully |
| Terminal block getting warm | Screws not tight, or cable too thin | Disconnect and fix before continuing |
Next steps
- Easier first: Using a Multimeter, which is what you will check this against.
- Related: Powering Your Project, for the current budget this sensor lets you verify.
- Next project: log a 12 V load’s current to an SD card for a day, and see what it really draws rather than what the label claims.
Sources and attribution
All text, wiring guidance and code in this tutorial are original Siratek work.
- ACS712 datasheet for the sensitivity of each variant, the output offset at half supply and the ratiometric behaviour with supply voltage.
- The
ACS712 ELC-20Achip marking, the two-pole screw terminal and theOUT GND VCCheader were read from the Siratek product photographs for item 5283. That marking is what fixes the sensitivity at 100 mV per amp.
The resolution figures are arithmetic from the Uno’s 10-bit converter and the part’s sensitivity. This tutorial is deliberately scoped to low-voltage DC, and says why a bare module is not the right tool for mains measurement. No third-party tutorial text, diagrams, photographs or code has been reproduced here.

