Arduino RC522射频卡 模拟充值 - 知乎
2021-12-24 02:18:45 Author: zhuanlan.zhihu.com(查看原文) 阅读量:22 收藏

大家好,我是兔子。是嵌入式工程师。

这次教大家如何玩转射频卡。就是下面这个玩意。某宝一搜一大堆。

我有些朋友认为是磁卡,卡里没钱了。他们就告诉我是卡没磁了。

我给大家纠正一下,这个卡是射频卡。有好几种规格。常见的有IC和ID卡。

不是用磁来存储数据的。卡片里内置了射频天线以及芯片。

通过和配套的读卡器近距离触碰。卡片里的芯片通过天线获得电能和信号来工作的。

1.准备工作

需要准备一张IC卡及读卡器芯片板RC522。并将读卡器板通过杜邦线线和Arduino连接。

RC522读卡器板及空白IC卡在某宝上很容易买到。

2.接线

RC522 RST --> Arduino 9

RC522 SDA(SS) --> Arduino 10

RC522 MOSI --> Arduino 11

RC522 MISO --> Arduino 12

RC522 SCK --> Arduino 13

RC522 3.3V --> Arduino 3.3V

RC522 GND --> Arduino GND

RC522 IRQ --> Arduino 不接

3.添加RC522库文件

这次,我们直接使用国外大哥写的库。

先在工具->管理库,然后搜索RC522。

稍等一会,等库安装好,我们就可以开始写程序了。

4.写程序之前补充的知识

IC卡有很多扇区可以写数据。读数据需要A密码,修改数据需要B密码。

如果密码不对,是无法读到卡里的数据的,也无法修改卡的数据。

A密码和B密码都是长度为6个字节的数组。

还好,新买的IC卡空卡。A密码和B密码都为默认值,即0xFFFFFFFFFFFF。

我们就使用默认密码进行操作,就不修改密码了。

PS:非空白卡,比如饭卡,公交卡啥的。设备厂家已经对数据进行了加密,即修改了密码,使用默认密码是无法读写数据的。各位就不要想着自己给自己饭卡、公交卡充值了。

就算破解了密码,饭卡和公交卡的数据一般也都存在云端。卡只是做一个认证。

5.写程序

我们程序就做个简单点的功能,模拟一下给卡充值。

/**
 /*程序 RC522读写IC卡程序
 *作者:兔子
  效果:可以读出IC卡的一个字节的数据,并可改写这个数据
  时间:19.04.22
 *
 *
 * RST/Reset   RST     -->       Arduino 9
 * SPI SS      SDA(SS) -->       Arduino 10 
 * SPI MOSI    MOSI    -->       Arduino 11
 * SPI MISO    MISO    -->       Arduino 12 
 * SPI SCK     SCK     -->       Arduino 13 
 */

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

#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;
String incomingByte = "";   // for incoming serial data

byte sector         = 1;
byte blockAddr      = 4;
byte dataBlock[]    = {
    0x01, 0x02, 0x03, 0x04, //  1,  2,   3,  4,
    0x05, 0x06, 0x07, 0x08, //  5,  6,   7,  8,
    0x09, 0x0a, 0xff, 0x0b, //  9, 10, 255, 11,
    0x0c, 0x0d, 0x0e, 0x0f  // 12, 13, 14, 15
};

byte trailerBlock   = 7;
MFRC522::StatusCode status;
byte buffer[18];
byte size = sizeof(buffer);

/**
 * Initialize.
 */
void setup() {
    Serial.begin(9600); // 初始化串口,设置波特率为9600
    while (!Serial);    // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
    SPI.begin();        // 初始化SPI总线,用来和射频卡芯片RC522通信
    mfrc522.PCD_Init(); // 初始化射频卡芯片RC522

    // 准备射频卡的A区和B区密码,出厂值为6个0xFF。即FFFFFFFFFFFF
    for (byte i = 0; i < 6; i++) {
        key.keyByte[i] = 0xFF;
    }

    Serial.println("欢迎使用兔子
射频卡充值业务");
}

/**
 * Main loop.
 */
void loop() {
    // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
    if ( ! mfrc522.PICC_IsNewCardPresent())  //
        return;

    // Select one of the cards
    if ( ! mfrc522.PICC_ReadCardSerial())
        return;
    
    // Authenticate using key A
    Serial.println("正在认证射频卡...");
    //射频卡读操作,需要用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("认证失败,密码不对");
        return;
    }

    // Show the whole sector as it currently is
    Serial.print("卡内余额:");
    status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(4,buffer,&size);
    if (status != MFRC522::STATUS_OK) {
      Serial.println("数据读取错误");
      return;
    }
    Serial.print(buffer[0]);
    Serial.println("元");
 
    while(1)
    {
      while(Serial.available() > 0)          //等待输入,有输入后才会继续下一步
      {
        incomingByte += char(Serial.read());
        delay(2);
      }
       if(incomingByte.length() > 0)    //判断数据长度是否大于0
       {
        //Serial.println(incomingByte);
        if(incomingByte.toInt() == 0)  //将字符串转换为数字,如果充值金额需在1~255之间
        {
          Serial.println("充值金额请勿为0/请勿输入除数字外的其他字符");
          }
        else if(incomingByte.toInt() > 255)
        {
          Serial.println("充值金额请勿超过255");
          }
        else
        {
          Serial.print("正在充值:");
          Serial.print(incomingByte);
          Serial.println("元");

          //验证B区的密码,写数据需要B区密码
             status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
              if (status != MFRC522::STATUS_OK) {
                  Serial.println("认证失败,密码不对");
                  return;
              }
              dataBlock[0] = incomingByte.toInt();  //充值的数量,写入缓存
            status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockAddr, dataBlock, 16);
            if (status != MFRC522::STATUS_OK) {
                  Serial.println("充值失败");
              }
              else
              {
                Serial.println("充值成功");
                }
            }
          }
        incomingByte = "";              //接收数据完成,将接收数据缓存清空
        }
}

6.充值界面

我们就使用串口来观看界面,并输入充值数额。

打开工具->串口监视器。

波特率设置为9600,并设置为没有结束符。

将我们的射频卡贴到读卡器板卡上。

可以看到,有字出来了。识别到卡片,并将卡内的余额打印出来。(这里的余额是我之前测试的时候写进去的)

然后在输入框中输入200后,点击发送。即将卡内金额改写为200。

然后,我们可以看到,金额改写成功了。

这个金额有没有被正确的充值到卡里呢?我们把读卡器重新断电,然后再上电。

再将卡片放在读卡器上查看。

确实在断电重启读卡器后,可以看到卡的金额就是我们之前刚写进去的。

7.为什么金额不可以改写为超过255。也不可含有字符。只能有数字。

应为简单起见,我只使用了1个字节存储数据。1个字节的范围为0~255。所以不可以改写超过255的数。

如果想存更大的数,可以使用多个字节来存储数据。

金额当然不可以有字符啦。

8.操作视频

Arduino RC522射频卡 模拟充值https://www.zhihu.com/video/1103786769341878272


文章来源: https://zhuanlan.zhihu.com/p/63339581
如有侵权请联系:admin#unsafe.sh