pdf-icon

Arduino入門

2. デバイス&サンプル

Dial RFID (NFC)

M5Dial RFID uses MFRC522 library as the driver, refer to the following API & examples to realize simple display, get more API content can refer to MFRC522 source code.

Example

Scanning UID Example

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#include "M5Dial.h"
void setup() {
auto cfg = M5.config();
M5Dial.begin(cfg, false, true);
}
void loop() {
if (M5Dial.Rfid.PICC_IsNewCardPresent() &&
M5Dial.Rfid.PICC_ReadCardSerial()) {
M5Dial.Display.clear();
Serial.print(F("PICC type: "));
uint8_t piccType = M5Dial.Rfid.PICC_GetType(M5Dial.Rfid.uid.sak);
Serial.println(M5Dial.Rfid.PICC_GetTypeName(piccType));
// Check is the PICC of Classic MIFARE type
if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&
piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
Serial.println(F("Your tag is not of type MIFARE Classic."));
return;
}
for (byte i = 0; i < M5Dial.Rfid.uid.size;
i++) { // Output the stored UID data.
Serial.printf("%02X ", M5Dial.Rfid.uid.uidByte[i]);
}
Serial.println();
}
}

Read/Write Card Example

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
#include "M5Dial.h"
MFRC522::MIFARE_Key key;
void setup() {
auto cfg = M5.config();
M5Dial.begin(cfg, false, true);
// Prepare the key (used both as key A and as key B)
// using FFFFFFFFFFFFh which is the default at chip delivery from the factory
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
}
/**
* Helper routine to dump a byte array as hex values to Serial.
*/
void dump_byte_array(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
}
void loop() {
M5Dial.update();
if (M5Dial.Rfid.PICC_IsNewCardPresent() && M5Dial.Rfid.PICC_ReadCardSerial()) {
Serial.print(F("PICC type: "));
uint8_t piccType = M5Dial.Rfid.PICC_GetType(M5Dial.Rfid.uid.sak);
Serial.println(M5Dial.Rfid.PICC_GetTypeName(piccType));
// Check is the PICC of Classic MIFARE type
if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI && piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
Serial.println(F("Your tag is not of type MIFARE Classic."));
return;
}
String uid = "";
for (byte i = 0; i < M5Dial.Rfid.uid.size; i++) { // Output the stored UID data. 将存储的UID数据输出
Serial.printf("%02X ", M5Dial.Rfid.uid.uidByte[i]);
uid += String(M5Dial.Rfid.uid.uidByte[i], HEX);
}
Serial.println();
// M5Dial.Rfid.PICC_DumpToSerial(&(M5Dial.Rfid.uid));
// In this sample we use the second sector,
// that is: sector #1, covering block #4 up to and including block #7
byte sector = 1;
byte blockAddr = 4;
byte dataBlock[] = {
0x01, 0x02, 0x03, 0x04, // 1, 2, 3, 4,
0x05, 0x06, 0x07, 0x08, // 5, 6, 7, 8,
0x09, 0x0a, 0xff, 0x0b, // 9, 10, 255, 11,
0x0c, 0x0d, 0x0e, 0x0f // 12, 13, 14, 15
};
byte trailerBlock = 7;
MFRC522::StatusCode status;
byte buffer[18];
byte size = sizeof(buffer);
// Authenticate using key A
Serial.println(F("Authenticating using key A..."));
status = (MFRC522::StatusCode)M5Dial.Rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key,
&(M5Dial.Rfid.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(M5Dial.Rfid.GetStatusCodeName(status));
return;
}
// Show the whole sector as it currently is
Serial.println(F("Current data in sector:"));
M5Dial.Rfid.PICC_DumpMifareClassicSectorToSerial(&(M5Dial.Rfid.uid), &key, sector);
Serial.println();
// Read data from the block
Serial.print(F("Reading data from block "));
Serial.print(blockAddr);
Serial.println(F(" ..."));
status = (MFRC522::StatusCode)M5Dial.Rfid.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read() failed: "));
Serial.println(M5Dial.Rfid.GetStatusCodeName(status));
}
Serial.print(F("Data in block "));
Serial.print(blockAddr);
Serial.println(F(":"));
dump_byte_array(buffer, 16);
Serial.println();
Serial.println();
// Authenticate using key B
Serial.println(F("Authenticating again using key B..."));
status = (MFRC522::StatusCode)M5Dial.Rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key,
&(M5Dial.Rfid.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(M5Dial.Rfid.GetStatusCodeName(status));
return;
}
// Write data to the block
Serial.print(F("Writing data into block "));
Serial.print(blockAddr);
Serial.println(F(" ..."));
dump_byte_array(dataBlock, 16);
Serial.println();
status = (MFRC522::StatusCode)M5Dial.Rfid.MIFARE_Write(blockAddr, dataBlock, 16);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Write() failed: "));
Serial.println(M5Dial.Rfid.GetStatusCodeName(status));
}
Serial.println();
// Read data from the block (again, should now be what we have written)
Serial.print(F("Reading data from block "));
Serial.print(blockAddr);
Serial.println(F(" ..."));
status = (MFRC522::StatusCode)M5Dial.Rfid.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read() failed: "));
Serial.println(M5Dial.Rfid.GetStatusCodeName(status));
}
Serial.print(F("Data in block "));
Serial.print(blockAddr);
Serial.println(F(":"));
dump_byte_array(buffer, 16);
Serial.println();
// Check that data in block is what we have written
// by counting the number of bytes that are equal
Serial.println(F("Checking result..."));
byte count = 0;
for (byte i = 0; i < 16; i++) {
// Compare buffer (= what we've read) with dataBlock (= what we've written)
if (buffer[i] == dataBlock[i]) count++;
}
Serial.print(F("Number of bytes that match = "));
Serial.println(count);
if (count == 16) {
Serial.println(F("Success :-)"));
} else {
Serial.println(F("Failure, no match :-("));
Serial.println(F(" perhaps the write didn't work properly..."));
}
Serial.println();
// Dump the sector data
Serial.println(F("Current data in sector:"));
M5Dial.Rfid.PICC_DumpMifareClassicSectorToSerial(&(M5Dial.Rfid.uid), &key, sector);
Serial.println();
// Halt PICC
M5Dial.Rfid.PICC_HaltA();
// Stop encryption on PCD
M5Dial.Rfid.PCD_StopCrypto1();
}
}
  • 读写案例输出, 可以看到扇区1的4号block被成功写入数据。
« PICC type: MIFARE 1KB
C2 34 D4 44 
Authenticating using key A...
Current data in sector:
   1      7   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 
          6   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 
          5   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 
          4   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

Reading data from block 4 ...
Data in block 4:
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Authenticating again using key B...
Writing data into block 4 ...
 01 02 03 04 05 06 07 08 09 0A FF 0B 0C 0D 0E 0F

Reading data from block 4 ...
Data in block 4:
 01 02 03 04 05 06 07 08 09 0A FF 0B 0C 0D 0E 0F
Checking result...
Number of bytes that match = 16
Success :-)

Current data in sector:
   1      7   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 
          6   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 
          5   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 
          4   01 02 03 04  05 06 07 08  09 0A FF 0B  0C 0D 0E 0F  [ 0 0 0 ] 

INIT API

The following is the use of common API instructions, general read and write MIFARE card using the process as follows.

    1. initialize RFID
    1. detect the existence of new cards, get the card uid
    1. select the card through the uid, enter the active state
    1. through the A,B KEY to unlock the corresponding block to be operated
    1. read and write data
    1. control the card to enter the dormant state

Operation return value status code

cpp
1 2 3 4 5 6 7 8 9 10 11
enum StatusCode {
STATUS_OK = 1, // Success
STATUS_ERROR = 2, // Error in communication
STATUS_COLLISION = 3, // Collission detected
STATUS_TIMEOUT = 4, // Timeout in communication.
STATUS_NO_ROOM = 5, // A buffer is not big enough.
STATUS_INTERNAL_ERROR = 6, // Internal error in the code. Should not happen ;-)
STATUS_INVALID = 7, // Invalid argument.
STATUS_CRC_WRONG = 8, // The CRC_A does not match
STATUS_MIFARE_NACK = 9 // A MIFARE PICC responded with NAK.
};

begin

Syntax:

void begin();

Description:

  • Initialize RFID

It can be initialized by setting the parameter enableRFID to true when calling M5Dial.begin.

M5Dial.begin(m5::M5Unified::config_t cfg, bool enableEncoder,bool enableRFID)

Parameters:

  • null

Return:

  • null

PICC_IsNewCardPresent

Syntax:

bool PICC_IsNewCardPresent();

Description:

  • Scans for the presence of cards that have not been detected and are in the IDLE state, cards in the HALT state are ignored.

Parameters:

  • null

Return:

  • bool:
    • true:New card scanned.
    • false:No new cards scanned

PICC_ReadCardSerial

Syntax:

bool PICC_ReadCardSerial();

Description:

  • The operation reads the card UID, the UID after successful reading can be read in class member Uid uid;. Before read operation, PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() should be executed to make sure the card is read.
cpp
1 2 3 4
for (byte i = 0; i < M5Dial.Rfid.uid.size;
i++) { // Output the stored UID data.
Serial.printf("%02X ", M5Dial.Rfid.uid.uidByte[i]);
}

Parameters:

  • null

Return:

  • bool:
    • true:Read successfully
    • false:Failed to read

PICC_RequestA

Syntax:

uint8_t PICC_RequestA(uint8_t *bufferATQA, uint8_t *bufferSize);

Description:

  • Scanning detects cards of Type A standard within reading range

Parameters:

  • uint8_t *bufferATQA:
    • Storage Request Response ATQA (Answer to request) 的buffer
  • uint8_t *bufferSize:
    • buffer Size(>2byte).

Return:

  • uint8_t:
    • StatusCode

PICC_WakeupA

Syntax:

uint8_t PICC_WakeupA(uint8_t *bufferATQA, uint8_t *bufferSize);

Description:

  • Wake up range of Type A compliant cards

Parameters:

  • uint8_t *bufferATQA:
    • Storage Request Response ATQA (Answer to request) 的buffer
  • uint8_t *bufferSize:
    • buffer Size(>2byte).

Return:

  • uint8_t:
    • StatusCode

PICC_Select

Syntax:

uint8_t PICC_Select(Uid *uid, uint8_t validBits = 0);

Description:

  • Select a card by uid to enter active state

Parameters:

  • Uid *uid:
    • Pointer to the card uid structure obtained through scanning
  • uint8_t validBits:
    • Valid bits in the last uint8_t, 0 means 8 valid bits.

Return:

  • uint8_t:
    • StatusCode

PICC_HaltA

Syntax:

uint8_t PICC_HaltA();

Description:

  • Select the current card to enter the hibernation state

Parameters:

  • null

Return:

  • uint8_t:
    • StatusCode

MIFARE API

PCD_Authenticate

Syntax:

uint8_t PCD_Authenticate(uint8_t command, uint8_t blockAddr, MIFARE_Key *key, Uid *uid);

Description:

  • For MIFARE authentication, before calling this function, you need to select the card to make it active. Call PCD_StopCrypto1() after the authenticated PICC communication is finished, otherwise a new communication cannot be started.

Parameters:

  • uint8_t command:
    • PICC_CMD_MF_AUTH_KEY_A
    • PICC_CMD_MF_AUTH_KEY_B
  • uint8_t blockAddr:
    • Block Address
  • MIFARE_Key *key:
    • By default, A,B keys are FFFFFFFFFFFFFFF.
  • Uid *uid

Return:

  • uint8_t:
    • StatusCode

PCD_StopCrypto1

Syntax:

void PCD_StopCrypto1();

Description:

  • Exit the authentication state of the PCD. PCD_StopCrypto1() must be called after the authenticated PICC communication is finished, otherwise a new communication cannot be started.

Parameters:

  • null

Return:

  • null

MIFARE_Read

Syntax:

uint8_t MIFARE_Read(uint8_t blockAddr, uint8_t *buffer, uint8_t *bufferSize);

Description:

  • Write data to the specified block addr

Parameters:

  • uint8_t blockAddr:
    • Block address in the actual card sector
  • uint8_t *buffer:
    • Pointer to the buffer that receives the data
  • uint8_t *bufferSize:
    • Length of buffer to receive data (>=18byte)

Return:

  • uint8_t:
    • StatusCode

MIFARE_Write

Syntax:

uint8_t MIFARE_Write(uint8_t blockAddr, uint8_t *buffer, uint8_t bufferSize);

Description:

  • Write data to the specified block addr

Parameters:

  • uint8_t blockAddr:
    • Block address in the actual card sector
  • uint8_t *buffer:
    • data pointer
  • uint8_t *bufferSize:
    • data length(16byte)

Return:

  • uint8_t:
    • StatusCode
On This Page