หน้าแรกคู่มือHMIพื้นฐาน HMI และ SKTool7.1ใช้ Barcode กำหนดสูตรการผลิต
HMIขั้นสูง · Advanced18 นาที

ใช้ Barcode กำหนดสูตรการผลิต

เขียน Script ใน SKTool เก็บ Barcode ที่สแกนย้อนหลัง 10 ชุดด้วย Loop ซ้อน แสดงผลด้วย ASCII Display แก้ Bug ข้อมูลค้างใน Memory แล้วใช้ค่าที่สแกนเลือก Recipe ผ่าน RWI0 และ LB60100 เพื่อส่งค่าไปที่ PLC

เก็บ Barcode ย้อนหลัง 10 ชุดได้ด้วย Loop ซ้อนที่เลื่อนข้อมูลทีละ 50 Word (LW10000 → LW10050 → … → LW10500) แล้วเลือกสูตรการผลิตจากค่าที่สแกนด้วยการเขียน Recipe ID ลง RWIWord[0] และสั่ง LB60100 = 1 ให้ HMI ส่ง Recipe ไปที่ PLC

อัพเดทล่าสุด: 26 ตุลาคม 2569

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

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

฿6,150

ในตอนนี้ทำอะไร

ต่อจาก EP.14 ที่อ่านค่าจากเครื่องสแกน Barcode เข้า HMI ได้แล้ว ตอนนี้เพิ่มอีก 2 อย่าง

  1. เก็บ Barcode ที่สแกนย้อนหลัง 10 ชุดและแสดงบนหน้าจอ
  2. ใช้ค่าที่สแกนได้เลือกสูตรการผลิต (Recipe) แล้วส่งค่าของสูตรนั้นไปที่ PLC

แนวคิดการเก็บประวัติ Barcode

Barcode แต่ละชุดใช้พื้นที่ 50 Word ข้อมูลที่สแกนล่าสุดเก็บที่ LW10000 ทุกครั้งที่สแกนใหม่ให้เลื่อนข้อมูลลงไปทีละชุด

  • LW10000 → LW10050
  • LW10050 → LW10100
  • LW10100 → LW10150
  • … ไปเรื่อยๆ จนถึงชุดสุดท้ายที่ LW10500

รวมเป็นประวัติทั้งหมด 10 ชุด (LW10050 ถึง LW10500)

ค่าที่ประกาศไว้ใน Script (จาก EP.14)

ชื่อค่าความหมาย
DownloadRecipeTriggerBit60100LB60100 สั่งเขียน Recipe ไปที่ PLC
ScanFinishFlag60147LB บอกว่าสแกนเสร็จ
ScanDataLength60999LW เก็บความยาวข้อมูลที่สแกน
ScanDataStart61000LW เริ่มต้นของข้อมูลที่สแกน
MaxDataLength50ความยาวสูงสุดต่อ 1 ชุด
NumberOfBarcodes10จำนวนชุดที่เก็บย้อนหลัง
SaveDataStart10000LW เริ่มต้นที่เก็บข้อมูล

เขียน Loop ซ้อนเลื่อนข้อมูล

  1. เพิ่มตัวแปร j ในบรรทัดเดียวกับ i ภาษา C ประกาศหลายตัวแปรในบรรทัดเดียวได้โดยคั่นด้วยจุลภาค
  2. Loop นอกให้ i เริ่มที่ NumberOfBarcodes (10) เงื่อนไข i > 0 และลดค่าทีละ 1 ด้วย i-- — Loop นี้วนตามจำนวนชุดที่เก็บย้อนหลัง
  3. Loop ในให้ j วิ่งจาก 0 ถึง MaxDataLength - 1 (50 รอบ) เพื่อ Copy ข้อมูลทีละ Word
C · SKTool Macro
#include "MacroInit.h"
//#include "subFun1.c" //Example

void Macro_main(IN *p)
{
 MarcoInit
 int i, j;

 for (i = NumberOfBarcodes; i > 0; i--)
 {
   for (j = 0; j < MaxDataLength; j++)
   {
       LocalWord[SaveDataStart + (MaxDataLength * i) + j] = LocalWord[SaveDataStart + (MaxDataLength * (i - 1)) + j];
   }
 }
}

เช็ควงเล็บให้ดีว่าอะไรคำนวณก่อนหลัง วิธีเข้าใจ Loop นี้ที่ง่ายที่สุดคือลองแทนค่า

ijบรรทัดนี้หมายถึง
100LW10500 = LW10450
101LW10501 = LW10451
1049LW10549 = LW10499
90LW10450 = LW10400
10LW10050 = LW10000

ที่ให้ i นับถอยหลังเพราะต้องย้ายชุดเก่าสุดก่อน ข้อมูลแต่ละชุดจะได้ไม่ถูกเขียนทับก่อนย้าย เขียนเสร็จกด Compile ให้ขึ้น Success ถ้าไม่ผ่านให้เช็คว่าเขียนตรงกับตัวอย่างหรือไม่

สร้าง ASCII Display แสดงประวัติ 10 ชุด

  1. Copy ASCII Display ตัวเดิมมา ปรับให้บางลง
  2. ตั้ง Monitor Address เป็น LW10050 และลดจำนวนตัวอักษรที่แสดง (Total) เหลือ 13 ตัว
  3. คลิกขวาที่ ASCII Display → Multiple Copies แล้วตั้งค่า
    • Type: Interval
    • Address setting: Increasing To Down, Increase value 50 (Address เพิ่มทีละ 50 ไล่ลงไปเรื่อยๆ)
    • Numbers: X = 1, Y = 10
    • Interval: X = 10, Y = 10 (ระยะห่างระหว่างแต่ละชุดที่ Copy)
  4. จะได้ ASCII Display 10 ตัว (LW10050, LW10100, … LW10500) จัดวางแล้ว Download ลงหน้าจอ ถอดสาย USB-C แล้วไปที่หน้า Barcode ลองสแกน ข้อมูลที่สแกนจะเลื่อนลงมาเรื่อยๆ

แก้ Bug ข้อมูลค้างใน Memory

ลองสแกน Barcode ที่ยาวไม่เท่ากัน เช่นสแกน CDEF (4 ตัวอักษร) แล้วสแกน AB (2 ตัวอักษร) หน้าจอจะแสดง ABEF ทั้งที่สแกน AB เพราะ EF จากครั้งก่อนยังค้างอยู่ใน Memory ของ Address ที่อ่านค่าสแกน

วิธีแก้คือ Clear Data ทุกครั้งหลังสแกน เปิด Script Editor ไปที่ Script ScanLogic แล้วเพิ่ม Loop ที่เขียนช่องว่าง (Space) ลงพื้นที่ข้อมูลสแกน 50 ตัว (LW61000 ถึง LW61049) ต่อจากจุดที่ Copy ข้อมูลไปเก็บแล้ว ข้อมูลไม่หายเพราะถูกเก็บไว้ที่ LW10000 แล้ว

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

void Macro_main(IN *p)
{
 MarcoInit
 int i, j;
 if (LocalBit[ScanFinishFlag] == 1)
 {
   for (i = 0; i < LocalWord[ScanDataLength]; i++)
   {
       LocalWord[SaveDataStart + i] = LocalWord[ScanDataStart + i];
   }

   LocalBit[ScanFinishFlag] = 0;

   // Clear scan data area before the next scan
   for (i = 0; i < MaxDataLength; i++)
   {
       LocalWord[ScanDataStart + i] = ' ';
   }

   for (i = NumberOfBarcodes; i > 0; i--)
   {
       for (j = 0; j < MaxDataLength; j++)
       {
           LocalWord[SaveDataStart + (MaxDataLength * i) + j] = LocalWord[SaveDataStart + (MaxDataLength * (i - 1)) + j];
       }
   }
 }
}

Compile และ Download อีกครั้ง แล้วลองสแกนตัวยาวสลับกับตัวสั้น ค่าที่แสดงจะถูกต้อง

ใช้ค่าที่สแกนเลือก Recipe

Reserved Register ที่ใช้มี 2 ตัว

  • RWI0 — Recipe ID ปัจจุบันของหน้าจอ ใน Script เข้าถึงด้วย RWIWord[0] (Index ที่ 0) เขียนค่าลงไปเพื่อเปลี่ยน Recipe ปัจจุบัน
  • LB60100 — Trigger Bit ที่สั่งให้ HMI เขียน Recipe ไปที่ PLC (ใน Script ใช้ชื่อ DownloadRecipeTriggerBit) ตั้งเป็น 1 แล้วระบบจะ Reset กลับเอง ไม่ต้องตั้งเป็น 0 ทีหลัง

Recipe ที่ทำไว้ใน EP.10 มี 3 สูตร คือ ID 0, 1, 2

เช็คค่า Barcode ด้วยเลขฐาน 16

ตัวอักษร ASCII A = 0x41 และ B = 0x42 แต่ละ Word เก็บได้ 2 ตัวอักษร โดยตัวอักษรตัวหลังอยู่ไบต์สูง ตอนเขียนเป็นเลขฐาน 16 จึงต้องเอาตัวหลังขึ้นก่อน — AB เขียนเป็น 0x4241, CD เป็น 0x4443 และ EF เป็น 0x4645

ต่อท้าย Script ScanLogic (ภายในบล็อก if (LocalBit[ScanFinishFlag] == 1))

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

void Macro_main(IN *p)
{
 MarcoInit
 if (LocalWord[SaveDataStart] == 0x4241) // 41 => A, 42 => B
 {
   RWIWord[0] = 0;
   LocalBit[DownloadRecipeTriggerBit] = 1;
 }
 else if (LocalWord[SaveDataStart] == 0x4443 && LocalWord[SaveDataStart + 1] == 0x4645) // CDEF
 {
   RWIWord[0] = 2;
   LocalBit[DownloadRecipeTriggerBit] = 1;
 }
 else if (LocalWord[SaveDataStart] == 0x4443) // CD
 {
   RWIWord[0] = 1;
   LocalBit[DownloadRecipeTriggerBit] = 1;
 }
}
  • ใช้ else if เพิ่มเงื่อนไขของ Barcode แต่ละค่า
  • Barcode ที่ยาวกว่า 2 ตัวอักษรต้องเช็คหลาย Word พร้อมกันด้วยตัวดำเนินการ && (AND) ซึ่งเป็นจริงเมื่อทั้งสองฝั่งเป็นจริง
  • เงื่อนไข CDEF ต้องอยู่ก่อน CD ถ้าเอา CD ไว้ก่อน สแกน CDEF ก็จะเข้าเงื่อนไข CD ก่อน และได้ Recipe ID 1 แทน 2

ทดสอบกับ PLC

ฝั่ง PLC Samkoon เขียนโปรแกรมทดสอบใน SamSoar2022 ให้หลอดไฟที่ Y0 แสดงผลต่างกันตามค่า D0 ที่ Recipe เขียนมา (Recipe สูตรที่ 1 ตั้ง D0 = 1, สูตรที่ 2 ตั้ง D0 = 4, สูตรที่ 3 ตั้ง D0 = 7)

เงื่อนไข (ต่อขนานกันไปที่ Y0)ผลที่ Y0
D0 = K1 อนุกรม M8160 (สัญญาณคาบ 1 วินาที)กะพริบทุก 1 วินาที
D0 = K4 อนุกรม M8159 (สัญญาณคาบ 100 ms)กะพริบทุก 100 ms
D0 = K7 อนุกรม M8152 (เป็น 0 ขณะ PLC Run)ไม่ติด

Compile และ Download ทั้งสองฝั่ง แล้วทดสอบที่หน้า Barcode

  • สแกน AB → Recipe ID 0 → D0 = 1 → ไฟกะพริบช้า
  • สแกน CD → Recipe ID 1 → D0 = 4 → ไฟกะพริบเร็ว
  • สแกน CDEF → Recipe ID 2 → D0 = 7 → ไฟไม่กะพริบ

พร้อมกันนั้นค่าที่สแกนจะถูกเก็บเป็นประวัติบนหน้าจอด้วย หลักการเดียวกันนี้นำไปใช้กับ Barcode หรือ Logic อื่นๆ ได้