Bridging the gap between hobby electronics and industrial IoT with Arduino requires understanding industrial communication protocols and sensor interfaces. While Arduino is not a replacement for industrial PLCs, it is an excellent platform for learning Modbus RTU, interfacing with 4-20mA sensors, and building prototype data acquisition systems. This guide covers the essential industrial protocols and hardware interfaces you need to connect Arduino to the real world of factory automation.
Table of Contents
- RS485 Communication Basics
- Modbus RTU Protocol Explained
- Implementing Modbus RTU on Arduino
- Reading 4-20mA Industrial Sensors
- Building a Data Acquisition System
- Industrial IoT Network Architecture
- Safety Considerations for Industrial Projects
- Frequently Asked Questions
- Conclusion
RS485 Communication Basics
RS485 is the physical layer standard used in most industrial serial communications. Unlike Arduino’s TTL serial (RS232-like), RS485 uses differential signalling, which provides:
- Long Distance: Up to 1,200 metres (vs ~15 metres for RS232/TTL)
- Noise Immunity: Differential signals reject common-mode electrical noise from motors and machinery
- Multi-drop: Up to 32 devices on a single bus (or 256 with high-impedance receivers)
- Half-duplex: Uses two wires (A and B) for bidirectional communication
RS485 Transceiver Module
To connect Arduino to an RS485 bus, you need a transceiver module based on the MAX485 or SP485 chip. These modules convert between TTL serial (Arduino) and RS485 differential signals.
Wiring an RS485 module to Arduino:
Arduino MAX485 Module
TX (Pin 1) --> DI (Data In)
RX (Pin 0) --> RO (Receiver Out)
Pin 2 --> DE (Driver Enable)
Pin 2 --> RE (Receiver Enable - connect to DE)
5V --> VCC
GND --> GND
RS485 Bus:
A --> Connect to other RS485 devices (A to A)
B --> Connect to other RS485 devices (B to B)
The DE/RE pins control whether the module is transmitting (DE=HIGH, RE=HIGH) or receiving (DE=LOW, RE=LOW). Since this is half-duplex, you switch between modes depending on whether you are sending or receiving data.
Modbus RTU Protocol Explained
Modbus RTU (Remote Terminal Unit) is the most widely used industrial communication protocol. Developed in 1979 by Modicon, it is an open standard supported by virtually every industrial device — PLCs, VFDs, energy meters, sensors, and HMIs.
Modbus Architecture
Modbus uses a master-slave architecture (now called client-server):
- Master (Client): Initiates communication by sending requests. Typically a PLC, SCADA system, or in our case, an Arduino.
- Slave (Server): Responds to requests. Each slave has a unique address (1-247).
Modbus Data Model
| Data Type | Access | Size | Arduino Equivalent |
|---|---|---|---|
| Coils (0xxxx) | Read/Write | 1 bit | Digital output pins |
| Discrete Inputs (1xxxx) | Read Only | 1 bit | Digital input pins |
| Input Registers (3xxxx) | Read Only | 16 bits | analogRead() values |
| Holding Registers (4xxxx) | Read/Write | 16 bits | Setpoint variables |
Common Function Codes
- FC 01: Read Coils
- FC 02: Read Discrete Inputs
- FC 03: Read Holding Registers
- FC 04: Read Input Registers
- FC 05: Write Single Coil
- FC 06: Write Single Register
- FC 16: Write Multiple Registers
Implementing Modbus RTU on Arduino
Arduino as Modbus Master (Reading a Sensor)
Using the ModbusMaster library to read data from an industrial temperature transmitter:
#include
#define MAX485_DE 2
#define MAX485_RE_NEG 2 // Connected together
ModbusMaster sensor;
void preTransmission() {
digitalWrite(MAX485_DE, HIGH);
}
void postTransmission() {
digitalWrite(MAX485_DE, LOW);
}
void setup() {
pinMode(MAX485_DE, OUTPUT);
digitalWrite(MAX485_DE, LOW);
Serial.begin(9600); // Debug serial
Serial1.begin(9600); // RS485 serial (Mega)
sensor.begin(1, Serial1); // Slave address 1
sensor.preTransmission(preTransmission);
sensor.postTransmission(postTransmission);
}
void loop() {
uint8_t result = sensor.readInputRegisters(0x0000, 2);
if (result == sensor.ku8MBSuccess) {
float temperature = sensor.getResponseBuffer(0) / 10.0;
float humidity = sensor.getResponseBuffer(1) / 10.0;
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print(" C, Humidity: ");
Serial.print(humidity);
Serial.println(" %");
} else {
Serial.print("Modbus Error: 0x");
Serial.println(result, HEX);
}
delay(2000);
}
Arduino as Modbus Slave (Exposing Data)
Making Arduino act as a Modbus slave device that a PLC or SCADA system can read:
#include
#define MAX485_DE 2
ModbusRTUSlave modbus(Serial1, MAX485_DE);
uint16_t holdingRegisters[10];
bool coils[10];
void setup() {
Serial1.begin(9600);
modbus.configureHoldingRegisters(holdingRegisters, 10);
modbus.configureCoils(coils, 10);
modbus.begin(1, 9600); // Slave address 1
}
void loop() {
// Update registers with sensor data
holdingRegisters[0] = analogRead(A0); // Raw ADC
holdingRegisters[1] = analogRead(A1);
holdingRegisters[2] = millis() / 1000; // Uptime in seconds
// Read coil states (set by master)
if (coils[0]) {
digitalWrite(8, HIGH); // Master-controlled output
} else {
digitalWrite(8, LOW);
}
modbus.poll(); // Process incoming Modbus requests
}
Reading 4-20mA Industrial Sensors
The 4-20mA current loop is the standard interface for industrial sensors. Unlike voltage-based sensors that lose accuracy over long cable runs due to resistance, current signals are immune to cable length and resistance effects.
Why 4-20mA?
- 4 mA = Zero/Minimum: The “live zero” means 0 mA indicates a broken wire (fault detection), while 4 mA is the actual zero reading.
- 20 mA = Full scale/Maximum: The maximum measurement range.
- Wire break detection: If current drops below 4 mA, the system knows the sensor is disconnected.
- Distance: Works over hundreds of metres without signal degradation.
Converting 4-20mA to Arduino-Readable Voltage
Arduino’s ADC reads voltage (0-5V). To convert a 4-20mA signal, place a precision resistor in series and read the voltage across it:
// 4-20mA to voltage conversion using a 250 ohm resistor
// 4 mA x 250 ohm = 1.0V
// 20 mA x 250 ohm = 5.0V
// Use a 250 ohm (or 249 ohm, nearest standard value) precision resistor
// Connect: Sensor+ --> Arduino Analog Pin --> 250R --> GND
#define SENSOR_PIN A0
#define R_SENSE 250.0 // Sense resistor in ohms
void setup() {
Serial.begin(9600);
analogReference(DEFAULT); // 5V reference
}
void loop() {
int adcValue = analogRead(SENSOR_PIN);
float voltage = adcValue * (5.0 / 1023.0);
float current_mA = (voltage / R_SENSE) * 1000.0;
// Convert 4-20mA to engineering units
// Example: Pressure transmitter 0-10 bar
float pressure = mapFloat(current_mA, 4.0, 20.0, 0.0, 10.0);
Serial.print("Current: ");
Serial.print(current_mA, 2);
Serial.print(" mA, Pressure: ");
Serial.print(pressure, 2);
Serial.println(" bar");
// Fault detection
if (current_mA < 3.8) {
Serial.println("WARNING: Wire break or sensor fault!");
}
delay(1000);
}
float mapFloat(float x, float inMin, float inMax, float outMin, float outMax) {
return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
}
Building a Data Acquisition System
Combine RS485 Modbus and 4-20mA inputs with an ESP32 to create an IoT-enabled data acquisition system that sends data to the cloud:
// Industrial Data Logger with MQTT
// ESP32 + RS485 + 4-20mA inputs
#include
#include
#include
#include
#define MQTT_SERVER "your-mqtt-broker.com"
WiFiClient espClient;
PubSubClient mqtt(espClient);
ModbusMaster sensor;
void setup() {
WiFi.begin("ssid", "password");
mqtt.setServer(MQTT_SERVER, 1883);
Serial2.begin(9600); // RS485 Modbus
sensor.begin(1, Serial2);
}
void loop() {
mqtt.loop();
// Read Modbus sensor
uint8_t result = sensor.readInputRegisters(0, 4);
// Read 4-20mA sensors
float pressure = read420mA(34, 0.0, 10.0);
float level = read420mA(35, 0.0, 100.0);
// Build JSON payload
StaticJsonDocument doc;
if (result == sensor.ku8MBSuccess) {
doc["temperature"] = sensor.getResponseBuffer(0) / 10.0;
doc["humidity"] = sensor.getResponseBuffer(1) / 10.0;
}
doc["pressure"] = pressure;
doc["level"] = level;
doc["timestamp"] = millis();
char buffer[256];
serializeJson(doc, buffer);
mqtt.publish("factory/line1/sensors", buffer);
delay(5000);
}
float read420mA(int pin, float minVal, float maxVal) {
int adc = analogRead(pin);
float voltage = adc * (3.3 / 4095.0);
float current = (voltage / 250.0) * 1000.0;
return mapFloat(current, 4.0, 20.0, minVal, maxVal);
}
Industrial IoT Network Architecture
A typical Industrial IoT architecture has three layers:
Field Level (OT – Operational Technology)
Sensors, actuators, PLCs, and VFDs communicate via RS485 Modbus, PROFINET, or 4-20mA signals. This layer operates in real-time with deterministic timing.
Edge Level (Gateway)
Arduino/ESP32/Raspberry Pi gateways collect data from field devices and translate between industrial protocols (Modbus) and IT protocols (MQTT, HTTP). This is where most Arduino-based projects fit.
Cloud Level (IT – Information Technology)
Cloud platforms (AWS IoT, Azure IoT Hub, ThingsBoard, or self-hosted solutions) store data, run analytics, generate alerts, and provide dashboards. Platforms like Node-RED on a Raspberry Pi can serve as a local cloud for smaller installations.
Safety Considerations for Industrial Projects
Working with industrial equipment involves serious safety risks. Always follow these guidelines:
- Never connect Arduino directly to mains voltage. Use properly rated relay modules, solid-state relays, or optocouplers with appropriate clearance and creepage distances.
- Use galvanic isolation between Arduino and industrial circuits. Optocouplers for digital signals, isolated RS485 transceivers for communication.
- 24V DC is the industrial standard. Use level shifters or voltage dividers when interfacing with 5V/3.3V Arduino logic.
- Industrial certification is required for any equipment installed in production environments. Arduino prototypes are for development and testing only.
- Emergency stop circuits must be hardwired, never software-controlled. A PLC or relay-based safety circuit must override any Arduino-controlled output.
Frequently Asked Questions
Can Arduino handle real industrial Modbus communication?
For prototyping and learning, yes. For production environments, use industrial-grade hardware. Arduino’s timing is not deterministic, and it lacks the electrical protection needed for factory floors. ESP32 with proper shielding is a step up, but certified industrial gateways are recommended for production.
What baud rate should I use for Modbus RTU?
9600 baud is the most common default. Other standard rates include 19200, 38400, and 115200. All devices on the bus must use the same baud rate, parity, and stop bits. The standard format is 9600, 8N1 (8 data bits, no parity, 1 stop bit) or 9600, 8E1 (even parity).
How long can an RS485 cable be?
Up to 1,200 metres at 9600 baud. Higher baud rates reduce the maximum distance. Use twisted-pair cable (Cat5e works well) and add 120-ohm termination resistors at both ends of the bus for cable lengths over 100 metres.
What is the difference between Modbus RTU and Modbus TCP?
Modbus RTU uses serial communication (RS485/RS232) with binary framing. Modbus TCP uses Ethernet with the same register model but TCP/IP framing. Modbus TCP is easier to implement on ESP32/Raspberry Pi and does not require RS485 hardware.
Can I mix 4-20mA sensors with Modbus sensors on the same system?
Absolutely. Many industrial systems combine both. Use Arduino’s analogue inputs for 4-20mA sensors and a serial port with RS485 transceiver for Modbus devices. This is exactly how many industrial data loggers work.
Conclusion
Industrial IoT with Arduino is an excellent learning pathway for understanding how real factories collect and process data. RS485 Modbus RTU and 4-20mA current loops are the foundation of industrial communication, and mastering them on Arduino prepares you for working with professional-grade systems.
Start with simple Modbus master/slave communication, add 4-20mA sensor reading, then build towards a complete data acquisition gateway with cloud connectivity. The skills you develop transfer directly to careers in industrial automation and IoT.
Browse our selection of development boards and electronic components at Zbotic to build your industrial IoT prototype.
Add comment