ArduinoでRFIDモジュール(MFRC522)を使ってタグに名前の書き込み・読み込みをする

今回使うもの

Aruduino UNO

MFRC522

使用する前のセッティング

以下の記事を参考にしてください。

非接触ICタグで遊ぼう!ArduinoでRFIDリーダRC522を使う方法

とりあえず私はこんなかんじ。無駄にマイクロビット繋げてますけど気にしないでください。

コード

ライブラリのサンプルをそのまま使います。

https://github.com/miguelbalboa/rfid/tree/master/examples

まずは書き込みから。

/*
 * Write personal data of a MIFARE RFID card using a RFID-RC522 reader
 * Uses MFRC522 - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 
 * -----------------------------------------------------------------------------------------
 *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
 *             Reader/PCD   Uno/101       Mega      Nano v3    Leonardo/Micro   Pro Micro
 * Signal      Pin          Pin           Pin       Pin        Pin              Pin
 * -----------------------------------------------------------------------------------------
 * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 * SPI SS      SDA(SS)      10            53        D10        10               10
 * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
 *
 * More pin layouts for other boards can be found here: https://github.com/miguelbalboa/rfid#pin-layout
 *
 * Hardware required:
 * Arduino
 * PCD (Proximity Coupling Device): NXP MFRC522 Contactless Reader IC
 * PICC (Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203.
 * The reader can be found on eBay for around 5 dollars. Search for "mf-rc522" on ebay.com. 
 */

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9           // Configurable, see typical pin layout above
#define SS_PIN          10          // Configurable, see typical pin layout above

MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance

void setup() {
  Serial.begin(9600);        // Initialize serial communications with the PC
  SPI.begin();               // Init SPI bus
  mfrc522.PCD_Init();        // Init MFRC522 card
  Serial.println(F("Write personal data on a MIFARE PICC "));
}

void loop() {

  // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  MFRC522::MIFARE_Key key;
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    return;
  }

  Serial.print(F("Card UID:"));    //Dump UID
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
  }
  Serial.print(F(" PICC type: "));   // Dump PICC type
  MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
  Serial.println(mfrc522.PICC_GetTypeName(piccType));

  byte buffer[34];
  byte block;
  MFRC522::StatusCode status;
  byte len;

  Serial.setTimeout(20000L) ;     // wait until 20 seconds for input from serial
  // Ask personal data: Family name
  Serial.println(F("Type Family name, ending with #"));
  len = Serial.readBytesUntil('#', (char *) buffer, 30) ; // read family name from serial
  for (byte i = len; i < 30; i++) buffer[i] = ' ';     // pad with spaces

  block = 1;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("PCD_Authenticate() success: "));

  // Write block
  status = mfrc522.MIFARE_Write(block, buffer, 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

  block = 2;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Write block
  status = mfrc522.MIFARE_Write(block, &buffer[16], 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

  // Ask personal data: First name
  Serial.println(F("Type First name, ending with #"));
  len = Serial.readBytesUntil('#', (char *) buffer, 20) ; // read first name from serial
  for (byte i = len; i < 20; i++) buffer[i] = ' ';     // pad with spaces

  block = 4;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Write block
  status = mfrc522.MIFARE_Write(block, buffer, 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

  block = 5;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Write block
  status = mfrc522.MIFARE_Write(block, &buffer[16], 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));


  Serial.println(" ");
  mfrc522.PICC_HaltA(); // Halt PICC
  mfrc522.PCD_StopCrypto1();  // Stop encryption on PCD

}

すると以下のような出力がシリアルモニターに表示されます。

Type Family name, ending with #

そしたら入力欄にファーストネーム「hoge#」を打ち込みましょう。入力の最後は#で終わらせる必要があります。すると以下の出力が続きます。

PCD_Authenticate() success:
MIFARE_Write() success:
MIFARE_Write() success:
Type First name, ending with #

最後に「taro#」と打ち込めば完了です。

次に読み込み。

/*
 * Initial Author: ryand1011 (https://github.com/ryand1011)
 *
 * Reads data written by a program such as "rfid_write_personal_data.ino"
 *
 * See: https://github.com/miguelbalboa/rfid/tree/master/examples/rfid_write_personal_data
 *
 * Uses MIFARE RFID card using RFID-RC522 reader
 * Uses MFRC522 - Library
 * -----------------------------------------------------------------------------------------
 *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
 *             Reader/PCD   Uno/101       Mega      Nano v3    Leonardo/Micro   Pro Micro
 * Signal      Pin          Pin           Pin       Pin        Pin              Pin
 * -----------------------------------------------------------------------------------------
 * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 * SPI SS      SDA(SS)      10            53        D10        10               10
 * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
 *
 * More pin layouts for other boards can be found here: https://github.com/miguelbalboa/rfid#pin-layout
*/

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9           // Configurable, see typical pin layout above
#define SS_PIN          10          // Configurable, see typical pin layout above

MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance

//*****************************************************************************************//
void setup() {
  Serial.begin(9600);                                           // Initialize serial communications with the PC
  SPI.begin();                                                  // Init SPI bus
  mfrc522.PCD_Init();                                              // Init MFRC522 card
  Serial.println(F("Read personal data on a MIFARE PICC:"));    //shows in serial that it is ready to read
}

//*****************************************************************************************//
void loop() {

  // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  MFRC522::MIFARE_Key key;
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  //some variables we need
  byte block;
  byte len;
  MFRC522::StatusCode status;

  //-------------------------------------------

  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    return;
  }

  Serial.println(F("**Card Detected:**"));

  //-------------------------------------------

  mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //dump some details about the card

  //mfrc522.PICC_DumpToSerial(&(mfrc522.uid));      //uncomment this to see all blocks in hex

  //-------------------------------------------

  Serial.print(F("Name: "));

  byte buffer1[18];

  block = 4;
  len = 18;

  //------------------------------------------- GET FIRST NAME
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(mfrc522.uid)); //line 834 of MFRC522.cpp file
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Authentication failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  status = mfrc522.MIFARE_Read(block, buffer1, &len);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Reading failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  //PRINT FIRST NAME
  for (uint8_t i = 0; i < 16; i++)
  {
    if (buffer1[i] != 32)
    {
      Serial.write(buffer1[i]);
    }
  }
  Serial.print(" ");

  //---------------------------------------- GET LAST NAME

  byte buffer2[18];
  block = 1;

  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid)); //line 834
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Authentication failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  status = mfrc522.MIFARE_Read(block, buffer2, &len);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Reading failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  //PRINT LAST NAME
  for (uint8_t i = 0; i < 16; i++) {
    Serial.write(buffer2[i] );
  }


  //----------------------------------------

  Serial.println(F("\n**End Reading**\n"));

  delay(1000); //change value if you want to read cards faster

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}
//*****************************************************************************************//

すると以下が出力されます。

**Card Detected:**
Card UID: xxxx
Card SAK: xxxx
PICC type: MIFARE 1KB
Name:
taro hoge
**End Reading**

注意点

一点はまったポイントがあるので記しておきます。書き込み時に以下のような出力が出る場合があります。

PCD_Authenticatie Failed…

MFRC522では各種操作の前に以下リンク先の205行目にあるPICC_CMD_MF_AUTH_KEY_Aを用いてタグの認証を行います。

https://github.com/miguelbalboa/rfid/blob/master/src/MFRC522.h

上記エラーはこの認証が通らなかったことを意味するのですが、事前の鍵情報の書き込みをしてない限りそれはあり得ません。

ではなぜ起こったのか?それは「書き込みが完了する前にタグをリーダから離してしまった」からです。書き込みが完了するまでは以下のようにしっかりとタグを読み込ませておかないと認証が失敗してしまうので気を付けてください。

オーディオ出力先切り替えスイッチを作成

在宅勤務をしていると,スピーカーとヘッドホンを切り替えることがしばしば.

TV会議しているとき以外は蒸れるので,スピーカー.

TV会議はヘッドホン.

ところが,突発でコールが入ると,スピーカーからヘッドホンに切り替えに手間取る手間取る.

というわけで,それ専用のスイッチを, Arduino pro micro を使って作成してみました.

動画内の画面左下あたりに,現在選択されているオーディオデバイスが表示されてますが,赤を押すとスピーカー,青を押すとヘッドホンになります.

準備するもの

  • Arduino pro micro
  • マイクロUSBケーブル
  • ブレッドボード
  • ジャンパワイヤパック
  • タクトスイッチ

作成手順

1. PCにaudioSwitcher をインストール&ホットキーを設定

詳細は https://keikenchi.com/how-to-switch-output-audio-with-shortcut-keys をご参考ください.

とても分かりやすく説明してくださってます.ありがとうございます.

今回は,他のアプリのホットキーと絶対に干渉しないように,「Ctrl+Shift+Alt+s」をスピーカーに,「Ctrl+Shift+Alt+g」をヘッドホンに割り当てました.

2. 回路の組み立て

ブレッドボード上に回路を組み上げていきます.

Arduino Pro Micro の ピンアサイン.

3. Arduino IDE でプログラムを書き込みます.

こちらは,https://qiita.com/MergeCells/items/17bdc1c1fb35949195b5 を参考に書いていきました.

#include "Keyboard.h"

#define RED_button 10
#define BLUE_button 18

void setup() {
  pinMode(RED_button, INPUT_PULLUP);
  pinMode(BLUE_button, INPUT_PULLUP);
  Keyboard.begin();
}

void loop() {
  if(digitalRead(RED_button)==LOW){
   Keyboard.press(KEY_LEFT_ALT);
   Keyboard.press(KEY_LEFT_CTRL);
   Keyboard.press(KEY_LEFT_SHIFT);   
   Keyboard.press('s');
   delay(100);
   Keyboard.releaseAll();
   while(digitalRead(RED_button)==LOW);
  }
  else if(digitalRead(BLUE_button)==LOW){
   Keyboard.press(KEY_LEFT_ALT);
   Keyboard.press(KEY_LEFT_CTRL);
   Keyboard.press(KEY_LEFT_SHIFT);  
   Keyboard.press('g');
   delay(100);
   Keyboard.releaseAll();
   while(digitalRead(BLUE_button)==LOW);
  }
  delay(100);
}

気づき

PC側のソフト設定とArduinoでやれることは他にもありそうな感じ.

あと,開発環境の重要性についても考えさせられました.

はじめは無名の安いブレッドボードを使用していたのですが,「線がうまくささらない,ささったら今度は抜けない」,挙句に「ジャンパワイヤが壊れる」,という事態に見舞われたため,サンハヤト製のものを購入してみ ました.

結果,「もっと早く買っておけばよかった」というくらいイライラが減りました.

いろいろなことを試すうえで,しょーもないところで事故が起きてその対応に迫られると,ものすごくフラストレーションが溜まります.

開発環境をケチってはいけないなぁ,と.

サンハヤト製のブレッドボードとジャンプワイヤパック
粗悪なブレッドボードから無理に引っこ抜いたら先が外れてしまった

Arduino でうまくLチカできない理由

Pro Micro の激安互換品(1980円/3pcs@Amazon) を使ってLチカを試してみました.

が,思ってたとおりに光りませんでした.なんか暗い...

書いたコードは下記の通り.

VCC をチェックすると,約5V出ているので,問題なし.

端子電圧は1.7Vなので,LEDを光らせるだけの電圧は出力されている.

ところが,電流が77μAしか出ていなかった.

本来は10-15mA なので,8000分の1しか電流が出ていない...

「Pro Micro 互換品の仕様なのかな?」とか「これは不良品なのか?」とか
色々と検討すること3時間.

で,3時間考え込んで,分かった原因はすごく初歩的なものでした.

出力側のピンモード設定を
入れ忘れてた!!!

おわり orz

Arduino micro pro を使って自作キーボードを作った話

作ろうと思った背景

子供の教材開発の一環で,microbit の次のステップとして Arduino を想定していて,
その使い方を学んでいるときに,HID機能というものを知りました.

これは何かというと,ヒューマン・インターフェース・デバイスの略称で,
USB接続であたかもキーボード,マウスのように振舞う(なりすます)ことが
できる機能のことです.

このいわゆる「なりすまし」が使えると,
「ある1つのボタンを押したら,xxxというキー入力をする」とかが
出来るようになります.

本当にそんなことが出来るのだろうか,難しくないのだろうか,と思ったので,
試してみた結果が本記事の内容です.

準備するもの

  • Arduino micro pro ※今回は,Amazon で3個で1980円の互換品を使用
  • microUSBケーブル
  • ブレッドボード
  • タクトスイッチ
  • ジャンパワイヤー

配線

Amazon で購入した Arduino micro pro 互換品は,ピンヘッダが半田付けされていないので,
最初にそれをはんだ付けする必要があります.
はんだ付けするにあたっては,ブレッドボードにピンヘッダを差し込み,
その上に,Arduino micro pro を乗せて,はんだ付けすると足が斜めにならずに済みます.

fig1. Arduino のはんだ付け準備 その1
fig2. Arduino のはんだ付け準備 その2 – ピンヘッダをブレッドボードに差します
fig3. Arduino のはんだ付け準備 その3- ピンヘッダに Arduino を置き,はんだ付け

次にブレッドボードに,Arduino, タクトスイッチを配置して,
ジャンパワイヤーで繋げていきます.

  • Arduino GND → スイッチ赤 → スイッチ青
  • Arduino 5番 → スイッチ青
  • Arduino 6番 → スイッチ赤
fig4.タクトスイッチは,赤丸で囲んだ隣同士の足がスイッチを押したときに繋がります
fig5. 配線図

プログラミング

  • Arduino へプログラムを書き込むための IDE をここからインストールします.
  • Arduino を起動し,Tools → Board: “Arduino Uno” → “Arduino Leonardo” を選択します.
fig6. 書き込むボードの対象を Arduino Leonardo にする
  • 補足すると,Uno は先述のHID(なりすまし)機能を持っておらず,
    ゆえにそのライブラリもありません.
  • Leonardo は HID機能を持ち,そのライブラリを持っています.
  • 今回はそのライブラリのうち,Keyboard.h というものを使っていきます.
  • なので,Board として Leonardo を選択する必要があります.
  • 次に,Arduino を microUSBコードで繋げて,PCに繋ぎます.
  • 書き込み先(ポート)の指定をしてあげます.
  • Tools → Port → COM3(Arduino Leonardo).
  • もしかしたら,PCによってはCOM3 と認識されないかもしれないです.
  • それっぽいもの(笑) を選びましょう.
fig7. 書き込み先 Port の指定
  • 下記コードを貼り付け,適宜好みに合うように編集します.
#include <Keyboard.h> // キーボードライブラリの読み込み

#define Button5 5 // 5番ピンを Button5 と呼ぶことにするよ
#define Button6 6

void setup() {
  Keyboard.begin(); // キーボード機能を使うおまじない
  pinMode(Button5, INPUT_PULLUP); // Button5 をプルアップしておく.スイッチ青を押すとGND に繋がる
  pinMode(Button6, INPUT_PULLUP);
}

void loop() {
  // Button5 が押された時の動作設定
  if(digitalRead(Button5) == LOW){ // Button5 がGND になったら,つまり,スイッチ青が押されたら
    Keyboard.print("hogehoge"); // hogehoge と入力される.
    Keyboard.write(9); // TABが入力される.参考先:http://www.asciitable.com/
    Keyboard.print("fugafuga");
    Keyboard.press(KEY_RETURN);
    delay(100); //wait PC busy // PC側が入力を受け付けるまで100ms待つ
    Keyboard.releaseAll(); // キーを離す

    while(digitalRead(Button5) == LOW); // Button5 が連続で入力されてるとき,無視する
  }
  // Button6 が押された時の動作設定
  if(digitalRead(Button6) == LOW){
    Keyboard.print("fugafuga");
    Keyboard.press(KEY_RETURN);
    delay(100); //wait PC busy
    Keyboard.releaseAll();

    while(digitalRead(Button6) == LOW);
  }
  delay(100);
}
  • File → Save as … より,ファイルを保存します.
fig8. File → Save as… より,プログラムファイルを保存する
  • プログラムを Arduino に書き込みます.
fig9. プログラムを Arduino に書き込む.赤丸のところの矢印を押すだけ.押すと黄色くなります.
fig10. 書き込み終わると,黄色くなってたボタンが元の色に戻り, Done uploading と出ます.
  • あとはメモ帳を開いて,タクトスイッチを押してみましょう.
fig11. メモ帳を開いて,タクトスイッチ青を押した図

むすび

やってみて,一番初めに思ったのは,「超簡単にできる!」です.

キーボード自作というと,正直ベーシック的な処理をいっぱい書かなきゃいけないのかな,と
勝手にイメージしていたのですが,今回書いたのは全部で35行程度でした.

で,これを作ってから,自作キーボードのその道には,もっと簡単に自作キーボードを作ることができる,QMKというファームウェアが存在することを知った(知ってしまった)ので,次はQMKについても記事を書こうかな,と思ってます.

ご参考:fabcross さんでも特集していたようです.
https://fabcross.jp/category/make/20200427_Zoom.html