前に戻る

※ 最低限のメモのようなもので、資料としてちゃんと整えておりません。あくまで参考までに。。

UHF を一言でいうと

「遠くまで飛びやすい電波の周波数帯」
Wi-Fi、Bluetooth、携帯電話、UHF帯RFID などがここに含まれる。


📡 電波帯の分類

名称周波数帯特徴
LF低周波(kHz)近距離・金属環境に強い
HF13.56MHzSuica・MIFARE(RC522)など。近距離。
UHF860–960MHz数m〜十数m読める RFID。物流で使うやつ。
SHF2.4GHz, 5GHzWi-Fi、Bluetooth

🚚 UHF RFID

研究・業界で “UHF” と言うとほぼ UHF帯 RFID のことを指す

周波数は国ごとに違う:

  • 日本:920 MHz帯
  • US:915 MHz帯

👉 特徴(HF:13.56MHz とは完全に別物)

  • 読み取り距離:数m 〜 20m
  • 大量タグの同時読み取りが得意(数百タグ一気に読む)
  • アパレル・物流・棚卸しで主流
  • 反射・金属で性能が変わる

例:ZARA や UNIQLO の商品タグがこれ。


🆚 HF (13.56MHz, MIFARE, RC522) と UHF の違い

項目HF (13.56MHz)UHF RFID (920MHz)
距離数cm〜10cm数m〜20m
読み取り基本1枚ずつ大量同時読み取りが得意
方向性弱い(アンテナ近距離)方向性が強い(直線で飛ぶ)
用途Suica, 学生証, NFC物流、棚卸し、入退室管理、大規模トラッキング

R200チップのものを使いました
https://ja.aliexpress.com/item/1005005244081462.html?spm=a2g0o.order_list.order_list_main.5.705d585aRGT1hK&gatewayAdapt=glo2jpn

ChatGPTに相談だとダメそうでした。

以下あたりのYouTubeを参考にしました

Download: https://tinyurl.com/r200-sdk-en-7z

上記でダウンロードできたものを使っていじってみました

ざっくり言うと、

  • YPD-R200 は UHF RFID(R200)モジュールで、
  • UART(シリアル) でしゃべるタイプなので、
  • M5StickC Plus2 とは「5V電源 + GND + TX/RX 4本」でつなげばOK、
  • プロトコルは R200 系モジュール用の既存コードをほぼ流用できます。GitHub+1

以下、「とりあえずタグIDをシリアルに吐かせる」までの最低限セットを書きます。


1. ハード接続(配線)

1-1. 電源まわり

GitHub の R200 解説によると、この系統のモジュールは

「中身は 3.3V 動作だが、3.3V ピンだけだと電流が足りないことがあるので **VIN は 5V 供給推奨、
UART は 3.3V レベルで接続せよ」GitHub

と書かれています。

なので M5StickC Plus2 とは、だいたい次のように結線するのが無難です:

YPD-R200 側M5StickC Plus2 側
VIN / VCC (5V)5V ピン
GNDGND
TXDGPIO26 (M5StickC Plus2 の RX2)
RXDGPIO0 (M5StickC Plus2 の TX2)
  • M5StickC/Plus 系では、USB シリアル以外の UART2 が G26(RX2)/G0(TX2) に出ているという情報があります。jhalfmoon.com
  • UART レベルはどちらも 3.3V なので、レベル変換は不要(ただし、使っている YPD-R200 ボードが「TTL UART」と明記されていることは一応確認しておいた方が安全)。

もしモジュール側に

  • EN / ENable
  • BEEP / BUZZER
  • WIEGAND など

のピンがあっても、まずは VIN/GND/TX/RX だけつないで動作確認でOKです。


2. 最低限のテストスケッチ(M5StickC Plus2 + YPD-R200)

前提

  • Arduino IDE で M5StickC Plus2 ボードが動く状態
  • ライブラリ:M5StickCPlus2(あなたが普段使ってるやつ)を想定

#include <M5StickCPlus2.h>

/*************************************************************
 *  ベンダ提供 ReadMulti コマンド(複数回読み)をそのまま使用
 *  10バイトで構成された「タグを読め」という指令
 *************************************************************/
unsigned char ReadMulti[10] = {
    0XAA, 0X00, 0X27, 0X00, 0X03,
    0X22, 0XFF, 0XFF, 0X4A, 0XDD
};

/*************************************************************
 *  状態管理用変数(ベンダコードと同じ)
 *************************************************************/
unsigned int timeSec = 0;     // 一定時間ごとにコマンド送信するカウンタ
unsigned int timemin = 0;     // 秒が溜まったらインクリメントされるカウンタ
unsigned int dataAdd = 0;     // 受信データ位置(何バイト目か)
unsigned int incomedate = 0;  // 受信した1バイト
unsigned int parState = 0;    // パラメータ判定ステート
unsigned int codeState = 0;   // コード判定ステート

/*************************************************************
 *  RFID モジュール用 UART(Serial2)
 *  配線:
 *   YPD-R200 TXD → M5 G26 (RX2)
 *   YPD-R200 RXD → M5 G0  (TX2)
 *************************************************************/
HardwareSerial RfidSerial(2);

/*************************************************************
 *  最後に取得した EPC を画面表示するためのバッファ
 *************************************************************/
String lastEpc = "";

void setup() {
  /***********************************************************
   *  M5StickC Plus2 初期化
   ***********************************************************/
  auto cfg = M5.config();
  M5.begin(cfg);

  // 画面設定
  M5.Display.setRotation(1);       // 横向き
  M5.Display.setBrightness(120);    // 輝度
  M5.Display.fillScreen(BLACK);     // 画面クリア
  M5.Display.setTextSize(2);
  M5.Display.setCursor(0, 0);
  M5.Display.println("YPD-R200 TEST");

  /***********************************************************
   *  USB シリアル(PC デバッグ用)
   ***********************************************************/
  Serial.begin(115200);
  Serial.println("\nM5StickC Plus2 + YPD-R200");

  /***********************************************************
   *  RFID モジュール用 UART2 初期化
   *  ※多くの YPD-R200 は 115200bps、違えば 9600 に変更
   ***********************************************************/
  RfidSerial.begin(115200, SERIAL_8N1, 26, 0);
  Serial.println("RFID UART2 started");

  /***********************************************************
   *  起動時に一発だけ読み取りコマンドを送る
   ***********************************************************/
  RfidSerial.write(ReadMulti, 10);
  Serial.println("Send first ReadMulti");
}

void loop() {
  /***********************************************************
   *  一定時間ごとに ReadMulti を送信する(元コード準拠)
   *  ベンダコードのタイマーロジックを再現している
   ***********************************************************/
  timeSec++;

  if (timeSec >= 50000) {      // 適当な間隔(50,000ループ後)
    timemin++;
    timeSec = 0;

    if (timemin >= 20) {       // さらに20回たまると送信
      timemin = 0;

      Serial.println("Send ReadMulti");
      RfidSerial.write(ReadMulti, 10);
    }
  }

  /***********************************************************
   *  RFID モジュール 受信処理
   *  ベンダ提供サンプルロジックに忠実
   ***********************************************************/
  while (RfidSerial.available() > 0) {

    // 1バイト受信
    incomedate = RfidSerial.read();

    /*********************************************************
     *  フレーム解析(AA 02 22 ... DD)
     *  02 → コマンドコード
     *  22 → パラメータ
     *********************************************************/

    // 受信したバイトが 0x02(コマンドコード)で、まだ開始状態でない
    if ((incomedate == 0x02) && (parState == 0)) {
      parState = 1;   // コマンドコードを受信した状態へ
    }

    // 次に 0x22(コマンドパラメータ)が来たら EPC 解析開始
    else if ((parState == 1) && (incomedate == 0x22) && (codeState == 0)) {
      codeState = 1;
      dataAdd  = 3;  // 「4バイト目」からデータが始まるため3から開始
    }

    // EPC データを読み取り中
    else if (codeState == 1) {
      dataAdd++;   // 何バイト目かを追跡

      /*******************************************************
       * RSSI(信号強度): 6バイト目
       *******************************************************/
      if (dataAdd == 6) {
        Serial.print("RSSI: ");
        Serial.println(incomedate, HEX);
      }

      /*******************************************************
       * PC コード(7・8バイト目)
       *******************************************************/
      else if ((dataAdd == 7) || (dataAdd == 8)) {
        if (dataAdd == 7) {
          Serial.print("PC: ");
          Serial.print(incomedate, HEX);
        } else {
          Serial.print(" ");
          Serial.println(incomedate, HEX);
        }
      }

      /*******************************************************
       * EPC 本体(9〜20 バイト目)
       *******************************************************/
      else if ((dataAdd >= 9) && (dataAdd <= 20)) {

        // 始めの一回のみヘッダ表示+EPCバッファ初期化
        if (dataAdd == 9) {
          Serial.print("EPC: ");
          lastEpc = "";
        }

        // シリアルに 16進で出力
        Serial.print(incomedate, HEX);
        Serial.print(" ");

        // EPC バッファに追加
        char buf[4];
        snprintf(buf, sizeof(buf), "%02X ", incomedate);
        lastEpc += String(buf);
      }

      /*******************************************************
       * EPC の終端付近 → 状態リセット
       *******************************************************/
      else if (dataAdd >= 21) {
        Serial.println();   // 改行

        // 状態を初期化(次のフレームに備える)
        dataAdd   = 0;
        parState  = 0;
        codeState = 0;

        // EPC が取得できたときのみ画面表示
        if (lastEpc.length() > 0) {
          M5.Display.fillRect(0, 30, 240, 100, BLACK);
          M5.Display.setCursor(0, 30);
          M5.Display.setTextSize(2);
          M5.Display.println("EPC:");
          M5.Display.setTextSize(1);
          M5.Display.setCursor(0, 50);
          M5.Display.println(lastEpc);
        }
      }
    }

    /*********************************************************
     * 想定外のデータが来た場合 → 状態リセット
     *********************************************************/
    else {
      dataAdd   = 0;
      parState  = 0;
      codeState = 0;
    }
  }

  /***********************************************************
   * ボタンAで画面クリア
   ***********************************************************/
  if (M5.BtnA.wasClicked()) {
    M5.Display.fillScreen(BLACK);
    M5.Display.setCursor(0, 0);
    M5.Display.setTextSize(2);
    M5.Display.println("YPD-R200 TEST");
    lastEpc = "";
    Serial.println("--- display cleared ---");
  }

  // 負荷軽減
  delay(1);
}

動作チェック

あまりちゃんとチェックしていませんが、タグを動かすと反応します。数m離れていても認識してました。