- หน้าแรก
- คลังความรู้
- เซนเซอร์และทรานส์ดิวเซอร์
- 20.15 Modbus
// บทที่ 20.15 · Sensors & Transducers · Modbus RTU & TCP
Modbus RTU และ Modbus TCP: จากสาย RS-485 ถึงไบต์ในเฟรม
Modbus เกิดขึ้นในปี 1979 ที่ Modicon ผู้ผลิต PLC ในสหรัฐฯ (ปัจจุบันอยู่ในเครือ Schneider Electric ของฝรั่งเศส) ความเรียบง่ายและการเปิดให้ใช้ฟรีทำให้มันกลายเป็นภาษาพื้นฐานของมิเตอร์ไฟฟ้า อินเวอร์เตอร์ ทรานสมิตเตอร์ และ PLC แทบทุกยี่ห้อ หน้านี้อธิบายจนสร้างและอ่านเฟรมได้ด้วยตัวเอง
- มาสเตอร์ถาม สเลฟตอบ · 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
- สาย: คู่บิดเกลียวมีชีลด์ อิมพีแดนซ์ราว 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 เลขรีจิสเตอร์กับแอดเดรสในเฟรม
เฟรม RTU, เฟรม TCP และ CRC-16 กลาง
D2 Modbus CRC-16 การตรวจสอบความผิดพลาด
- ตั้ง CRC = 0xFFFF
- XOR ไบต์ข้อมูลเข้ากับไบต์ต่ำของ CRC
- เลื่อนขวา 8 ครั้ง ทุกครั้งที่บิตที่หลุดออกเป็น 1 ให้ XOR ด้วย 0xA001
- ทำซ้ำทุกไบต์ ผลลัพธ์ส่งไบต์ต่ำก่อน — คุณสมบัติที่ใช้ตรวจ: CRC ของทั้งเฟรมรวม CRC แล้วต้องได้ 0
อ่าน 40001–40002 (float อุณหภูมิ) จากสเลฟ 1
D1: 40001 → แอดเดรส 0x0000 · จำนวน 2 → PDU
03 00 00 00 02D2: 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
| รหัส | ชื่อ | สาเหตุที่พบบ่อย |
|---|---|---|
| 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
เวลาบนสายและรอบการโพล กลาง
D3 Character time เวลาต่ออักขระ
D4 RTU framing gaps ช่องว่างระหว่างเฟรม
D5 Polling cycle รอบโพลทั้งบัส
มิเตอร์ 8 ตัว อ่านตัวละ 10 รีจิสเตอร์ ที่ 19200 8E1
D3: · D4:
คำขอ 8 ไบต์ คำตอบ ไบต์ → บนสาย
D5 (สเลฟประมวลผล 5 ms): ต่อตัว → 223 ms ต่อรอบ
เพิ่มเป็น 115200 baud ได้ 93 ms — ไม่ลดลง 6 เท่าเพราะเวลาประมวลผลและ t3.5 ขั้นต่ำไม่ลดตาม Modbus RTU จึงเหมาะกับการเฝ้าดูและตั้งค่า ไม่ใช่การควบคุมความเร็วสูง
ค่า 32 บิตบนรีจิสเตอร์ 16 บิต: Float32 และลำดับคำ ขั้นสูง
D6 IEEE 754 single precision เลขทศนิยม 32 บิต
อ่านได้ N = 0x0000, N+1 = 0x41BE
ตีความแบบ ABCD:
00 00 41 BE= 2.4 × 10⁻⁴¹ — เล็กจนไม่สมเหตุสมผลตีความแบบ CDAB (สลับคำ):
41 BE 00 00= 23.75 → อุปกรณ์นี้ส่งคำต่ำก่อนบันทึกลำดับคำไว้ในเอกสาร I/O list ทุกครั้ง เพราะอุปกรณ์รุ่นอื่นของผู้ผลิตเดียวกันอาจไม่เหมือนกัน
อุปกรณ์บางรุ่นเลี่ยงปัญหานี้ด้วยการส่งจำนวนเต็มที่ขยายสเกล เช่น 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) ที่มาสเตอร์หนึ่งชุด เพื่อให้บัสอยู่ในสถานะที่แน่นอนเมื่อไม่มีใครส่ง