EL-UHF-RMT01 Menggunakan Mikrokontroler

EL-UHF-RMT01 Merupakan sebuah modul RFID ultra high frequency dengan konsumsi daya yang rendah dan dapat dihubungkan ke mikrokontroler menggunakan TTL UART 3,3V dengan protokol komunikasi EPC ISO18000-6C.

Pada modul EL-UHF-RMT01 terdapat sebuah kontroler untuk menghubungkan antena, UHF RFID, dan juga memori sehingga dapat digunakan untuk mendeteksi barang–barang pada penyimpanan dengan kemampuan membaca lebih dari 50 tag/detik sekaligus.

Berikut akan diperlihatkan cara menghubungkan EL-UHF-RMT01 dengan Arduino Mega.

Persiapan

Siapkan dahulu benda perlengkapan yang dibutuhkan :

  • Microcontroller
    • Pada tutorial ini contohnya ESP32 dan Arduino Mega
    • Microcontroller lain yang memiliki 2 serial port bisa digunakan
    • Microcontroller yang hanya memiliki 1 serial port tidak bisa mengikuti tutorial ini karena serial port-nya jika digunakan untuk debugging, tidak bisa berkomunikasi dengan EL-UHF-RMT01, misalnya Arduino Uno, Nano hanya memiliki 1 serial port
  • EL-UHF-RMT01 dengan kabel wafer agar dapat melakukan komunikasi dengan komputer.

Koneksi EL-UHF-RMT01 dengan microcontroller

Saat development, power bisa menggunakan power dari USB ke microcontroller, tanpa power supply, saat penggunaan di lapangan, direkomendasikan menggunakan power supply yang stabil.

Pin Enable boleh dilepas dari Pin 4 dan disambung ke VCC jika reader akan selalu digunakan selama microcontroller dinyalakan. Tapi jika konsumsi daya merupakan faktor penting, misalnya power supply menggunakan baterai, set pin 4 ke LOW untuk mengurangi penggunaan daya EL-UHF-RMT01.

Koneksi EL-UHF-RMT01 dengan ESP32

Khusus ESP32, RX TX di board merupakan RX0 TX0 yang terhubung port USB, sehingga, untuk kebutuhan debugging menggunakan RX1 TX1 di atas menggunakan GPIO 16 dan 17, dan perlu dideklarasikan pada saat setup dengan cara:

Serial1.begin(115200, SERIAL_8N1, 16, 17);

ESP32 board is an exception due to being based on the ESP32 core. Here, Serial0 refers to RX0 and TX0, while Serial1 and Serial2 are additional ports that can be assigned to any free GPIO.

Serial - Arduino Reference

Koneksi EL-UHF-RMT01 dengan Arduino Mega

Arduino Mega akan melakukan komunikasi dengan EL-UHF-RMT01 dengan menggunakan hardware serial dengan sambungan rangkaian dari El-uhf-RMT01 sebagai berikut.

WarnaArduinoEL-UHF-RMT01
Merah5V5V
HijauRx1Tx
PutihTx1Rx
BiruPin 4Enable
HitamGndGnd

Meskipun EL-UHF-RMT01 melakukan interface dengan mengunakan uart TTL3,3 V, Arduino tetap dapat membaca nilai 3,3 volt sebagai kondisi high.

Cara Kerja Alat

Sebelum masuk kedalam kode, perlu diketahui bahwa komunikasi dilakukan dimulai Arduino mengirimkan perintah dengan komunikasi serial dengan format data tertentu, contoh format frame yang diperlukan adalah seperti pada tabel berikut.

HTypeCMDPLParameterCRCEnd
BB000300 0100047E

Contoh frame perintah pada tabel diatas merupakan perintah untuk mendapatkan versi hardware dari reader, dari frame tersebut dapat dilihat ada bagian bagian seperti H, Type, CMD, PL, Parameter, CRC dan END.

Bagian - bagian yang telah disebutkan memiliki peran masing-masing untuk memastikan pengiriman dan penerimaan data diterima dengan baik, berikut adalah penjelasan masing-masing frame.

Contoh jenis jenis Frame yang lain dapat dilihat pada dokumentasinya di EL-UHF-RMT01 Protocol

H —> H adalah Header yang berarti pembuka, setiap pesan yang diterima ataupun dikirim memerlukan H sebagai tanda awal dari sebuah pesan.

Type –> tipe adalah bentuk komunikasi yang sedang pada sebuah pesan, dimana tipe dibagi menjadi 3 bagian seperti pada tabel di bawah ini.

TypeDescription
0x00Command from the Host Computer to the Interrogator
0x01Response from the Interrogator to the Host Computer
0x02Notification from the Interrogator to the Host Computer

Dari tipe tersebut dapat dilihat komunikasi terjadi pada host komputer dan interrogator, dimana interrogator merupakan bagian utama dari EL-UHF-RMT01, sedangkan komputer merupakan pemberi perintah yang merupakan Arduino pada tutorial ini.

CMD –> CMD adalah jenis perintah yang dikirim, dimana pada contoh respon interrogator adalah perintah untuk mendapatkan informasi modul interrogator. jenis-jenis perintah CMD ada pada tabel dibawah

CodeInstruction
0x03Get Interrogator Module Information
0x22Single Inventory
0x27Multiple Inventory
0x28Stop Multiple Inventory
0x0CSet Select
0x12Get Select
0x39Read Tag
0x49Write Tag
0x82Lock Tag

Untuk lebih lengkapnya perintah dapat dilihat di EL-UHF-RMT01 Protocol

PL –> PL adalah Parameter Length yaitu panjang parameter yang dikirim mengikuti perintah yang dikirim contoh pada respon interrogator memiliki PL dengan nilai 1, dan isi parameter nya adalah 0.

Parameter –> parameter merupakan data yang dikirim mengikuti command, dimana parameter ini tidak selalu ada, pada contoh 2 dapat dilihat memiliki isi parameter length dengan panjang 1 maka akan dibutuhkan parameter.

CRC –> CRC adalah nilai penjumlah mulai dari frame type hingga frame sebelum CRC lalu diambil 2 nilai lsb nya, sehingga dapat dilihat pada respon interrogator memiliki nilai CRC 4 yang merupakan total dari penjumlahan tersebut 00 + 03 + 00 + 01 + 00 = 04.

END –> end merupakan tanda akhir dari pesan yang dikirim ataupun diterima sehingga meruapakan tanda akhir dari 1 frame data.

Kode dan Penjelasan

Dari penjelasan langkah 2 maka yang perlu disiapkan adalah frame data yang mau dikirim terlebih dahulu yang disimpan didalam array seperti di bawah ini.

uint8_t singleRead[7] = {0xBB, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7E};

Setelah itu data pada frame yang dibuat dikirim secara berurutan dengan menggunakan fungsi seperti di bawah ini.

for(int i = 0; i < 7 ; i++){
      Serial1.write(singleRead[i]);
      delay(50);
    }

Begitu interrogator sudah menerima pesan yang dikirim dari host, interrogator akan memberikan respon ke Host, untuk membaca perintah yang dikirim dapat dengan mudah dibuat seperti di bawah ini.

while(Serial1.available()){
    Serial.println(Serial1.read());
  }

Fungsi diatas memang sudah bisa menerima pesan yang dikirim dari interrogator, namun memiliki kelemahan, data yang diterima akan ditampilkan secara langsung tanpa memastikan data tersebut bagus atau rusak seperti berikut:

Respon Interrogator

19:21:09.530 -> BB->1-FF-0-1-15-16-7F-
19:21:13.355 -> BB->1-FF-0-1-15-16-7F-
19:21:18.412 -> BB->1-FF-0-1-15-16-7F-
19:21:21.223 -> BB->1-FF-0-1-15-16-7F-

Data yang ditampilkan seperti pada baris paling atas terdapat nilai 7F yang merupakan ending pesan tersebut yang seharusnya tidak baik untuk ditampilkan karena data tersebut terhitung rusak, sehingga diperlukan sebuah proses untuk menerima pesan, sehingga frame parameter length dan CRC akan berguna kode untuk melakukan filter data rusak. kode lengkap untuk filter dapat dilihat seperti di bawah ini.

Kode

#define HEADER 0xBB
#define FRAME_TYPE_COMMAND 0x00
#define FRAME_TYPE_RESP 0x01
#define FRAME_TYPE_NOTIF 0x02
#define FRAME_TYPE_NOTIF_EMPTY 0x01
#define FRAME_CMD_SINGLE_INV 0x22
#define FRAME_CMD_SINGLE_INV_EMPTY 0xFF
#define FRAME_CMD_SINGLE_MULTI 0x27
#define FRAME_END 0x7E
#define PIN_EN 4
#define FRAME_PARAM_SINGLE_INV_EMPTY 0x15
#define TIMEOUT_MS 1000  // Maximum wait time for data in milliseconds
 
uint8_t singleRead[7] = {HEADER, FRAME_TYPE_COMMAND, FRAME_CMD_SINGLE_INV, 
                         0x00, 0x00, 0x22, FRAME_END};
uint8_t multiRead[10] = {HEADER, FRAME_TYPE_COMMAND, FRAME_CMD_SINGLE_MULTI,
                         0x00, 0x03, 0x22, 0x00, 0x10, 0x5c, FRAME_END};
 
uint8_t i;
uint8_t crc;
uint8_t header;
uint8_t frameType;
uint8_t frameCmd;
uint8_t framePl[2];
uint8_t paramL;
uint8_t tagRssi;
uint8_t tagPc[2];
uint8_t epcLength;
uint8_t tagEpc[16];
uint8_t tagCrc[2];
uint8_t frameCrc;
uint8_t frameEnd;
 
void setup() {
  // For Arduino
  Serial1.begin(115200);
  // For ESP32
  //Serial1.begin(115200, SERIAL_8N1, 16, 17);
 
  Serial.begin(9600);
 
  pinMode(PIN_EN, OUTPUT);
  clearSerial1Buffer();
  digitalWrite(PIN_EN, HIGH);
}
 
void loop() {
  sendRequestFrame();
 
  // Wait until data is available or timeout occurs
  if (!waitForSerialData(Serial1, TIMEOUT_MS)) {
    Serial.println("Timeout: No data received.");
    return;
  }
 
  // Read and validate the frame
  if (!readAndValidateFrame()) return;
 
  // Print the received frame data
  printFrameData();
}
 
// Function to send the inventory request frame
void sendRequestFrame() {
  for (i = 0; i < 7; i++) {
    Serial1.write(singleRead[i]);
    delay(50);
  }
}
 
// Function to wait for data with a timeout
bool waitForSerialData(HardwareSerial& serial, unsigned long timeout) {
  unsigned long startTime = millis();
  while (!serial.available()) {
    if (millis() - startTime >= timeout) {
      return false;  // Timeout occurred
    }
    delay(1);  // Avoid tight loop
  }
  return true;
}
 
// Function to read and validate the frame
bool readAndValidateFrame() {
  header = Serial1.read();
  if (header != HEADER) {
//    Serial.print("X Invalid header: ");
//    Serial.println(header, HEX);
    clearSerial1Buffer();
    return false;
  }
 
  frameType = Serial1.read();
  frameCmd = Serial1.read();
  crc = frameType + frameCmd;
 
  // Check if no tag found
  if (frameType == FRAME_TYPE_NOTIF_EMPTY && frameCmd == FRAME_CMD_SINGLE_INV_EMPTY) {
    uint8_t emptyParameter[5];
    for (i = 0; i < 5; ++i) {
      emptyParameter[i] = Serial1.read();
    }
    if (emptyParameter[2] == FRAME_PARAM_SINGLE_INV_EMPTY) {
//      Serial.println("Tag not found!");
    }
    return false;
  }
 
  if (frameType != FRAME_TYPE_NOTIF) {
    Serial.print("X Invalid frame type: ");
    Serial.println(frameType, HEX);
  }
 
  if (frameCmd != FRAME_CMD_SINGLE_INV) {
    Serial.print("X Invalid command code: ");
    Serial.println(frameCmd, HEX);
  }
 
  for (i = 0; i < 2; ++i) {
    crc += framePl[i] = Serial1.read();
  }
 
  paramL = (framePl[0] << 8) + framePl[1];
 
  crc += tagRssi = Serial1.read();
 
  for (i = 0; i < 2; ++i) {
    crc += tagPc[i] = Serial1.read();
  }
 
  epcLength = paramL - 5;
  for (i = 0; i < epcLength; ++i) {
    crc += tagEpc[i] = Serial1.read();
  }
 
  for (i = 0; i < 2; ++i) {
    tagCrc[i] = Serial1.read();
    crc += tagCrc[i];
  }
 
  crc &= 0xFF;
 
  frameCrc = Serial1.read();
  if (crc != frameCrc) {
//    Serial.print("X CRC mismatch: calculated ");
//    Serial.println(crc, HEX);
//    Serial.print("X Received CRC: ");
//    Serial.println(frameCrc, HEX);
  }
 
  frameEnd = Serial1.read();
  if (frameEnd != FRAME_END) {
//    Serial.print("X Invalid frame end: ");
//    Serial.println(frameEnd, HEX);
    return false;
  }
 
  return true;
}
 
// Function to print the frame data
void printFrameData() {
  Serial.println("Received frame:");
  Serial.print("- Header: ");
  Serial.println(header, HEX);
  Serial.print("- Frame type: ");
  Serial.println(frameType, HEX);
  Serial.print("- Command: ");
  Serial.println(frameCmd, HEX);
  Serial.print("- Parameter length: ");
  printBytes(framePl, 2);
  Serial.print("- RSSI: ");
  Serial.println(tagRssi, HEX);
  Serial.print("- Tag PC: ");
  printBytes(tagPc, 2);
  Serial.print("- Tag EPC: ");
  printBytes(tagEpc, epcLength);
  Serial.print("- Tag CRC: ");
  printBytes(tagCrc, 2);
  Serial.print("- CRC: ");
  Serial.println(frameCrc, HEX);
  Serial.print("- End: ");
  Serial.println(frameEnd, HEX);
}
 
// Function to print bytes in hexadecimal format
void printBytes(const uint8_t* data, uint8_t size) {
  for (uint8_t i = 0; i < size; i++) {
    if (data[i] < 0x10) Serial.print("0");
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
}
 
// Function to clear the Serial1 buffer
void clearSerial1Buffer() {
  if (Serial1.available()) {
//    Serial.print("Cleared buffer");
    while (Serial1.available()) {
      uint8_t data = Serial1.read();
//      if (data < 0x10) Serial.print("0");
//      Serial.print(data, HEX);
//      Serial.print(" ");
    }
//    Serial.println();
  }
}

Dari program diatas output yang dihasilkan akan seperti dibawah berikut ini, dari hasil tersebut dapat dilihat scan tag yang ditampilkan akan memiliki nilai dengan CRC yang sama, yang berarti dalam perhitungannya seperti di bawah ini.

CRC ==> 2 + 22 + 11 + c4 + 34 + 9 + b1 + e8 + 80 + 4e + 21 + 51 + 9 + ee + 5b = 561, yang berarti 2 lsb nya adalah 61 maka data tersebut dipastikan tidak rusak.

// Data yang sudah difilter
02:38:07:751 -> bb-2-22-0-11-c4-34-0-0-9-b1-e8-80-0-0-0-4e-21-51-9-ee-5b-61-7e
02:38:07:751 -> bb-2-22-0-11-ca-34-0-e2-80-11-70-0-0-2-c-c3-78-31-ad-3d-58-d2-7e

Dengan menggunakan contoh data: bb-2-22-0-11-c4-34-0-0-9-b1-e8-80-0-0-0-4e-21-51-9-ee-5b-61-7e, jika di breakdown sesuai dokumentasi (0x22 Single Inventory) berarti:

HTypeCMDPLRSSIPC TagEPCCRC TagCRCEnd
BB022200 11C434 0000 09 B1 E8 80 00 00 00 4E 21 51 09EE 5B617E

Informasi Tambahan

Pada kode yang telah dibuat di langkah 3 berfungsi untuk menjalankan perintah single inventory dari yang berarti dilakukan scanning tag sebanyak 1 kali, karena EL-UHF-RMT01 juga memiliki fungsi multi inventory, dimana perintah tersebut adalah proses scanning berulang sebanyak yang diinginkan dengan limit angka 0 – 65535, perintah tersebut dapat langsung dijalankan cukup dengan mengganti pada bagian void setup, lalu ganti nilai array yang dikirim menjadi seperti pada program di bawah ini.

uint8_t singleRead[7] = {0xBB, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7E};
uint8_t multiRead[10] = {0xBB, 0x00, 0x27, 0x00, 0x03, 0x22, 0x00, 0x10, 0x5c, 0x7E};
 
void setup() {
  Serial1.begin(115200);
  Serial.begin(9600);
 
  for(int i = 0; i < 10 ; i++){
      Serial1.write(multiRead[i]);
      delay(50);
    }
}

Format perintah yang dimiliki oleh multi inventory dapat dilihat pada tabel di bawah ini.

HTypeCMDPLReservedCNTCRCEnd
BB002700 032227 10837E

Pada format perintah multi inventory, jumlah scan yang dilakukan adalah sebanyak 10.000 kali (27 10 dalam hexa) sehingga jika hanya ingin melakukan perintah sebanyak 32 kali, cukup ganti nilai dalam frame cnt menjadi 0x0 dan 0x20 sehingga nilai CRC berubah menjadi 0x6c dan output dari perintah tersebut akan menjadi seperti berikut:

17:48:30.951 -> bb-2-22-0-11-df-34-0-0-9-b1-e8-80-0-0-0-4e-21-51-9-ee-5b-7c-7e
17:48:30.951 -> bb-2-22-0-11-d6-30-0-e2-80-68-94-0-0-50-9-56-71-b8-dl-c3-d9-de-7e
17:48:30.951 -> bb-2-22-0-11-df-34-0-0-9-b1-e8-80-0-0-0-4e-21-51-9-ee-5b-7c-7e
17:48:30.984 -> bb-2-22-0-11-d9-34-0-e2-80-11-70-0-0-2-c-c3-78-31-ad-3d-58-e1-7e
17:48:30.984 -> bb-2-22-0-11-d6-30-0-e2-80-68-94-0-0-50-9-56-71-b8-dl-c3-d9-de-7e
17:48:31.086 -> bb-2-22-0-11-e0-34-0-0-9-b1-e8-80-0-0-0-4e-21-51-9-ee-5b-7d-7e
17:48:31.086 -> bb-2-22-0-11-dc-34-0-e2-80-11-70-0-0-2-c-c3-78-31-ad-3d-58-e4-7e
17:48:31.188 -> bb-2-22-0-11-dc-34-0-e2-80-11-70-0-0-2-c-c3-78-31-ad-3d-58-e4-7e
17:48:31.188 -> bb-2-22-0-11-dc-34-0-e2-80-11-70-0-0-2-c-c3-78-31-ad-3d-58-e4-7e

Video