Arduino improvement chapter 20—S50 card data reading and writing

The RC522 module can not only read the data in the tag, but also write the data into the tag. This article introduces the card write operation of the S50 card.

1. Introduction of S50 card

The capacity of S50 non-contact IC card is 1K byte EEPROM, also known as M1 card. The internal EEPROM is divided into 16 sectors, each sector is divided into 4 blocks, with blocks as access units, each block is composed of 16 bytes.

1. M1 card main indicators:

  • Each sector has an independent set of passwords and access control.
  • Each card has a unique 32-bit serial number.
  • No power supply, with its own antenna, contains encrypted control logic and communication logic circuit.
  • Data retention period is 10 years, can be rewritten 100,000 times, read unlimited times
  • Working frequency: 13.56MHZ
  • Communication rate: 106 KBPS
  • Working temperature: -20 ℃ ~ 50 ℃ (humidity 90%)

2. M1 card storage structure

The storage structure is as follows, 16 sectors, 4 blocks per sector, 64 blocks of 16 sectors can be numbered 0-63 according to absolute addresses.

M1 card storage structure

The block 0 in sector 0 is used to store the manufacturer's code. The first four bytes are generally UIDs, which have been solidified and generally cannot be changed.

Block 0, block 1, and block 2 of each sector are data blocks, which can be used to store data, and block 3 is a control block, including password A, access control, and password B.

Control block

3. Reading and writing process

The password and access control of each sector are independent, and each password and access control can be set according to actual needs. The factory default password 6 bytes are 0xFF.

The access conditions of each block in the sector are determined jointly by the password and the access control. Each block has three corresponding control bits, which are restricted according to certain rules. For details, please refer to the M1 card data manual.

This demo demonstrates writing data to block 0 in sector 1 and the absolute address is block 4. The main process is as follows: the module performs card scanning to read the card information, performs identity authentication through the password, then reads the block data before writing, then performs identity authentication again and writes custom data, and then reads again after identity authentication Block data to detect whether the write was successful.

2. Experimental materials

  • Uno R3 development board
  • Supporting USB data cable
  • Breadboard and supporting cable
  • RFID-RC522 module and supporting S50 white card and special-shaped card

3. Experimental steps

1. Build the circuit diagram according to the schematic diagram.

The 3.3V and GND of the RC522 module respectively correspond to the 3.3V and GND of the development board. The MOSI, MISO and SCK of the module are respectively connected to the SPI interfaces 11, 12, 13 of the development board, and the SDA and RST of the module are connected to the digital pins of the development board. 10, 9.

The experimental schematic diagram is shown below:

Experimental schematic

The physical connection diagram is shown below:

Physical connection diagram

2. Create a new sketch, copy the following code to replace the automatically generated code and save it.

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9
#define SS_PIN          10

MFRC522 mfrc522(SS_PIN, RST_PIN);
MFRC522::MIFARE_Key key;

void setup() {
  Serial.begin(9600);
  while (!Serial);    // 等待串口打开
  SPI.begin();
  mfrc522.PCD_Init();

  // 出厂默认使用FF FF FF FF FF FF作为密码A和B
  for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;
  }

  Serial.println(F("开始扫描卡进行读写..."));
  Serial.print(F("使用密码:"));
  dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE);
  Serial.println();
  Serial.println(F("数据将被写入到#1扇区"));
}

void loop() {
  //寻找新卡
  if ( ! mfrc522.PICC_IsNewCardPresent())
    return;

  //验证UID是否可读
  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("不支持读取此卡类型"));
    return;
  }

  // 操作扇区1
  // 扇区1包括:块4~块7
  byte sector         = 1;
  byte blockAddr      = 4;
  byte dataBlock[]    = {
    0x01, 0x02, 0x03, 0x04,
    0x05, 0x06, 0x07, 0x08,
    0x09, 0x0A, 0x0B, 0x0C,
    0x0D, 0x0E, 0x0F, 0x10
  };//要写入的数据
  byte trailerBlock   = 7;
  MFRC522::StatusCode status;
  byte buffer[18];
  byte size = sizeof(buffer);

  // 使用密码A进行身份认证
  Serial.println(F("使用密码A进行身份认证..."));
  status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("身份认证失败 "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // 显示当前扇区数据
  Serial.println(F("当前扇区数据:"));
  mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
  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();

  // 使用密码B进行身份认证
  Serial.println(F("使用密码B进行身份认证..."));
  status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("身份认证失败 "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  //写入数据
  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("当前扇区数据:"));
  mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
  Serial.println();

  //使放置在读卡区的IC卡进入休眠状态,不再重复读卡
  mfrc522.PICC_HaltA();

  // 停止读卡模块编码
  mfrc522.PCD_StopCrypto1();
}

// 十六进制输出
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);
  }
}

3. Connect the development board, set the corresponding port number and development board type, and download the program.

Program download

4. Experimental phenomena

Open the serial monitor and set the baud rate to 9600 which is consistent with the program. Move the card close to the module, and according to the printing information, you can see that the data is written to the specified block.

Experimental phenomena


Follow the public account "TonyCode" for more exciting content sharing.
Reply "1024" to get 1000G learning materials.
personal blog
Insert picture description here

Published 73 original articles · praised 275 · 270,000 views +

Guess you like

Origin blog.csdn.net/TonyIOT/article/details/105505863