HMIขั้นสูง · Advanced21 นาที

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

ชุดอุปกรณ์สำหรับบทความนี้

ราคาชุดอุปกรณ์

฿6,150

บทนำ 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 จะทำงาน

C · SKTool Macro
#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 แทน

C · SKTool Macro
#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

  1. Compile Script ให้ผ่าน
  2. บนหน้าจอ สร้าง Bit Switch ของ LB0 ตั้ง Function เป็น Invert และ Numeric Display แสดง LW12
  3. เรียกใช้ Script แบบ Global Script (Run ตลอดทุกช่วงเวลา): ดับเบิลคลิก Global Script กด New เลือก CBasic2 ตั้ง Frequency เป็น 50 ms แล้วกด OK
  4. Offline Simulate — LB0 ดับ LW12 = 666 (ค่าใน else) พอสั่ง LB0 ติด LW12 = 555

ปกติเราคุ้นกับการทำเงื่อนไขที่ PLC แต่ถ้าเขียน Script เป็น เงื่อนไขก็เกิดขึ้นที่ฝั่ง HMI ได้เลย

การใช้ else if

ถ้ามีหลายเงื่อนไขก่อนถึง else ให้แทรกด้วย else if

C · SKTool Macro
#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 ตัวจะเสียเวลาและไม่มีประสิทธิภาพ

C · SKTool Macro
#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() ก่อน

C · SKTool Macro
#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)

C · SKTool Macro
#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 ตัว

C · SKTool Macro
#include "MacroInit.h"
//#include "subFun1.c" //Example

void Macro_main(IN *p)
{
 MarcoInit
 char myChar = 'a';
 char myString[] = "IoT HMI";
}

ปัญหาการแสดงผล String

C · SKTool Macro
#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 เดิม

C · SKTool Macro
#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 ตัว

  1. ตำแหน่งปลายทางของข้อมูล — LocalWord + 30 คือเริ่มที่ LW30
  2. String ต้นทาง — myString
  3. ขนาดข้อมูล — strlen(myString) (String Length) หาความยาว String ให้อัตโนมัติ ไม่ต้องนับเอง
C · SKTool Macro
#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 ได้โดยไม่ต้องพึ่ง PLC
  • for loop + 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

13 นาทีขั้นสูง · Advanced

ควรอ่านก่อน: