4-20 mA signal measurement with Arduino

In this video I show you how to measure the output signal of a 4-20 mA-type sensor and convert it into some values using an Arduino. You will learn how to build a "current to voltage" circuit with a simple protection (Zener diode) and you will also learn how you can customize my source code to convert the signal of any sensor into a human-readable format.



Drawings and schematics

Simulation of the circuit at 20 mA current using a 250 Ohm resistor. The drawing and simulation was made using Circuit Lab.

Simulation of the circuit at 20 mA current using a 250 Ohm resistor. The drawing and simulation was made using Circuit Lab.

KiCAD drawing of the same circuit as above. As a side note, I saw some discussions on the internet where people are questioning the use of a Zener diode as its leakage current can manipulate the analog signals.

KiCAD drawing of the same circuit as above. As a side note, I saw some discussions on the internet where people are questioning the use of a Zener diode as its leakage current can manipulate the analog signals.



Arduino source code

//Arduino Nano; SDA = A4, SCL = A5
#include <Wire.h>

//--Display---------------------------------------------
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

float Current = 0; //4-20 mA (mapped)
float rawADCValue = 0; //0-1023
float ADCVoltage = 0; //0-5 V
float pressure = 0; //0-250 bar (mapped)
int ADC_Pin = A1;

void setup()
{
  Serial.begin(115200);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
  {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Don't proceed, loop forever
  }

  display.display();

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextSize(2);
  display.clearDisplay();     // Clear display
  display.setCursor(0, 0);    // Start at top-left corner
  display.print("0.00");
  display.display();
  display.clearDisplay();

}

void loop()
{
  readADC();
  printLCD();
}

void readADC()
{
  rawADCValue = 0; //Reset the value before summation

  for (int i = 0; i < 100; i++) //Do 100 readings
  {
    rawADCValue += analogRead(ADC_Pin);
    delay(5); //"settling time" for the ADC
    //Sum the results 100 times
  }

  ADCVoltage = (float)(rawADCValue / 100.0) * (4630 / 1023.0); //The average is converted into voltage (5000 mV = 5 V)
  //measure the real 5 V of your board and substitute the result (mine was 4630 mV)
  Serial.print("RAW: ");
  Serial.println((rawADCValue / 100.0));
  Serial.print("Voltage: ");
  Serial.println(ADCVoltage);

  //For 220 Ohm: 4 mA * 220 Ohm = 880 mV, 20 mA * 220 Ohm = 4400 mV
  //For 250 Ohm: 4 mA * 250 Ohm = 1000 mV, 20 mA * 250 Ohm = 5000 mV
  //Note: measure the 220 (or 250) resistor, and calculate the actual voltages
  Current = mapfloat(ADCVoltage, 880, 4400, 4, 20);
  // Voltage between 880-4400 mV is distributed as current 4-20 mA
  //2640 mV should be 12 mA equivalent
  Serial.print("Current: ");
  Serial.println(Current);

  pressure = mapfloat(Current, 4, 20, 0, 250);
  Serial.print("Pressure: ");
  Serial.println(pressure);
  //Current between 4-20 mA is distributed as pressure between 0-250 bar.
  //12 mA should be 125 bar equivalent
}

void printLCD()
{
  display.clearDisplay();
  display.setTextSize(3);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(ADCVoltage); //Print the voltage (in mV)
  display.setCursor(0, 40);
  display.println(Current); //Print the corresponding current
  display.display();
}

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Previous
Previous

Building a coil winder [Part 7] - New electronics

Next
Next

Building a coil winder [Part 6] - A few improvements