RFID-MFRC522射频识别S50白卡

简介: 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

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灯闪烁三下)

不刷卡(显示成功次数)

串口监视器(打印刷卡信息)

相关文章
|
7月前
|
传感器 物联网 芯片
毕业设计 基于STM32单片机无线ZIGBEE智能大棚土壤湿度光照检测
毕业设计 基于STM32单片机无线ZIGBEE智能大棚土壤湿度光照检测
142 0
|
7月前
|
物联网
RFID
物联网关键技术——RFID。
184 0
|
传感器 存储 数据采集
VS208~432型振弦传感器无线采集仪的主要特点
VS208-432型振弦传感器无线采集仪是结合多年的项目实际及产品研发经验而研发的一款安装方便、实用性强、性能稳定、数据远传、价优质美的振弦型数据采集仪产品特别适合野外无人环境。
VS208~432型振弦传感器无线采集仪的主要特点
|
传感器 存储
振弦传感器的智能识别技术
当数十上百支传感器接长电缆,并安装到各个监测点,成捆电被挖断或传感器上的标签丢失损毁老化等,在工程监测项目初期数十上百支传感器使用人工读数,这个工作量可想而知。
振弦传感器的智能识别技术
|
传感器 存储 供应链
【基于 Arduino 的 RFID门锁】
【基于 Arduino 的 RFID门锁】
171 0
|
存储 算法 API
基于单片机的无线语音遥控智能车设计
基于单片机的无线语音遥控智能车设计
245 0
基于单片机的无线语音遥控智能车设计
|
传感器
手持振弦采集仪VH501TC对智能振弦传感器的激励信号
采集仪对振弦传感器激励:也称为“激振”,是振弦类传感器频率数据获取的必须过程,仅当传感器收 到合适的激励信号后才能产生自振,而仅当振弦传感器产生自振后才能输出频率信号,进一步的,读数电路会检测并读取振弦传感器的自振信号,才能通过计算得到 振动频率值。振弦传感器的激励信号(能够使传感器产生自振的外部信号)一般分 为两类,一类为高压短促脉冲,一类为特定频率的多组连续低压脉冲信号。
手持振弦采集仪VH501TC对智能振弦传感器的激励信号
|
数据格式
智能车常用的上下位机:匿名上位机 V7,TFMiniPlus 激光雷达测距
智能车常用的上下位机:匿名上位机 V7,TFMiniPlus 激光雷达测距
243 0
|
传感器 编解码 网络协议
基于STM32设计的智能插座+人体感应灯(ESP8266+人体感应+手机APP)
基于STM32设计的智能插座+人体感应灯(ESP8266+人体感应+手机APP)
628 0
基于STM32设计的智能插座+人体感应灯(ESP8266+人体感应+手机APP)
|
索引 数据处理
便携式人体脉搏检测系统(2)
LabView+VISA+PL2303
1626 0