---
title: "Modbus RTU และ Modbus TCP: จากสาย RS-485 ถึงไบต์ในเฟรม"
url: https://modsengineeringmath.com/learn/sensors-transducers/modbus/
site: "Mod's Engineering Mathematics (อาจารย์มด)"
language: th
updated: 2026-10-14
---

> Modbus ฉบับใช้งานจริง: RS-485 การต่อแบบเดซี่เชน ตัวต้านทานปลายสาย 120 Ω ไบแอส แบบจำลองข้อมูล coils discrete inputs input registers holding registers แอดเดรส 40001 กับแอดเดรสในเฟรม ฟังก์ชันโค้ด 01 03 04 05 06 15 16 exception เฟรม RTU กับ MBAP ของ Modbus TCP การคำนวณ CRC-16 เวลาอักขระ t3.5 รอบโพล การอ่าน Float32 และลำดับไบต์ ABCD CDAB พร้อมเครื่องสร้างเฟรมและเครื่องคำนวณ CRC

ฉบับ Markdown ของ https://modsengineeringmath.com/learn/sensors-transducers/modbus/ สำหรับผู้ช่วย AI และเครื่องมือค้นหา สูตรเขียนเป็น LaTeX ($…$ และ $$…$$) แล็บโต้ตอบและรูปมีเฉพาะในหน้าเว็บ

# Modbus RTU และ Modbus TCP: จากสาย RS-485 ถึงไบต์ในเฟรม

// บทที่ 20.15 · Sensors & Transducers · Modbus RTU & TCP


Modbus เกิดขึ้นในปี 1979 ที่ Modicon ผู้ผลิต PLC ในสหรัฐฯ (ปัจจุบันอยู่ในเครือ Schneider Electric ของฝรั่งเศส) ความเรียบง่ายและการเปิดให้ใช้ฟรีทำให้มันกลายเป็นภาษาพื้นฐานของมิเตอร์ไฟฟ้า อินเวอร์เตอร์ ทรานสมิตเตอร์ และ PLC แทบทุกยี่ห้อ หน้านี้อธิบายจนสร้างและอ่านเฟรมได้ด้วยตัวเอง

สรุปใน 30 วินาที

- มาสเตอร์ถาม สเลฟตอบ · RTU บน RS-485 (สเลฟ 1–247) · TCP พอร์ต 502

- 4 ตาราง: coils · discrete inputs · input registers · holding registers — "40001" = แอดเดรส 0 ในเฟรม

- อ่าน 2 รีจิสเตอร์จากสเลฟ 1: 01 03 00 00 00 02 C4 0B · CRC ไบต์ต่ำก่อน

- float32 ใช้ 2 รีจิสเตอร์ ลำดับคำ ABCD หรือ CDAB แล้วแต่ผู้ผลิต

## ชั้นกายภาพ: RS-485 พื้นฐาน

RS-485 (TIA/EIA-485) ส่งข้อมูลด้วยผลต่างแรงดันระหว่างสองสาย สัญญาณรบกวนที่เหนี่ยวนำเข้าทั้งสองสายเท่า ๆ กันจึงหักล้างกัน ทำให้ส่งได้ไกลถึงราว 1200 m ที่ความเร็วต่ำ บัสเดียวรองรับ 32 unit load (ทรานซีฟเวอร์รุ่นใหม่ที่เป็น 1/8 unit load ทำให้ต่อได้มากกว่านั้น) ขณะที่ Modbus เองกำหนดแอดเดรสสเลฟได้ 1–247

รูป 1 · บัส RS-485 ที่ถูกต้อง: เดซี่เชนจากมาสเตอร์ไปยังสเลฟตัวสุดท้าย ตัวต้านทานปลายสายสองตัว และไบแอสหนึ่งชุด

- สาย: คู่บิดเกลียวมีชีลด์ อิมพีแดนซ์ราว 120 Ω พร้อมสายที่สามเป็นกราวด์อ้างอิง (common) — RS-485 ไม่ใช่ "สองสายจริง" แรงดันโหมดร่วมต้องอยู่ในขอบเขตของทรานซีฟเวอร์

- ชื่อขั้ว: มาตรฐานเรียก A/B แต่ผู้ผลิตหลายรายสลับกัน ถ้าต่อแล้วไม่ตอบ ลองสลับสองสายก่อนทำอย่างอื่น (ไม่ทำให้อุปกรณ์เสีย)

- ค่าเริ่มต้นของ Modbus serial line: 8 บิตข้อมูล พาริตีคู่ (Even) 1 stop · ถ้าไม่ใช้พาริตีต้องใช้ 2 stop bit เพื่อให้ยังเป็น 11 บิตต่ออักขระ (ในทางปฏิบัติหลายอุปกรณ์ตั้ง 8N1)

## แบบจำลองข้อมูล: 4 ตารางและแอดเดรส พื้นฐาน

| ตาราง | ขนาด | อ่าน/เขียน | แบบเดิม | ฟังก์ชันโค้ด | ตัวอย่าง |

| Coils | 1 บิต | อ่าน/เขียน | 0xxxx | 01 อ่าน · 05 เขียนตัวเดียว · 15 เขียนหลายตัว | สั่งเปิดปั๊ม รีเซ็ตเตือน |

| Discrete inputs | 1 บิต | อ่านอย่างเดียว | 1xxxx | 02 | สถานะสวิตช์ |

| Input registers | 16 บิต | อ่านอย่างเดียว | 3xxxx | 04 | ค่าวัด |

| Holding registers | 16 บิต | อ่าน/เขียน | 4xxxx | 03 อ่าน · 06 เขียนตัวเดียว · 16 เขียนหลายตัว | ค่าวัด ค่าตั้ง ช่วงวัด |

D1 Register number vs PDU address เลขรีจิสเตอร์กับแอดเดรสในเฟรม

$$\text{แอดเดรสในเฟรม} = \text{เลขแบบ 4xxxx} - 40001 \qquad 40001 \to \texttt{0x0000},\;\; 40010 \to \texttt{0x0009}$$

## เฟรม RTU, เฟรม TCP และ CRC-16 กลาง

รูป 2 · PDU (ฟังก์ชัน + ข้อมูล) เหมือนกันทั้งสองแบบ RTU ห่อด้วยแอดเดรสสเลฟกับ CRC ส่วน TCP ห่อด้วย MBAP header 7 ไบต์

D2 Modbus CRC-16 การตรวจสอบความผิดพลาด

$$g(x) = x^{16} + x^{15} + x^2 + 1 \;(\texttt{0x8005},\ \text{กลับบิต } \texttt{0xA001}) \qquad \text{ค่าเริ่ม } \texttt{0xFFFF} \;\cdot\; \text{ส่งไบต์ต่ำก่อน}$$

- ตั้ง CRC = 0xFFFF

- XOR ไบต์ข้อมูลเข้ากับไบต์ต่ำของ CRC

- เลื่อนขวา 8 ครั้ง ทุกครั้งที่บิตที่หลุดออกเป็น 1 ให้ XOR ด้วย 0xA001

- ทำซ้ำทุกไบต์ ผลลัพธ์ส่งไบต์ต่ำก่อน — คุณสมบัติที่ใช้ตรวจ: CRC ของทั้งเฟรมรวม CRC แล้วต้องได้ 0

ตัวอย่าง D-1

### อ่าน 40001–40002 (float อุณหภูมิ) จากสเลฟ 1

- D1: 40001 → แอดเดรส 0x0000 · จำนวน 2 → PDU 03 00 00 00 02

- D2: CRC ของ 01 03 00 00 00 02 = 0x0BC4 → ส่ง C4 0B · คำขอเต็ม 01 03 00 00 00 02 C4 0B

- คำตอบ: 01 03 04 41 BE 00 00 8E 2B — byte count 04 แล้วตามด้วยข้อมูล 4 ไบต์

- D6: 41 BE 00 00 แบบ ABCD = 23.75 °C

ต้องเปิด JavaScript

Exception: สเลฟตอบด้วยฟังก์ชันโค้ด + 0x80 ตามด้วยรหัส

| รหัส | ชื่อ | สาเหตุที่พบบ่อย |

| 01 | ILLEGAL FUNCTION | อุปกรณ์ไม่รองรับฟังก์ชันนั้น เช่น ใช้ 03 กับอุปกรณ์ที่มีแต่ input register |

| 02 | ILLEGAL DATA ADDRESS | แอดเดรสเลื่อนหนึ่ง (0-based/1-based) หรืออ่านข้ามช่วงที่ไม่มี |

| 03 | ILLEGAL DATA VALUE | จำนวนเกิน 125 รีจิสเตอร์ หรือค่าที่เขียนนอกขอบเขต |

| 04 | SERVER DEVICE FAILURE | อุปกรณ์ทำคำสั่งไม่สำเร็จ |

Modbus TCP ตัด CRC ออก (TCP/IP ตรวจความถูกต้องเอง) และเพิ่ม MBAP header: Transaction ID 2 ไบต์ (จับคู่คำถาม–คำตอบ) · Protocol ID = 0 · Length 2 ไบต์ · Unit ID 1 ไบต์ (ใช้เมื่อผ่านเกตเวย์ไปยังสเลฟ RTU) ใช้พอร์ต 502 ส่วน Modbus/TCP Security ห่อด้วย TLS ที่พอร์ต 802

## เครื่องสร้างเฟรม Modbus กับทรานสมิตเตอร์เสมือน กลาง

เลือกฟังก์ชัน แอดเดรส และจำนวน แล้วดูคำขอทั้งแบบ RTU และ TCP พร้อมคำตอบจริงจากทรานสมิตเตอร์เสมือน ลองอ่านแอดเดรส 20 (ได้ exception 02) ลองใช้ฟังก์ชัน 01 (exception 01) และลองเขียนค่าเข้ารีจิสเตอร์ 9

ต้องเปิด JavaScript

## เวลาบนสายและรอบการโพล กลาง

D3 Character time เวลาต่ออักขระ

$$t_\text{char} = \frac{11\ \text{bit}}{\text{baud}} \qquad (1\ \text{start} + 8\ \text{data} + 1\ \text{parity} + 1\ \text{stop})$$

D4 RTU framing gaps ช่องว่างระหว่างเฟรม

$$t_{3.5} = 3.5\,t_\text{char} \quad t_{1.5} = 1.5\,t_\text{char} \qquad \text{baud} > 19200:\ t_{3.5} = 1.75\ \text{ms},\ t_{1.5} = 0.75\ \text{ms}$$

D5 Polling cycle รอบโพลทั้งบัส

$$T_\text{cycle} \approx \sum_{\text{slaves}}\left[(n_\text{req} + n_\text{resp})\,t_\text{char} + 2t_{3.5} + t_\text{proc}\right]$$

ตัวอย่าง D-2

### มิเตอร์ 8 ตัว อ่านตัวละ 10 รีจิสเตอร์ ที่ 19200 8E1

- D3: $t_\text{char} = 11/19200 = 573\ \mu\text{s}$ · D4: $t_{3.5} = 2.0\ \text{ms}$

- คำขอ 8 ไบต์ คำตอบ $5 + 2(10) = 25$ ไบต์ → บนสาย $33 \times 0.573 = 18.9\ \text{ms}$

- D5 (สเลฟประมวลผล 5 ms): $18.9 + 4.0 + 5 = 27.9\ \text{ms}$ ต่อตัว → 223 ms ต่อรอบ

- เพิ่มเป็น 115200 baud ได้ 93 ms — ไม่ลดลง 6 เท่าเพราะเวลาประมวลผลและ t3.5 ขั้นต่ำไม่ลดตาม Modbus RTU จึงเหมาะกับการเฝ้าดูและตั้งค่า ไม่ใช่การควบคุมความเร็วสูง

## ค่า 32 บิตบนรีจิสเตอร์ 16 บิต: Float32 และลำดับคำ ขั้นสูง

D6 IEEE 754 single precision เลขทศนิยม 32 บิต

$$x = (-1)^s \times 1.f \times 2^{\,e - 127} \qquad \texttt{0x41BE0000} = 1.484375 \times 2^4 = 23.75$$

ตัวอย่าง D-3

### อ่านได้ N = 0x0000, N+1 = 0x41BE

- ตีความแบบ ABCD: 00 00 41 BE = 2.4 × 10⁻⁴¹ — เล็กจนไม่สมเหตุสมผล

- ตีความแบบ CDAB (สลับคำ): 41 BE 00 00 = 23.75 → อุปกรณ์นี้ส่งคำต่ำก่อน

- บันทึกลำดับคำไว้ในเอกสาร I/O list ทุกครั้ง เพราะอุปกรณ์รุ่นอื่นของผู้ผลิตเดียวกันอาจไม่เหมือนกัน

ต้องเปิด JavaScript

อุปกรณ์บางรุ่นเลี่ยงปัญหานี้ด้วยการส่งจำนวนเต็มที่ขยายสเกล เช่น 2375 แทน 23.75 (×100) ซึ่งต้องรู้ตัวคูณจากคู่มือ และระวังค่าลบ (int16 แบบ two's complement) กับค่าที่เกิน 32767

## เช็กลิสต์แก้ปัญหา Modbus หน้างาน พื้นฐาน

| อาการ | ตรวจอะไร |

| ไม่ตอบเลย (timeout) | แอดเดรสสเลฟ · baud/พาริตี/stop ตรงกันทุกตัว · สาย A/B สลับ · มีอุปกรณ์สองตัวใช้แอดเดรสเดียวกัน |

| ตอบบ้าง CRC ผิดบ้าง | ตัวต้านทานปลายสายขาดหรือมีมากเกินไป · ต่อแบบดาว · ไม่มีไบแอส · สายใกล้สายกำลังหรือไดรฟ์ |

| ได้ exception 02 | แอดเดรสเลื่อนหนึ่ง (0-based/1-based) · อ่านเกินช่วงที่อุปกรณ์มี |

| ค่าผิดแบบสุดขั้ว | ลำดับคำ/ไบต์ของ float · ตัวคูณสเกล · signed/unsigned |

| ช้า ข้อมูลไม่ทันใจ | รวมการอ่านเป็นบล็อกเดียว (ลดจำนวนคำขอ) · ลด timeout · แบ่งบัสเป็นหลายพอร์ต |

ข้อควรรู้ด้านความปลอดภัยไซเบอร์: Modbus แบบดั้งเดิมไม่มีการยืนยันตัวตน ใครเข้าถึงเครือข่ายได้ก็สั่งเขียนค่าได้ ระบบที่ต่ออินเทอร์เน็ตต้องแยกเครือข่ายและใช้แนวทางตามชุดมาตรฐาน IEC 62443 ต่อไป: ฟิลด์บัสและ Industrial Ethernet · ดูรีจิสเตอร์ที่อัปเดตสดใน แล็บวัดคุมเสมือน

## แหล่งอ้างอิง

- Modbus Organization — MODBUS Application Protocol Specification V1.1b3 · MODBUS over Serial Line V1.02 · MODBUS Messaging on TCP/IP Implementation Guide

- TIA/EIA-485-A Electrical Characteristics of Generators and Receivers for Use in Balanced Digital Multipoint Systems

- IEEE 754-2019 Standard for Floating-Point Arithmetic · IEC 62443 (ชุด) Security for industrial automation and control systems

## คำถามที่พบบ่อย

แอดเดรส 40001 ในคู่มือกับแอดเดรสในเฟรม Modbus ต่างกันอย่างไร?
40001 เป็นการเขียนแบบดั้งเดิมที่ตัวเลขแรก 4 บอกตาราง holding register และนับเริ่มจาก 1 ส่วนในเฟรมจริงส่งเฉพาะออฟเซ็ตที่นับจาก 0 ดังนั้น 40001 คือแอดเดรส 0x0000 และ 40010 คือ 0x0009 โปรแกรมหลายตัวให้เลือกว่าจะใช้แบบใด ความผิดพลาดที่พบบ่อยที่สุดคืออ่านเลื่อนไปหนึ่งรีจิสเตอร์

ทำไมอ่านค่า float จาก Modbus แล้วได้ตัวเลขแปลก ๆ?
Modbus กำหนดเพียงรีจิสเตอร์ 16 บิตแบบ big-endian ค่า float 32 บิตจึงต้องใช้สองรีจิสเตอร์ และผู้ผลิตแต่ละรายเรียงคำต่างกัน ลำดับที่พบบ่อยคือ ABCD (คำสูงก่อน) และ CDAB (คำต่ำก่อน) ถ้าเลือกผิด ค่าที่ได้จะเป็นเลขเล็กมากหรือใหญ่มากผิดปกติ วิธีแก้คือลองทุกลำดับกับค่าที่รู้ เช่น อุณหภูมิห้อง แล้วเลือกลำดับที่สมเหตุสมผล

RS-485 ต้องใส่ตัวต้านทานปลายสายที่ไหน?
ใส่ตัวต้านทานประมาณ 120 Ω (เท่ากับอิมพีแดนซ์ลักษณะของสาย) ที่ปลายทั้งสองของบัสเท่านั้น ไม่ใช่ทุกอุปกรณ์ และต่ออุปกรณ์แบบเดซี่เชนเรียงต่อกัน ไม่ต่อแบบดาว นอกจากนี้ควรมีไบแอส (pull-up/pull-down) ที่มาสเตอร์หนึ่งชุด เพื่อให้บัสอยู่ในสถานะที่แน่นอนเมื่อไม่มีใครส่ง

## คำถามที่พบบ่อย (FAQ)

**แอดเดรส 40001 ในคู่มือกับแอดเดรสในเฟรม Modbus ต่างกันอย่างไร?**
40001 เป็นการเขียนแบบดั้งเดิมที่ตัวเลขแรก 4 บอกตาราง holding register และนับเริ่มจาก 1 ส่วนในเฟรมจริงส่งเฉพาะออฟเซ็ตที่นับจาก 0 ดังนั้น 40001 คือแอดเดรส 0x0000 และ 40010 คือ 0x0009 โปรแกรมหลายตัวให้เลือกว่าจะใช้แบบใด ความผิดพลาดที่พบบ่อยที่สุดคืออ่านเลื่อนไปหนึ่งรีจิสเตอร์

**ทำไมอ่านค่า float จาก Modbus แล้วได้ตัวเลขแปลก ๆ?**
Modbus กำหนดเพียงรีจิสเตอร์ 16 บิตแบบ big-endian ค่า float 32 บิตจึงต้องใช้สองรีจิสเตอร์ และผู้ผลิตแต่ละรายเรียงคำต่างกัน ลำดับที่พบบ่อยคือ ABCD (คำสูงก่อน) และ CDAB (คำต่ำก่อน) ถ้าเลือกผิด ค่าที่ได้จะเป็นเลขเล็กมากหรือใหญ่มากผิดปกติ วิธีแก้คือลองทุกลำดับกับค่าที่รู้ เช่น อุณหภูมิห้อง แล้วเลือกลำดับที่สมเหตุสมผล

**RS-485 ต้องใส่ตัวต้านทานปลายสายที่ไหน?**
ใส่ตัวต้านทานประมาณ 120 Ω (เท่ากับอิมพีแดนซ์ลักษณะของสาย) ที่ปลายทั้งสองของบัสเท่านั้น ไม่ใช่ทุกอุปกรณ์ และต่ออุปกรณ์แบบเดซี่เชนเรียงต่อกัน ไม่ต่อแบบดาว นอกจากนี้ควรมีไบแอส (pull-up/pull-down) ที่มาสเตอร์หนึ่งชุด เพื่อให้บัสอยู่ในสถานะที่แน่นอนเมื่อไม่มีใครส่ง
