arduino + RC522 讀寫字元串資料
- 實驗描述
- RFID子產品基本知識
-
- MFRC522庫
- NXP_MFRC522讀寫器(Proximity Coupling Device)
- PICC(Proximity Integrated Circuit Card)
- 硬體連接配接
- 程式流程圖
- 程式源碼
實驗描述
本實驗将會實作一個通過序列槽發送指令讀取資訊或者寫入特定資訊到指定位置,我目前做的是實作對某藥品名稱、性狀、用法用量等具體資訊的存取,是以,此處我實作的是對藥品名稱進行讀寫,我在代碼中定義了一個有關藥品資訊的結構體,讀者可以通過在其中添加成員來實作添加資訊項的目的,在此記錄下來供以後參考,由于本人菜鳥一個且本實驗還未成熟,大佬發現有錯誤煩請指正。
RFID子產品基本知識
MFRC522庫
本實驗基于MFRC522庫進行開發,需要先加載此庫檔案。
NXP_MFRC522讀寫器(Proximity Coupling Device)
恩智浦生産的一種工作在13.56MHz電磁場下的RFID讀卡器,可以讀取MIFARE 4K、MIFARE 1K、MIFARE Mini等卡片。
PICC(Proximity Integrated Circuit Card)
一種使用ISO 14443A接口的RFID卡片,例如:MIFARE、NTAG203。
MIFARE 經常使用的又有MIFARE 4K,MIFARE 1K和MIFARE Mini幾種,由于我使用的時MIFARE 1K,是以我下面以MIFARE 1K為例進行介紹。
MIFARE 1K共有16個扇區,每個扇區4個塊,每個塊可以存儲16個位元組,是以似乎我們一共有16 x 4 x 16 Byte的存儲空間,即1KB。然而事實并非如此,每個扇區中都固定最後一個塊(稱之為Sector Trailer)我們不能存儲資料,而被用來存儲整個扇區通路控制有關的資料。具體每個字段是什麼意思我也不是也太清楚,可以查閱一下恩智浦公司相關産品的資料手冊(但是我知道對每個塊進行讀寫時需要使用Key B進行驗證,驗證通過後才能完成讀寫)Key B出廠時預設設定為FF FF FF FF FF FF。每個扇區中最後一個塊的内字段定義如下:
Bytes 0-5 | Key A |
---|---|
Bytes 6-8 | Access Bits |
Bytes 9 | User data |
Bytes 10-15 | Key B (or user data) |
而對于扇區0來說,它的第0塊存儲的為該卡片的序列号等資訊,是以我們也是隻能讀取不能寫入使用者新資料。是以MIFARE 1K實際可用容量為[(15 x 3)+2 ] x 16 = 752 B,其餘MIFARE 4K 和 MIFARE Mini類似。是以,對于一個MIFARE 1K 我們實際可用的空間分布為:
Block0 | UID、Type、etc… |
---|---|
Block1 | UserData |
Block2 | UserData |
Block3 | Sector trailer |
Block4 | UserData |
Block5 | UserData |
Block6 | UserData |
Block7 | Sector trailer |
Block8 | UserData |
Block9 | UserData |
Block10 | UserData |
Block11 | Sector trailer |
Block12 | UserData |
Block13 | UserData |
Block14 | UserData |
Block15 | Sector trailer |
硬體連接配接
MFRC522 | Arduino UNO |
---|---|
RST | 9 |
SDA(SS) | 10 |
MOSI | 11 / ICSP-4 |
MISO | 12 / ICSP-1 |
SCK | 13 / ICSP-3 |
程式流程圖
主程式運作過程:
程式源碼
/*
* Write and Read 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
*
* 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>
typedef struct{
byte DrugName[48]; //藥品名稱
byte Dosage[12]; //用法用量
byte Remaining[4]; //剩餘量
}DrugInfo;
#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
MFRC522::MIFARE_Key key;
MFRC522::StatusCode status;
DrugInfo drugInfo; //執行個體化一個藥品資訊的結構體變量
byte block;
byte len;
const byte drugNameBlockAddr[3] = {1,2,4}; //藥品名稱的存儲位址
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 card
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
Serial.println(F("Write and Read personal data on a MIFARE PICC "));
}
void loop(){
char cmd = ' ';
byte count = 0;
while(Serial.read() >= 0); //清空在PICC卡讀寫期間的序列槽資料
Serial.println("please input a command(0:read; 1:write):");
while(Serial.available() <= 0); //等待指令輸入
delay(10); //等待資料全部進入緩沖區
if(Serial.available() != 1)
{
Serial.println("error: Invalid command!");
while(Serial.read() >= 0);
return;
}
cmd = (char)Serial.read();
if(cmd != '0' && cmd != '1')
{
Serial.println("error: Invalid command!");
return;
}
/*###############################################################################################################################*/
if(cmd == '0')
{
//read a PICC card
Serial.println("Waiting for the appearance of the PICC card in one minute(read)...");
// Look for new cards
while ( ! mfrc522.PICC_IsNewCardPresent())
{
delay(1000);
if(count++>60)
{
Serial.println("Waiting timeout...");
count = 0;
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("Drug Name: "));
len = 18;
for(uint8_t i = 0; i < sizeof(drugNameBlockAddr);i++)
{
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, drugNameBlockAddr[i], &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(drugNameBlockAddr[i], &drugInfo.DrugName[i*16], &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 < sizeof(drugInfo.DrugName); i++)
{
Serial.write(drugInfo.DrugName[i]);
}
Serial.print(" ");
Serial.println(F("\n**End Reading**\n"));
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}
/*###############################################################################################################################*/
else if(cmd == '1')
{
//write a PICC card
Serial.println("Waiting for the appearance of the PICC card in one minute(write)...");
// Look for new cards
while( ! mfrc522.PICC_IsNewCardPresent())
{
delay(1000);
count++;
if(count > 60)
{
count = 0;
Serial.println("Waiting timeout...");
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(" \nPICC type: ")); // Dump PICC type
MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
Serial.println(mfrc522.PICC_GetTypeName(piccType));
for(byte i = 0; i < sizeof(drugInfo.DrugName); i++) drugInfo.DrugName[i] = ' ';
while(Serial.read() >= 0);
Serial.println("please input drug name(Less than 48 characters):");
while(Serial.available()<=0)//等待輸入
{
delay(1000);
count++;
if(count > 300)
{
Serial.println("No drug name entered");
count = 0;
return;
}
}
delay(10);//等待資料全部進入緩沖區
int length = Serial.available();
for(byte i = 0; i < length; i++)
{
drugInfo.DrugName[i] = Serial.read();
}
for(byte i = 0; i < sizeof(drugNameBlockAddr); i++)
{
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, drugNameBlockAddr[i], &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(drugNameBlockAddr[i], &drugInfo.DrugName[i*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
}
}