Skip to Content

PLC Solution Library · Engineering tools

4-20 mA calculator: scaling, 0-10 V shunt and PLC input check

To read a 4-20 mA signal on a 0-10 V PLC input, put a 500 Ω resistor between the input and 0 V: 4 mA gives 2 V and 20 mA gives 10 V.Scale it with value = min + (mA - 4) / 16 x (max - min). At 3.6 mA or less, treat it as a fault: broken wire, no power or a low fault signal.

The calculator uses the analog input data of the M-Duino, Ardbox, ESP32 PLC and Raspberry PLC datasheets. Free and with no sign-up: the result is always on screen.

1Your signal

Type the current, the value or the PLC reading. The other two follow.

2Your PLC input

ESP32 PLC 14: inputs AI0.0 and AI0.1 read 4-20 mA directly in 4-20 mA mode, with no shunt. This calculator covers the 0-10 V inputs.

3Your loop

The transmitter values are examples: take them from its datasheet.

Result

Valid measurement

Value5.00 bar
At the input5.924 V
PLC reading606 / 1023
Loop current12.00 mA
Resistor in parallel with the input
493.7 Ω
Input impedance
39 kΩ
Input at full scale (10 V) at
20.26 mA
Reading at 4 mA · at 20 mA
202 · 1010
Useful steps · effective bits
808 · 9.7 bit
One step is
19.8 µA · 0.012 bar
Sees saturation · sees NE 43 high fault
no · no
Resistor power at 20 mA · 21 mA
0.200 W · 0.221 W
Error from the tolerance, at 20 mA
± 0.125 bar
Loop
14.1 V left at 20 mA (minimum 12.0 V)

A shunt resistor is enough

  • With this resistor the input reaches full scale at 20.26 mA: the PLC cannot tell saturation or the NAMUR NE 43 high fault (21 mA or more). If you need them, use 477 Ω or less, for example 470 Ω.
  • For 500 Ω there is the IS.ACANTO10-0.5k DIN rail terminal, with the resistor at ±1 %.

See the IS.ACANTO10-0.5k terminal

Wiring
24 VDC+0 VPLCI0.7GND500 ΩTransmitter2-wire4 mA = 1.97 V · 20 mA = 9.87 V

The loop current flows from the transmitter into the resistor on input I0.7. The PLC GND, the resistor and the 0 V of the supply share one point.

Code for your PLC · loop420.ino

// 4-20 mA transmitter on M-Duino 21+ input I0.7 (M-Duino: 0-10 Vdc, 10 bit)
// Shunt resistor of 500 ohm between I0.7 and GND turns the loop current into a voltage.
// Generated by the Industrial Shields 4-20 mA calculator: https://www.industrialshields.com/plc-solution-library/tools/4-20ma-calculator
// Check the values on your hardware with a loop calibrator before you use them.
// Arduino IDE with the Industrial Shields AVR boards package. Select your M-Duino model.

const int AI_PIN = I0_7;   // analog input used for the loop
const float ADC_MAX   = 1023.0;   // 10 bit, from the M-Duino Family datasheet
const float AI_RANGE  = 10.0;     // input range in volts
const float R_SHUNT   = 500.0;    // shunt resistor in ohm
const float R_INPUT   = 39000.0;    // input impedance in ohm (0 = not known, treated as ideal)
const float R_EQ = (R_INPUT > 0.0) ? R_SHUNT * R_INPUT / (R_SHUNT + R_INPUT) : R_SHUNT;

const float PV_MIN = 0.000;   // value at 4 mA (bar)
const float PV_MAX = 10.000;   // value at 20 mA (bar)

// NAMUR NE 43 limits in mA
const float MA_FAULT_LOW  = 3.6;   // 3.6 mA or less: broken wire or low fault signal
const float MA_RANGE_LOW  = 3.8;   // 3.6 to 3.8 mA: under range
const float MA_RANGE_HIGH = 20.5;  // 20.5 to 21 mA: over range (saturated)
const float MA_FAULT_HIGH = 21.0;  // 21 mA or more: high fault signal

const int N_SAMPLES = 16;

float readCounts() {
  uint32_t sum = 0;
  for (int i = 0; i < N_SAMPLES; i++) {
    sum += analogRead(AI_PIN);
  }
  return (float)sum / N_SAMPLES;
}

float countsToMilliamps(float counts) {
  float volts = counts * AI_RANGE / ADC_MAX;
  return volts / R_EQ * 1000.0;
}

float milliampsToValue(float mA) {
  float pv = PV_MIN + (mA - 4.0) * (PV_MAX - PV_MIN) / 16.0;
  if (PV_MIN < PV_MAX) {
    if (pv < PV_MIN) pv = PV_MIN;
    if (pv > PV_MAX) pv = PV_MAX;
  }
  return pv;
}

void setup() {
  Serial.begin(115200);
  pinMode(AI_PIN, INPUT);
}

void loop() {
  float counts = readCounts();
  float mA = countsToMilliamps(counts);
  float pv = milliampsToValue(mA);

  Serial.print(mA, 2);
  Serial.print(" mA  ");
  if (MA_FAULT_LOW >= mA) {
    Serial.println("LOOP FAULT: broken wire or low fault signal");
  } else if (mA >= MA_FAULT_HIGH) {
    Serial.println("HIGH FAULT SIGNAL from the transmitter");
  } else if (counts >= ADC_MAX - 0.5) {
    Serial.print(pv, 2);
    Serial.println(" bar  (input at full scale: the current can be higher)");
  } else {
    Serial.print(pv, 2);
    Serial.print(" bar");
    if (MA_RANGE_LOW > mA) Serial.println("  (under range)");
    else if (mA > MA_RANGE_HIGH) Serial.println("  (over range, saturated)");
    else Serial.println();
  }
  delay(500);
}

It reads 16 samples, converts them to mA with the resistor and the input impedance, checks the NAMUR NE 43 limits and scales the value. M-Duino, Ardbox and ESP32 PLC: Arduino IDE with the Industrial Shields boards package. Raspberry PLC: C++ with librpiplc. Comments are in English.

Send me the calculation and the code

We send this configuration, the code and the wiring to your email, and an engineer reviews them for your project.

Send it to me

How the 4-20 mA calculation works

A 4-20 mA transmitter sets a current between 4 and 20 mA in proportion to what it measures. The analog inputs of the M-Duino, Ardbox, ESP32 PLC and Raspberry PLC families measure 0 to 10 V, so a resistor turns the current into a voltage. These are the formulas the calculator uses, in this order.

  1. Resistor seen by the loop. The input impedance sits in parallel with the shunt: R_eq = R x Z_in / (R + Z_in)
  2. Voltage at the input. Ohm's law: V = I x R_eq
  3. PLC reading. With an input of 0 to 10 V and N bits: reading = V / 10 x (2^N - 1)
  4. Back to mA in the program. I = reading x 10 / (2^N - 1) / R_eq
  5. Engineering units. value = min + (I - 4) / 16 x (max - min)
  6. Full scale. The input saturates at I_fs = 10 V / R_eq. Above it, every current reads the same.
  7. Resistor power. P = I² x R
  8. Loop voltage, 2-wire. What is left for the transmitter, with R_cable = 2 x length x 0.0175 / section (copper): V_tx = V_supply - I x (R_eq + R_cable)

Analog inputs of Industrial Shields PLCs for 4-20 mA

All four families have 0-10 Vdc analog inputs. What changes is the resolution and, on the M-Duino and the Ardbox, the 39 kΩ input impedance given in the datasheet. Values with a 500 Ω shunt:

FamilyResolutionInput impedanceReading at 4 mA · 20 mAFull scale at
M-DuinoResolution: 10 bit (0 to 1023)Input impedance: 39 kΩReading at 4 mA · 20 mA: 202 · 1010Full scale at: 20.26 mA
Ardbox AnalogResolution: 10 bit (0 to 1023)Input impedance: 39 kΩReading at 4 mA · 20 mA: 202 · 1010Full scale at: 20.26 mA
ESP32 PLCResolution: 11 bit (0 to 2047)Input impedance: Not given (ideal)Reading at 4 mA · 20 mA: 409 · 2047Full scale at: 20.00 mA
Raspberry PLCResolution: 12 bit (0 to 4095)Input impedance: Not given (ideal)Reading at 4 mA · 20 mA: 819 · 4095Full scale at: 20.00 mA

ESP32 PLC 14: inputs AI0.0 and AI0.1 read 4-20 mA directly in 4-20 mA mode, with no shunt. This calculator covers the 0-10 V inputs.

On the M-Duino 21+, the ESP32 PLC 21+ and the Raspberry PLC 21, the analog inputs are I0.7 to I0.12; larger models add more zones with the same pattern. On the Ardbox Analog they are I0.2 to I0.9.

With an ideal input and 500 Ω, 20 mA lands exactly on 10 V, so the ESP32 PLC and the Raspberry PLC have no margin above 20 mA: 470 Ω gives that margin.

Worked examples

CaseInputResult
Pressure 0 to 10 bar, M-Duino, 500 ΩInput: 12 mAResult: 5.92 V, reading 606, 5.00 bar
Level 0 to 4 m, ESP32 PLC, 500 ΩInput: reading 1000Result: 9.77 mA, 1.44 m
Temperature -50 to 150 °C, Raspberry PLC, 470 ΩInput: 21 mAResult: 9.87 V, reading 4042: NAMUR NE 43 high fault. With 500 Ω it would read 4095, full scale, and the fault would look like 150 °C.
Broken wire, Ardbox Analog, 500 ΩInput: 0 mAResult: 0 V, reading 0: fault, below 3.6 mA
250 Ω on an M-Duino, 0 to 10 barInput: 20 mAResult: 4.97 V, reading 508: half of the range, 0.025 bar per step instead of 0.012 bar with 500 Ω
2-wire loop at 24 V, 300 m of 0.5 mm², ESP32 PLC, 500 ΩInput: 20 mAResult: Cable 21 Ω, 13.58 V left for the transmitter

How to connect a 4-20 mA transmitter to a 0-10 V PLC input

  1. Choose the resistor. 500 Ω for a 0-10 V input, or 470 Ω if you need to see the NAMUR NE 43 high fault. Use 1 % or better and at least 0.5 W.
  2. Wire the loop. 2-wire: +24 V to the + of the transmitter, the - of the transmitter to the analog input, and the resistor between the input and 0 V. 3-wire and 4-wire: the output of the transmitter to the input, its 0 V to the common 0 V.
  3. Check the loop voltage. At 20 mA the supply must still leave the minimum voltage of the transmitter after the resistor and the cable.
  4. Scale and check faults in the program. Convert the reading to mA, check the NAMUR NE 43 limits, then scale to units. Check 4, 12 and 20 mA with a loop calibrator.

Shunt resistor or isolated converter?

A shunt resistor is enough when the transmitter and the PLC share the same 0 V, the loop has only one grounded receiver and the cable stays in a clean cabinet. The IS.ACANTO10-0.5k is that shunt in DIN rail format: a feed-through terminal with a 500 Ω resistor at ±1 %.

Use an isolated 4-20 mA to 0-10 V signal converter when:

  • the transmitter or its supply has another ground reference, such as a 4-wire instrument fed from another panel;
  • another device with a grounded input, such as a second controller or a recorder, reads the same loop;
  • the cable runs between buildings or next to drives and power cables, and the readings move.

The datasheets of the M-Duino, the Ardbox, the ESP32 PLC and the Raspberry PLC say that the equipment has no galvanic isolation between the grounds of different systems, and recommend galvanic isolators when the grounds are different.

Broken wire and saturation: NAMUR NE 43 limits

CurrentMeaningWhat the program does
3.6 mA or lessFault: broken wire, no power or low fault signalProgram: Alarm, no value
3.6 to 3.8 mAUnder rangeProgram: Value at the bottom of the scale, with a flag
3.8 to 20.5 mAValid measurementProgram: Scaled value
20.5 to 21 mAOver range: the transmitter is saturatedProgram: Value at the top of the scale, with a flag
21 mA or moreFault: high fault signalProgram: Alarm, no value

To see the last two rows the input must not saturate before 21 mA. With 500 Ω it saturates at 20.0 to 20.3 mA; with 470 Ω, at 21.3 to 21.5 mA.

Example code: 4-20 mA on an M-Duino

This is the code the calculator gives for a 0 to 10 bar transmitter on input I0.7 of an M-Duino with 500 Ω. Change the values above and copy your version from the calculator.

// 4-20 mA transmitter on M-Duino 21+ input I0.7 (M-Duino: 0-10 Vdc, 10 bit)
// Shunt resistor of 500 ohm between I0.7 and GND turns the loop current into a voltage.
// Generated by the Industrial Shields 4-20 mA calculator: https://www.industrialshields.com/plc-solution-library/tools/4-20ma-calculator
// Check the values on your hardware with a loop calibrator before you use them.
// Arduino IDE with the Industrial Shields AVR boards package. Select your M-Duino model.

const int AI_PIN = I0_7;   // analog input used for the loop
const float ADC_MAX   = 1023.0;   // 10 bit, from the M-Duino Family datasheet
const float AI_RANGE  = 10.0;     // input range in volts
const float R_SHUNT   = 500.0;    // shunt resistor in ohm
const float R_INPUT   = 39000.0;    // input impedance in ohm (0 = not known, treated as ideal)
const float R_EQ = (R_INPUT > 0.0) ? R_SHUNT * R_INPUT / (R_SHUNT + R_INPUT) : R_SHUNT;

const float PV_MIN = 0.000;   // value at 4 mA (bar)
const float PV_MAX = 10.000;   // value at 20 mA (bar)

// NAMUR NE 43 limits in mA
const float MA_FAULT_LOW  = 3.6;   // 3.6 mA or less: broken wire or low fault signal
const float MA_RANGE_LOW  = 3.8;   // 3.6 to 3.8 mA: under range
const float MA_RANGE_HIGH = 20.5;  // 20.5 to 21 mA: over range (saturated)
const float MA_FAULT_HIGH = 21.0;  // 21 mA or more: high fault signal

const int N_SAMPLES = 16;

float readCounts() {
  uint32_t sum = 0;
  for (int i = 0; i < N_SAMPLES; i++) {
    sum += analogRead(AI_PIN);
  }
  return (float)sum / N_SAMPLES;
}

float countsToMilliamps(float counts) {
  float volts = counts * AI_RANGE / ADC_MAX;
  return volts / R_EQ * 1000.0;
}

float milliampsToValue(float mA) {
  float pv = PV_MIN + (mA - 4.0) * (PV_MAX - PV_MIN) / 16.0;
  if (PV_MIN < PV_MAX) {
    if (pv < PV_MIN) pv = PV_MIN;
    if (pv > PV_MAX) pv = PV_MAX;
  }
  return pv;
}

void setup() {
  Serial.begin(115200);
  pinMode(AI_PIN, INPUT);
}

void loop() {
  float counts = readCounts();
  float mA = countsToMilliamps(counts);
  float pv = milliampsToValue(mA);

  Serial.print(mA, 2);
  Serial.print(" mA  ");
  if (MA_FAULT_LOW >= mA) {
    Serial.println("LOOP FAULT: broken wire or low fault signal");
  } else if (mA >= MA_FAULT_HIGH) {
    Serial.println("HIGH FAULT SIGNAL from the transmitter");
  } else if (counts >= ADC_MAX - 0.5) {
    Serial.print(pv, 2);
    Serial.println(" bar  (input at full scale: the current can be higher)");
  } else {
    Serial.print(pv, 2);
    Serial.print(" bar");
    if (MA_RANGE_LOW > mA) Serial.println("  (under range)");
    else if (mA > MA_RANGE_HIGH) Serial.println("  (over range, saturated)");
    else Serial.println();
  }
  delay(500);
}

Related guides, cases and simulators

Questions about 4-20 mA signals

Which resistor do I need to read 4-20 mA on a 0-10 V PLC input?

Use 500 Ω for an M-Duino or an Ardbox: with their 39 kΩ input impedance in parallel, 500 Ω gives 493.7 Ω, so 4 mA reads 1.97 V and 20 mA reads 9.87 V.

On an input with an ideal impedance, such as the ESP32 PLC and the Raspberry PLC in the calculator, 500 Ω puts 20 mA exactly at 10 V, with no margin: 470 Ω gives margin and lets you see the NAMUR NE 43 high fault.

Choose 1 % or better. Full guide: How to convert a 4-20 mA signal to 0-10 V in an Arduino PLC.

How do I scale a 4-20 mA signal to engineering units?

Use value = min + (mA - 4) / 16 x (max - min), where min is the value at 4 mA and max the value at 20 mA.

For a 0 to 10 bar transmitter, 12 mA is 0 + 8 / 16 x 10 = 5 bar. The reverse is mA = 4 + 16 x (value - min) / (max - min).

How does a PLC detect a broken wire on a 4-20 mA loop?

A broken wire drops the current to 0 mA, below the live zero of 4 mA.

NAMUR NE 43 treats 3.6 mA or less as a fault, 3.6 to 3.8 mA as under range, 3.8 to 20.5 mA as a valid measurement, 20.5 to 21 mA as over range and 21 mA or more as a high fault. The program checks the current against these limits before it scales the value.

Why can the PLC not see 21 mA with a 500 Ω resistor?

Because 500 Ω turns 20 mA into 10 V, the top of a 0-10 V input. Anything above that reads as full scale, so the PLC cannot tell over range from a high fault.

If you need the NAMUR NE 43 high fault, use 470 Ω: the full scale moves to 21.28 mA with an ideal input, or 21.53 mA on an M-Duino or an Ardbox, and you lose about 6 % of the resolution.

What power rating does the shunt resistor need?

P = I² x R. A 500 Ω resistor dissipates 0.2 W at 20 mA and 0.22 W at 21 mA. A rating of at least twice that, 0.5 W, keeps it cool and stable. The calculator gives the figure for your resistor.

When do I need an isolated converter instead of a shunt resistor?

A shunt is enough when the transmitter and the PLC share the same 0 V and nothing else with a grounded input sits on the loop.

Use an isolated 4-20 mA to 0-10 V converter when the transmitter or its supply has another ground reference, when another grounded device reads the same loop, or when a long cable picks up noise.

The datasheets of the M-Duino, Ardbox, ESP32 PLC and Raspberry PLC say the equipment has no galvanic isolation between the grounds of different systems.

How do Industrial Shields PLCs read a 4-20 mA signal?

The ESP32 PLC 14 reads it directly: its analog inputs AI0.0 and AI0.1 have a 4-20 mA mode that you select in software.

The M-Duino, Ardbox, ESP32 PLC and Raspberry PLC families have 0-10 Vdc analog inputs (10 bit on the M-Duino and the Ardbox, 11 bit on the ESP32 PLC, 12 bit on the Raspberry PLC).

On these, a 4-20 mA transmitter connects through a 500 Ω shunt, such as the IS.ACANTO10-0.5k DIN rail terminal, or through an isolated converter.

Send me the calculation and the code

The form sends your current settings with it. We reply by email with the calculation, the code for your PLC and the wiring, and an engineer reviews them for your project.

Thanks, we have your calculation

An engineer from our team will reply by email with the calculation, the code for your PLC and the wiring. The calculator above keeps your values.