赞
踩
无线射频识别即射频识别技术(Radio Frequency Identification,RFID),是自动识别技术的一种,通过无线射频方式进行非接触双向数据通信,利用无线射频方式对记录媒体(电子标签或射频卡)进行读写,从而达到识别目标和数据交换的目的。
MFRC522是高度集成的非接触式读写卡芯片,是一款低电压、低成本、体积小的非接触式读写卡芯片,是智能仪表和便携式手持设备研发的较好选择。
S50卡是采用NXP MF1 IC S50制作的非接触智能卡,通常简称S50卡或Mifare 1K,符合ISO14443A标准,4或7字节UID。具有1K数据存储区,数据有密钥保护。
一、主要指标:
· 容量为 8K 位 EEPROM
· 分为 16 个扇区,每个扇区为 4 块,每块 16 个字节,以块为存取单位
· 每个扇区有独立的一组密码及访问控制
· 每张卡有唯一序列号,为 32 位
· 具有防冲突机制,支持多卡操作
· 无电源,自带天线,内含加密控制逻辑和通讯逻辑电路
· 数据保存期为 10 年,可改写 10 万次,读无限次
· 工作温度: -20℃ ~50℃ (湿度为 90%)
· 工作频率: 13.56MHZ
· 通信速率: 106 KBPS
· 读写距离: 10 cm 以内(与读写器有关)
二、存储结构
具体了解S50卡的相关信息请查看相关的中文说明书,链接放下方了。
(1)在S50白卡的第15扇区第2块写入系统特征码,前三字节AAH BBH CCH + 其他(任意,各组不同);异形卡不做任何设置。
(2)当刷本组的白卡时,液晶屏显示欢迎词,否则(异形卡或者他组白卡)液晶屏显示拒绝信息,并闪烁LED灯3次以示报警。
(3)在液晶屏上显示当日(开机或重启后)刷卡总次数。
RC522
RC522 | NodeMcu |
---|---|
SDA | D2(GPIO4) |
SCK | D5(GPIO14) |
MOSI | D7(GPIO13) |
MISO | D6(GPIO12) |
IRQ | 空 |
GND | GND |
RST | D1(GPIO5) |
3.3V | 3.3V |
SSD1306
SSD1306 | NodeMcu |
---|---|
GND | GND |
VCC | 3.3V |
D0 | D5(DPIO14) |
D1 | D7(GPIO13) |
RES | D8(GPIO15) |
DC | D4(GPIO2) |
CS | D10(GPIO1) |
1.特征码写入
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 5 // 配置针脚
#define SS_PIN 4
MFRC522 mfrc522(SS_PIN, RST_PIN); // 创建新的RFID实例
MFRC522::MIFARE_Key key; //6字节的密码
void dump_byte_array(byte *buffer, byte bufferSize); //声明dump_byte_array函数
void setup() {
Serial.begin(9600); // 设置串口波特率为9600
while (!Serial); // 如果串口没有打开,则死循环下去不进行下面的操作
SPI.begin(); // SPI开始
mfrc522.PCD_Init(); // Init MFRC522 card
for (byte i = 0; i < 6; i++) {//设置key为:FF FF FF FF FF FF
key.keyByte[i] = 0xFF;
}
Serial.println(F("扫描卡开始进行读或者写"));
Serial.print(F("使用A和B作为键"));
dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE);
Serial.println();
Serial.println(F("注意,会把数据写入到卡第15扇区"));
}
void loop() {
// 寻找新卡
if ( ! mfrc522.PICC_IsNewCardPresent())
return;
// 选择一张卡
if ( ! mfrc522.PICC_ReadCardSerial())
return;
// 显示卡片的详细信息
Serial.print(F("卡片 UID:"));
dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
Serial.println();
Serial.print(F("卡片类型: "));
MFRC522::PICC_Type 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(F("仅仅适合Mifare Classic卡的读写"));
return;
}
// 我们只使用第14个扇区
byte sector = 14;
byte blockAddr = 58;//第58个块为第14个扇区第2个数据块
byte dataBlock[] = {
0xaa, 0xbb, 0xcc, 0x01, // aa,bb,cc,1
0x00, 0x00, 0x00, 0x00, // 0,0,0,0
0x00, 0x00, 0x00, 0x00, // 0,0,0,0
0x00, 0x00, 0x00, 0x00 // 0,0,0,0
};//写入的数据定义
byte trailerBlock = 59;//第59个块为第14个扇区的控制块
MFRC522::StatusCode status;
byte buffer[18];
byte size = sizeof(buffer);
// 原来的数据
Serial.println(F("显示原本的数据..."));
status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));//在uid为mfrc522.uid的卡的trailerBlock块(此块为扇区控制块)验证key是否与A密码相同
if (status != MFRC522::STATUS_OK) {
Serial.print(F("身份验证失败?或者是卡链接失败"));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
// 显示整个扇区
Serial.println(F("显示所有扇区的数据"));
mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);//串行输出uid卡,第sector扇区的数据
Serial.println();
// 从块儿读取数据
Serial.print(F("读取块儿的数据在:")); Serial.print(blockAddr);
Serial.println(F("块 ..."));
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);//读取size个第blockAddr块的数据到buffer
if (status != MFRC522::STATUS_OK) {
Serial.print(F("读卡失败,没有连接上 "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
//开始进行写入准备
Serial.println(F("开始进行写入的准备..."));
status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));//验证密码B
if (status != MFRC522::STATUS_OK) {
Serial.print(F("写入失败,没有连接上或者没有权限 "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
// Write data to the block
Serial.print(F("在第: ")); Serial.print(blockAddr);
Serial.println(F(" 块中写入数据..."));
dump_byte_array(dataBlock, 16); Serial.println();//显示要写入的数据
status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockAddr, dataBlock, 16);//写入数据
if (status != MFRC522::STATUS_OK) {
Serial.print(F("写入失败... "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.println();
// 再次读取卡中数据,这次是写入之后的数据
Serial.print(F("读取写入后第")); Serial.print(blockAddr);
Serial.println(F(" 块的数据 ..."));
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("读取失败... "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.print(F("块 ")); Serial.print(blockAddr); Serial.println(F("数据为 :"));
dump_byte_array(buffer, 16); Serial.println();
// 验证一下数据,要保证写入前后数据是相等的
// 通过计算块中的字节数量
Serial.println(F("等待验证结果..."));
byte count = 0;
for (byte i = 0; i < 16; i++) {
// 比较一下缓存中的数据(我们读出来的数据) = (我们刚刚写的数据)
if (buffer[i] == dataBlock[i])
count++;
}
Serial.print(F("匹配的字节数量 = ")); Serial.println(count);
if (count == 16) {
Serial.println(F("验证成功 :"));
} else {
Serial.println(F("失败,数据不匹配"));
Serial.println(F("也许写入的内容不恰当"));
}
Serial.println();
// 转储扇区数据
Serial.println(F("写入后的数据内容为::"));
mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
Serial.println();
// 停止 PICC
mfrc522.PICC_HaltA();
//停止加密PCD
mfrc522.PCD_StopCrypto1();
}
/**
* 将字节数组串行输出为16进制字符
*/
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);
}
}
2.实现门禁效果
#include <SPI.h>
#include <MFRC522.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SS_PIN 4
#define RST_PIN 5
//显示屏和LED灯定义
#define redLed 16
#define OLED_MOSI 13
#define OLED_CLK 14
#define OLED_DC 2
#define OLED_CS 1
#define OLED_RESET 15
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class
MFRC522::MIFARE_Key key;
// Init array that will store new NUID
byte nuidPICC[4];
void dump_byte_array(byte *buffer, byte bufferSize); //声明dump_byte_array函数
byte cnt =0;
void setup() {
pinMode(redLed,OUTPUT);
digitalWrite(redLed,LOW);
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC);
display.clearDisplay();
display.setTextSize(1); //字体大小
display.setTextColor(WHITE); //字体颜色
display.setCursor(0,0); //调整位置
display.println(cnt);
display.display();
SPI.begin(); // Init SPI bus
rfid.PCD_Init(); // Init MFRC522
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
Serial.println(F("This code scan the MIFARE Classsic NUID."));
Serial.print(F("Using the following key:"));
printHex(key.keyByte, MFRC522::MF_KEY_SIZE);
}
void loop() {
// 我们只使用第14个扇区
byte sector = 14;
byte blockAddr = 58;//第58个块为第14个扇区第2个数据块
byte trailerBlock = 59;//第59个块为第14个扇区的控制块
MFRC522::StatusCode status;
byte buffer[18];
byte size = sizeof(buffer);
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( ! rfid.PICC_IsNewCardPresent())
return;
// Verify if the NUID has been readed
if ( ! rfid.PICC_ReadCardSerial())
return;
rfid.PICC_DumpMifareClassicSectorToSerial(&(rfid.uid), &key, sector);//串行输出uid卡,第sector扇区的数据
Serial.print(F("读取写入后第:")); Serial.print(blockAddr);
Serial.println(F("块的数据 ..."));
status = (MFRC522::StatusCode) rfid.MIFARE_Read(blockAddr, buffer, &size);//读取size个第blockAddr块的数据到buffer
if (status != MFRC522::STATUS_OK) {
Serial.print(F("读卡失败,没有连接上 "));
Serial.println(rfid.GetStatusCodeName(status));
}
Serial.print(F("该块: ")); Serial.print(blockAddr);Serial.println(F("数据为:"));
dump_byte_array(buffer, 16); Serial.println();
// Store NUID into nuidPICC array
for (byte i = 0; i < 4; i++) {
nuidPICC[i] = rfid.uid.uidByte[i];
}
Serial.println(F("The NUID tag is:"));
Serial.print(F("In hex: "));
printHex(rfid.uid.uidByte, rfid.uid.size);
Serial.println();
Serial.print(F("In dec: "));
printDec(rfid.uid.uidByte, rfid.uid.size);
Serial.println();
// Halt PICC
rfid.PICC_HaltA();
// Stop encryption on PCD
rfid.PCD_StopCrypto1();
}
/**
* Helper routine to dump a byte array as hex values to Serial.
*/
void printHex(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
}
/**
* Helper routine to dump a byte array as dec values to Serial.
*/
void printDec(byte *buffer, byte bufferSize) {
String s = "";
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], DEC);
s += buffer[i];
if(i == bufferSize-1){
Serial.print(" CardID Str: " + s);
}
}
}
//验证卡
void dump_byte_array(byte *buffer, byte bufferSize) {
byte buffer0[18] = { 0xaa, 0xbb, 0xcc };
int count = 0;
for(byte i =0 ;i<bufferSize ;i++) {
if(i<3) {
if(buffer[i] == buffer0[i]){
count++;
}
}
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
Serial.println();
if(count==3){
Serial.println("成功");
display.println("Welcome!");
cnt=cnt+1;
}
else{
Serial.println("验证失败");
display.println("NO Permission!");
digitalWrite(redLed,HIGH);
delay(200);
digitalWrite(redLed,LOW);
delay(200);
digitalWrite(redLed,HIGH);
delay(200);
digitalWrite(redLed,LOW);
delay(200);
digitalWrite(redLed,HIGH);
delay(200);
digitalWrite(redLed,LOW);
delay(200);
}
Serial.print("成功次数:");
Serial.println(cnt);
display.display();
delay(1000);
}
1.修改特征码(AA BB CC 01)
2.读卡
不刷卡(显示成功的次数)
可通行(显示“Welcome!” cnt次数加一)
不可通行(显示“No permission!”;LED灯闪烁三下)
不刷卡(显示成功次数)
串口监视器(打印刷卡信息)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。