RFID-MFRC522射频识别S50白卡

RFID-MFRC522射频识别S50白卡

硬件介绍

RFID

无线射频识别即射频识别技术(Radio Frequency Identification,RFID),是自动识别技术的一种,通过无线射频方式进行非接触双向数据通信,利用无线射频方式对记录媒体(电子标签或射频卡)进行读写,从而达到识别目标和数据交换的目的。

MFRC522

MFRC522是高度集成的非接触式读写卡芯片,是一款低电压、低成本、体积小的非接触式读写卡芯片,是智能仪表和便携式手持设备研发的较好选择。

在这里插入图片描述

S50卡

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卡的相关信息请查看相关的中文说明书,链接放下方了。

点击下载——提取码:6666

系统设计(一个刷卡门禁系统)

设计要求

(1)在S50白卡的第15扇区第2块写入系统特征码,前三字节AAH BBH CCH + 其他(任意,各组不同);异形卡不做任何设置。

(2)当刷本组的白卡时,液晶屏显示欢迎词,否则(异形卡或者他组白卡)液晶屏显示拒绝信息,并闪烁LED灯3次以示报警。

(3)在液晶屏上显示当日(开机或重启后)刷卡总次数。

Fritzing图

在这里插入图片描述

线路连接

RC522

RC522NodeMcu
SDAD2(GPIO4)
SCKD5(GPIO14)
MOSID7(GPIO13)
MISOD6(GPIO12)
IRQ
GNDGND
RSTD1(GPIO5)
3.3V3.3V

SSD1306

SSD1306NodeMcu
GNDGND
VCC3.3V
D0D5(DPIO14)
D1D7(GPIO13)
RESD8(GPIO15)
DCD4(GPIO2)
CSD10(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灯闪烁三下)
在这里插入图片描述
不刷卡(显示成功次数)
在这里插入图片描述
串口监视器(打印刷卡信息)
在这里插入图片描述

  • 15
    点赞
  • 123
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

失散多年的哥哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值