ผมใช้ Delta DVP14SS211R (ตระกูล SS2) เป็น Modbus RTU Master อ่านค่าจากโมดูลอนาล็อกและอุปกรณ์อื่นบนบัส RS-485 เดียวกัน กว่าจะเดินได้ลื่นก็ชนกำแพงหลายรอบ

บทความนี้รวมทุกจุดที่ทำให้เสียเวลา เรียงตามลำดับที่มักจะเจอ ถ้าคุณกำลังนั่งงงว่าทำไมส่งคำสั่งออกไปแล้วเงียบ ลองไล่ตามนี้ครับ

รู้จักพอร์ตก่อน

DVP ตระกูล SS2 มีสองพอร์ตที่หน้าตาต่างกันชัดเจน:

พอร์ตรูปร่างใช้ทำอะไร
COM1หัวกลม (RS-232)โหลดโปรแกรมจาก ISPSoft/WPLSoft
COM2ขั้วเขียว + / (RS-485)Modbus RTU

ถ้าต่อ Modbus ให้ใช้ COM2 เท่านั้น

กับดักที่ 1 — พารามิเตอร์สื่อสารที่ลอกกันมาผิด

ค้นในเน็ตจะเจอคนแนะนำให้ตั้ง D1120 เป็น H87 กันเยอะมาก ค่านั้นเป็นของอินเวอร์เตอร์ Delta VFD ซึ่งใช้ Even parity

ถ้าอุปกรณ์ปลายทางของคุณเป็น 8N1 (8 data bit, ไม่มี parity, 1 stop bit) ซึ่งเป็นค่ามาตรฐานของอุปกรณ์ Modbus ส่วนใหญ่ ต้องตั้งเป็น:

1
MOV  16#81  D1120      // 9600, 8 data, None parity, 1 stop (RTU)

parity สองฝั่งต้องตรงกันเป๊ะ ผิดตัวเดียวคือคุยกันไม่รู้เรื่องเลย ไม่มี error ให้เห็นด้วย

ชุดคำสั่งตั้งค่าเต็ม ๆ ที่ผมใช้ (วางใน network แรก ขับด้วย M1002 ซึ่งทำงานครั้งเดียวตอนเริ่ม):

1
2
3
4
5
M1002 ─┬─ MOV 16#81 D1120     // พารามิเตอร์สื่อสาร
       ├─ SET M1143            // โหมด RTU (ไม่ใช่ ASCII)
       ├─ SET M1161            // โหมด 8-bit
       ├─ SET M1120            // คงค่า D1120 ไว้
       └─ MOV 50   D1129       // timeout 50 ms

แล้วเพิ่มการเคลียร์แฟล็กค้างไว้ด้วย ไม่งั้นพอเจอ error ครั้งเดียวจะค้างไปเลย:

1
2
3
M1123 ─── RST M1123    // รับข้อมูลเสร็จ
M1127 ─── RST M1127    // ส่ง/รับ สมบูรณ์
M1129 ─── RST M1129    // timeout

💡 ถ้าไม่อยากพิมพ์เอง ISPSoft มี Communication Wizard ให้เลือก “MODBUS MODRD/MODWR/MODRW” แล้วตั้ง Parity = None, RTU, 8-bit มันจะสร้างบล็อกนี้ให้อัตโนมัติ

กับดักที่ 2 — ขาด SET M1122 แล้วเงียบสนิท ⭐

อันนี้กินเวลาผมไปทั้งวัน

ทุกคำสั่ง MODRW ต้องมี SET M1122 คู่กันเสมอ — M1122 คือแฟล็ก “ส่งคำขอออกไป” ถ้าไม่ได้เซ็ต PLC จะไม่ส่งอะไรออกสายเลย

อาการที่เจอคือ ladder ทำงานปกติทุกอย่าง ไม่มี error ไม่มี timeout แต่อุปกรณ์ปลายทางเงียบ วัดสายก็ไม่มีสัญญาณ จนหลงคิดว่าพอร์ต COM2 เสียหรือสายขาด

1
2
[= D500 K1] ─── MODRW K2 K4 H0 D100 K4
                SET M1122            ← ขาดบรรทัดนี้ = ไม่มีอะไรเกิดขึ้น

ถ้าอยากรู้ว่า PLC ส่งออกจริงไหม ให้ใช้ ESP32 ต่อโมดูล MAX485 ทำเป็นตัวดักฟังบัส:

1
2
3
4
5
6
7
8
9
void setup() {
  Serial.begin(115200);
  Serial2.begin(9600, SERIAL_8N1, 16, 17);   // RX=16, TX=17
}
void loop() {
  while (Serial2.available()) {
    Serial.printf("%02X ", Serial2.read());   // พิมพ์ทุกไบต์บนบัสเป็น hex
  }
}

เห็นไบต์วิ่งก็แปลว่า PLC ส่งจริง ปัญหาอยู่ปลายทาง — ไม่เห็นอะไรเลยก็กลับมาดู M1122

กับดักที่ 3 — ค่าที่อ่านกลับมาไม่ได้อยู่ที่ D ตัวแรก

เพราะเราตั้ง M1161 (โหมด 8-bit) ค่าที่ MODRW อ่านกลับมาจะเก็บเป็น เฟรมดิบแยกทีละไบต์ ไม่ใช่ค่าที่ใช้ได้ทันที

ถ้าปลายทางเป็น D100 หน้าตาจะเป็นแบบนี้:

รีจิสเตอร์เก็บอะไร
D100slave address
D101function code
D102byte count
D103data ไบต์แรก (high)
D104data ไบต์ที่สอง (low)
ไล่ไปเรื่อย ๆ

ค่าจริงแบบ 16 บิตต้องประกอบเอง:

1
2
MUL  D103  K256  D200      // high × 256
ADD  D200  D104  D201      // + low  →  D201 คือค่าจริง

⚠️ ลำดับสำคัญ — บล็อก MUL ต้องอยู่เหนือ ADD ใน ladder ไม่งั้นจะได้ค่าของรอบก่อนหน้า

กับดักซ้อนกับดัก: D100 เก็บ slave address ซึ่งเป็นค่าคงที่ ถ้าเขียนเงื่อนไขเทียบคำสั่งแบบ [= D100 K2] เพื่อดูว่า “slave 2 ตอบมาไหม” มันจะเป็นจริงตลอดเวลา เพราะ D100 เป็น 2 อยู่แล้วทุกรอบ ค่าที่อยากเช็คจริง ๆ อยู่ที่ไบต์ล่างของข้อมูล

ค่าที่ไม่เกิน 255 หยิบจากไบต์ล่างได้ตรง ๆ แต่ค่ามาก ๆ เช่นอนาล็อก 0–4095 ต้องประกอบสองไบต์เสมอ

กับดักที่ 4 — SS2 รองรับ FC16 อยู่แล้ว

หลายคนเข้าใจว่า Delta DVP เขียนได้ทีละรีจิสเตอร์ (FC06) เท่านั้น เลยไล่เขียนทีละตัว จริง ๆ SS2 รองรับ function code 01–06, 0F และ 10 (FC16)

1
2
3
4
FC03 = อ่าน Holding Register
FC04 = อ่าน Input Register (พวกอนาล็อกอินพุตมักอยู่ตรงนี้)
FC06 = เขียนทีละตัว
FC16 = เขียนหลายตัวรวดเดียว  ← ใช้ได้ ไม่ต้องเขียนทีละตัว

กับดักที่ 5 — อ่านหลาย slave บนบัสเดียวต้องเข้าคิว

บัส RS-485 คุยได้ทีละคู่ ถ้ายิงคำสั่งซ้อนกันจะชนกันมั่ว วิธีที่ใช้ได้ดีคือทำตัวนับเป็น sequencer:

1
2
3
4
5
[= D500 K0] AND [M1012↑]  ─── MODRW ... (slave 1)  + SET M1122
[= D500 K1] AND [M1012↑]  ─── MODRW ... (slave 2)  + SET M1122
[= D500 K2] AND [M1012↑]  ─── MODRW ... (slave 3)  + SET M1122
                              INC D500
[>= D500 K3] ─── MOV K0 D500       // วนกลับ

สองจุดที่ต้องระวัง:

  • วาง INC D500 ไว้เหนือเงื่อนไขวนกลับ ไม่งั้นตัวนับจะข้ามหรือค้าง
  • ใช้ M1012 (พัลส์ 100 ms) อย่าใช้ M1013 (1 วินาที) — 100 ms ทำให้การอ่านลื่นและไม่ค้าง ส่วน 1 วินาทีจะหน่วงจนรู้สึกได้ถ้ามีหลาย slave

กับดักที่ 6 — ISPSoft กับ WPLSoft พิมพ์ค่าคงที่ไม่เหมือนกัน

ถ้าย้ายจาก WPLSoft มา ISPSoft แล้วโปรแกรมคอมไพล์ไม่ผ่านหรือค่าเพี้ยน อาจเป็นเพราะเรื่องนี้:

พิมพ์ยังไง
WPLSoftK100, H87 ได้ตรง ๆ
ISPSoftพิมพ์ K หรือ H นำหน้า มันจะกลายเป็นชื่อตัวแปร → ต้องใช้ 16#81 สำหรับเลขฐานสิบหก และเลขล้วนสำหรับฐานสิบ

กับดักที่ 7 — โมดูลอนาล็อกราคาประหยัดที่ใช้ได้ดี

โมดูล MODBUS-4AI4AO (ยี่ห้อ AMSAMOTION) เป็นตัวที่ผมใช้อยู่ ค่าเริ่มต้นคือ:

  • Slave ID = 1, 9600, 8N1
  • ตั้ง DIP switch เลือกโหมดกระแส 4–20 mA
  • อ่านอนาล็อกอินพุต: FC04 แอดเดรส 0–3
  • เขียนอนาล็อกเอาต์พุต: FC06 หรือ FC16 แอดเดรส 0–3

สเกลที่ต้องจำ: ค่าดิบ 820 = 4 mA และ 4095 = 20 mA (ไม่ใช่ 0 = 4 mA อย่างที่หลายคนคิด) แปลงเป็นค่าจริงด้วย:

1
ค่าจริง = (raw − 820) × ช่วงที่ต้องการ ÷ (4095 − 820)

สรุปเป็นเช็กลิสต์

เวลาต่อ Modbus RTU กับ Delta DVP ไล่ตามนี้แล้วจะไม่หลงทาง:

  1. ต่อที่ COM2 (ขั้วเขียว) ไม่ใช่ COM1
  2. D1120 = 16#81 ถ้าปลายทางเป็น 8N1 — อย่าลอก H87 มาใช้
  3. M1143 (RTU) + M1161 (8-bit) + M1120 (คงค่า) + D1129 (timeout)
  4. ทุก MODRW ต้องมี SET M1122
  5. ค่าที่อ่านกลับอยู่ที่ D+3 เป็นต้นไป และต้องประกอบ high/low เอง
  6. หลาย slave ให้ทำ sequencer ด้วย M1012
  7. ISPSoft ใช้ 16#81 ไม่ใช่ H87

ถ้ายังเงียบอยู่ ให้เอา ESP32 ไปดักฟังบัสดูว่ามีไบต์วิ่งจริงไหม จะตัดปัญหาได้ครึ่งหนึ่งทันทีว่าอยู่ฝั่งส่งหรือฝั่งรับ


บทความนี้เขียนจากการลงมือทำจริง อุปกรณ์ที่ใช้คือ Delta DVP14SS211R กับโมดูล MODBUS-4AI4AO บนบัส RS-485 เดียวกัน หากมีจุดไหนที่คุณเจอต่างออกไป เล่าให้ฟังได้ครับ