EST. 2026 — บันทึกงานเซิร์ฟเวอร์จริง SYSADMIN · SECURITY · AI · DIRECTADMIN เล่มที่ 01
THE SYSADMIN ALMANAC
หน้าหลัก / Hardware / ข้อมูลจาก PLC อีกตัวค้างค่าเดิมเหมือนของจริง เช็กลิสต์ตรวจลิงก์
Hardware

ข้อมูลจาก PLC อีกตัวค้างค่าเดิมเหมือนของจริง เช็กลิสต์ตรวจลิงก์

โดย Ton-Or ·8 พ.ย. 2026·อ่าน 12 นาที
ข้อมูลจาก PLC อีกตัวค้างค่าเดิมเหมือนของจริง เช็กลิสต์ตรวจลิงก์

โหนดที่หลุดจากเครือข่ายไม่ได้ส่งค่าผิดมาให้ มันแค่หยุดส่ง แล้วค่าสุดท้ายก็ค้างอยู่ในหน่วยความจำฝั่งรับโดยไม่มีอะไรบอกว่าเป็นของเก่า

สรุปใน 1 นาที

อาการ/ปัญหา
PLC ฝั่งส่งหลุด แต่ฝั่งรับยังค้างค่าสุดท้ายที่หน้าตาเหมือนข้อมูลจริง
ใครควรอ่าน
คนที่ทำลิงก์ระหว่าง PLC ด้วย TSEND_C และ TRCV_C
ทางแก้แบบสั้น
ใช้เช็กลิสต์ 11 ข้อ ตั้ง timeout ตามเวลาที่กระบวนการทนได้ และอ่าน STATUS กับ T_DIAG เพื่อรู้ว่าข้อมูลเก่า
ข้ามไปขั้นตอน

พอดีผมนั่งทบทวนลิงก์ข้อมูลระหว่าง PLC สองตัวที่ผมเขียนขึ้นเองบนบล็อก TSEND_C/TRCV_C ของ Siemens ตัวหนึ่งเป็นเจ้าของ logic อีกตัวเป็นสถานีที่รับคำสั่งไปขับเอาต์พุต ส่ง DB ทั้งก้อนหากันแบบวนรอบ ตอนแรกผมมองว่าลิงก์นี้ครบแล้ว เพราะมี heartbeat กับ watchdog อยู่ในตัว แต่พอถามตัวเองว่า "ครบ" ของลิงก์ระหว่าง PLC คือเท่าไร ผมตอบไม่ได้ เพราะไม่มีอะไรให้เทียบ ผมเลยไปเปิดคู่มือทางการของเครือข่ายสำเร็จรูปฝั่ง Omron ดูว่าของที่เขาทำมาขายให้อะไรมาในตัวบ้าง แล้วเอามาวางเทียบกับของที่เขียนเองทีละข้อ ผลคือของที่ผมคิดว่าครบ ขาดไปหลายข้อ

ต้องบอกระดับหลักฐานไว้ก่อน ส่วนที่เป็น Omron ทั้งหมดในบทความนี้ผมอ่านจากคู่มือ ยังไม่ได้ลองกับเครื่องจริง ส่วนค่า STATUS กับ T_DIAG ของบล็อกสื่อสารฝั่ง Siemens ผมวัดเองบน simulator ไม่ใช่บน PLC ตัวจริง ชื่อ PLC ชื่อ DB และชื่อตัวแปรในบทความเป็นชื่อกลางทั้งหมด เลขหน้าที่อ้างเป็นเลขหน้าของไฟล์ PDF ไม่ใช่เลขที่พิมพ์บนหน้ากระดาษ

เรื่องนี้แตะเอาต์พุตของเครื่องจักร

ค่า timeout สถานะเอาต์พุตเมื่อลิงก์หาย และการกลับมาเดินเองหลังลิงก์คืน เป็นเรื่องความปลอดภัยของคนหน้าเครื่อง ตัวเลขในบทความนี้เป็นของลิงก์ทดลองชุดเดียว ใช้เป็น กรอบในการตรวจ ได้ แต่งานจริงต้องให้วิศวกรที่รับผิดชอบเครื่องจักรประเมินความเสี่ยงและลงนาม ส่วน interlock ด้านความปลอดภัย เช่น ปุ่มหยุดฉุกเฉิน ต้องเป็นวงจรสายแข็งหรือระบบ safety โดยเฉพาะ ไม่ใช่ฝากไว้กับลิงก์ข้อมูล

ค่าค้างหน้าตาเหมือนค่าจริงทุกประการ

ประโยคที่ทำให้ผมหยุดอ่านแล้วกลับไปดูโปรแกรมตัวเอง อยู่ในคู่มือ Controller Link Units Operation Manual ของ Omron (W309-E1-12) หน้า 235 ของไฟล์ PDF ในหมายเหตุท้ายคำสั่งอ่านสถานะ data link เขียนไว้ว่า

Any node which is not active in the network retains the status that existed
immediately prior to the generation of the communications error.

แปลตรงตัวคือ โหนดที่ไม่ active ในเครือข่ายแล้ว จะคงสถานะที่มีอยู่ก่อนเกิด communications error ไว้ ไม่มีการเคลียร์เป็นศูนย์ ไม่มีค่าพิเศษที่บอกว่าข้อมูลนี้ตายแล้ว บิตที่เคยเป็น 1 ก็ยังเป็น 1 ตัวเลขที่เคยเป็น 137 ก็ยังเป็น 137 โปรแกรมฝั่งรับที่อ่านค่านั้นไปตัดสินเอาต์พุตก็ทำงานต่อไปเหมือนไม่มีอะไรเกิดขึ้น

ลิงก์ TCP ดิบที่เขียนเองบน Siemens ก็เป็นแบบเดียวกัน TRCV_C เขียนลง DB ฝั่งรับเฉพาะตอนที่มีข้อมูลเข้ามา พออีกฝั่งหยุดส่ง ไม่ว่าเพราะสายหลุด CPU เข้า STOP หรือไฟดับ DB ก้อนนั้นก็นิ่งอยู่ที่ค่าสุดท้าย ไม่มีใครมาเคลียร์ให้ การส่ง DB ทั้งก้อนวนรอบด้วย TSEND_C/TRCV_C ทำหน้าที่เหมือน Data Link ที่เขียนขึ้นเอง แล้วก็ได้นิสัยค้างค่ามาด้วยครบ

heartbeat ที่ฝั่งรับเห็นโหนดฝั่งส่งหลุดค้างที่ค่าสุดท้าย ไม่สลับอีกค่าใน DB ฝั่งรับwatchdog หมดเวลาค่าสด = 137ค่าค้าง = 137 เหมือนเดิมค้าง แต่รู้แล้วว่าเก่าPeerOKTRUEยัง TRUE อีก 3 วินาทีFALSEwatchdog 3 s = 6 คาบของ heartbeat 0.5 s
หลังโหนดฝั่งส่งหลุด ค่าใน DB ฝั่งรับไม่เปลี่ยน และ PeerOK ยังเป็น TRUE ต่ออีก 3 วินาทีจน watchdog หมดเวลา ช่วงสีแดงคือช่วงที่โปรแกรมทำงานด้วยข้อมูลเก่าโดยไม่รู้ตัว ค่า 137 เป็นค่าสมมติ

จากผังจะเห็นว่าช่วงที่อันตรายไม่ใช่ตอนที่ watchdog หมดเวลาแล้ว ตอนนั้นโปรแกรมรู้ตัวแล้ว ช่วงที่อันตรายคือช่วงระหว่างโหนดหลุดจนถึง watchdog หมดเวลา ในลิงก์ของผมคือ 3 วินาที ตลอดช่วงนี้ค่าใน DB เป็นของเก่า แต่ PeerOK ยังเป็น TRUE อยู่ นี่คือเหตุผลที่ต้องมีตัวบอกความสดของข้อมูล และเหตุผลที่ค่า timeout ต้องเลือกอย่างตั้งใจ ซึ่งจะพูดถึงในหัวข้อถัดไป

ของ 5 อย่างที่เครือข่ายสำเร็จรูปให้มาในตัว

พออ่านคู่มือของ Controller Link กับ DeviceNet ต่อ ผมไล่ได้ว่าของที่เขาให้มาโดยผู้ใช้ไม่ต้องเขียนโปรแกรมเองมีอย่างน้อย 5 อย่าง

  1. สถานะรายโหนดของ Data Link แบบ 4 บิตต่อโหนด คือ PLC status (โปรแกรมรันอยู่หรือไม่), CPU Unit error, Communications error และ Data link participation ถ้าเลือกแบบ 8 บิตจะได้เพิ่มอีก 3 ธงตามข้อ 4 (W309)
  2. เลือก hold หรือ clear เอาต์พุต เมื่อสื่อสารขัดข้อง ที่ DeviceNet unit เป็น DIP ขา 4 ฝั่ง Slave OFF คือ Clear remote outputs ON คือ Hold (W380-E1-10 หน้า 74)
  3. เลือก continue หรือ stop เมื่อเกิด error ที่ DIP ขา 3 ฝั่ง Master OFF คือสื่อสารต่อ ON คือหยุดการสื่อสาร (W380 หน้า 74)
  4. ธงขนาดและ offset ไม่ตรง คือ Offset error, Insufficient receive area (พื้นที่รับเล็กกว่าที่ส่ง ส่วนเกินถูกตัดทิ้ง) และ Remaining receive area (พื้นที่รับใหญ่กว่า ส่วนที่เหลือถูกเคลียร์)
  5. ตัวนับ error กับเวลารอบสื่อสาร เช่นจำนวน CRC error จำนวน token timeout และเวลารอบ refresh ทั้งค่าปัจจุบันและค่าสูงสุด อ่านได้ด้วยคำสั่ง FINS
4 บิตสถานะต่อโหนด
8 บิตเพิ่มธงขนาดไม่ตรง
DIP ขา 4hold หรือ clear
DIP ขา 3continue หรือ stop

ข้อ 5 ผมแยกรายละเอียดคำสั่งกับวิธีอ่านตัวนับไปไว้ใน บทความเรื่องคำสั่ง FINS ของ Controller Link ตรงนี้ขอพูดแค่ว่ามันมีอยู่ และมีมาโดยไม่ต้องเขียนเอง

สิ่งที่ผมได้จากรายการนี้ไม่ใช่ว่าต้องไปซื้อเครือข่ายสำเร็จรูปมาใช้ แต่คือคนออกแบบเครือข่ายพวกนี้เจอปัญหาเดียวกันมาก่อน แล้วสรุปออกมาเป็นของที่ต้องมี ถ้าผมเลือกเขียนลิงก์เองบน TCP ของทั้ง 5 อย่างนี้ไม่ได้หายไปไหน มันแค่ย้ายมาเป็นงานของผม

ของที่ต้องมีเครือข่ายสำเร็จรูปลิงก์ TCP เขียนเองสถานะรายโหนดมี: 4 หรือ 8 บิตต่อโหนดไม่มี: ทำ word สถานะเองhold / clear เอาต์พุตมี: DIP ขา 4 ฝั่ง Slaveไม่มี: เขียนในโปรแกรมcontinue / stopมี: DIP ขา 3 ฝั่ง Masterไม่มี: ทำ fault ค้างเองธงขนาด / offset ไม่ตรงมี: 3 ธงในแบบ 8 บิตไม่มี: ใส่เลขเวอร์ชันเองตัวนับ error / เวลารอบมี: อ่านด้วยคำสั่ง FINSไม่มี: ทำตัวนับเอง
ของ 5 อย่างที่ Controller Link และ DeviceNet ให้มาในตัว เทียบกับลิงก์ที่เขียนเองบน TSEND_C/TRCV_C ซึ่งต้องสร้างเองทุกข้อ

เทียบกับลิงก์ที่เขียนเองบน TSEND_C/TRCV_C

เอารายการข้างบนมาวางเทียบกับลิงก์ที่ผมเขียนไว้ทีละแถว

สิ่งที่เครือข่ายสำเร็จรูปมี ลิงก์เขียนเองตอนที่ทบทวน สิ่งที่ผมเสนอให้เพิ่ม
ค่าค้างเมื่อโหนดหลุด DB ฝั่งรับค้างเหมือนกัน เลยมี heartbeat 0.5 วินาที กับ watchdog 3 วินาที ถูกทางแล้ว คงไว้
สถานะรายโหนด 4 บิต มีบิตเดียวคือ PeerOK เพิ่ม word สถานะ บอกว่าฝั่งตรงข้าม RUN อยู่ มี fault หรือไม่ และ PeerOK ให้ HMI แสดง
hold / clear เลือกได้ สถานะเอาต์พุตเมื่อลิงก์หายถูกกำหนดตายตัวในโปรแกรม ให้คนหน้างานยืนยันว่าเป็นสถานะปลอดภัยจริงของทุกสถานี
continue / stop เลือกได้ กลับมาทำงานเองทันทีที่ heartbeat กลับ พิจารณาแบบค้าง fault จนกด Reset
ธงขนาด / offset ไม่ตรง ตรวจขนาดโครงสร้างสองฝั่งแบบ offline ก่อน build ถ้าจะตรวจตอนรัน ใส่เลขเวอร์ชันโครงสร้างไว้ต้น DB แล้วเทียบสองฝั่ง
ตัวนับ error และเวลารอบ ไม่มี ตัวนับจำนวนครั้งที่ PeerOK ตก และวัดเวลาตอบสนองคำสั่งตอน commissioning

แถวแรกคือข้อเดียวที่ผมทำถูกมาตั้งแต่ต้น ที่เหลือคือของที่ผมไม่ได้คิดถึงเพราะตอนเขียนลิงก์ผมคิดแค่ว่าข้อมูลไปถึงหรือไม่ถึง ไม่ได้คิดว่าคนที่ยืนหน้า HMI ตอนลิงก์มีปัญหาจะรู้ได้อย่างไรว่าปัญหาอยู่ฝั่งไหน บิต PeerOK ตัวเดียวบอกได้แค่ว่าข้อมูลหยุดไหล แต่ไม่ได้บอกว่าอีกฝั่งยัง RUN อยู่หรือเปล่า หรือ RUN อยู่แต่ตัวเองมี fault

โครงที่ผมร่างไว้เป็น SCL หน้าตาประมาณนี้ ส่วนนี้เป็นแบบร่าง ยังไม่ได้ลงเครื่องจริง ใครจะเอาไปใช้ต้อง compile และทดสอบเอง

// ฝั่งส่ง: หัวของโครงสร้างที่ส่งข้ามลิงก์ สองฝั่งต้องเหมือนกัน
"DB_Link".Tx.StructVer   := 16#0103;       // เปลี่ยนเลขทุกครั้งที่แก้โครงสร้าง
"DB_Link".Tx.Status.%X0  := TRUE;          // โปรแกรมฝั่งนี้รันอยู่ (เขียนทุก scan)
"DB_Link".Tx.Status.%X1  := #AnyFault;     // ฝั่งนี้มี fault
"DB_Link".Tx.Status.%X2  := #PeerOK;       // ฝั่งนี้เห็น heartbeat ของอีกฝั่ง

// ฝั่งรับ: ตรวจเวอร์ชัน นับครั้งที่ลิงก์ตก และค้าง fault จนกด Reset
#VerMismatch := "DB_Link".Rx.StructVer <> "DB_Link".Tx.StructVer;

#fDrop(CLK := #PeerOK);                    // F_TRIG instance ใน static
IF #fDrop.Q THEN
    #DropCount := #DropCount + 1;
END_IF;

IF NOT #PeerOK OR #VerMismatch THEN
    #LinkFault := TRUE;
END_IF;
IF #Reset AND #PeerOK AND NOT #VerMismatch THEN
    #LinkFault := FALSE;
END_IF;

#DataValid := #PeerOK AND NOT #LinkFault;

มีข้อที่ต้องระวังในแบบร่างนี้ บิต "โปรแกรมฝั่งนี้รันอยู่" ที่เขียน TRUE ทุก scan มีความหมายก็ต่อเมื่อ PeerOK เป็น TRUE ด้วยเท่านั้น เพราะถ้า CPU ฝั่งส่งเข้า STOP บิตนี้ก็ค้าง TRUE อยู่ในฝั่งรับตามกฎค่าค้างข้างบน ทุกบิตใน word สถานะต้องอ่านคู่กับตัวบอกความสดเสมอ

สองข้อที่ต้องถามคนหน้างานก่อนเดินเครื่อง

ข้อแรก สถานะเอาต์พุตที่โปรแกรมบังคับเมื่อลิงก์หาย เป็นสถานะปลอดภัยจริงของแอคชูเอเตอร์ทุกตัวหรือไม่ บางตัว "ดับ" คือปลอดภัย บางตัว "ค้างตำแหน่งเดิม" ปลอดภัยกว่า คนเขียนโปรแกรมตอบแทนไม่ได้ ข้อสอง เมื่อ heartbeat กลับมา เครื่องควรเดินต่อเองหรือรอคนกด Reset เครือข่ายสำเร็จรูปให้เลือกสองข้อนี้ได้จาก DIP ลิงก์ที่เขียนเองต้องตัดสินใจตอนออกแบบ แล้วเขียนไว้เป็นเอกสารว่าใครเป็นคนยืนยัน

เลือก timeout จากเวลาที่กระบวนการทนได้

ลิงก์ของผม heartbeat สลับค่าทุก 500 ms แล้ว watchdog ตั้งไว้ 3 วินาที เท่ากับ 6 คาบของ heartbeat ตอนตั้งผมเลือกเลขนี้เพราะมันกลม และกว้างพอที่ลิงก์จะไม่ตกเล่นเวลาเครือข่ายสะดุดนิดหน่อย ซึ่งเป็นวิธีคิดที่ผิดด้าน

timeout ไม่ได้เป็นแค่ความทนทานต่อสัญญาณรบกวน มันคือ ระยะเวลาที่โปรแกรมฝั่งรับยอมทำงานด้วยข้อมูลเก่า ตามผังเส้นเวลาข้างบน คำถามที่ถูกเลยไม่ใช่ว่าลิงก์สะดุดได้นานแค่ไหน แต่คือกระบวนการทนการสั่งงานจากข้อมูลค้างได้นานแค่ไหน แล้วค่อยดูว่าค่านั้นยังมากกว่าคาบ heartbeat หลายเท่าพอหรือไม่

toggle_ms  = 500     # heartbeat สลับค่าทุก 500 ms
timeout_ms = 3000    # watchdog ของลิงก์ชุดนี้

print('timeout เท่ากับ', timeout_ms / toggle_ms, 'คาบ')   # 6.0

# ช่วงที่ฝั่งรับยังเชื่อค่าค้าง ยาวได้ถึง timeout เต็ม
speed_m_s = 0.2      # ตัวเลขสมมติ ให้ใส่ความเร็วของสิ่งที่เคลื่อนที่จริง
print('ระยะที่ของเคลื่อนไปก่อนโปรแกรมรู้ตัว', speed_m_s * timeout_ms / 1000, 'm')

ถ้าคำตอบของบรรทัดสุดท้ายเป็นระยะที่ทำให้ของชนกันหรือคนเจ็บได้ ค่า 3 วินาทีก็ยาวเกินไปสำหรับสัญญาณตัวนั้น ไม่ว่าลิงก์จะนิ่งแค่ไหน และสัญญาณแบบนั้นอาจไม่ควรเดินทางผ่านลิงก์ข้อมูลตั้งแต่ต้น

อีกข้อที่อยู่คู่กัน PeerOK ต้องเป็น FALSE ไว้ก่อน จนกว่าจะเห็น heartbeat เปลี่ยนค่าครั้งแรกจริง ๆ ถ้าปล่อยให้เริ่มต้นเป็น TRUE ช่วงเปิดเครื่องจะมีหน้าต่างที่โปรแกรมเชื่อข้อมูลที่ยังไม่เคยได้รับเลย เรื่องนี้ผมเขียนแยกไว้ใน บทความช่องโหว่ช่วง scan แรกของ watchdog ไม่เล่าซ้ำตรงนี้

เช็กลิสต์ 11 ข้อ ใช้ได้ทุกยี่ห้อ

จากคู่มือทั้งสองฝั่ง ผมสรุปออกมาเป็นคำถาม 11 ข้อที่ใช้ตรวจลิงก์ระหว่าง PLC ได้โดยไม่ผูกกับยี่ห้อ ข้อ 1 ถึง 3 เป็นพื้นฐานของตัวโปรแกรม ข้อ 4 ถึง 10 เป็นเรื่องของลิงก์โดยตรง ข้อ 11 เป็นฮาร์ดแวร์

  1. เอาต์พุตแต่ละตัวถูกเขียนที่เดียวหรือไม่ ถ้า PLC สองตัวต่างมี logic สั่งตัวเดียวกัน ถือว่าไม่ผ่าน
  2. บล็อกที่ถูกข้ามการทำงาน ทำให้เอาต์พุตในช่วงนั้น OFF หรือค้างค่า ตามเอกสารพื้นฐานของ Omron ช่วง IL/ILC เอาต์พุตจะ OFF ส่วนช่วง JMP/JME จะคงสถานะเดิม
  3. timer และ counter ไม่ใช้เบอร์หรือ instance ซ้ำกัน
  4. ข้อมูลที่รับจาก PLC อื่นมีตัวบอกความสด เช่น heartbeat หรือสถานะโหนด
  5. เมื่อสื่อสารขัดข้อง เอาต์พุตถูกกำหนดเป็น hold, clear หรือสถานะเฉพาะ และมีคนยืนยันว่าปลอดภัย
  6. หลังสื่อสารกลับมา ระบบเดินต่อเองหรือรอ reset
  7. ขนาดและ offset ของพื้นที่รับกับพื้นที่ส่งตรงกันทั้งสองฝั่ง
  8. ใครเป็นเจ้าของ logic ของอุปกรณ์แต่ละตัว
  9. มีตัวนับ error และ error log ให้ย้อนดู
  10. การแก้โครงสร้างข้อมูลมีขั้นตอน หยุด โหลดทั้งคู่ แล้วลงทะเบียนใหม่
  11. ชนิดเอาต์พุตตรงกับโหลดและความถี่การสวิตช์

ข้อ 10 มาจากวิธีคิดของ DeviceNet ที่มี Scan List เป็นทะเบียนของ Slave ถ้าจะเพิ่ม ย้าย หรือเปลี่ยน node address ของ Slave ต้องปิด Scan List ก่อน แก้เสร็จแล้วลงทะเบียนใหม่ ลิงก์ที่เขียนเองไม่มีทะเบียนแบบนี้ แต่มีสถานการณ์เดียวกัน คือเมื่อแก้โครงสร้าง DB ที่ส่งหากัน ต้องโหลดโปรแกรมทั้งสองฝั่งคู่กัน ถ้าโหลดฝั่งเดียวแล้วเดินเครื่อง ข้อมูลจะเลื่อนตำแหน่งโดยไม่มีอะไรเตือน เลขเวอร์ชันโครงสร้างในแบบร่างข้างบนคือสิ่งที่มาแทนธง offset error ของเครือข่ายสำเร็จรูป

เวลาใช้งานจริงผมเก็บผลตรวจเป็นไฟล์ต่อหนึ่งลิงก์ แล้วให้ทุกข้อมีชื่อคนยืนยัน ข้อไหนยังไม่มีคนยืนยันถือว่ายังไม่ผ่าน

link: Main_PLC <-> Station_A
reviewed: 2026-10-01
items:
  - id: 4
    question: ข้อมูลที่รับมีตัวบอกความสด
    answer: heartbeat สลับทุก 500 ms, watchdog 3 s
    result: pass
  - id: 5
    question: สถานะเอาต์พุตเมื่อลิงก์หาย
    answer: กำหนดตายตัวในโปรแกรม
    confirmed_by: ""          # ยังไม่มีคนหน้างานยืนยัน
    result: open
  - id: 6
    question: หลังลิงก์กลับ เดินเองหรือรอ reset
    answer: เดินเองทันที
    result: open
  - id: 9
    question: ตัวนับ error
    answer: ไม่มี
    result: fail
ทำไมข้อ 1 ถึงอยู่บนสุด

กฎห้ามเขียนเอาต์พุตตัวเดียวกันจากหลายที่เป็นกฎพื้นฐานของ ladder ที่ทุกยี่ห้อสอนเหมือนกัน พอมี PLC สองตัว กฎนี้ขยายข้ามเครื่อง ถ้าทั้งสองฝั่งมี logic ตัดสินเอาต์พุตตัวเดียวกัน ลิงก์จะดีแค่ไหนก็ไม่ช่วย เพราะปัญหาอยู่ที่การแบ่งหน้าที่ ไม่ได้อยู่ที่การสื่อสาร ข้อ 8 คือคำถามเดียวกันในมุมของเอกสาร ต้องเขียนลงไปให้ชัดว่าอุปกรณ์ตัวไหนใครเป็นเจ้าของ

อ่าน STATUS กับ T_DIAG ของบล็อกสื่อสาร

ส่วนนี้คือของที่ผมวัดเองบน simulator ตอนไล่ว่าลิงก์ไม่ไหลเพราะอะไร ผมเขียน OB วินิจฉัยขึ้นมาอ่านค่า STATUS ของ TSEND_C/TRCV_C กับผลของ T_DIAG แล้วดูค่าไปทีละฝั่ง ค่าที่เห็นและความหมายที่ยืนยันได้จากการทดลองมีเท่านี้

ค่า STATUS ความหมายที่เห็นจากการวัด
16#7000 ไม่มีงาน หรือกำลังอ่านผิด instance
16#7002 กำลังทำงานหรือรออยู่
16#7004 เชื่อมต่อแล้ว และส่งวนรอบอยู่
16#80C5 partner ปฏิเสธ หรือไม่มีอยู่ที่ปลายทาง

ค่า 7000 มีวงเล็บว่าอ่านผิด instance เพราะถ้าไปอ่าน STATUS จาก instance ของบล็อกที่ไม่ได้ถูกเรียกใช้จริง จะได้ 7000 นิ่งตลอด ก่อนจะเชื่อค่านี้ต้องตรวจก่อนว่าอ่านจาก instance ตัวเดียวกับที่ network เรียก ส่วน 80C5 เป็นค่าที่ใช้ยืนยันกลับด้าน ถ้าลิงก์ไปหาปลายทางที่ไม่มีอยู่ขึ้น 80C5 ได้ ค่า State 4 ที่เห็นในลิงก์อื่นก็เป็นการเชื่อมต่อจริง ไม่ใช่ค่าที่ขึ้นเสมอ

ฝั่ง T_DIAG ค่า State เท่ากับ 4 แปลว่า connected แต่ตัวที่บอกความจริงได้มากกว่าคือ SentBytes กับ ReceivedBytes ต้องอ่านสองครั้งห่างกันแล้วดูว่าตัวเลขเพิ่มจริงหรือไม่

ลำดับการอ่านเมื่อลิงก์ไม่ไหลSTATUSถูก instance หรือยัง->T_DIAG State4 = connected->SentBytesเพิ่มหรือไม่->ReceivedBytesอีกฝั่งเพิ่มหรือไม่->heartbeatชั้นข้อมูล
# ค่า STATUS ที่ผมเห็นเองบน simulator ค่าอื่นให้เปิด help ของบล็อกก่อนอ้าง
STATUS = {
    0x7000: 'ไม่มีงาน หรืออ่านผิด instance',
    0x7002: 'กำลังทำงาน / รอ',
    0x7004: 'เชื่อมต่อแล้ว ส่งวนรอบ',
    0x80C5: 'partner ปฏิเสธ หรือไม่มีอยู่',
}

def verdict(status, bytes_first, bytes_second):
    text = STATUS.get(status, 'ไม่อยู่ในรายการที่วัด')
    moving = 'เพิ่ม' if bytes_second > bytes_first else 'ไม่ขยับ'
    return f'{status:04X}: {text} | ตัวนับไบต์{moving}'

# ตัวเลขไบต์ด้านล่างเป็นค่าสมมติเพื่อให้เห็นรูปแบบผลลัพธ์
print(verdict(0x7004, 1200, 1840))
print(verdict(0x7002, 0, 0))
ชั้นการเชื่อมต่อ

STATUS 7004 กับ State 4

บอกว่าบล็อกสื่อสารฝั่งนี้เชื่อมต่อได้และกำลังส่ง เป็นมุมมองของฝั่งเดียว ผมเจอบน simulator ว่าฝั่งส่งขึ้น 7004 และ SentBytes เพิ่มเรื่อย ๆ ขณะที่โปรแกรมฝั่งรับไม่ได้ข้อมูลเลยสักไบต์

ชั้นข้อมูล

heartbeat ที่เปลี่ยนค่า

บอกว่าข้อมูลของอีกฝั่งเดินทางมาถึงโปรแกรมฝั่งนี้จริง และยังสดอยู่ เป็นตัวเดียวที่ใช้ตัดสินได้ว่าค่าใน DB เชื่อได้หรือไม่ ค่า STATUS ใช้ไล่หาสาเหตุ ไม่ได้ใช้แทน heartbeat

กรณีฝั่งส่งดูปกติแต่ฝั่งรับไม่ได้ข้อมูลที่ผมเจอ เป็นข้อจำกัดของ simulator เอง รายละเอียดการทดลองอยู่ใน บทความเรื่อง interface ตัวที่สองบน PLCSIM อีกข้อที่ต้องรู้เวลาทดสอบลิงก์แบบนี้บน simulator มาจากคู่มือ S7-PLCSIM V15 หน้า 143 คือ T-block ไม่มีบัฟเฟอร์ฝั่งรับ TSEND จะไม่จบจนกว่าโปรแกรมฝั่งรับจะรัน TRCV และรับได้สูงสุดครั้งละ 1024 ไบต์ ถ้า DB ที่ส่งใหญ่กว่านั้น ผลบน simulator กับบนเครื่องจริงอาจไม่เหมือนกัน ข้อนี้ผมอ่านจากคู่มือ ยังไม่ได้ทดลองแยกให้เห็นกับตา

สิ่งที่ยังไม่ได้พิสูจน์

เพื่อไม่ให้ใครเอาไปอ้างเกินจริง ผมแยกไว้ตรงนี้ว่าอะไรอยู่ระดับไหน

เรื่อง ระดับหลักฐาน
โหนดที่หลุดคงสถานะเดิม อ่านจากคู่มือ W309 หน้า 235 ของไฟล์ PDF
สถานะรายโหนด 4 บิตและ 8 บิต อ่านจากคู่มือ W309
DIP ขา 3 และขา 4 ของ DeviceNet unit อ่านจากคู่มือ W380 หน้า 74
ค่า STATUS 7000, 7002, 7004, 80C5 และ State 4 วัดเองบน simulator
T-block ไม่มีบัฟเฟอร์ฝั่งรับ 1024 ไบต์ อ่านจากคู่มือ S7-PLCSIM V15 หน้า 143
แบบร่าง word สถานะ เลขเวอร์ชัน ตัวนับ ร่างไว้ ยังไม่ได้ลงเครื่อง

ความหมายของ STATUS ค่าอื่นนอกจากสี่ค่านี้ผมไม่ได้วัด ใครเจอค่าอื่นให้เปิด help ของบล็อกในเวอร์ชันที่ใช้อยู่ก่อนจะสรุป ไม่ควรเดาจากรูปแบบตัวเลข

สรุปคือ ลิงก์ระหว่าง PLC ที่เขียนเองบน TCP ใช้งานได้ แต่ต้องยอมรับว่าของ 5 อย่างที่เครือข่ายสำเร็จรูปให้มาในตัวกลายเป็นงานที่ต้องเขียน ต้องทดสอบ และต้องมีคนยืนยันเอง ส่วนตัวผมถ้าต้องเลือกทำก่อนแค่ข้อเดียวจาก 11 ข้อ ผมเลือกข้อ 5 เพราะเป็นข้อเดียวที่คนเขียนโปรแกรมตอบคนเดียวไม่ได้ ที่เหลือจะทำมากน้อยแค่ไหนก็ตามความเสี่ยงของแต่ละงาน ตรงไหนผมอ่านคู่มือคลาดเคลื่อนหรือได้ลองกับเครื่องจริงแล้วผลต่างจากที่เขียนไว้ เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ

เคยเจองานแบบนี้ไหม? ติดตรงไหน?

มาแลกวิธีกันต่อในบอร์ด LinuxThai

→ คุยต่อในบอร์ด

ความคิดเห็น 0

ยังไม่มีความคิดเห็น — เป็นคนแรกเลย