Wiznet makers

Lihan__

Published February 26, 2026 ©

36 UCC

8 WCC

3 VAR

0 Contests

0 Followers

0 Following

Original Link

Modbus_server_slave_ESP32

ESP32'en fungerer som en dual-mode Modbus gateway med to separate RS-485 interfaces:

COMPONENTS
PROJECT DESCRIPTION

https://github.com/Jangreenlarsen/ModbuESP32 Dual-Mode Modbus Gateway with IEC 61131-3 ST Logic Engine

Industrial-Grade Modbus RTU Server/Slave with Structured Text PLC Programming


ENGLISH VERSION

1. Introduction: Industrial Automation and Modbus Protocol

Modbus RTU is the de facto standard for industrial serial communication, connecting PLCs, SCADA systems, sensors, and actuators in manufacturing environments worldwide. Since its introduction by Modicon in 1979, Modbus has become ubiquitous due to its simplicity, royalty-free specification, and universal vendor support.

Why Modbus Matters in Modern Industry:

  • Universal Compatibility: Every major automation vendor supports Modbus (Siemens, Allen-Bradley, Schneider, ABB, WAGO)
  • Cost-Effective: No licensing fees, open specification, minimal hardware requirements
  • Proven Reliability: 45+ years of field deployment in harsh industrial environments
  • Flexible Topology: Point-to-point, multi-drop, and Ethernet

gateway configurations

  • Real-Time Performance: Deterministic response times suitable for process control

This project implements a dual-mode Modbus gateway on ESP32-WROOM-32, functioning simultaneously as:

  • Modbus Slave (UART0): Accepts commands from SCADA/HMI systems
  • Modbus Master (UART1): Controls remote I/O devices and sensors

Additionally, it integrates a full IEC 61131-3 Structured Text (ST) programming environment, enabling PLC-like logic execution directly on the microcontroller.

2. Technical Challenge: Why Dual-Mode Architecture?

Traditional industrial automation architectures suffer from rigid hierarchies:

ArchitectureLimitations
Centralized PLCSingle point of failure; expensive hardware; limited I/O expansion
Distributed I/ORequires proprietary fieldbus; vendor lock-in; complex configuration
Gateway + PLCTwo devices increase cost; redundant processing; communication overhead

The Problem:

Most Modbus implementations force a choice: operate as either a slave (controlled by SCADA) or a master (controlling field devices). This creates a three-tier architecture: SCADA → Gateway/PLC → Field Devices, requiring multiple hardware units and increasing points of failure.

The Solution: Dual-Mode Gateway with Embedded Logic

This project collapses the traditional three-tier architecture into a single ESP32 microcontroller by:

  1. Dual Modbus Interfaces: Separate RS-485 transceivers on UART0 (slave mode) and UART1 (master mode) enable simultaneous bidirectional communication
  2. Embedded ST Logic Engine: IEC 61131-3 compliant Structured Text interpreter executes PLC logic directly on the ESP32, eliminating the need for external PLC hardware
  3. Hardware-Accelerated Counters: ESP32 Pulse Counter Units (PCNT) handle high-frequency counting (up to 40MHz) without CPU intervention
  4. Persistent Data Storage: NVS (Non-Volatile Storage) preserves configuration, logic programs, and process data across power cycles

Result: A $10 microcontroller replaces $500+ of traditional automation hardware while maintaining industrial-grade reliability.

3. Hardware Architecture: ESP32-WROOM-32 and Dual RS-485 Interfaces

Component Selection Rationale:

ESP32-WROOM-32 Microcontroller:

  • Dual-core Xtensa LX6 @ 240MHz: Sufficient computational power for real-time Modbus protocol handling, ST bytecode execution, and simultaneous WiFi operations
  • 520KB SRAM: Accommodates ST logic programs (max 2KB source per program × 4 programs), Modbus register maps (256 registers × 2 bytes × 4 types = 2KB), and TCP/IP stack
  • 4MB Flash: Stores compiled ST bytecode, persistent configuration (NVS), and OTA firmware updates
  • Three Hardware UARTs: UART0 (Modbus Slave), UART1 (Modbus Master), UART2 (USB debug console)
  • Eight PCNT Units: Hardware pulse counters for high-frequency encoder inputs without CPU overhead

Dual RS-485 Transceivers:

  • UART0 Interface (Modbus Slave):
    • TX: GPIO16, RX: GPIO17, DE/RE: GPIO15
    • Function: ESP32 operates as Modbus Slave (device ID 1-247)
    • Use case: SCADA/HMI systems read/write process data (counters, timers, ST variables)
  • UART1 Interface (Modbus Master):
    • TX: GPIO25, RX: GPIO26, DE/RE: GPIO27
    • Function: ESP32 operates as Modbus Master
    • Use case: Poll remote temperature sensors, control relay boards, expand distributed I/O

Memory Management Strategy:

The system uses a hybrid memory model optimized for real-time performance:

  • SRAM Allocation:
    • Modbus register buffers: 2KB (static allocation)
    • ST bytecode cache: 4KB (4 programs × 1KB max)
    • TCP/IP stack: ~40KB (ESP-IDF lwIP)
    • Application heap: ~200KB remaining
  • Flash Storage:
    • Firmware: ~835KB
    • ST source code: SPIFFS filesystem (persistent)
    • NVS partition: 64KB (configuration + persistent registers)

4. Core System Components

A. Modbus Slave Interface (UART0) - SCADA Integration

The Modbus Slave interface enables external SCADA/HMI systems to monitor and control the ESP32 as if it were a traditional PLC or RTU (Remote Terminal Unit).

Protocol Implementation:

  • Supported Function Codes:
    • FC01: Read Coils (digital outputs)
    • FC02: Read Discrete Inputs (digital inputs)
    • FC03: Read Holding Registers (read/write data)
    • FC04: Read Input Registers (read-only process data)
    • FC05: Write Single Coil
    • FC06: Write Single Register
    • FC0F (15): Write Multiple Coils
    • FC10 (16): Write Multiple Registers
  • CRC16-CCITT Validation: Every Modbus frame is validated with CRC before processing
  • Timeout Handling: 3.5 character times (baudrate-adaptive, per Modbus RTU specification)
  • Error Responses: Illegal function, illegal address, illegal data value exceptions

Register Map Organization:

The system provides 1024 data points organized into four memory areas:

Memory AreaAddress RangeAccessPurpose
Holding Registers (HR)0-255Read/WriteProcess data, setpoints, configuration
Input Registers (IR)0-255Read-OnlySensor readings, calculated values, status
Coils0-255Read/WriteDigital outputs, control bits
Discrete Inputs0-255Read-OnlyDigital inputs, status flags

Auto-Mapped System Resources:

The system automatically exposes internal state to Modbus:

  • Counters: HR100-170 (4 counters × 15 registers each)
    • Value (scaled), Raw count, Frequency (Hz), Control/Status, Compare threshold
  • Timers: HR180-210 (4 timers × 8 registers each)
    • Current phase, Elapsed time, Control register, Output state
  • ST Logic Variables: IR220-251 (exported variables from ST programs)
    • Variables marked with EXPORT keyword automatically map to Input Registers
    • Type-aware: INT (1 register), DINT (2 registers), REAL (2 registers)

Configuration via CLI:

set modbus-slave id:1 baudrate:9600 parity:none stopbits:1
show modbus-slave  # Display current configuration

B. Modbus Master Interface (UART1) - Remote Device Control

The Modbus Master interface enables the ESP32 to initiate communication with external Modbus slave devices, effectively functioning as a PLC that can read sensors and write to actuators.

Protocol Implementation:

  • Supported Function Codes: FC01-FC06 (Read Coils/Inputs/Registers, Write Coil/Register)
  • Configurable Serial Parameters: Baudrate (300-115200), Parity (None/Even/Odd), Stop bits (1/2)
  • Timeout Management: Configurable timeout (default: 500ms)
  • Rate Limiting: Max 10 requests per ST execution cycle (prevents bus overload)

ST Logic Integration (Built-in Functions):

The Modbus Master functionality is exposed to ST programs through six built-in functions:

Read Functions:

MB_READ_COIL(slave_id, address) → BOOL
MB_READ_INPUT(slave_id, address) → BOOL
MB_READ_HOLDING(slave_id, address) → INT
MB_READ_INPUT_REG(slave_id, address) → INT

Write Functions (Assignment-Based Syntax):

MB_WRITE_COIL(slave_id, address) := boolean_value
MB_WRITE_HOLDING(slave_id, address) := int_value

Type Conversion Support:

The functions support automatic type conversion for flexibility:

  • slave_id & address: Accept INT, DINT, DWORD (auto-clamped to valid range)
  • MB_WRITE_COIL value: Accepts BOOL, INT, REAL, DINT, DWORD (non-zero → TRUE)
  • MB_WRITE_HOLDING value: Accepts INT, REAL, DINT, DWORD (auto-converted to 16-bit)

Global Status Variables:

mb_last_error (INT)   (* 0=OK, 1=TIMEOUT, 2=CRC, 3=EXCEPTION, 4=MAX_REQ, 5=DISABLED *)
mb_success (BOOL)     (* TRUE if last operation succeeded *)

Real-World Example: Temperature Control System

VAR
  remote_temp: INT;        (* Temperature from slave ID 5, HR#100 *)
  heating_on: BOOL;
  setpoint: INT := 20;
END_VAR

BEGIN
  (* Read temperature sensor *)
  remote_temp := MB_READ_HOLDING(5, 100);

  (* Control decision based on sensor reading *)
  IF mb_success THEN
    IF remote_temp < setpoint THEN
      MB_WRITE_COIL(3, 20) := TRUE;   (* Slave 3, Coil 20: Heater ON *)
    ELSE
      MB_WRITE_COIL(3, 20) := FALSE;  (* Heater OFF *)
    END_IF;
  END_IF;
END

C. Counter Engine - Hardware Pulse Counting

The counter engine provides three distinct hardware modes for pulse counting applications:

Mode 1: Software Polling (SW)

  • Mechanism: GPIO pin read in main loop (~1ms polling rate)
  • Edge Detection: Software-based level change tracking
  • Max Frequency: ~500Hz (limited by loop execution rate)
  • CPU Overhead: Low (periodic polling)
  • Use Case: Low-frequency events (door contacts, limit switches)

Mode 2: Software ISR (SW-ISR)

  • Mechanism: GPIO interrupt-driven counting
  • Edge Detection: Rising, falling, or both edges (configurable)
  • Max Frequency: ~10kHz
  • CPU Overhead: Medium (interrupt service routine)
  • Use Case: Mid-frequency events (flow meters, RPM sensors)

Mode 3: Hardware PCNT (HW)

  • Mechanism: ESP32 Pulse Counter Unit (dedicated hardware)
  • Counting Range: 32-bit (±2,147,483,647)
  • Max Frequency: 40MHz (hardware specification limit)
  • CPU Overhead: Zero (fully hardware-accelerated)
  • Prescaler: Hardware divider (1-65535)
  • Use Case: High-frequency encoders, shaft encoders, high-speed pulse trains

Advanced Features:

  • Scaling: Prescaler (hardware) + Scale factor (software float multiplier)
  • Bit Width: 8/16/32/64-bit output (multi-register support for large values)
  • Direction Control: Bidirectional counting (up/down)
  • Frequency Measurement: Real-time Hz calculation (1-second update rate)
  • Compare Threshold: Configurable threshold with edge detection (≥, >, ==)
    • Outputs trigger signal to Control Register bit 4
    • Runtime-modifiable via Modbus FC06 Write Single Register

Register Layout (per counter):

Counter 1: HR100-114 (15 registers)
  HR100-101: Scaled Value (32-bit, LSW first)
  HR104-105: Raw Value (32-bit prescaled count)
  HR108:     Frequency (Hz)
  HR110:     Control/Status Register
             - Bit 0: Reset (write 1 to reset, auto-clears)
             - Bit 1: Start (write 1 to start, auto-clears)
             - Bit 2: Running status (read-only)
             - Bit 3: Overflow flag (read-only)
             - Bit 4: Compare match (read-only)
  HR111-112: Compare Threshold (32-bit, runtime writable)

D. Timer Engine - Deterministic Timing Control

The timer engine provides four distinct operating modes for time-based control:

Mode 1: One-Shot (3-Phase Sequencer)

  • Application: Sequential operations (valve actuation, batch processes)
  • Behavior: Three configurable phases, each with duration and output state
  • Trigger: Control register bit 1 (start command)
  • Example: Phase 1: Fill tank (30s, output HIGH) → Phase 2: Mix (60s, output LOW) → Phase 3: Drain (20s, output HIGH)

Mode 2: Monostable (Retriggerable Pulse)

  • Application: Pulse stretching, watchdog timing, event detection
  • Behavior: Single pulse output, extends on re-trigger
  • Timing: 1ms to 4,294,967,295ms (49 days maximum)
  • Example: Convert short button press to 5-second relay pulse

Mode 3: Astable (Oscillator/Blink)

  • Application: LED blinking, PWM simulation, periodic polling
  • Behavior: Continuous toggle between ON/OFF states
  • Configuration: Independent ON duration and OFF duration
  • Example: Heartbeat LED (500ms ON, 500ms OFF)

Mode 4: Input-Triggered (Edge-Responsive)

  • Application: Delayed alarm response, debounced input processing
  • Behavior: Monitors discrete input for edge, delays action
  • Trigger Edge: Rising (0→1) or falling (1→0), configurable
  • Delay: 0ms to 4,294,967,295ms after edge detection
  • Example: Trigger alarm 10 seconds after door contact opens

Timing Precision: ±1ms accuracy using ESP32 millis() hardware timer.

E. ST Logic Engine - IEC 61131-3 Structured Text Programming

The ST Logic Engine is a full IEC 61131-3 compliant interpreter that executes PLC-style programs directly on the ESP32.

Language Features:

  • Data Types: INT (16-bit), DINT (32-bit), REAL (float), BOOL, DWORD
  • Type Conversion: Explicit functions (INT_TO_REAL, REAL_TO_INT, BOOL_TO_INT, DWORD_TO_INT)
  • Operators: Arithmetic (+, -, *, /, MOD), Logical (AND, OR, NOT, XOR), Comparison (=, <>, <, >, <=, >=)
  • Control Flow: IF/THEN/ELSIF/ELSE, WHILE, FOR, REPEAT/UNTIL, CASE
  • Variable Sections:
    • VAR_INPUT: Read-only inputs (bound to Modbus registers)
    • VAR_OUTPUT: Write-only outputs
    • VAR: Persistent internal variables

Built-in Function Library (60+ Functions):

Mathematical Functions:

ABS(x)           (* Absolute value *)
SQRT(x)          (* Square root *)
MIN(a, b)        (* Minimum of two values *)
MAX(a, b)        (* Maximum of two values *)
SUM(a, b, ...)   (* Sum of multiple values *)
LIMIT(min, val, max) (* Clamp value to range *)

Trigonometric Functions:

SIN(x)           (* Sine (radians) *)
COS(x)           (* Cosine (radians) *)
TAN(x)           (* Tangent (radians) *)

Exponential Functions:

EXP(x)           (* e^x *)
LN(x)            (* Natural logarithm *)
LOG(x)           (* Base-10 logarithm *)
POW(base, exp)   (* base^exponent *)

IEC 61131-3 Timers:

TON(IN, PT, Q, ET)   (* On-delay timer *)
TOF(IN, PT, Q, ET)   (* Off-delay timer *)
TP(IN, PT, Q, ET)    (* Pulse timer *)

IEC 61131-3 Counters:

CTU(CU, R, PV, Q, CV)   (* Count-up *)
CTD(CD, LD, PV, Q, CV)  (* Count-down *)
CTUD(CU, CD, R, LD, PV, QU, QD, CV) (* Up/down counter *)

Edge Detection:

R_TRIG(CLK, Q)   (* Rising edge detector *)
F_TRIG(CLK, Q)   (* Falling edge detector *)

Latches (SR/RS Flip-Flops):

SR(S, R1, Q1)    (* Set-dominant latch *)
RS(S1, R, Q1)    (* Reset-dominant latch *)

Signal Processing:

SCALE(val, in_min, in_max, out_min, out_max) (* Linear scaling *)
HYSTERESIS(val, low, high)                    (* Hysteresis comparator *)
BLINK(period)                                 (* Oscillator *)
FILTER(val, time_constant)                    (* Low-pass filter *)

User-Defined Functions (FEAT-003, v6.1.0):

IEC 61131-3 compliant user functions and function blocks:

FUNCTION (Stateless):

FUNCTION DOUBLE : INT
VAR_INPUT val : INT; END_VAR
BEGIN
  DOUBLE := val * 2;  (* Return via function name *)
END_FUNCTION

FUNCTION_BLOCK (Stateful):

FUNCTION_BLOCK INTEGRATOR
VAR_INPUT en : BOOL; value : REAL; END_VAR
VAR_OUTPUT sum : REAL; END_VAR
VAR state : REAL; END_VAR  (* Persistent between calls *)
BEGIN
  IF en THEN state := state + value; END_IF;
  sum := state;
END_FUNCTION_BLOCK

Capabilities:

  • Max 16 user-defined functions per program
  • Max 16 function block instances per program
  • Max 8 parameters per function
  • Max 16 local variables per function
  • Max 8 nested function calls (recursion stack)

Compiler Architecture:

  1. Lexical Analysis: Source code tokenized into keywords, identifiers, operators, literals
  2. Syntax Parsing: Tokens validated against IEC 61131-3 grammar
  3. Semantic Analysis: Type checking, variable binding, function resolution
  4. Bytecode Generation: Compiled to stack-based bytecode (max 1KB per program)
  5. Real-Time Execution: Bytecode interpreter runs at fixed 10ms cycle (configurable to 20/25/50/75/100ms)

Performance Monitoring:

Every ST program tracks execution statistics:

  • Min/Max/Avg Execution Time: Microsecond precision
  • Cycle Overruns: Count of executions exceeding target interval
  • Performance Rating: EXCELLENT/GOOD/ACCEPTABLE/POOR with auto-recommendations
  • Modbus Access: Statistics readable via IR252-293

Interactive Debugger (v5.3.0):

  • Pause/Continue: Halt program execution at any point
  • Single-Step: Execute one bytecode instruction at a time
  • Breakpoints: Set up to 8 breakpoints per program at PC addresses
  • Variable Inspection: View all variable values when paused
  • CLI Commands: set logic <id> debug pause, step, continue, stop

5. Network Communication: WiFi and HTTP REST API

WiFi Client Mode:

  • DHCP Support: Automatic IP assignment from router
  • Static IP Support: Manual IP, gateway, netmask, DNS configuration
  • WPA/WPA2 Authentication: Password-protected networks (8-63 character passwords)
  • Auto-Reconnect: Automatic reconnection on disconnect

Telnet Server (Port 23):

  • Authentication: Optional username/password
  • Line Editing: Arrow keys for cursor movement, command history
  • Concurrent Connections: 1 simultaneous client
  • Graceful Disconnect: exit command

HTTP REST API (Port 80):

Provides JSON-based RESTful API for integration with Node-RED, web dashboards, and third-party systems:

Endpoints:

GET  /api/status              (* System status *)
GET  /api/counters            (* All counter values *)
GET  /api/counters/<id>       (* Specific counter *)
GET  /api/timers              (* All timer values *)
GET  /api/registers/hr/<addr> (* Read holding register *)
POST /api/registers/hr/<addr> (* Write holding register *)
GET  /api/registers/ir/<addr> (* Read input register *)
GET  /api/coils/<addr>        (* Read coil *)
POST /api/coils/<addr>        (* Write coil *)

Authentication: Optional HTTP Basic Auth

Example (Node-RED Integration):

// Read temperature from HR100
GET http://192.168.1.100/api/registers/hr/100
Response: {"address": 100, "value": 2350, "type": "holding"}

// Write setpoint to HR200
POST http://192.168.1.100/api/registers/hr/200
Body: {"value": 2500}
Response: {"success": true, "address": 200, "value": 2500}

Configuration Backup/Restore (v6.0.7):

Full configuration backup and restore via HTTP API:

# Download backup (includes ALL settings: Modbus, WiFi, counters, timers, ST source)
curl -u api_user:password http://192.168.1.100/api/system/backup -o backup.json

# Restore from backup
curl -u api_user:password -X POST \
     -H "Content-Type: application/json" \
     -d @backup.json \
     http://192.168.1.100/api/system/restore

Backup includes: Modbus config, network settings (including passwords), counters, timers, GPIO mappings, persistent register groups, and ST Logic source code (plain text, auto-compiled on restore).

6. Persistent Data System

NVS (Non-Volatile Storage) Configuration

The ESP32's NVS partition preserves critical configuration across power cycles:

  • Storage Size: 64KB NVS partition
  • Data Integrity: CRC16-CCITT checksum validation on every read
  • Schema Migration: Automatic upgrade from older config versions (v5 → v8)
  • Auto-Load on Boot: Configuration loaded before main loop execution

Saved Configuration:

  • Modbus slave ID, baudrate, parity, stop bits
  • System hostname (max 31 characters)
  • WiFi SSID, password, static IP configuration, telnet credentials
  • All 4 counter configurations (mode, GPIO, prescaler, scale, compare)
  • All 4 timer configurations (mode, durations, output coils)
  • All 4 ST Logic programs (source code + compiled bytecode)
  • GPIO mappings (64 slots: discrete inputs → GPIO pins, coils → GPIO outputs)

Persistent Registers (Runtime Data Preservation)

Unlike the NVS configuration (which saves static settings), the Persistent Registers system provides runtime-controlled data preservation for process data that must survive power cycles.

Use Cases:

  • Calibration coefficients (sensor offset, scale factor, linearization)
  • Production counters (total parts manufactured, batch count)
  • Recipe setpoints (temperature, pressure, flow rate)
  • Last known good configuration backup

Architecture:

  • Groups: Up to 8 named groups, each containing up to 16 holding registers
  • Selective Persistence: Save/restore specific groups or all groups
  • Runtime Control: Trigger saves from ST Logic programs or CLI
  • Auto-Load on Boot: Configured groups automatically restore at startup

ST Logic Integration:

SAVE(group_id) → INT   (* 0=all groups, 1-8=specific group; returns 0=OK, -1=error, -2=rate_limit *)
LOAD(group_id) → INT   (* 0=all groups, 1-8=specific group; returns 0=OK, -1=error *)

Example: Production Counter with Periodic Save

VAR
  total_parts: DINT;
  last_save_count: DINT;
  save_result: INT;
END_VAR

BEGIN
  (* Save every 100 parts to group #2 "production" *)
  IF (total_parts - last_save_count) >= 100 THEN
    save_result := SAVE(2);
    IF save_result = 0 THEN
      last_save_count := total_parts;
    END_IF;
  END_IF;
END

Rate Limiting: Max 1 save per 5 seconds (prevents excessive NVS wear, ~100k write cycle limit).

7. Comparison with Traditional PLC Architecture

Traditional Architecture (Three-Tier):

SCADA/HMI System
    ↕ Modbus TCP/RTU
Industrial PLC ($500-2000)
    - Proprietary IDE
    - Limited I/O (expansion modules expensive)
    - Closed ecosystem
    ↕ Modbus RTU
Remote I/O Modules ($100-500 each)
    - Temperature sensors
    - Relay boards
    - Analog inputs

This Project (Single-Tier):

SCADA/HMI System
    ↕ Modbus RTU (UART0)
ESP32 Gateway ($10)
    - Open-source ST Logic IDE
    - 4 hardware counters (40MHz)
    - 4 timers (microsecond precision)
    - WiFi + HTTP REST API
    - IEC 61131-3 compliant
    ↕ Modbus RTU (UART1)
Remote I/O Modules

Key Advantages:

  • Cost Reduction: 95% lower hardware cost vs traditional PLC
  • Single Point of Integration: One device replaces gateway + PLC
  • Open Architecture: No vendor lock-in, fully programmable via ST Logic
  • Modern Connectivity: Built-in WiFi, HTTP REST API for IoT integration
  • Rapid Development: Upload ST programs via telnet/serial in seconds (no proprietary IDE licensing)

Key Difference: ESP32 Integration vs Multi-Chip Solutions

Unlike Arduino + W5500 Ethernet Shield (two chips communicating via SPI bus), ESP32 integrates dual hardware UARTs on a single die, eliminating SPI bus bottlenecks and reducing board complexity.

8. Conclusion and Industrial Applications

Technical Achievements:

  • Zero-Dependency ST Implementation: Pure C++ IEC 61131-3 interpreter with no external libraries
  • Hardware-Accelerated Counting: ESP32 PCNT units handle 40MHz pulse trains without CPU intervention
  • Dual-Mode Modbus: Simultaneous slave + master operation on separate RS-485 buses
  • Real-Time Determinism: Fixed 10ms execution cycle (±1ms jitter) for predictable control response

Practical Applications:

  • Manufacturing Automation: Replace traditional PLCs in cost-sensitive applications (packaging machines, conveyors, assembly lines)
  • Building Management: HVAC control, lighting automation, access control integration
  • Process Control: Chemical batch reactors, water treatment, food processing
  • Energy Monitoring: Power metering, load shedding, demand response
  • IoT Gateway: Bridge legacy Modbus devices to modern cloud platforms (MQTT, HTTP)

Real-World Deployment Example:

Packaging Machine Control System
├─ SCADA (Modbus Slave UART0) ← Operator HMI
│  - Monitor production rate (counter frequency)
│  - Adjust setpoints (fill volume, speed)
│  - View alarms and diagnostics
│
├─ ESP32 Gateway (ST Logic Engine)
│  - Production counter logic (parts per minute calculation)
│  - Quality control (reject defective parts)
│  - Recipe management (load/save persistent setpoints)
│
└─ Field Devices (Modbus Master UART1)
   ├─ Proximity sensors (Slave ID 1-4)
   ├─ Servo drives (Slave ID 10-12)
   └─ Weight scale (Slave ID 20)

Final Thoughts: By combining Modbus RTU protocol with IEC 61131-3 Structured Text programming and hardware-accelerated peripherals, this project demonstrates that industrial-grade automation is achievable on low-cost microcontrollers. The open architecture scales from single-machine control to distributed factory automation, providing a foundation for modern IoT-enabled manufacturing.

Technical Specifications

ComponentSpecification
MCUESP32-WROOM-32 (Dual-core Xtensa LX6 @ 240MHz)
Memory520KB SRAM + 4MB Flash
Modbus InterfacesDual RS-485 (UART0 Slave + UART1 Master)
Counters4× hardware counters (SW/ISR/PCNT modes, max 40MHz)
Timers4× timers (One-shot/Monostable/Astable/Input-triggered)
ST Logic4× programs, IEC 61131-3 compliant, 60+ builtin functions
NetworkingWiFi 802.11 b/g/n, Telnet, HTTP REST API
StorageNVS (64KB config) + SPIFFS (ST source code)
DevelopmentPlatformIO, C++17, Open-source

References

  • IEC 61131-3 Structured Text Specification: https://www.plcopen.org/iec-61131-3
  • Modbus RTU Protocol: https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf
  • ESP32 Technical Reference: https://www.espressif.com/en/products/socs/esp32
  • Project Repository: https://github.com/Jangreenlarsen/Modbus_server_slave_ESP32

한국어 버전

1. 서론: 산업 자동화와 Modbus 프로토콜

Modbus RTU는 산업용 직렬 통신의 사실상 표준으로, 전 세계 제조 환경에서 PLC, SCADA 시스템, 센서 및 액추에이터를 연결합니다. 1979년 Modicon이 도입한 이후 Modbus는 단순성, 무료 사용 규격 및 범용 공급업체 지원으로 인해 유비쿼터스화되었습니다.

산업에서 Modbus가 중요한 이유:

  • 범용 호환성: 모든 주요 자동화 공급업체가 Modbus를 지원 (Siemens, Allen-Bradley, Schneider, ABB, WAGO)
  • 비용 효율성: 라이선스 비용 없음, 공개 사양, 최소한의 하드웨어 요구사항
  • 검증된 신뢰성: 45년 이상 가혹한 산업 환경에서의 현장 배포
  • 유연한 토폴로지: 점대점, 멀티드롭 및 이더넷 게이트웨이 구성
  • 실시간 성능: 프로세스 제어에 적합한 결정적 응답 시간

이 프로젝트는 ESP32-WROOM-32에서 이중 모드 Modbus 게이트웨이를 구현하며, 동시에 다음 기능을 수행합니다:

  • Modbus Slave (UART0): SCADA/HMI 시스템의 명령 수신
  • Modbus Master (UART1): 원격 I/O 장치 및 센서 제어

또한 완전한 IEC 61131-3 Structured Text (ST) 프로그래밍 환경을 통합하여 마이크로컨트롤러에서 직접 PLC와 같은 로직 실행을 가능하게 합니다.

2. 기술적 과제: 이중 모드 아키텍처가 필요한 이유

전통적인 산업 자동화 아키텍처는 경직된 계층 구조로 고통받고 있습니다:

아키텍처한계
중앙 집중식 PLC단일 장애점; 비싼 하드웨어; 제한된 I/O 확장
분산 I/O독점 필드버스 필요; 공급업체 종속; 복잡한 구성
게이트웨이 + PLC두 장치로 비용 증가; 중복 처리; 통신 오버헤드

문제점:

대부분의 Modbus 구현은 선택을 강요합니다: 슬레이브로 작동(SCADA에 의해 제어) 또는 마스터로 작동(현장 장치 제어). 이는 3계층 아키텍처를 생성합니다: SCADA → 게이트웨이/PLC → 현장 장치, 여러 하드웨어 유닛이 필요하고 장애 지점이 증가합니다.

해결책: 임베디드 로직이 있는 이중 모드 게이트웨이

이 프로젝트는 단일 ESP32 마이크로컨트롤러에서 전통적인 3계층 아키텍처를 축소합니다:

  1. 이중 Modbus 인터페이스: UART0(슬레이브 모드)와 UART1(마스터 모드)의 별도 RS-485 트랜시버가 동시 양방향 통신 가능
  2. 임베디드 ST 로직 엔진: IEC 61131-3 호환 Structured Text 인터프리터가 ESP32에서 직접 PLC 로직 실행, 외부 PLC 하드웨어 불필요
  3. 하드웨어 가속 카운터: ESP32 펄스 카운터 유닛(PCNT)이 CPU 개입 없이 고주파 카운팅(최대 40MHz) 처리
  4. 영구 데이터 저장: NVS(비휘발성 저장소)가 전원 사이클에 걸쳐 구성, 로직 프로그램 및 프로세스 데이터 보존

결과: $10 마이크로컨트롤러가 $500+ 이상의 전통적인 자동화 하드웨어를 대체하면서 산업 등급 신뢰성 유지.

3. 하드웨어 아키텍처: ESP32-WROOM-32와 이중 RS-485 인터페이스

구성 요소 선택 근거:

ESP32-WROOM-32 마이크로컨트롤러:

  • 듀얼 코어 Xtensa LX6 @ 240MHz: 실시간 Modbus 프로토콜 처리, ST 바이트코드 실행 및 동시 WiFi 작업을 위한 충분한 계산 능력
  • 520KB SRAM: ST 로직 프로그램(프로그램당 최대 2KB 소스 × 4 프로그램), Modbus 레지스터 맵(256 레지스터 × 2 바이트 × 4 유형 = 2KB) 및 TCP/IP 스택 수용
  • 4MB Flash: 컴파일된 ST 바이트코드, 영구 구성(NVS) 및 OTA 펌웨어 업데이트 저장
  • 3개의 하드웨어 UART: UART0(Modbus Slave), UART1(Modbus Master), UART2(USB 디버그 콘솔)
  • 8개의 PCNT 유닛: CPU 오버헤드 없이 고주파 엔코더 입력을 위한 하드웨어 펄스 카운터

이중 RS-485 트랜시버:

  • UART0 인터페이스 (Modbus Slave):
    • TX: GPIO16, RX: GPIO17, DE/RE: GPIO15
    • 기능: ESP32가 Modbus Slave로 작동 (장치 ID 1-247)
    • 사용 사례: SCADA/HMI 시스템이 프로세스 데이터(카운터, 타이머, ST 변수) 읽기/쓰기
  • UART1 인터페이스 (Modbus Master):
    • TX: GPIO25, RX: GPIO26, DE/RE: GPIO27
    • 기능: ESP32가 Modbus Master로 작동
    • 사용 사례: 원격 온도 센서 폴링, 릴레이 보드 제어, 분산 I/O 확장

메모리 관리 전략:

시스템은 실시간 성능을 위해 최적화된 하이브리드 메모리 모델을 사용합니다:

  • SRAM 할당:
    • Modbus 레지스터 버퍼: 2KB (정적 할당)
    • ST 바이트코드 캐시: 4KB (4 프로그램 × 최대 1KB)
    • TCP/IP 스택: ~40KB (ESP-IDF lwIP)
    • 애플리케이션 힙: ~200KB 남음
  • Flash 저장소:
    • 펌웨어: ~835KB
    • ST 소스 코드: SPIFFS 파일 시스템 (영구)
    • NVS 파티션: 64KB (구성 + 영구 레지스터)

4. 핵심 시스템 구성 요소

A. Modbus Slave 인터페이스 (UART0) - SCADA 통합

Modbus Slave 인터페이스는 외부 SCADA/HMI 시스템이 ESP32를 전통적인 PLC 또는 RTU(원격 터미널 유닛)처럼 모니터링하고 제어할 수 있게 합니다.

프로토콜 구현:

  • 지원되는 기능 코드:
    • FC01: 코일 읽기 (디지털 출력)
    • FC02: 이산 입력 읽기 (디지털 입력)
    • FC03: 홀딩 레지스터 읽기 (읽기/쓰기 데이터)
    • FC04: 입력 레지스터 읽기 (읽기 전용 프로세스 데이터)
    • FC05: 단일 코일 쓰기
    • FC06: 단일 레지스터 쓰기
    • FC0F (15): 다중 코일 쓰기
    • FC10 (16): 다중 레지스터 쓰기
  • CRC16-CCITT 검증: 처리 전 모든 Modbus 프레임이 CRC로 검증됨
  • 타임아웃 처리: 3.5 문자 시간 (보드레이트 적응형, Modbus RTU 사양에 따름)
  • 오류 응답: 불법 기능, 불법 주소, 불법 데이터 값 예외

레지스터 맵 구성:

시스템은 4개의 메모리 영역으로 구성된 1024개의 데이터 포인트를 제공합니다:

메모리 영역주소 범위액세스목적
홀딩 레지스터 (HR)0-255읽기/쓰기프로세스 데이터, 설정값, 구성
입력 레지스터 (IR)0-255읽기 전용센서 판독값, 계산된 값, 상태
코일0-255읽기/쓰기디지털 출력, 제어 비트
이산 입력0-255읽기 전용디지털 입력, 상태 플래그

자동 매핑된 시스템 리소스:

시스템은 내부 상태를 Modbus에 자동으로 노출합니다:

  • 카운터: HR100-170 (4 카운터 × 각 15 레지스터)
    • 값(스케일), 원시 카운트, 주파수(Hz), 제어/상태, 비교 임계값
  • 타이머: HR180-210 (4 타이머 × 각 8 레지스터)
    • 현재 단계, 경과 시간, 제어 레지스터, 출력 상태
  • ST 로직 변수: IR220-251 (ST 프로그램의 내보낸 변수)
    • EXPORT 키워드로 표시된 변수가 자동으로 입력 레지스터에 매핑
    • 유형 인식: INT(1 레지스터), DINT(2 레지스터), REAL(2 레지스터)

CLI를 통한 구성:

set modbus-slave id:1 baudrate:9600 parity:none stopbits:1
show modbus-slave  # 현재 구성 표시

B. Modbus Master 인터페이스 (UART1) - 원격 장치 제어

Modbus Master 인터페이스는 ESP32가 외부 Modbus 슬레이브 장치와 통신을 시작할 수 있게 하여, 센서를 읽고 액추에이터에 쓸 수 있는 PLC처럼 효과적으로 기능합니다.

프로토콜 구현:

  • 지원되는 기능 코드: FC01-FC06 (코일/입력/레지스터 읽기, 코일/레지스터 쓰기)
  • 구성 가능한 직렬 매개변수: 보드레이트(300-115200), 패리티(None/Even/Odd), 정지 비트(1/2)
  • 타임아웃 관리: 구성 가능한 타임아웃 (기본값: 500ms)
  • 속도 제한: ST 실행 사이클당 최대 10개 요청 (버스 과부하 방지)

ST 로직 통합 (내장 함수):

Modbus Master 기능은 6개의 내장 함수를 통해 ST 프로그램에 노출됩니다:

읽기 함수:

MB_READ_COIL(slave_id, address) → BOOL
MB_READ_INPUT(slave_id, address) → BOOL
MB_READ_HOLDING(slave_id, address) → INT
MB_READ_INPUT_REG(slave_id, address) → INT

쓰기 함수 (할당 기반 구문):

MB_WRITE_COIL(slave_id, address) := boolean_value
MB_WRITE_HOLDING(slave_id, address) := int_value

유형 변환 지원:

함수는 유연성을 위한 자동 유형 변환을 지원합니다:

  • slave_id & address: INT, DINT, DWORD 허용 (유효 범위로 자동 클램프)
  • MB_WRITE_COIL value: BOOL, INT, REAL, DINT, DWORD 허용 (0이 아닌 값 → TRUE)
  • MB_WRITE_HOLDING value: INT, REAL, DINT, DWORD 허용 (16비트로 자동 변환)

전역 상태 변수:

mb_last_error (INT)   (* 0=OK, 1=TIMEOUT, 2=CRC, 3=EXCEPTION, 4=MAX_REQ, 5=DISABLED *)
mb_success (BOOL)     (* 마지막 작업 성공 시 TRUE *)

실제 예제: 온도 제어 시스템

VAR
  remote_temp: INT;        (* 슬레이브 ID 5의 온도, HR#100 *)
  heating_on: BOOL;
  setpoint: INT := 20;
END_VAR

BEGIN
  (* 온도 센서 읽기 *)
  remote_temp := MB_READ_HOLDING(5, 100);

  (* 센서 판독값 기반 제어 결정 *)
  IF mb_success THEN
    IF remote_temp < setpoint THEN
      MB_WRITE_COIL(3, 20) := TRUE;   (* 슬레이브 3, 코일 20: 히터 ON *)
    ELSE
      MB_WRITE_COIL(3, 20) := FALSE;  (* 히터 OFF *)
    END_IF;
  END_IF;
END

C. 카운터 엔진 - 하드웨어 펄스 카운팅

카운터 엔진은 펄스 카운팅 애플리케이션을 위한 3가지 별도 하드웨어 모드를 제공합니다:

모드 1: 소프트웨어 폴링 (SW)

  • 메커니즘: 메인 루프에서 GPIO 핀 읽기 (~1ms 폴링 속도)
  • 엣지 감지: 소프트웨어 기반 레벨 변경 추적
  • 최대 주파수: ~500Hz (루프 실행 속도에 의해 제한)
  • CPU 오버헤드: 낮음 (주기적 폴링)
  • 사용 사례: 저주파 이벤트 (도어 접점, 리미트 스위치)

모드 2: 소프트웨어 ISR (SW-ISR)

  • 메커니즘: GPIO 인터럽트 구동 카운팅
  • 엣지 감지: 상승, 하강 또는 양쪽 엣지 (구성 가능)
  • 최대 주파수: ~10kHz
  • CPU 오버헤드: 중간 (인터럽트 서비스 루틴)
  • 사용 사례: 중간 주파수 이벤트 (유량계, RPM 센서)

모드 3: 하드웨어 PCNT (HW)

  • 메커니즘: ESP32 펄스 카운터 유닛 (전용 하드웨어)
  • 카운팅 범위: 32비트 (±2,147,483,647)
  • 최대 주파수: 40MHz (하드웨어 사양 제한)
  • CPU 오버헤드: 제로 (완전한 하드웨어 가속)
  • 프리스케일러: 하드웨어 분주기 (1-65535)
  • 사용 사례: 고주파 엔코더, 샤프트 엔코더, 고속 펄스 트레인

고급 기능:

  • 스케일링: 프리스케일러(하드웨어) + 스케일 팩터(소프트웨어 부동 소수점 승수)
  • 비트 폭: 8/16/32/64비트 출력 (큰 값을 위한 다중 레지스터 지원)
  • 방향 제어: 양방향 카운팅 (상승/하강)
  • 주파수 측정: 실시간 Hz 계산 (1초 업데이트 속도)
  • 비교 임계값: 엣지 감지가 있는 구성 가능한 임계값 (≥, >, ==)
    • 제어 레지스터 비트 4에 트리거 신호 출력
    • Modbus FC06 단일 레지스터 쓰기를 통해 런타임 수정 가능

레지스터 레이아웃 (카운터당):

카운터 1: HR100-114 (15 레지스터)
  HR100-101: 스케일된 값 (32비트, LSW 먼저)
  HR104-105: 원시 값 (32비트 프리스케일된 카운트)
  HR108:     주파수 (Hz)
  HR110:     제어/상태 레지스터
             - 비트 0: 재설정 (1 쓰기로 재설정, 자동 클리어)
             - 비트 1: 시작 (1 쓰기로 시작, 자동 클리어)
             - 비트 2: 실행 상태 (읽기 전용)
             - 비트 3: 오버플로 플래그 (읽기 전용)
             - 비트 4: 비교 일치 (읽기 전용)
  HR111-112: 비교 임계값 (32비트, 런타임 쓰기 가능)

D. 타이머 엔진 - 결정적 타이밍 제어

타이머 엔진은 시간 기반 제어를 위한 4가지 별도 작동 모드를 제공합니다:

모드 1: 원샷 (3단계 시퀀서)

  • 애플리케이션: 순차 작동 (밸브 작동, 배치 프로세스)
  • 동작: 각각 지속 시간과 출력 상태가 있는 3개의 구성 가능한 단계
  • 트리거: 제어 레지스터 비트 1 (시작 명령)
  • 예제: 단계 1: 탱크 채우기 (30초, 출력 HIGH) → 단계 2: 혼합 (60초, 출력 LOW) → 단계 3: 배수 (20초, 출력 HIGH)

모드 2: 단안정 (재트리거 가능 펄스)

  • 애플리케이션: 펄스 스트레칭, 워치독 타이밍, 이벤트 감지
  • 동작: 단일 펄스 출력, 재트리거 시 연장
  • 타이밍: 1ms ~ 4,294,967,295ms (최대 49일)
  • 예제: 짧은 버튼 누름을 5초 릴레이 펄스로 변환

모드 3: 비안정 (발진기/블링크)

  • 애플리케이션: LED 깜박임, PWM 시뮬레이션, 주기적 폴링
  • 동작: ON/OFF 상태 간 연속 토글
  • 구성: 독립적인 ON 지속 시간 및 OFF 지속 시간
  • 예제: 하트비트 LED (500ms ON, 500ms OFF)

모드 4: 입력 트리거 (엣지 응답)

  • 애플리케이션: 지연된 알람 응답, 디바운스된 입력 처리
  • 동작: 엣지에 대한 이산 입력 모니터링, 동작 지연
  • 트리거 엣지: 상승 (0→1) 또는 하강 (1→0), 구성 가능
  • 지연: 엣지 감지 후 0ms ~ 4,294,967,295ms
  • 예제: 도어 접점이 열린 후 10초 후 알람 트리거

타이밍 정밀도: ESP32 millis() 하드웨어 타이머를 사용한 ±1ms 정확도.

E. ST 로직 엔진 - IEC 61131-3 Structured Text 프로그래밍

ST 로직 엔진은 ESP32에서 직접 PLC 스타일 프로그램을 실행하는 완전한 IEC 61131-3 호환 인터프리터입니다.

언어 기능:

  • 데이터 유형: INT (16비트), DINT (32비트), REAL (부동), BOOL, DWORD
  • 유형 변환: 명시적 함수 (INT_TO_REAL, REAL_TO_INT, BOOL_TO_INT, DWORD_TO_INT)
  • 연산자: 산술 (+, -, *, /, MOD), 논리 (AND, OR, NOT, XOR), 비교 (=, <>, <, >, <=, >=)
  • 제어 흐름: IF/THEN/ELSIF/ELSE, WHILE, FOR, REPEAT/UNTIL, CASE
  • 변수 섹션:
    • VAR_INPUT: 읽기 전용 입력 (Modbus 레지스터에 바인딩)
    • VAR_OUTPUT: 쓰기 전용 출력
    • VAR: 영구 내부 변수

내장 함수 라이브러리 (60+ 함수):

수학 함수:

ABS(x)           (* 절대값 *)
SQRT(x)          (* 제곱근 *)
MIN(a, b)        (* 두 값의 최소값 *)
MAX(a, b)        (* 두 값의 최대값 *)
SUM(a, b, ...)   (* 다중 값의 합 *)
LIMIT(min, val, max) (* 범위로 값 클램프 *)

삼각 함수:

SIN(x)           (* 사인 (라디안) *)
COS(x)           (* 코사인 (라디안) *)
TAN(x)           (* 탄젠트 (라디안) *)

지수 함수:

EXP(x)           (* e^x *)
LN(x)            (* 자연 로그 *)
LOG(x)           (* 상용 로그 *)
POW(base, exp)   (* base^exponent *)

IEC 61131-3 타이머:

TON(IN, PT, Q, ET)   (* On-delay 타이머 *)
TOF(IN, PT, Q, ET)   (* Off-delay 타이머 *)
TP(IN, PT, Q, ET)    (* 펄스 타이머 *)

IEC 61131-3 카운터:

CTU(CU, R, PV, Q, CV)   (* 상승 카운터 *)
CTD(CD, LD, PV, Q, CV)  (* 하강 카운터 *)
CTUD(CU, CD, R, LD, PV, QU, QD, CV) (* 상승/하강 카운터 *)

엣지 감지:

R_TRIG(CLK, Q)   (* 상승 엣지 감지기 *)
F_TRIG(CLK, Q)   (* 하강 엣지 감지기 *)

래치 (SR/RS 플립플롭):

SR(S, R1, Q1)    (* Set-dominant 래치 *)
RS(S1, R, Q1)    (* Reset-dominant 래치 *)

신호 처리:

SCALE(val, in_min, in_max, out_min, out_max) (* 선형 스케일링 *)
HYSTERESIS(val, low, high)                    (* 히스테리시스 비교기 *)
BLINK(period)                                 (* 발진기 *)
FILTER(val, time_constant)                    (* 저역 통과 필터 *)

사용자 정의 함수 (FEAT-003, v6.1.0):

IEC 61131-3 호환 사용자 함수 및 함수 블록:

FUNCTION (무상태):

FUNCTION DOUBLE : INT
VAR_INPUT val : INT; END_VAR
BEGIN
  DOUBLE := val * 2;  (* 함수 이름을 통한 반환 *)
END_FUNCTION

FUNCTION_BLOCK (상태 유지):

FUNCTION_BLOCK INTEGRATOR
VAR_INPUT en : BOOL; value : REAL; END_VAR
VAR_OUTPUT sum : REAL; END_VAR
VAR state : REAL; END_VAR  (* 호출 간 지속 *)
BEGIN
  IF en THEN state := state + value; END_IF;
  sum := state;
END_FUNCTION_BLOCK

기능:

  • 프로그램당 최대 16개의 사용자 정의 함수
  • 프로그램당 최대 16개의 함수 블록 인스턴스
  • 함수당 최대 8개의 매개변수
  • 함수당 최대 16개의 로컬 변수
  • 최대 8개의 중첩 함수 호출 (재귀 스택)

컴파일러 아키텍처:

  1. 어휘 분석: 소스 코드를 키워드, 식별자, 연산자, 리터럴로 토큰화
  2. 구문 파싱: IEC 61131-3 문법에 대해 토큰 검증
  3. 의미 분석: 유형 검사, 변수 바인딩, 함수 해결
  4. 바이트코드 생성: 스택 기반 바이트코드로 컴파일 (프로그램당 최대 1KB)
  5. 실시간 실행: 바이트코드 인터프리터가 고정 10ms 사이클에서 실행 (20/25/50/75/100ms로 구성 가능)

성능 모니터링:

모든 ST 프로그램은 실행 통계를 추적합니다:

  • 최소/최대/평균 실행 시간: 마이크로초 정밀도
  • 사이클 오버런: 목표 간격을 초과한 실행 횟수
  • 성능 등급: EXCELLENT/GOOD/ACCEPTABLE/POOR 자동 권장 사항 포함
  • Modbus 액세스: IR252-293을 통해 읽을 수 있는 통계

대화형 디버거 (v5.3.0):

  • 일시 정지/계속: 언제든지 프로그램 실행 중지
  • 단계별 실행: 한 번에 하나의 바이트코드 명령 실행
  • 중단점: PC 주소에서 프로그램당 최대 8개의 중단점 설정
  • 변수 검사: 일시 정지 시 모든 변수 값 보기
  • CLI 명령: set logic <id> debug pause, step, continue, stop

5. 네트워크 통신: WiFi 및 HTTP REST API

WiFi 클라이언트 모드:

  • DHCP 지원: 라우터로부터 자동 IP 할당
  • 정적 IP 지원: 수동 IP, 게이트웨이, 넷마스크, DNS 구성
  • WPA/WPA2 인증: 암호로 보호된 네트워크 (8-63자 암호)
  • 자동 재연결: 연결 끊김 시 자동 재연결

Telnet 서버 (포트 23):

  • 인증: 선택적 사용자 이름/암호
  • 라인 편집: 커서 이동을 위한 화살표 키, 명령 기록
  • 동시 연결: 1개의 동시 클라이언트
  • 우아한 연결 끊기: exit 명령

HTTP REST API (포트 80):

Node-RED, 웹 대시보드 및 타사 시스템과의 통합을 위한 JSON 기반 RESTful API 제공:

엔드포인트:

GET  /api/status              (* 시스템 상태 *)
GET  /api/counters            (* 모든 카운터 값 *)
GET  /api/counters/<id>       (* 특정 카운터 *)
GET  /api/timers              (* 모든 타이머 값 *)
GET  /api/registers/hr/<addr> (* 홀딩 레지스터 읽기 *)
POST /api/registers/hr/<addr> (* 홀딩 레지스터 쓰기 *)
GET  /api/registers/ir/<addr> (* 입력 레지스터 읽기 *)
GET  /api/coils/<addr>        (* 코일 읽기 *)
POST /api/coils/<addr>        (* 코일 쓰기 *)

인증: 선택적 HTTP 기본 인증

예제 (Node-RED 통합):

// HR100에서 온도 읽기
GET http://192.168.1.100/api/registers/hr/100
응답: {"address": 100, "value": 2350, "type": "holding"}

// HR200에 설정값 쓰기
POST http://192.168.1.100/api/registers/hr/200
본문: {"value": 2500}
응답: {"success": true, "address": 200, "value": 2500}

구성 백업/복원 (v6.0.7):

HTTP API를 통한 전체 구성 백업 및 복원:

# 백업 다운로드 (모든 설정 포함: Modbus, WiFi, 카운터, 타이머, ST 소스)
curl -u api_user:password http://192.168.1.100/api/system/backup -o backup.json

# 백업에서 복원
curl -u api_user:password -X POST \
     -H "Content-Type: application/json" \
     -d @backup.json \
     http://192.168.1.100/api/system/restore

백업 포함: Modbus 구성, 네트워크 설정(암호 포함), 카운터, 타이머, GPIO 매핑, 영구 레지스터 그룹 및 ST 로직 소스 코드 (일반 텍스트, 복원 시 자동 컴파일).

6. 영구 데이터 시스템

NVS (비휘발성 저장소) 구성

ESP32의 NVS 파티션은 전원 사이클에 걸쳐 중요한 구성을 보존합니다:

  • 저장 크기: 64KB NVS 파티션
  • 데이터 무결성: 모든 읽기에서 CRC16-CCITT 체크섬 검증
  • 스키마 마이그레이션: 이전 구성 버전에서 자동 업그레이드 (v5 → v8)
  • 부팅 시 자동 로드: 메인 루프 실행 전 구성 로드

저장된 구성:

  • Modbus 슬레이브 ID, 보드레이트, 패리티, 정지 비트
  • 시스템 호스트 이름 (최대 31자)
  • WiFi SSID, 암호, 정적 IP 구성, telnet 자격 증명
  • 모든 4개 카운터 구성 (모드, GPIO, 프리스케일러, 스케일, 비교)
  • 모든 4개 타이머 구성 (모드, 지속 시간, 출력 코일)
  • 모든 4개 ST 로직 프로그램 (소스 코드 + 컴파일된 바이트코드)
  • GPIO 매핑 (64 슬롯: 이산 입력 → GPIO 핀, 코일 → GPIO 출력)

영구 레지스터 (런타임 데이터 보존)

NVS 구성(정적 설정 저장)과 달리, 영구 레지스터 시스템은 전원 사이클에서 살아남아야 하는 프로세스 데이터를 위한 런타임 제어 데이터 보존을 제공합니다.

사용 사례:

  • 보정 계수 (센서 오프셋, 스케일 팩터, 선형화)
  • 생산 카운터 (총 제조 부품, 배치 수)
  • 레시피 설정값 (온도, 압력, 유량)
  • 마지막으로 알려진 양호한 구성 백업

아키텍처:

  • 그룹: 최대 8개의 명명된 그룹, 각각 최대 16개의 홀딩 레지스터 포함
  • 선택적 지속성: 특정 그룹 또는 모든 그룹 저장/복원
  • 런타임 제어: ST 로직 프로그램 또는 CLI에서 저장 트리거
  • 부팅 시 자동 로드: 구성된 그룹이 시작 시 자동으로 복원

ST 로직 통합:

SAVE(group_id) → INT   (* 0=모든 그룹, 1-8=특정 그룹; 0=OK, -1=오류, -2=속도_제한 반환 *)
LOAD(group_id) → INT   (* 0=모든 그룹, 1-8=특정 그룹; 0=OK, -1=오류 반환 *)

예제: 주기적 저장이 있는 생산 카운터

VAR
  total_parts: DINT;
  last_save_count: DINT;
  save_result: INT;
END_VAR

BEGIN
  (* 100개 부품마다 그룹 #2 "생산"에 저장 *)
  IF (total_parts - last_save_count) >= 100 THEN
    save_result := SAVE(2);
    IF save_result = 0 THEN
      last_save_count := total_parts;
    END_IF;
  END_IF;
END

속도 제한: 5초당 최대 1회 저장 (과도한 NVS 마모 방지, ~100k 쓰기 사이클 제한).

7. 전통적인 PLC 아키텍처와의 비교

전통적 아키텍처 (3계층):

SCADA/HMI 시스템
    ↕ Modbus TCP/RTU
산업용 PLC ($500-2000)
    - 독점 IDE
    - 제한된 I/O (확장 모듈 비쌈)
    - 폐쇄된 생태계
    ↕ Modbus RTU
원격 I/O 모듈 (각 $100-500)
    - 온도 센서
    - 릴레이 보드
    - 아날로그 입력

이 프로젝트 (단일 계층):

SCADA/HMI 시스템
    ↕ Modbus RTU (UART0)
ESP32 게이트웨이 ($10)
    - 오픈 소스 ST 로직 IDE
    - 4개 하드웨어 카운터 (40MHz)
    - 4개 타이머 (마이크로초 정밀도)
    - WiFi + HTTP REST API
    - IEC 61131-3 호환
    ↕ Modbus RTU (UART1)
원격 I/O 모듈

주요 장점:

  • 비용 절감: 전통적인 PLC 대비 95% 낮은 하드웨어 비용
  • 단일 통합 지점: 하나의 장치가 게이트웨이 + PLC 대체
  • 개방형 아키텍처: 공급업체 종속 없음, ST 로직을 통해 완전히 프로그래밍 가능
  • 현대적 연결성: 내장 WiFi, IoT 통합을 위한 HTTP REST API
  • 빠른 개발: 텔넷/직렬을 통해 ST 프로그램을 몇 초 만에 업로드 (독점 IDE 라이선스 불필요)

주요 차이점: ESP32 통합 vs 다중 칩 솔루션

Arduino + W5500 이더넷 쉴드(SPI 버스를 통해 통신하는 두 개의 칩)와 달리, ESP32는 단일 다이에 이중 하드웨어 UART를 통합하여 SPI 버스 병목 현상을 제거하고 보드 복잡성을 줄입니다.

8. 결론 및 산업 응용

기술적 성과:

  • 제로 의존성 ST 구현: 외부 라이브러리 없는 순수 C++ IEC 61131-3 인터프리터
  • 하드웨어 가속 카운팅: ESP32 PCNT 유닛이 CPU 개입 없이 40MHz 펄스 트레인 처리
  • 이중 모드 Modbus: 별도 RS-485 버스에서 슬레이브 + 마스터 동시 작동
  • 실시간 결정론: 예측 가능한 제어 응답을 위한 고정 10ms 실행 사이클 (±1ms 지터)

실제 응용:

  • 제조 자동화: 비용에 민감한 애플리케이션에서 전통적인 PLC 대체 (포장 기계, 컨베이어, 조립 라인)
  • 빌딩 관리: HVAC 제어, 조명 자동화, 출입 통제 통합
  • 프로세스 제어: 화학 배치 반응기, 수처리, 식품 가공
  • 에너지 모니터링: 전력 계측, 부하 차단, 수요 응답
  • IoT 게이트웨이: 레거시 Modbus 장치를 최신 클라우드 플랫폼(MQTT, HTTP)에 연결

실제 배포 예제:

포장 기계 제어 시스템
├─ SCADA (Modbus Slave UART0) ← 운영자 HMI
│  - 생산 속도 모니터링 (카운터 주파수)
│  - 설정값 조정 (충전 볼륨, 속도)
│  - 알람 및 진단 보기
│
├─ ESP32 게이트웨이 (ST 로직 엔진)
│  - 생산 카운터 로직 (분당 부품 계산)
│  - 품질 관리 (불량 부품 거부)
│  - 레시피 관리 (영구 설정값 로드/저장)
│
└─ 현장 장치 (Modbus Master UART1)
   ├─ 근접 센서 (슬레이브 ID 1-4)
   ├─ 서보 드라이브 (슬레이브 ID 10-12)
   └─ 무게 저울 (슬레이브 ID 20)

최종 생각: Modbus RTU 프로토콜을 IEC 61131-3 Structured Text 프로그래밍 및 하드웨어 가속 주변기기와 결합함으로써, 이 프로젝트는 산업 등급 자동화가 저비용 마이크로컨트롤러에서 달성 가능함을 증명합니다. 개방형 아키텍처는 단일 기계 제어에서 분산 공장 자동화로 확장되어 현대 IoT 지원 제조를 위한 기반을 제공합니다.

기술 사양

구성 요소사양
MCUESP32-WROOM-32 (듀얼 코어 Xtensa LX6 @ 240MHz)
메모리520KB SRAM + 4MB Flash
Modbus 인터페이스이중 RS-485 (UART0 Slave + UART1 Master)
카운터4× 하드웨어 카운터 (SW/ISR/PCNT 모드, 최대 40MHz)
타이머4× 타이머 (원샷/단안정/비안정/입력 트리거)
ST 로직4× 프로그램, IEC 61131-3 호환, 60+ 내장 함수
네트워킹WiFi 802.11 b/g/n, Telnet, HTTP REST API
저장소NVS (64KB 구성) + SPIFFS (ST 소스 코드)
개발PlatformIO, C++17, 오픈 소스

참고 자료

  • IEC 61131-3 Structured Text 사양: https://www.plcopen.org/iec-61131-3
  • Modbus RTU 프로토콜: https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf
  • ESP32 기술 참조: https://www.espressif.com/en/products/socs/esp32
  • 프로젝트 저장소: https://github.com/Jangreenlarsen/Modbus_server_slave_ESP32s_server_slave_ESP32/blob/main/CLAUDE.md
Documents
Comments Write