Arduinoで近距離無線通信 RFID-RC522 NFC

by ボクにもわかる地上デジタル

[Arduino Menu] [XBee Menu] [地デジ Menu]


RFID-RC522 NFC MFRC522 Mifare
Mifareカードに対応した RFID-RC522 NXP製 MFRC522搭載

はじめに

 このページでは600円台(US$5前後)で市販されているRFIDリーダライタRFID-RC522をArduinoに接続する方法について説明します。非接触Mifareカード(もしくはMifareタグ)を使った防犯システム、施錠・入門管理カードシステムの構築などに利用できるでしょう。
 但し、購入したリーダライタRFID-RC522の出力を微弱無線局(322MHz以下 3m法で500uV/m 以下)へ調整してから使用するなど、電波法を遵守する必要があります。(注意喚起1回目)

各種NFCの概要

 RFID-RC522はNXP(元フィリップス)製のMFRC522搭載したRFIDリーダライタです。本RFIDリーダライタに対応する「Mifareカード」は1994年に誕生し、1996年に事業を開始し、2001年にはISO/IEC 14443 Type Aの国際標準規格で標準化されました。MifareカードはType Aカードとも呼ばれ、現在のNFC IP-1(ISO/IEC 18092)やNFC IP-2(ISO/IEC 21481)対応リーダライタで読み書きすることが出来ます。
 一方、国内で普及しているソニーのFeliCa方式(Suica、ICOCA、manacaなどで採用)も同時期の1995年に事業化しましたが、残念ながら国際規格化では後発です。
 元々、本Mifareカード(Type Aカード)の他にモトローラのType Bカードが規格化されており、FeliCaはその後に続くType Cカードとして標準化に取り組んでしましたが、規格の乱立の懸念から国際規格化としては採用されませんでした。その後、ソニーのFeliCa方式は、2003年にMifareカードとともに策定したNFC IP-1(ISO/IEC 18092)において、ようやく国際標準の仲間に入ることが出来ました。

 以上の通り、(1) RFID-RC522は国際規格として既に世界中に広まっているMifareカード(Type Aカード)方式に対応するRFIDリーダライタです。(2) MifareカードとFeliCaカードのどちらもが最新のNFCカードリーダライタで読み書きが出来ます。ただし、(3) RFID-RC522を使ってFeliCaカードを読むことは出来ません(これ、重要)。

各種NFCカード方式の比較
方式名 NFC IP-1 NFC IP-2 推進企業 国内での利用実績(例)
ISO/IEC 14443 Type A NXPセミコンダクタ Taspo、Mifareカード
ISO/IEC 14443 Type B Motorola 住基カード、運転免許、パスポート
FeliCa SONY Suica、ICOCA、manaca、PASMO、Edy

 世界中で普及しているMifareカードの最大の利点は価格です。リーダライタ基板とキーホルダ型のタグ1つ、Mifareカード1枚の3点セットで600円台で市販されており、使用するためのライブラリ(ドライバソフトウェア)も充実しています。
 正確な数は不明ですがMifareチップは数十億の累計生産量。一方、日本で孤立しているFeliCa方式のチップは7億個(2014年)です。FeliCaは随分、少ないですね。いや違います。これを普及率で考えると、変わって見えてきます。Mifareは世界中で使われているのに対し、FeliCaはほぼ国内でしか使われていないにも関わらず、FeliCaの数倍ほどの違いしかないのです。つまり、FeliCaは1.3億人の国民1人当たりに換算すると5.4個/人の普及率。もし今後、全世界の70億人に今の日本の状況の5.4個/人のチップが行き渡れば、380億個の市場があると考えられます。FeliCaが既に日本中に行き渡っていることから考えてると、日本は関連技術を含めて世界の最先端を進んでおり、この高普及率で運用しているFeliCaの仕組みこそ技術資産なのだと思います。
 話を戻すと、Mifareチップは数十億個。FeliCaの7億個よりも個数が多いことは確かです。当然、価格にも強みがあるのです。

MIFARE Classicのセキュリティ問題

 RFID-RC522に付属するMIFAREカードには致命的なセキュリティ問題があります(ここ、重要)。本機に付属しているMIFAREカードは「MIFARE Classic」と呼ばれるNXP独自の認証方式が採用されていますが、暗号キーを短時間で特定できる脆弱性があることが見つかっています。したがって、セキュリティを要する用途ではMIFARE Plusカードを利用する必要があります。(本RFID-RC522はMIFARE Plusカードにも対応していますので、移行も可能だと思います。)
 本ページでは脆弱性のあるMIFARE Classicを使用し、さらに暗号キーも初期値のまま使用します。セキュリティの観点では不十分な場合がありますので予めご理解ください。例えば、住居の施錠管理には向いていないませんが、住居内の部屋の施錠管理程度であれば差支えない等が考えられます。なお、本ページの掲載情報で何らかの被害が発生したとしても当方は一切の責任を負いません。
 また、FeliCa方式のリーダライタは電波法上の型式指定を受けているものが殆どですが、RFID-RC522を使用するには個別に設置許可を申請するか型式指定を受ける、あるいは微弱無線局(322MHz以下 500uV/m 以下)の範囲内で使用する必要があります(注意喚起2回目)。

Mifareカードを利用した入門証
Mifareカードを利用した入門証の一例

RFID-RC522とArduinoとのSPI接続と信号表

 RFIDリーダライタRFID-RC522をArduinoに接続する際にも注意点があります。それはRFID-RC522が3.3Vであることです。下記に信号表を示しますが、5本の信号のうち4本(SDA、SCK、MOSI、RST)については、Arduino Unoの5V信号を3.3Vに変換してRFID-RC522に入力する必要があります(ここも重要)。RFID-RC522の誤作動や出力オーバー、不要輻射の原因になるので、電波法の観点からも必ず電圧を変換してください。SPI MISOについては、直結でも問題ありませんが、Arduinoマイコンの仕様の範囲外となります。冷蔵庫の中など、特殊な温度条件下で使用する場合や、大量生産する場合は電圧変換が必要です。

Arduinoとの接続信号表
+-----------+----------+--+---------------------+
|           |RFID-RC522|方| Arduino Uno         |
|           |(MFRC522) |向|                     |
+-----------+----------+  +---------------------+
| Signal    | Pin      |  | Pin                 |
+===========+==========+==+=====================+
| RST/Reset | RST      |←| Digital 9 [1]_      |
+-----------+----------+--+---------------------+
| SPI SS    | SDA [3]_ |←| Digital 10 [2]_     |
+-----------+----------+--+---------------------+
| SPI MOSI  | MOSI     |←| Digital 11 / ICSP-4 |
+-----------+----------+--+---------------------+
| SPI MISO  | MISO     |→| Digital 12 / ICSP-1 |
+-----------+----------+--+---------------------+
| SPI SCK   | SCK      |←| Digital 13 / ICSP-3 |
+-----------+----------+--+---------------------+
(出典:ライブラリ説明書)

RFID-RC522とArduinoとの接続回路図

 5V信号を3.3Vに変換する方法は「3.3V XBee 5V Arduino 信号電圧相互変換方法」で説明した回路を用いました。分かりにくかった点はSPI SS信号をRFID-RC522基板上の「SDA」と書かれた端子に接続することです。RQ端子に接続するものだと思い込んでいたのですが、NXPのMFRC522のデータシートを見て、ようやく気づきました(これ、重要)。

回路図
RFID-RC522とArduinoとの接続回路図

 この回路図ではダイオードのカソード(K)側をArduinoに、アノード(A)側をRFIDリーダライタRFID-RC522に接続します。ダイオードは1N4148を使用しましたが、BAT43の方がLowレベル時の信号が安定すると思います。
 RFID-RC522側にはプルアップ抵抗が必要です。プルアップ抵抗の値は10kΩ程度で良いでしょう。なお、RFID-RC522はマイコンとの通信用のインタフェースにSPI、I2C、UARTの3種類のいずれかを使用可能です。チップMFRC522にはI2CやUARTが搭載されていますが、RFID-RC522はSPI専用なので、SPIモードで使用します。

Mifareカード対応RFIDリーダライタRFID-RC522
Mifareカード対応RFIDリーダライタRFID-RC522(右端に接続端子がある)

使用するRFID用ライブラリ

 ここではArduino MFRC522 Library(ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT)を使用します。「https://github.com/miguelbalboa/rfid」から「Download ZIP」にてダウンロードし、ダウンロードしたファイル「rfid-master.zip」をArduino IDEに組み込みます。(ZIPを展開してからArduinoの「〜\Arduino\libraries」フォルダにコピーし、Arduino IDEを再起動する。)
 Arduino IDEの情報にある「↑」アイコンをクリックし、「rfid-master」を選択するとサンプルスケッチのリストが表示されます。なおサンプルの中にはMifareカード内の情報を書き換えてしまうものもありますので、使い方を把握してから動かしましょう。

Arduino IDE
Arduino IDEでサンプルスケッチを開く

動作確認

 ここでは動作確認のためにカード内の情報を読み取る「DumpInfo」を実行してみます。このサンプルは書き込みの実行を行わないので安全です。表示された初期値をバックアップしておくと良いでしょう。
 DumpInfoを実行し、Arduino IDEの右上の「シリアルモニタ」を開くと下図の上2行のメッセージが表示されます。この状態でMifareカードをRFIDリーダライタRFID-RC522にかざすと、Card UIDやカード内の全ブロックのデータが表示されます。

Arduino IDE DumpInfo
サンプルスケッチ DumpInfo の実行画面

セクタとブロックとトレーラブロック

 付属していたMifareカードのメモリ容量は1KBでした。1KBのMifareカードは64バイトずつの全16のセクタ(Sector)に分けられています。データの読み書きを行う際は各セクタ毎に認証を行います。
 また、全16のセクタは、さらに4つの16バイトのブロック(Block)に分かれています。そして4つのブロックの内の1つのブロックを管理用トレーラ・ブロックとして割り当てる必要があります。したがって、ユーザがメモリとして使用可能なユーザ・ブロックの領域は4ブロック中3ブロックしかありません。

Mifareカードのセクタとブロック(MIFARE Classic 1KBの場合)
単位 容量 セクタ数 ブロック数 ユーザ・ブロック数
トレーラ・ブロック数
カード全体 1024バイト 16セクタ 64ブロック 48ブロック
16ブロック
セクタ 64バイト 1セクタ 4ブロック 3ブロック
1ブロック
ブロック 16バイト 1ブロック

 セクタ番号は0〜15、ブロック番号は0〜65までが定義されています。セクタ0はブロック0〜3、セクタ1はブロック4〜7のように割り当てられています(異なるセクタにおいてもブロック番号は重複しません)。
 このうち先頭のセクタ番号0、ブロック番号0の領域にはカード固有のIDであるUIDが登録されています。このカードのUIDは4バイトです。「DumpInfo」を実行して表示された「Card UID」と同じデータが、セクタ0ブロック0に記録されていることが確認できると思います。(サンプルスケッチ DumpInfo の実行画面にはブロック0は写っていませんので、実際にテストして確認してください。)
 もし何らかの事情でUDIを変更する場合はUIDが重複しないように留意します。通常は初期値のまま使用するのが良いでしょう。

サンプルスケッチ

 次にサンプルスケッチを見ながらライブラリの使い方を学習しましょう。先ほどの「DumpInfo」は、あまり学習には適しませんので、「ReadAndWrite」を開いてみます。
 このスケッチは名前のとおり、Mifareカードへの書込みを実行するサンプルです。ただし、暗号キーが初期状態のままの運用中の他のカードをかざしてしまうと、元のカードに復旧できなくなる場合がありますので、十分に注意して下さい。まずは付属のカードで動きを理解してみましょう。
 下記はサンプルスケッチの主要部に動作に関するコメントを追加したものです。本サンプルを理解すれば、ダウンロードしたサンプルも理解しやすいと思います。

Mifareカード対応RFIDリーダライタRFID-RC522用サンプルスケッチ
void loop() {
    // Mifareカードの確認(新しいカードが無ければ終了し、loop関数を繰り返す)
    if ( ! mfrc522.PICC_IsNewCardPresent()) return;

    // Mifareカードのデータ読み込み(読み取れなければ終了し、loop関数を繰り返す)
    if ( ! mfrc522.PICC_ReadCardSerial()) return;

    // Mifareカード(もしくはMifareタグ)のUID情報の表示
    Serial.print("Card UID:");                  // MifareカードのUIDの表示
    dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
    Serial.println();
    Serial.print("PICC type: ");                // Mifareカードのタイプ表示
    byte piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
    Serial.println(mfrc522.PICC_GetTypeName(piccType));

    // Mifareカードのタイプが対応しているかどうかを確認
    if (    piccType != MFRC522::PICC_TYPE_MIFARE_MINI
        &&  piccType != MFRC522::PICC_TYPE_MIFARE_1K
        &&  piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
        Serial.println("This sample only works with MIFARE Classic cards.");
        return;
    }

    // Mifareカードの先頭から2番目のセクタ(セクタ番号#1)へデータを書き込むサンプル
    byte sector         = 1;                    // 書き込みを実行するセクタ番号 #1
    byte blockAddr      = 4;                    // セクタ #1の先頭ブロック番号 #4
    byte dataBlock[]    = {                     // 書き込みデータ
        0x01, 0x02, 0x03, 0x04,                 //  1,  2,   3,  4,
        0x05, 0x06, 0x07, 0x08,                 //  5,  6,   7,  8,
        0x08, 0x09, 0xff, 0x0b,                 //  8,  9, 255, 11,
        0x0c, 0x0d, 0x0e, 0x0f                  // 12, 13,  14, 15
    };
    byte trailerBlock   = 7;                    // セクタ#1のトレーラブロック番号#7
    byte status;
    byte buffer[18];
    byte size = sizeof(buffer);

    // Mifareカードへ暗号キーAを使って認証を実行
    // 暗証キーは MIFARE_Key keyで定義される6バイトのコード。
    // 新品のMifareカードの初期値 FF FF FF FF FF FFをsetup関数で代入済
    Serial.println("Authenticating using key A...");
    status = mfrc522.PCD_Authenticate(
        MFRC522::PICC_CMD_MF_AUTH_KEY_A,        // 暗号キーAを使った認証
        trailerBlock,                           // トレーラブロック番号(#7)を指定
        &key,                                   // 暗号キー(FF FF FF FF FF FF)を指定
        &(mfrc522.uid)                          // 対象となるMifareカードのUIDを指定
    );
    if (status != MFRC522::STATUS_OK) return;   // 認証に成功しなかった場合は終了

    // Mifareカード内のセクタ(#1)データを読み取って表示
    Serial.println("Current data in sector:");
    mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
    Serial.println();

    // Mifareカード内のブロック(#4)データを読み取って変数bufferへ代入
    Serial.print("Reading data from block "); Serial.println(blockAddr);
    mfrc522.MIFARE_Read(blockAddr, buffer, &size);
    Serial.print("Data in block "); Serial.print(blockAddr); Serial.println(":");
    dump_byte_array(buffer, 16); Serial.println(); Serial.println();

    // Mifareカードへ暗号キーBを使って認証を実行
    // 暗証キーは暗号キーAと同じ変数MIFARE_Key keyおよび同じ値を使用
    Serial.println("Authenticating again using key B...");
    status = mfrc522.PCD_Authenticate(
        MFRC522::PICC_CMD_MF_AUTH_KEY_B,        // 暗号キーBを使った認証
        trailerBlock,                           // トレーラブロック番号(#7)を指定
        &key,                                   // 暗号キー(FF FF FF FF FF FF)を指定
        &(mfrc522.uid)                          // 対象となるMifareカードのUIDを指定
    );
    if (status != MFRC522::STATUS_OK) return;   // 認証に成功しなかった場合は終了

    // Mifareカード内のブロック(#4)へ変数dataBlockのデータを書き込む
    Serial.print("Writing data into block "); Serial.println(blockAddr);
    dump_byte_array(dataBlock, 16); Serial.println();
    mfrc522.MIFARE_Write(blockAddr, dataBlock, 16);

    // 正しく書き込まれたかどうかを確認するためのMifareカードからの読み込み
    Serial.print("Reading data from block "); Serial.println(blockAddr);
    status = mfrc522.MIFARE_Read(blockAddr, buffer, &size);
    Serial.print("Data in block "); Serial.print(blockAddr); Serial.println(":");
    dump_byte_array(buffer, 16); Serial.println();
        
    // 正しく書き込まれたかどうかを確認
    Serial.println("Checking result...");
    byte count = 0;
    for (byte i = 0; i < 16; i++) if (buffer[i] == dataBlock[i]) count++;
    if (count == 16) Serial.println("Success :-)");
    else Serial.println("Failure, no match :-(");
    Serial.println();
        
    // Mifareカード内のセクタ(#1)データを読み取って表示
    Serial.println("Current data in sector:");
    mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
    Serial.println();

    mfrc522.PICC_HaltA();                       // PICCの停止
    mfrc522.PCD_StopCrypto1();                  // PCD暗号化の停止
}
(参考文献:ライブラリのソースリスト)

ワイヤレス電力伝送と非接触ワイヤレス通信

 ワイヤレスでデータ通信が行えるNFC技術を使ったシステムでは、リーダライタとMifareカードとの距離が離れると通信が出来ません。本RFIDリーダライタRFID-RC522においてもアンテナから3cmあたりから通信が不安定になり、6cm程度の距離で通信が出来なくなります。
 この様子を見ていると、(微弱な電波を使っているので)電波もせいぜい10cm程度しか飛んでいないと勘違いするかもしれません。(実は、私もそう認識していました。)
 しかし、実際の電波や信号の飛距離は、隣の家でも容易に受信することが出来るような高いレベルです(もちろん、実際に遠くまで飛ぶような状態で使用してはいけません)。実用上の通信可能な距離は短いのですが、その電波はや信号は広範囲に放射してしまっているのです。

 この「実用上の通信可能距離」は、Mifareカード内のICを動かすためのワイヤレス電力伝送の距離で決まります。NFC通信の通信距離とは、信号の届く距離ではなく、ワイヤレス電力伝送の到達距離なのです。実際の通信距離は数cmくらいと短いにも関わらず、電波や通信データは遥か遠くまで飛んでゆき、簡単な受信機でデータの内容を確認することが出来ます(このため、暗号化も重要です)。

 さて、ここでは少しだけワイヤレス電力伝送の実験を行ってみることにしました。下図は学研の大人の科学マガジンプラスの「電磁実験スピーカー」を使って電力伝送実験を行った様子です。輪の中の各デバイスはワイヤレス電力伝送でエネルギーを受けて動作しています。(但しNFCは13.15MHz、下記の実験は150kHz)

学研の大人の科学マガジンプラス「電磁実験スピーカー」
学研の大人の科学マガジンプラス「電磁実験スピーカー」によるワイヤレス電力伝送実験の様子

 ブレッドボード上の回路は100nHのインダクタと0.01uFのコンデンサで構成した約150kHzの共振回路(アンテナ)をLEDへ接続した例です。似た回路を異なるインダクタで2つ作成してみました。電子部品として売られているインダクタは電磁シールドされている場合があり、構造上、アンテナとしては非力ですが、それでも実際に電力伝送が行えました。
 似たような回路がRFIDリーダライタRFID-RC522の基板上にも実装されています。インダクタL1、L2のほか、コンデンサC4、C5、C6〜C11、そしてパターンアンテナと、多くの部品で複雑に構成されていることが分かるでしょう。

 このような電力伝送の物理特性については100年以上も前から知られており、これまでも電話機の充電器などに応用されてきました。近年になってNFCやワイヤレス給電システムのQiで使われ始めたのは、2000年代になってユビキタス社会で必要な技術として研究が進んだためだと思います。

リーダライタ RFID-RC522 の入手方法

 Mifareカードに対応したRFIDリーダライタ RFID-RC522 は海外では非常に多く販売されており、例えば、eBay(http://www.ebay.com/)であればUS$5程度で購入することが出来ます。
 しかし、eBayでの購入は個人輸入となるので、海外通貨での支払いが必要だったり、国際貨物の追加送料が必要になります。まれに通関手続の処理や関税が発生する場合もあります。
 一方、国内の代理店から購入すれば、支払いや配送の心配が軽減されます。また、代理店品と中国直売品とでは仕様や品質が異なることもあるので、粗悪品や不良品である懸念も軽減され、仮に不具合がったとしても、サポートを受けやすいでしょう。
 私が中国から直輸入した本品には、細かな汚れが全体的に、多数、付着しており、梱包もクッションなし、内容物に紙が一切ない(説明書も注意書きも何も無い)というもので、オークションで購入した新品同様と書かれた「中古品」のよような感じでした(目立つ傷はないが明らかに新品とは思えない状態)。

 

高周波利用設備に関して

 本品(リーダライタ RFID-RC522)を国内で使用する場合は、電波法に基づいて、高周波利用設備として総務大臣の設置許可を得るなどの必要があります。実験を行う前に、必ず、以下のいづれかの対応を行ってください(注意喚起3回目)。

  1. 高周波利用設備(誘導式読み書き通信設備)として総務大臣から個別に設置許可を得る
  2. 高周波利用設備(誘導式読み書き通信設備)として総務大臣から型式指定を受ける
  3. 高周波利用設備(誘導式読み書き通信設備)として型式確認を行って、総務大臣へ届ける
  4. 微弱無線局(13.56MHz・3mの距離における電界強度が500uV/m 以下)であることを確認してから使用する

 電波法違反は刑事罰の対象です。前科者・犯罪者となってしまい、この先の人生が大きく変わってしまう恐れがあります(1年以下の懲役又は100万円以下の罰金の対象。公共性の高い無線局に妨害を与えた場合は、5年以下の懲役又は250万円以下の罰金の対象。)
 規制を受けるのはリーダライタ側だけで、MifareカードやMifareタグについては規制の対象外です。詳しくはTELEC等にお問い合わせください。

微弱無線の検証のための情報

 RFID-RC522は、27.120MHzの水晶を基に、その半分の13.56MHzの電波を送信します。送信アンテナから3m、離れた距離で500uV/mとなることを確認する必要があります。
 500uV/mをダイポールアンテナで受信すると、およそ-70dBmに相当します。しかし、約10mものダイポールアンテナを作成することは難しいので、小型のアンテナを作成して代用することになります。作成した小型アンテナの利得が-15dBdであった場合、測定値を-70-15=-85dBm以下に抑える必要があります。測定対象から高さ方向も含め半径3mの距離内で、最大となる測定点での測定結果が-85dBm以下であることを確認してください。事前に近距離で放射方向を確認してから、実測定を行うと効率的でしょう。
 少なくとも実験機器を金属などで覆うなどの対策を行わなければ、使用できません。ACアダプタやUSBなどで電源を供給すると、放射が増大するので、電源には乾電池などを利用すると良いでしょう。
 なお、本ページや当方のサイト内の情報を用いて実験したにも関わらず、電波法に違反してしまうというリスクも考えられますが、当方は一切の責任を負いません。当方の情報に誤りがあったとしても、同様です。


Arduinoメインメニューへ戻る

XBeeメインメニューへ戻る

地デジトップへ戻る