Arduino Uno + W5100 Ethernet Shield: Network Programming (ตอนที่ 3)#

Keywords: Arduino Uno, Arduino Ethernet Shield, Network Programming, Industrial Automation, Modbus TCP / RTU


Arduino Uno + W5100 Ethernet Shield for Industrial Automation#

บอร์ด Arduino ยุคแรก ๆ เช่น Arduino Uno และ Arduino Mega 2560 ไม่ได้ถูกออกแบบมา เพื่อใช้งานในระดับอุตสาหกรรมโดยตรง เช่น ระบบควบคุมอัตโนมัติในโรงงาน (Industrial Automation) เนื่องจากมีข้อจำกัดทางฮาร์ดแวร์หลายด้าน ได้แก่

  • ใช้ไมโครคอนโทรลเลอร์สถาปัตยกรรม 8-bit AVR ซึ่งมีประสิทธิภาพการประมวลผลจำกัด
  • มีหน่วยความจำ (RAM / Flash) ค่อนข้างน้อย เมื่อเทียบกับงานระบบอุตสาหกรรมสมัยใหม่
  • ไม่มีอินเทอร์เฟซอุตสาหกรรมโดยตรง เช่น CAN bus, Modbus, RS-485 (ต้องใช้โมดูลเสริม)
  • การเชื่อมต่อเครือข่ายต้องพึ่งพาอุปกรณ์ภายนอก เช่น Ethernet Shield (W5100/W5500) หรือ โมดูล Wi-Fi

ในทางปฏิบัติ หากต้องการนำบอร์ด Arduino Uno + Shields มาใช้เป็นอุปกรณ์ทดลองและฝึกเขียนโปรแกรม เพื่อประยุกต์ใช้งานในด้าน "ระบบควบคุมอัตโนมัติในโรงงาน" (Industrial Automation) ก็สามารถทำได้เช่นกัน

โดยเฉพาะการเรียนรู้การสื่อสารข้อมูลระหว่างอุปกรณ์ผ่านระบบเครือข่าย เช่น

  • การเชื่อมต่อกับ PLC (Programmable Logic Controller)
  • การทำงานร่วมกับ Industrial IoT Embedded Controllers
  • การสื่อสารกับอุปกรณ์ Industrial HMI (Human Machine Interface)

ตัวอย่างโปรโตคอลที่สามารถนำมาทดลองใช้งานร่วมกันได้ ได้แก่

  • Modbus TCP / Modbus RTU
  • TCP/IP Socket Communication
  • HTTP REST API
  • MQTT (Message Queuing Telemetry Transport)

แม้ว่า Arduino Uno จะไม่ใช่อุปกรณ์ระดับอุตสาหกรรมโดยตรง แต่ก็สามารถใช้เป็น "แพลตฟอร์มสำหรับการเรียนรู้และการสร้างต้นแบบ" ได้เป็นอย่างดี แต่ก็ต้องคำนึงถึงข้อจำกัดต่าง ๆ ด้วย หากจะนำไปใช้งานจริง เช่น

  • ความเสถียรของระบบ (Reliability)
  • ความทนทานต่อสภาพแวดล้อม (Industrial Environment)
  • ความปลอดภัยของการสื่อสาร (Security)
  • มาตรฐานอุตสาหกรรม (Industrial Standards Compliance)

Modbus RTU & TCP#

รูปแบบการเชื่อมต่อระหว่างอุปกรณ์ในระบบเครือข่ายสำหรับงาน Industrial Automation ที่พบเห็นได้บ่อย คือ โปรโตคอล Modbus แบ่งเป็น 2 ตัวเลือกหลัก ที่นิยมใช้งาน ได้แก่

  • Modbus RTU (RS-485)
  • Modbus TCP (Ethernet / TCP-IP)

รูป: โครงสร้างสถาปัตยกรรมของ Modbus Protocol และแสดงให้เห็นว่า Modbus สามารถทำงานบนหลายชั้นและหลายรูปแบบการสื่อสารได้ เช่น RS-232 / RS-485 และ Ethernet / Network (Source: Wikipedia)

Modbus RTU เป็นโปรโตคอลการสื่อสารแบบอนุกรม (Serial Communication) ที่นิยมใช้งานร่วมกับมาตรฐานทางไฟฟ้า RS-485 และลักษณะสำคัญ ดังนี้

  • เป็นระบบสื่อสารแบบ Master–Slave
  • รองรับการเชื่อมต่อหลายอุปกรณ์บนบัสเดียว (Multi-drop)
  • ใช้สายสัญญาณแบบ Differential Signaling ทำให้ทนต่อสัญญาณรบกวนได้ดี และต้องใช้ร่วมกับวงจร RS485 Transceiver
  • นิยมใช้ในการเชื่อมต่อกับอุปกรณ์ Sensors & Actuators
  • เหมาะกับงานระยะไกลระดับโรงงาน แต่ก็มีความเร็วในการสื่อสารข้อมูล ค่อนข้างต่ำเมื่อเทียบกับ Ethernet

Modbus TCP เป็นการนำโปรโตคอล Modbus มาทำงานบนเครือข่าย TCP/IP และลักษณะสำคัญ ดังนี้

  • ใช้โครงสร้างแบบ Client–Server
  • ทำงานบนเครือข่าย Ethernet (LAN / Industrial LAN)
  • ใช้พอร์ตมาตรฐาน TCP โดยทั่วไปคือ 502 (default)
  • มีความเร็วสูงกว่า Modbus RTU

โปรโตคอล Modbus TCP เป็นการนำมาตรฐาน Modbus มาทำงานบนระบบเครือข่าย TCP/IP (Ethernet) ซึ่งทำให้สามารถเชื่อมต่ออุปกรณ์ในระบบควบคุมอุตสาหกรรมได้สะดวกและยืดหยุ่นมากขึ้น โดยโครงสร้างการสื่อสาร จะถูกแบ่งบทบาทของอุปกรณ์ออกเป็น 2 ฝั่งหลัก ได้แก่

  • Modbus TCP Server อุปกรณ์ที่ให้บริการข้อมูล และคอยรับการเชื่อมต่อเข้ามา
  • Modbus TCP Client อุกรณ์ที่ขอใช้บริการ เริ่มต้นการสื่อสารข้อมูลในระบบเครือข่าย ใช้สำหรับอ่านหรือเขียนข้อมูลไปยังอุปกรณ์ปลายทาง

ในมุมมองของการเขียนโปรแกรมตามรูปแบบของ Modbus Protocol อุปกรณ์ฝั่ง Server (Modbus Slave) จะต้องมีการกำหนดชุดข้อมูลภายใน สำหรับให้บริการแก่ Client ชุดข้อมูลดังกล่าวถูกจัดเก็บในรูปแบบของ Register Map ซึ่งเป็นโครงสร้างหน่วยความจำภายในที่ถูกแบ่งออกเป็นหลายประเภทตามลักษณะการใช้งานของข้อมูล

หากจะทดลองเชื่อมต่อกับ Modbus TCP Server ก็สามารถใช้ซอฟต์แวร์ Modbus Poll (Freeware, Windows 32-bit / 64-bit / Arm 64-bit) ได้

 


Modbus Registers#

โดยทั่วไป Modbus จำแนกรีจิสเตอร์ออกเป็น 4 กลุ่มหลัก ได้แก่

  1. Coils (0xxxx)
    • เป็นข้อมูลแบบบิต (1-bit) ใช้สำหรับสถานะ ON / OFF เช่น LED Lamp และ Relay เป็นต้น
    • สามารถอ่านและเขียนได้ (Read/Write)
  2. Discrete Inputs (1xxxx)
    • เป็นข้อมูลแบบ 1-bit เช่นกัน แต่ใช้สำหรับสถานะอินพุตเท่านั้น (Read-only)
    • ใช้อ่านค่าสถานะของอินพุต จากปุ่มกด Push Button, Limit Switch หรือสถานะลอจิกของอุปกรณ์ Sensor
  3. Input Registers (3xxxx)
    • เป็นข้อมูลแบบ 16-bit (unsigned int)
    • ใช้สำหรับข้อมูลแบบอ่านอย่างเดียว (Read-only) เช่น ค่า Analog เป็นต้น
  4. Holding Registers (4xxxx)
    • เป็นข้อมูลแบบ 16-bit และสามารถอ่านและเขียนได้ (Read/Write)

หากข้อมูลจริงมีขนาดมากกว่า 16-bit สามารถแบ่งเก็บโดยใช้หลายรีจิสเตอร์ต่อเนื่องกันได้ โดยจะอ้างอิงผ่าน Register Address ที่เรียงต่อกัน (Sequential Addressing) เช่น

  • 32-bit float: ใช้รีจิสเตอร์ 2 ตัว
  • 64-bit integer: ใช้รีจิสเตอร์ 4 ตัว

ในฝั่ง Modbus TCP Server จะทำหน้าที่

  • สร้าง Register Map ภายในหน่วยความจำ
  • อัปเดตค่าจากฮาร์ดแวร์จริงเป็นระยะ ๆ
  • รอรับคำสั่งจาก Client
  • ประมวลผลคำขอในการอ่านหรือเขียนข้อมูล (Read / Write Register)
  • ส่งค่ากลับตาม Register Address ที่ Client ต้องการ

โครงสร้างของ Modbus TCP Packet#

ในการสื่อสารระหว่าง Modbus TCP Client กับ Server จะมีการส่งข้อมูลในรูปแบบที่เรียกว่า Modbus TCP Packet (Modbus Application Data Unit - ADU) ซึ่งประกอบด้วยโครงสร้างข้อมูลที่ถูกกำหนดอย่างเป็นมาตรฐาน เพื่อให้ทั้งสองฝั่งเข้าใจตรงกัน

โดยทั่วไปแพ็กเกต Modbus TCP จะประกอบด้วย 2 ส่วนหลัก

  1. MBAP Header (Modbus Application Protocol Header) เป็นส่วนหัวของแพ็กเกต ใช้สำหรับควบคุมการสื่อสารผ่าน TCP/IP และประกอบด้วย
    • Transaction ID ใช้ระบุหมายเลขของคำขอ (Request ID)
    • Protocol ID (0x0000 สำหรับ Modbus)
    • Data Length ซึ่งระบุความยาวของข้อมูล
    • Unit ID ใช้ระบุอุปกรณ์ปลายทาง (ถ้ามี Gateway หรือ Bridge ไปยัง Modbus RTU)
  2. PDU (Protocol Data Unit) เป็นส่วนที่ใช้กำหนดคำสั่งของ Modbus ประกอบด้วย
    • Function Code (FC) ระบุประเภทคำสั่ง
    • Register Address (Start Address) ตำแหน่งหรือแอดเดรสเริ่มต้นของข้อมูล (รีจิสเตอร์)
    • Data Length / Quantity จำนวนข้อมูล (รีจิสเตอร์) ที่ต้องการอ่านหรือเขียน
    • Data Payload ข้อมูล (เฉพาะกรณี Write Operation)

Function Code ใช้ระบุประเภทของคำสั่งที่ต้องการให้ Server ทำงาน เช่น

  • 0x01: Read Coils (อ่านรีจิสเตอร์ หลายตัว ได้ตาม Quantity)
  • 0x02: Read Discrete Inputs (อ่านอินพุตแบบบิตได้หลายตัว ตามค่า Quantity)
  • 0x03: Read Holding Registers (อ่านรีจิสเตอร์แบบ 16-bit ได้หลายตัว ตามค่า Quantity)
  • 0x04: Read Input Registers (อ่านรีจิสเตอร์แบบ 16-bit ได้หลายตัว ตามค่า Quantity)
  • 0x05: Write Single Coil (เขียนบิตสถานะ 1 ตัว)
  • 0x06: Write Single Register (เขียนรีจิสเตอร์ 16-bit 1 ตัว)
  • 0x10: Write Multiple Registers (เขียนรีจิสเตอร์ 16-bit หลายตัวต่อเนื่อง)
  • 0x17: Read/Write Multiple Registers (อ่าน-เขียนรีจิสเตอร์ 16-bit หลายตัวต่อเนื่อง)

ข้อสังเกต

  • ยกตัวอย่าง Holding Register อ้างอิงแบบมาตรฐานคือ 40001 แต่ในแพ็กเกตจริง จะใช้ค่า Register Address Offset เริ่มต้นที่ 0
  • เนื่องจาก Modbus TCP ใช้ TCP/IP Layer ในการสื่อสารข้อมูล ซึ่งมีการตรวจสอบความถูกต้องของข้อมูลอยู่แล้ว ดังนั้นจึงไม่ต้องมีส่วนที่เป็น CRC (Cyclic Redundancy Check) / Error Checking Checksum ในขณะที่ Modbus RS485 / RTU จะต้องมีส่วนนี้ด้วย

Arduino Uno + W5100 Ethernet Shield - Modbus TCP#

เมื่อใช้ Arduino Uno + W5100 Ethernet Shield สามารถนำมาใช้งานเป็น Modbus TCP Client หรือ Server ได้

ในส่วนของการเขียนโค้ด ก็มีไลบรารี สำหรับ Modbus TCP / RTU ให้เลือกใช้งาน เช่น

ไลบรารีแต่ละตัวมีความสามารถและฟีเจอร์แตกต่างกันไป แต่ข้อควรระวังสำคัญในการเลือกใช้งานคือ การใช้หน่วยความจำ SRAM ซึ่งมีอยู่อย่างจำกัด โดยเฉพาะบนบอร์ดอย่าง Arduino Uno

 


ตัวอย่างโค้ด: Modbus TCP Server#

ตัวอย่างโค้ดต่อไปนี้สาธิตการสร้าง Modbus TCP Server โดยใช้ Arduino Uno + W5100 และใช้ไลบรารีต่อไปนี้ในการพัฒนาโปรแกรม

ไลบรารี <Ethernet.h> ใช้สำหรับจัดการการสื่อสารผ่านเครือข่าย Ethernet (TCP/IP) ส่วน modbus-arduino และ modbus-ethernet ใช้สำหรับจัดการโปรโตคอล Modbus TCP โดยช่วยลดความซับซ้อนในการจัดการแพ็กเกตและฟังก์ชันโค้ดของ Modbus

สำหรับไลบรารี modbus-arduino และ modbus-ethernet โดยทั่วไปจะต้องดาวน์โหลดเป็นไฟล์ .ZIP จาก GitHub Repository แล้วนำเข้าใน Arduino IDE ให้เรียบร้อยก่อนทำการ Build / Upload

นอกจากนั้นแล้ว จะต้องเปิดไฟล์ ModbusEthernet.h ของไลบรารี modbus-ethernet เพื่อใช้งาน

#define TCP_KEEP_ALIVE

โดยปกติการสื่อสารแบบ Modbus TCP จะใช้การเชื่อมต่อแบบ TCP (Connection-oriented) ซึ่งมีการเปิดการเชื่อมต่อค้างไว้ระหว่าง Client กับ Server แต่ในทางปฏิบัติอาจเกิดปัญหา เช่น Client หลุดการเชื่อมต่อ

เมื่อเปิดใช้งาน TCP_KEEP_ALIVE Arduino จะมีการตรวจสอบเป็นระยะ ๆ ว่า Client ยังออนไลน์อยู่หรือไม่ หาก Client หายไป จะปิด Connection (Socket) อัตโนมัติ

โค้ดตัวอย่างนี้สาธิตการใช้งาน Coil Registers จำนวน 2 รีจิสเตอร์ (เริ่มต้นที่ 0) และค่าของรีจิสเตอร์แต่ละตัว เชื่อมต่อกับขาเอาต์พุต D5 และ D6 ตามลำดับ

#include <SPI.h>

// Required libraries:
// 1) https://github.com/arduino-libraries/ethernet.git
#include <Ethernet.h>
// 2) https://github.com/epsilonrt/modbus-arduino
#include <Modbus.h>
// 3) https://github.com/epsilonrt/modbus-ethernet
#include <ModbusEthernet.h>
// Uncomment //#define TCP_KEEP_ALIVE in ModbusEthernet.h

#define INTERVAL_MS 100

const int numLEDs = 2;
const int ledPins[] = {5,6};
const uint16_t coilRegOffset = 0x00;
int lastValues[] = {0,0};

byte ip[] = { 192, 168, 10, 100 };
byte mac[] = { 0x02, 0xAA, 0xBB, 0xCC, 0xDD, 0x01 };

ModbusEthernet mb;

void setup() {
  Serial.begin(115200);
  Serial.println(F("\n\nUno Modbus TCP Server Demo..."));

  // Initialize Ethernet + Modbus TCP
  mb.config(mac, ip);

  for (int i=0; i < numLEDs; i++ ) {
    pinMode(ledPins[i], OUTPUT);
    mb.addCoil(coilRegOffset+i, false /*initial value*/);
    lastValues[i] = mb.coil(coilRegOffset+i);
    digitalWrite(ledPins[i], lastValues[i]);
  }
}

void loop() {
  static uint32_t ts = 0;
  mb.task();  // Handle Modbus TCP requests
  uint32_t now = millis();
  if (now - ts >= INTERVAL_MS) {  // Check register every 100 ms
    ts = now;
    for (int i=0; i < numLEDs; i++ ) {
       int value = mb.coil(coilRegOffset+i);
      // Update output only if value changed
       if (value != lastValues[i]) {
         lastValues[i] = value;
         digitalWrite(ledPins[i], value);
         Serial.print("LED ");
         Serial.print(i);
         Serial.print(": ");
         Serial.println(value);
       }
    }
  }
}

การทดสอบการทำงานของ Arduino Modbus TCP Server สามารถทำได้โดยใช้คำสั่ง mbpoll ใน Linux ดังนี้

# Install mbpoll (Modbus master simulator tool)
$ sudo apt install mbpoll

# Read 2 Coil registers starting from address 0
# -q       : quiet mode (suppress banner/output)
# -m tcp   : use Modbus TCP protocol
# -t 0     : data type = Coils (0xxxx)
# -r 1     : start address = 1 (mbpoll uses 1-based addressing → offset 0)
# -c 2     : read 2 coils
# -l 500   : polling interval = 500 ms
$ mbpoll -q -1 -m tcp -t 0 -r 1 -c 2 -l 500 192.168.10.100

# Write multiple coils starting from address 0
# -1       : write multiple values (Write Multiple Coils)
# Values: 1 0 => Coil[0]=1, Coil[1]=0
$ mbpoll -q -1 -m tcp -t 0 -r 1 192.168.10.100 1 0

# Write multiple coils starting from address 0
# Values: 0 1 => Coil[0]=0, Coil[1]=1
$ mbpoll -q -1 -m tcp -t 0 -r 1 192.168.10.100 0 1

รูป: ตัวอย่างการทำคำสั่ง mbpoll เพื่อเชื่อมต่อกับ Arduino Modbus TCP Server

 

อีกวิธีหนึ่งคือ การลองใช้ซอฟต์แวร์ Modbus Poll โดยขั้นตอนแรกจะต้องตั้งค่าการเชื่อมต่อ ไปยัง Arduino Modbus TCP Server ก่อน

รูป: ตั้งค่า Connection สำหรับ Modbus TCP/IP รวมถึง IP Address และ Server Port

รูป: การเลือกรูปแบบคำสั่งสำหรับอ่านค่า Coil Registers เป็นระยะ ๆ

รูป: การทดลองเขียนค่าไปยัง Coil Register

 


กล่าวสรุป#

บทความนี้นำเสนอแนวทางการใช้งานบอร์ด Arduino Uno ร่วมกับ Arduino Ethernet Shield (W5100) เพื่อนำมาทดลองใช้งานเป็นอุปกรณ์ในระบบอัตโนมัติสำหรับงานอุตสาหกรรม โดยใช้โปรโตคอล Modbus TCP มีโค้ดตัวอย่างสาธิตการทำงานในรูปแบบ Modbus TCP Server ด้วยบอร์ด Arduino

 


This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Created: 2026-04-18 | Last Updated: 2026-04-19