ในฐานะ CODESYS Solutions Architect ยินดีต้อนรับสู่โลกของ IEC 61131-3 ครับ สำหรับ C# Developer การทำความเข้าใจ Function Block (FB) นั้นง่ายมากครับ
ให้มองว่า Function Block คือ “Class” ใน C# ครับ
- ก่อนใช้งาน ต้อง Instantiate (ประกาศตัวแปร) ก่อนเสมอ (เหมือน
new Timer()) - FB มี Memory/State (จำค่าเก่าได้ เช่น เวลาที่นับค้างไว้ หรือสถานะปุ่มรอบที่แล้ว)
- การเรียกใช้ (Call) คือการสั่งให้ Object นั้นทำงานในรอบสแกน (Cyclic Scan) นั้นๆ
นี่คือ Best Practices ในการใช้งาน Standard Libraries (TON, R_TRIG) ในภาษา ST ครับ
1. วิธีการประกาศตัวแปร Instance (Declaration)
ใน CODESYS เราไม่ใช้ keyword new ในการสร้าง Object แต่เราจะประกาศในส่วน VAR ครับ การประกาศนี้ระบบจะจอง Memory ให้โดยอัตโนมัติ
PROGRAM PLC_PRG
VAR
// Inputs
xButton : BOOL;
// Outputs
xMotor : BOOL;
xCmdShoot : BOOL; // คำสั่งยิงสัญญาณครั้งเดียว
// --- 1. การประกาศ Instance (เหมือน: Timer fbTimerLongPress = new Timer();) ---
fbTimerLongPress : TON; // Timer On-Delay (หน่วงเวลาเปิด)
fbTrigOneShot : R_TRIG; // Rising Edge Trigger (จับขอบขาขึ้น)
END_VAR
2. ตัวอย่าง Code: Long Press Logic (TON)
โจทย์: ต้องกดปุ่มแช่ไว้นาน 3 วินาที มอเตอร์ถึงจะทำงาน (ถ้าปล่อยก่อน เวลาจะ Reset)
หลักการทำงานของ TON (Timer On-Delay):
IN: เงื่อนไขขาเข้า (BOOL)PT: เวลาที่ตั้งไว้ (Preset Time)Q: Output จะ True เมื่อ IN ค้างไว้นานครบ PTET: เวลาที่นับผ่านไป (Elapsed Time)
// ============================================================
// Logic: Long Press 3 Seconds to Start Motor
// ============================================================
// 1. เรียกใช้งาน Instance (Call the Object)
// ส่ง Parameter แบบ Named Parameters (แนะนำวิธีนี้เพื่อความอ่านง่าย)
fbTimerLongPress(IN := xButton, PT := T#3S);
// 2. นำค่า Output (.Q) ไปใช้งาน
// ถ้ากดค้างครบ 3 วินาที fbTimerLongPress.Q จะเป็น TRUE
xMotor := fbTimerLongPress.Q;
// 💡 C# Analogy:
// เหมือนการเรียก fbTimerLongPress.Update(input, timeSet); ใน Game Loop
// แล้วค่อยเช็ค if (fbTimerLongPress.IsFinished) { ... }
3. ตัวอย่าง Code: Rising Edge (One-shot)
โจทย์: เมื่อกดปุ่ม (จังหวะ 0 -> 1) ให้ส่งคำสั่ง xCmdShoot ทำงานแค่ 1 รอบสแกน (Pulse) แม้จะกดปุ่มค้างไว้
หลักการทำงานของ R_TRIG:
CLK: สัญญาณ Clock ขาเข้าQ: จะ True แค่ 1 รอบสแกน เมื่อ CLK เปลี่ยนจาก False เป็น True
// ============================================================
// Logic: Rising Edge Detection (One-Shot)
// ============================================================
// 1. เรียกใช้งาน Instance ทุกรอบสแกน
fbTrigOneShot(CLK := xButton);
// 2. เช็คสถานะ Output (.Q)
// Q จะเป็น TRUE แค่ "แวบเดียว" ตอนที่มือกดปุ่มลง
IF fbTrigOneShot.Q THEN
// Code ในนี้จะทำงานแค่ครั้งเดียว ต่อการกด 1 ครั้ง
// เหมาะสำหรับสั่ง Toggle ค่า, บวกเลข Counter, หรือส่ง Data communication
xCmdShoot := TRUE;
ELSE
xCmdShoot := FALSE;
END_IF
4. ⚠️ Architect Warning: ทำไมต้องเรียก FB ภายนอก IF?
นี่คือ “The #1 Mistake” ของโปรแกรมเมอร์ที่ย้ายมาจาก C# ครับ ใน C# เรามักจะเขียนแบบนี้เพื่อประหยัด Resource:
// ❌ C# Style (ผิดมหันต์ใน PLC)
if (StartProcess) {
timer.Update(); // เรียก Timer เฉพาะตอนใช้งาน
}
แต่ใน PLC ห้ามทำแบบนั้นเด็ดขาด! เพราะ:
- FB ต้องการการรีเซ็ต:
TONจะจับเวลาได้ ต้องเห็น IN เปลี่ยนจาก TRUE เป็น FALSE (Falling Edge) เพื่อ Reset ค่า ET (Elapsed Time) กลับเป็น 0 - FB ต้องการเห็นการเปลี่ยนแปลง:
R_TRIGต้องจำค่ารอบที่แล้ว (Last Cycle) เพื่อเทียบกับรอบปัจจุบัน ถ้าคุณหยุดเรียกมันใน IF มันจะจำค่าไม่ได้ และ Logic จะเพี้ยน
✅ วิธีที่ถูกต้อง (Best Practice):
ต้องเรียก FB ให้ทำงาน ทุกรอบสแกน (Outside IF) แล้วค่อยเอาผลลัพธ์ (.Q) ไปใช้ใน IF ครับ
// ❌ BAD Code (เสี่ยง Bug รุนแรง)
IF xButton THEN
// ถ้า xButton เป็น FALSE, fbTimer จะหยุดทำงาน และ "ค้าง" ค่าเดิมไว้
// ครั้งหน้ากดใหม่ เวลาอาจจะไม่เริ่มนับจาก 0 หรือ Output ค้างเป็น TRUE ตลอดกาล
fbTimerLongPress(IN := TRUE, PT := T#3S);
END_IF
// ✅ GOOD Code (Industrial Standard)
// เรียก FB เสมอ เพื่อให้มัน update state ภายในของมันเอง
fbTimerLongPress(IN := xButton, PT := T#3S);
IF fbTimerLongPress.Q THEN
// เอาผลลัพธ์มาใช้ตรงนี้
xMotor := TRUE;
END_IF
สรุป: ให้มอง Function Block เหมือน “Hardware Component” (เช่น ชิปจับเวลา) ที่ต้องจ่ายไฟเลี้ยงตลอดเวลา (เรียกใช้นอก IF) ส่วน Logic การควบคุมให้ไปจัดการที่ขา Input/Output ของมันแทนครับ
ติดตามต่อใน EP.5: เราจะนำความรู้ทั้งหมด (IF, CASE, FB) มารวมร่างกันเพื่อสร้าง “State Machine” สำหรับควบคุมเครื่องจักรเต็มรูปแบบครับ
