if, else, loop และ String
ภาษา C ใน HMI ตอนที่ 2: เงื่อนไข if / else / else if, for loop กับ sizeof(), char และ String, การสร้าง Function ใน Sub script และ memcpy() เพื่อแสดงข้อความบน ASCII Display เตรียมพร้อมใช้งาน Barcode Scanner
เขียนเงื่อนไขใน Script ของ HMI ด้วย if / else / else if, วนซ้ำด้วย for โดยหาความยาว Array จาก sizeof(myData) / sizeof(myData[0]), แยก Function ไว้ใน Sub script แล้วเรียกด้วย #include ส่วน String ต้องใช้ memcpy(LocalWord + 30, myString, strlen(myString)) คัดลอกลง Local Word ก่อน ASCII Display จึงแสดงได้
อัพเดทล่าสุด: 26 ตุลาคม 2569
บทนำ C Language สำหรับงานบาร์โค้ดใน HMI
ตอนนี้เป็นการเขียน Script ด้วยภาษา C ตอนที่ 2 ต่อจากตอนที่แล้ว ครอบคลุมเรื่องที่ยังเหลือ ได้แก่ เงื่อนไข (if / else), การวนซ้ำ (for loop), ตัวอักษรและ String และการสร้าง Function เพื่อใช้ซ้ำ ซึ่งจะนำไปใช้กับ Barcode Scanner ในตอนถัดไป
เริ่มจากเปิด Script Editor กด New มุมซ้ายบนเพื่อสร้าง Script ใหม่ ในคลิปตั้งชื่อว่า CBasic2 แล้วทดสอบทุกอย่างบนหน้า C LANGUAGE ด้วย Offline Simulate
Conditional Statement (เงื่อนไขการทำงาน)
การใช้ if Statement
if ตามด้วยวงเล็บ สิ่งที่อยู่ในวงเล็บต้องคำนวณออกมาเป็นจริงหรือเท็จ ถ้าเป็นจริง Code Block ใต้ if จะทำงาน
#include "MacroInit.h"
//#include "subFun1.c" //Example
void Macro_main(IN *p)
{
MarcoInit
if (LocalBit[0] == 1)
{
LocalWord[12] = 555;
}
}หมายเหตุ: การเปรียบเทียบค่าใช้ == (เท่ากับ 2 ตัว) เรียกว่า Comparison Operator
การใช้ if-else
ถ้าเงื่อนไขใน if เป็นเท็จ สิ่งที่อยู่ใน else จะถูก Run แทน
#include "MacroInit.h"
//#include "subFun1.c" //Example
void Macro_main(IN *p)
{
MarcoInit
if (LocalBit[0] == 1)
{
LocalWord[12] = 555;
}
else
{
LocalWord[12] = 666;
}
}การทดสอบ if-else
- Compile Script ให้ผ่าน
- บนหน้าจอ สร้าง Bit Switch ของ LB0 ตั้ง Function เป็น Invert และ Numeric Display แสดง LW12
- เรียกใช้ Script แบบ Global Script (Run ตลอดทุกช่วงเวลา): ดับเบิลคลิก Global Script กด New เลือก
CBasic2ตั้ง Frequency เป็น50ms แล้วกด OK - Offline Simulate — LB0 ดับ LW12 = 666 (ค่าใน else) พอสั่ง LB0 ติด LW12 = 555
ปกติเราคุ้นกับการทำเงื่อนไขที่ PLC แต่ถ้าเขียน Script เป็น เงื่อนไขก็เกิดขึ้นที่ฝั่ง HMI ได้เลย
การใช้ else if
ถ้ามีหลายเงื่อนไขก่อนถึง else ให้แทรกด้วย else if
#include "MacroInit.h"
//#include "subFun1.c" //Example
void Macro_main(IN *p)
{
MarcoInit
if (LocalWord[13] > 100)
{
LocalWord[14] = 1;
}
else if (LocalWord[13] < 10)
{
LocalWord[14] = 2;
}
else
{
LocalWord[14] = 3;
}
}ทดสอบด้วย Numeric Input ของ LW13 และ Numeric Display ของ LW14: LW13 = 0 → LW14 = 2, LW13 = 101 → LW14 = 1, LW13 = 44 (อยู่ระหว่าง 10 ถึง 100) → LW14 = 3
for Loop (การวนซ้ำ)
ปัญหาของการเขียนแบบ Manual
สมมติมี Array myData 5 ตัว (2, 4, 6, 8, 10) และอยากคัดลอกไปไว้ที่ Local Word ตั้งแต่ LW20 (2 ไป LW20, 4 ไป LW21 …) ถ้าไม่ใช้ Loop ต้องเขียนทีละบรรทัด แค่ 5 ตัวยังพอไหว แต่ถ้ามี 10 หรือ 100 ตัวจะเสียเวลาและไม่มีประสิทธิภาพ
#include "MacroInit.h"
//#include "subFun1.c" //Example
void Macro_main(IN *p)
{
MarcoInit
// วิธีที่ไม่ดี
LocalWord[20] = myData[0];
LocalWord[21] = myData[1];
// ... ต่อไปเรื่อยๆ
}หาความยาว Array ด้วย sizeof()
ถ้าเขียนเงื่อนไขของ Loop เป็น i < 5 วันหนึ่งที่เพิ่มข้อมูลใน Array ก็ต้องตามแก้โค้ดตรงนี้ด้วย จึงควรคำนวณความยาว Array เป็นตัวแปร ลองดูค่าของ sizeof() ก่อน
#include "MacroInit.h"
//#include "subFun1.c" //Example
void Macro_main(IN *p)
{
MarcoInit
short myData[] = { 2, 4, 6, 8, 10 };
LocalWord[15] = sizeof(myData); // 10
LocalWord[16] = sizeof(myData[0]); // 2
}ผลที่ Simulate ได้คือ LW15 = 10 และ LW16 = 2 เพราะ sizeof() คืนค่าเป็นหน่วย Byte และ short หนึ่งตัวมีขนาด 2 Byte (16 บิต) Array 5 ตัวจึงเป็น 10 Byte ความยาว Array = 10 / 2 = 5 เขียนสูตรแบบนี้แล้วเพิ่มข้อมูลใน Array ได้โดยไม่ต้องแก้ตัวแปรเลย
การใช้ for Loop
ในวงเล็บของ for มี 3 ส่วน: ค่าเริ่มต้นของ index, เงื่อนไขที่ Loop จะทำงานต่อ และสิ่งที่ทำหลังจบแต่ละรอบ (i++ คือบวก 1)
#include "MacroInit.h"
//#include "subFun1.c" //Example
void Macro_main(IN *p)
{
MarcoInit
short myData[] = { 2, 4, 6, 8, 10 };
short myDataLength = sizeof(myData) / sizeof(myData[0]); // 10 / 2 => 5
short i;
for (i = 0; i < myDataLength; i++)
{
LocalWord[20 + i] = myData[i];
}
}รอบแรก i = 0 จึงได้ LocalWord[20] = myData[0] รอบถัดไป i เป็น 1, 2, 3, 4 พอ i เป็น 5 เงื่อนไข 5 < 5 เป็นเท็จ Loop จึงหยุด รวมทำงาน 5 รอบตามขนาด Array ตรวจผลด้วย Numeric Display ของ LW20 (ได้ 2) และ LW24 (ได้ 10)
ตัวอักษรและ String
char กับ String
ตัวอักษรในภาษา C ใช้ชนิดข้อมูล char และต้องเป็นตัวอักษร ASCII คือตัวเลข ภาษาอังกฤษตัวเล็กตัวใหญ่ และอักขระพิเศษบางตัว ไม่มีภาษาไทย ประกาศตัวอักษรเดี่ยวด้วยฟันหนู 1 ตัว ('a')
ตัวอักษรตัวเดียวยังไม่ค่อยมีประโยชน์ ต้องเอาหลายตัวมาต่อกันเป็น String เช่นรหัสบาร์โค้ดของสินค้า ในภาษา C String คือ Array ของ char เขียนด้วยฟันหนู 2 ตัว
#include "MacroInit.h"
//#include "subFun1.c" //Example
void Macro_main(IN *p)
{
MarcoInit
char myChar = 'a';
char myString[] = "IoT HMI";
}ปัญหาการแสดงผล String
#include "MacroInit.h"
//#include "subFun1.c" //Example
void Macro_main(IN *p)
{
MarcoInit
LocalWord[25] = myChar; // แสดงได้
LocalWord[26] = myString; // แสดงไม่ได้
}สร้าง ASCII Display ของ LW25 และ LW26 แล้ว Offline Simulate: LW25 แสดงตัว a ได้ แต่ LW26 ไม่แสดงอะไร (ตอน Compile จะมี warning assignment makes integer from pointer without a cast ที่บรรทัดนี้) วิธีแก้ต้องใช้ Function สำหรับ String ซึ่งจะพูดถึงหลังเรื่อง Function
Function (การสร้างฟังก์ชัน)
การสร้าง Function
จริงๆ เราเรียก Function มาตลอดโดยไม่รู้ตัว เช่น sizeof() ที่คำนวณขนาดข้อมูลและเรียกซ้ำได้ การสร้าง Function เอง: คลิกขวาที่ Sub script เลือก Add subscript แล้วตั้งชื่อ ในคลิปสร้าง Function increment ที่บวก 1 ให้จำนวนเต็ม
short increment(short number)
{
short newNumber = number + 1;
return newNumber;
}
shortหน้าชื่อ คือชนิดข้อมูลที่ Function คืนค่าออกไป- ในวงเล็บคือ Parameter (Input) โปรแกรมตั้งชื่อเริ่มต้นให้ เปลี่ยนเป็นชื่ออะไรก็ได้ ในคลิปเปลี่ยนเป็น
number returnระบุค่าที่จะคืนออกไป
การใช้ Function
กลับไปที่ Script CBasic2 แล้ว Import Function เข้ามาที่บรรทัดบนสุดด้วย #include ตามด้วยชื่อไฟล์ในฟันหนู (.c เพราะเป็นไฟล์ภาษา C) จากนั้นเรียกใช้ใน Loop เดิม
#include "MacroInit.h"
//#include "subFun1.c" //Example
#include "increment.c"
void Macro_main(IN *p)
{
MarcoInit
short myData[] = { 2, 4, 6, 8, 10 };
short myDataLength = sizeof(myData) / sizeof(myData[0]);
short i;
for (i = 0; i < myDataLength; i++)
{
LocalWord[20 + i] = increment(myData[i]);
}
}ทุกค่าจะถูกบวก 1 ก่อนเก็บ ผล Simulate คือ LW20 = 3 และ LW24 = 11
memcpy() — แสดง String บนหน้าจอ
Function สำคัญเวลาทำงานกับ String ใน HMI คือ memcpy() (Memory Copy) รับ Parameter 3 ตัว
- ตำแหน่งปลายทางของข้อมูล —
LocalWord + 30คือเริ่มที่ LW30 - String ต้นทาง —
myString - ขนาดข้อมูล —
strlen(myString)(String Length) หาความยาว String ให้อัตโนมัติ ไม่ต้องนับเอง
#include "MacroInit.h"
//#include "subFun1.c" //Example
void Macro_main(IN *p)
{
MarcoInit
memcpy(LocalWord + 30, myString, strlen(myString));
}จากนั้น Copy ASCII Display มาอีกตัว ตั้ง Address เป็น LW30 ขยายกล่องให้ยาวขึ้นเผื่อไว้ และเพิ่มจำนวนตัวอักษรที่แสดง แล้ว Offline Simulate จะเห็นคำว่า IoT HMI บนหน้าจอ
สรุป
if/else/else ifทำเงื่อนไขที่ฝั่ง HMI ได้โดยไม่ต้องพึ่ง PLCforloop +sizeof(array) / sizeof(array[0])วนตามขนาด Array โดยไม่ต้องแก้โค้ดเมื่อเพิ่มข้อมูล- String คือ Array ของ
char(ASCII เท่านั้น) ต้องคัดลอกลง Local Word ด้วยmemcpy()+strlen()ก่อนแสดงบน ASCII Display - Function สร้างใน Sub script แล้วเรียกใช้ด้วย
#include
ตอนถัดไปจะเอาความรู้จากตอนนี้และตอนที่แล้วไปใช้กับ Barcode Scanner
ตอนถัดไป
14. การใช้งาน Barcode Scanner กับ HMI
ควรอ่านก่อน:
มีคำถาม? ติดต่อทีมงาน
