บทความ RFID พร้อมตัวอย่างการต่อใช้งาน ตอนที่ 3 RFID ICODE

บทความ RFID พร้อมตัวอย่างการต่อใช้งาน
ตอนที่ 3 มาตรฐาน ISO15693 หรือ ICODE

โดยเนื้อหาหลักๆ จะประกอบด้วยเนื้อหาดังนี้

          RFID ชื่อเต็มๆ ก็คือ Radio Frequency Identification หรือการระบุข้อมูลสิ่งต่างๆ โดยใช้คลื่นความถี่วิทยุ ซึ่งพวกเราทุกคนคงจะคุ้นเคยกับระบบนี้เป็นอย่างดี เพราะว่า RFID ถูกนำเข้ามาใช้ในชีวิตประจำวันของเราอย่างหลากหลาย เพียงแต่ว่าเราจะรู้หรือไม่เท่านั้นเองว่าสิ่งเหล่านั้นใช้เทคโนโลยี RFID

          จากตารางในบทความตอนที่ 1 (คลิกดูตาราง) จะเห็นว่า RFID ที่ขายในเว็บไซต์ของเรามี 3 ประเภท คือ
          1. มาตรฐาน ISO10536 หรือ RFID 125 KHz 
          2. มาตรฐาน ISO15693 หรือ ICODE
          3. มาตรฐาน ISO14443 Type A หรือ Mifare
         ในการเลือกใช้แต่ละมาตรฐานต้องคำนึงถึงว่าเครื่องอ่าน-เขียนรองรับมาตรฐานของการ์ดที่ใช้อยู่หรือไม่ เช่น เครื่องอ่าน-เขียนตามมาตรฐาน Mifare ไม่สามารถใช้ได้กับบัตร ICODE ถึงแม้ว่าจะใช้ย่านความถี่เดียวกัน คือ 13.56MHz แต่โปรโตคอลที่รับส่งข้อมูลแตกต่างกัน หากต้องการใช้ร่วมกันอาจเปลี่ยนไปใช้เครื่องอ่าน-เขียนที่รองรับหลายมาตรฐาน (Multi-Protocol) แทน เช่น Pi‐931‐X34CC จาก บจก. ซิลิคอน คราฟท์ เทคโนโลยี หรือ SL500F-USB Reader/Write จาก StrongLink Technology Co., Ltd.

2. มาตรฐาน ISO15693 หรือ ICODE เป็นมาตรฐาน RFID ที่ความถี่ 13.56 MHz เหมาะสำหรับงานต้องการเก็บข้อมูลไว้ที่บัตร ไม่ต้องการความปลอดภัยของข้อมูลบนบัตร

2.1 I.CODE SLI 13.56MHz 128 Byte Tag Card (ERFC008)

           รูปแบบบัตร I.CODE ที่ทางเราจำหน่ายมีแบบการ์ดและฉลาก โดยก่อนที่เราจะใช้งาน RFID ประเภท ICODE จำเป็นจะต้องทราบถึงรายละเอียดโครงสร้างข้อมูลบนบัตรว่าส่วนใดเป็นข้อมูลของที่ผู้ใช้สามารถเขียนหรืออ่านได้ หรือส่วนใดเป็นส่วนแสดงรายละเอียดของบัตร จึงจะสามารถใช้งานบัตรได้ถูกต้อง 
โครงสร้างข้อมูลของบัตร I.CODE SLI ขนาด 128 ไบต์ดังนี้

จากภาพแสดงรูปแบบข้อมูลบนบัตรจะเห็นได้ว่าบัตรแบ่งข้อมูลออกเป็นบล็อค (Block) ทั้งหมด 
32 บล็อค (-4 ถึง 27) ในแต่ละบล็อคเก็บข้อมูล 4 ไบต์ โดยบล็อคต่างๆ เก็บข้อมูล ดังนี้
         – บล็อค -4 และ -3 เก็บค่า UID (Unique Identifier) คือ ข้อมูลของการ์ด เช่น ผู้ผลิต ชนิดของการ์ด หมายเลขซีเรียลนัมเบอร์ โดยค่า UID มีขนาดถึง 64 บิต ทำให้ต้องใช้ข้อมูล 2 บล็อคโดยบล็อค -4 เก็บ 4 ไบต์แรก บล็อค -3 เก็บ 4 ไบต์หลัง ซึ่งข้อมูลในส่วนนี้ผู้ใช้สามารถอ่านข้อมูลได้อย่างเดียว ไม่สามารถเขียนลงไปได้
         – บล็อค -2 เก็บค่าคุณสมบัตรพิเศษบนบัตร ผู้ใช้สามารถเปิดใช้งานคุณสมบัติพิเศษต่างๆ เหล่านี้หรือไม่ก็ได้ ไม่มีผลต่อการอ่านหรือเขียนข้อมูลบนบัตร โดย
               o ไบต์ 0 เป็นค่าที่ใช้ภายในบัตร ผู้ใช้ไม่สามารถเขียนหรืออ่านได้
               o ไบต์ 1 ค่า EAS หรือย่อมาจาก Electronic Article Surveillance เป็นโหมดที่ออกแบบมาให้ทำงานในระบบป้องกันการขโมยสินค้าที่ใช้ในห้างร้านค้าทั่วไป สามารถเปิดการใช้งาน EAS โดยเซตที่บิต 0 มีค่าเป็น 1 หรือปิดโดยเซตเป็น 0 แต่จะใช้งานจะได้สมบูรณ์เมื่อนำไปใช้กับเครื่องอ่านบัตร ICODE ที่มีคำสั่งตรวจสอบค่า EAS บนบัตรด้วย

               o ไบต์ 2 ค่า AFI หรือย่อมาจาก Application Family Identifier เป็นการกำหนดรูปแบบการใช้งานของบัตร เช่น ผู้ใช้ต้องการกำหนดให้บัตรใช้ในประเภทขนส่งเท่านั้น เมื่อนำบัตรนี้ไปใช้กับเครื่องอ่านอื่นที่ตรวจค่า AFI เฉพาะด้านการแพทย์จะไม่สามารถใช้งานได้ แต่โดยค่าเริ่มต้นของบัตรกำหนดให้ใช้ได้กับงานทุกประเภท รายละเอียดสามารถอ่านเพิ่มเติมได้ที่ ISO/IEC 15693-3:2009
               o ไบต์ 3 ค่า DSFID ย่อมาจาก Data storage format identifier เป็นค่าที่บรรยายโครงสร้างข้อมูลในบัตรรายละเอียดสามารถอ่านเพิ่มเติมได้ที่ ISO/IEC 15693-3:2009
        – บล็อค -1 เก็บข้อมูล Write Access Condition โดยข้อมูลนี้เป็นการกำหนดสิทธิในการเขียนข้อมูลของผู้ใช้ทั้ง 28 บล็อค (0 ถึง 27) ค่ากำหนดการเขียนข้อมูลแต่ละบล็อคกำหนดดังตาราง

           จากตารางจะเห็นได้ว่าค่าเริ่มต้นของทุกบล็อคกำหนดเป็น ‘0’ คือสามารถเขียนได้ ถ้าผู้ใช้ต้องการป้องกันการเขียนข้อมูลในบล็อคที่ต้องการ เช่น ป้องกันบล็อคที่ 5 ต้องกำหนดไบต์ ที่ 1 บิตที่ 1 จาก ‘0’ เปลี่ยนเป็น ‘1’ แทน แต่เมื่อเปลี่ยนเป็น ‘1’ แล้ว Block ที่ 5 นี้จะไม่สามารถเขียนข้อมูลลงไปได้อีก
       – บล็อค 0-27 เป็นข้อมูล ผู้ใช้สามารถอ่านหรือเขียนบล็อคที่ต้องการได้ ถ้าข้อมูลของ Write Access Condition (Block -1) ยังเป็นมีค่าเป็น 0 อยู่

2.2 RFID 13.56MHz Read/Write I.CODE SLI Module (UART TTL) (รหัสสินค้า EFDV029)

         จากตารางคุณสมบัติแสดงว่าโมดูลนี้เชื่อมต่อแบบ Serial ระดับแรงดัน TTL รองรับการเขียน-อ่านข้อมูลเฉพาะบัตร ICODE เท่านั้น

ขาที่ใช้งานบนโมดูล
        – ขา IO แสดงสถานะเมื่อมีบัตรทาบที่โมดูล โดยเมื่อมีบัตรขา IO มีสถานะเป็น ‘0’ หรือ 0 V ในทางกลับกันเมื่อไม่บัตรขา IO จะมีสถานะเป็น ‘1’ หรือ 5V
       – ขา TX ขาส่งข้อมูล Serial
       – ขา 3 RX ขารับข้อมูล Serial
       – ขา 4 ขาไฟ VCC ใช้แรงดันที่ 4.5 – 5.5 V
       – ขา 5 ขากราวด์ GND
         ไฟสถานะ LED State เป็น LED ที่ควบคุมโดยคำสั่งจากผู้ใช้ และ LED Tag In จะติดเมื่อมีบัตร ICODE มาทาบที่โมดูล

          สามารถกำหนดความเร็ว Serial ได้ด้วยค่า R6 และ R7 ถ้าต้องการ Baud Rate เป็น 9600 ต้องลอยwไม่เชื่อมต่อ R ทั้ง 2 ตัว ดังภาพ แต่ปกติค่าเริ่มต้นจากโรงงานกำหนดไว้ที่ 115,200 คือ บัดกรี R6 และ R7 มาให้แล้ว 

คำสั่งในโมดูล RFID I.CODE

โมดูล RFID I.CODE กำหนดรูปแบบการส่งข้อมูล (Protocol) ดังนี้
          1. ผู้ใช้ต้องส่งคำสั่งไปยังโมดูล (Host to Reader) เริ่มต้นจากการส่งข้อมูล 0xBA เป็นส่วนเริ่ม (Preamble) ไปก่อน ตามด้วยขนาดของข้อมูล (Len) ขนาด 1 ไบต์ คำสั่ง (Command) ขนาด 1 ไบต์ และข้อมูล (Data) แล้วปิดท้ายด้วยผลรวมสำหรับตรวจสอบ (Checksum) ขนาด 1 ไบต์
          2. โมดูลส่งสถานะกลับมาที่ผู้ใช้ (Reader to Host) เริ่มต้นจากการส่งข้อมูลกลับ 0xBD เป็นส่วนเริ่มของข้อมูล (Preamble) ตามด้วยขนาดของข้อมูล (Len) ขนาด 1 ไบต์ คำสั่ง (Command) ขนาด 1 ไบต์ สถานะของคำสั่ง (Status) ขนาด 1 ไบต์ และข้อมูล (Data) แล้วปิดท้ายด้วยผลรวมสำหรับตรวจสอบ (Checksum) ขนาด 1 ไบต์ 
          ผู้ใช้สามารถดูข้อมูลเพิ่มเติมได้จากคู่มือ RFID 13.56MHz Read/Write I.CODE SLI Module (UART TTL)

ทดลองการใช้งาน
การใช้งานโมดูล RFID I.CODE อ่าน-เขียนข้อมูลลงบนบัตร โมดูล RFID I.CODE ไม่สามารถเชื่อมต่อกับ PC ได้โดยตรง ต้องต่อวงจรเพิ่มเพื่อแปลงระดับสัญญาณเป็น Serial (RS-232) เข้า PC ทางพอร์ต Serial RS-232 หรือต่อกับ USB to Serial ที่สื่อสารในระดับแรงดัน TTL ในการทดลองนี้เชื่อมต่อกับ USB to Serial

           หรือเลือกใช้ RFID ICODE ที่เชื่อมต่อแบบ RFID 13.56MHz Read/Write I.CODE Module (RS232) (EFDV026) ที่สามารถเชื่อมต่อเข้ากับ PC ที่มีพอร์ต Serial RS232 ได้โดยตรงใช้ไฟเลี้ยงจากหัว PS/2

          จากภาพเชื่อมต่อโมดูลเข้ากับ USB to Serial ถ้าดูที่ Device Manager จะเห็น USB to Serial เชื่อมต่ออยู่ พร้อมกับแสดงหมายเลขพอร์ต 

ทดลองนำบัตร RFID ICODE ไปทาบบนโมดูล ไฟ LED Tag In จะติดดังภาพ
1. เปิดโปรแกรม ThaiEasyEelec I.CODE โดยดาวน์โหลดได้ที่ link

2. เลือก Comport ให้ตรงกับที่เชื่อมต่ออยู่กับโมดูล กำหนด Baud rate ตรงกับโมดูล จากนั้นกดปุ่ม Connect

3. กดปุ่ม Get tag Information เมื่อต้องการทราบรายละเอียดของบัตร RFID ที่ใช้งานอยู่

โปรแกรมส่งคำสั่ง Get tag Information (0xBA,0x02,0x31,0x89) ไปยังโมดูล จากนั้นโมดูล จะส่งข้อมูลของบัตรกลับมา เป็นไปตาม Protocol ที่กำหนดไว้ในคู่มือ

4. เมื่อต้องการทราบข้อมูลว่าบล็อคที่กำหนดมีการป้องกันการเขียนข้อมูลไว้หรือไม่ ใช้คำสั่ง Get block security state โดยกำหนด Block และ Byte (Number) บนบล็อคนั้นนั้นแล้วกดปุ่ม GET

โมดูลจะตอบกลับดังภาพ

5. หัวข้อ Read Block คำสั่งเมื่อผู้ใช้ต้องการอ่านข้อมูลบนบัตรโดยกำหนดบล็อคที่ให้โมดูลเริ่มอ่าน (Read Block) และหยุดอ่าน (To Block) จากนั้นกดปุ่ม Read

6. หัวข้อ Write data to block เมื่อผู้ใช้ต้องการเขียนข้อมูลลงไปที่บัตร โดยกำหนดบล็อค (Block) และข้อมูลในช่อง Data (Hex) จากนั้นกดปุ่ม Write แล้วทดลองอ่านข้อมูลกลับจากบล็อคที่เขียนข้อมูลลงไป ซึ่งข้อมูลควรจะตรงกัน

7. หัวข้อ Accept to lock card เมื่อผู้ใช้ต้องการป้องกันการเขียนข้อมูลจากบล็อคที่กำหนด ให้เลือกบล็อคที่ต้องการล็อค จากนั้นกดปุ่ม LOCK

8. นอกจากจะสามารถ Lock การเขียนข้อมูลของแต่ละบล็อค ผู้ใช้ยังสามารถ Lock การเขียน Register AFI และ DSFID ได้โดยเลือก AFI หรือ DSFID แล้วกดปุ่ม LOCK

9. หัวข้อ Write AFI และ DSFID เมื่อผู้ใช้ต้องการกำหนดค่าให้กับ Register ทั้งสอง แต่ต้องไม่ถูกล็อคอยู่

ทดลองเชื่อมต่อ Arduino กับโมดูล RFID I.CODE

          ต่อบอร์ด Arduino กับโมดูล RFID ICODE ผ่านขา Serial (TTL) ขาไฟ +5V และ GND โมดูล RFID กำหนด Baud rate เป็น 9600 bps โดยลอย R6 และ R7 การทดลองนี้ใช้ Library TEE_RFID_ICODE โดย Unzip แล้ววางโฟลเดอร์ไว้ที่ .. Arduino\libraries ดังภาพ

          ลองทดสอบโดยเปิด Arduino IDE ขึ้นมา ไปที่ File > Example > TEE_RFID_ICODE > RFID_Icode_test จากนั้นกดปุ่ม Upload แล้วบอร์ดจะแสดงสถานะการทำงานผ่าน Serial Monitor (Download ที่นี่)

ตัวอย่างโค้ดโปรแกรม 

#include <SoftwareSerial.h>
#include <icode_rfid.h>
/* ------------------------  Icode RFID Library  ------------------------ */
//  function   IcodeRFID(Rx,Tx);  :: SoftwareSerial(Rx,Tx); define Rx and Tx
IcodeRFID IcodeRFID(2,3);
//  function .begin(baudrate);   for example it's define baudrate = 9600
//  SoftwareSerial is use for ----->   SL015M Icode RFID Reader
//  HarewareSerial is use for ----->   PC for monitor and test function
void setup(){
  IcodeRFID.begin(9600);
  Serial.begin(9600);
  Serial.println("");
  Serial.println("Hello RFID READER");
}
 
void read_Taginfo(void){
    taginfo *tag;
    tag = (taginfo *) malloc(sizeof(taginfo));
    if (IcodeRFID.readTaginfo(tag)==0x00){
        Serial.println("Operation Success");
        Serial.print ("UID  IS : ");
        for(int n = 0 ;n<8;n++){
            String c = String(tag->uid[n],HEX);
            Serial.print(" ");
            Serial.print(c);
        }
        Serial.println("");
        Serial.print("AFI : ");  Serial.println(tag->afi,HEX);
        Serial.print("DSFID : ");  Serial.println(tag->dsfid,HEX);
        Serial.print("TYPE IS :  ");
        switch(tag->type){
        case 0x31: Serial.println("Tag it"); break;
        case 0x32: Serial.println("I.code SLI"); break;
                }
    }
    free(tag);
    tag = NULL; 
}
 
void test_readDATA(byte startblock,byte number){
    datablock *storedata;
    storedata = (datablock *) malloc(sizeof(datablock));
    if (IcodeRFID.readBlock(startblock,number,storedata) == OPERATION_OK){
        Serial.println("Read DATA Complete");
        Serial.print("DATA Block ");
        Serial.print(startblock,DEC);  Serial.print (" To ");
        Serial.print(startblock+number,DEC);
        Serial.print(" : ");
        for(int n = 0 ;n<number*4;n++){
            String c = String(storedata->data[n],HEX);
            Serial.print(" ");
            Serial.print(c);
        }
    }
    free(storedata);
    storedata = NULL;
}
void test_writeblock(byte block,byte byte1,byte byte2,byte byte3,byte byte4){
    byte DAT_to_Write[4] = {byte1,byte2,byte3,byte4};
    if (IcodeRFID.writeBlockFromData(block,DAT_to_Write) == OPERATION_OK){
        Serial.println("Write Block Complete");
        Serial.print ("DATA Block ");
        Serial.print (block,DEC);
        Serial.print (" : ");
        for(int n = 0 ;n<4;n++){
            String c = String(DAT_to_Write[n],HEX);
            Serial.print(" ");
            Serial.print(c);
        }
    }
}
 
void test_writeAFI(byte AFI){
    if (IcodeRFID.writeAFI(AFI) == OPERATION_OK){
        Serial.println("Write AFI Complete");
    }
}
 
void test_writeDSFID(byte DSFID){
    if (IcodeRFID.writeDSFID(DSFID) == OPERATION_OK){
        Serial.println("Write DSFID Complete");
    }
}
 
void loop() {
    char a;
    byte startblock;
    byte number;
    if (IcodeRFID.WaitStatus(A5)){  // found card == 1
        Serial.println("");
        Serial.println("Found Card !!!");
        int sector = 0;
        while(digitalRead(A5)==0){      // wait for next operation
            if (Serial.available() > 0){
                a = Serial.read();
                Serial.println("");
                switch(a){
                    case 't': Serial.println("To Test Read TagInfo");
                            read_Taginfo();
                            break;
                    case 'r':   Serial.println("To Test Read DATA");
                            startblock = 0;
                            number = 3;
                            test_readDATA(startblock,number);
                            break;
                    case 'w':   Serial.println("To Test Write Block");
                            test_writeblock(2,0x01,0x02,0x03,0x04);
                            break;
                    case 'a':   Serial.println("To Test Write AFI");
                            test_writeAFI(0xAF); // set for sector 0
                            break;
                    case 'd':   Serial.println("To Test Write DSFID");
                            test_writeDSFID(0xDD); // set for sector 0
                            break;
                    case 'L':   Serial.println("To Test LED ON");
                            IcodeRFID.LED(0x01);
                            break;
                    case 'l':   Serial.println("To Test LED OFF");
                            IcodeRFID.LED(0x00);
                            break;
                }
            }
        }
    }
}

จากโค้ดโปรแกรมทำงานดังนี้

void setup(){
  IcodeRFID.begin(9600);
  Serial.begin(9600);
  Serial.println("");
  Serial.println("Hello RFID READER");
}

         ในฟังก์ชั่น setup() กำหนด software Serial IcodeRFID Baud Rate เป็น 9600 และ Hardware Serial Baud Rate เป็น 9600 เช่นกัน ส่งข้อความ “Hello RFID READER”

void loop() {
	char a;
	byte startblock;
	byte number;
	if (IcodeRFID.WaitStatus(A5)){  // found card == 1
		Serial.println("");
		Serial.println("Found Card !!!");
		int sector = 0;
		while(digitalRead(A5)==0){      // wait for next operation
			if (Serial.available() > 0){
				a = Serial.read();
				Serial.println("");

          ในฟังก์ชั่น Loop() ตรวจสอบเมื่อมีการ์ดเข้ามาทาบขา IO เปลี่ยนสถานะเป็น ‘1’ โดยตรวจสอบจากฟังก์ชั่น IcodeRFID.WaitStatus() แล้วโปรแกรมจะส่งข้อความ “Found Card !!!” จากนั้นจะวนตรวจสอบคำสั่งที่ส่งมาจาก PC

case 't': Serial.println("To Test Read TagInfo");
			  read_Taginfo();
			  break;

           เมื่อผู้ใช้ส่งตัว “t” มา โปรแกรมจะส่งข้อความ “To Test Read TagInfo” และส่งข้อมูลของการ์ดผ่านฟังก์ชั่น read_Taginfo();

case 'r':	Serial.println("To Test Read DATA");
				startblock = 0;
				number = 3;
				test_readDATA(startblock,number);
				break;

           เมื่อผู้ใช้ส่งตัว “r” มา โปรแกรมจะส่งข้อความ “To Test Read DATA” โปรแกรมจะอ่านข้อมูลของการ์ดจากฟังก์ชั่น test_readDATA ใน Block 0 Byte ที่ 3