大家好,我是兔子。是嵌入式工程师。
这次教大家如何玩转射频卡。就是下面这个玩意。某宝一搜一大堆。
我有些朋友认为是磁卡,卡里没钱了。他们就告诉我是卡没磁了。
我给大家纠正一下,这个卡是射频卡。有好几种规格。常见的有IC和ID卡。
不是用磁来存储数据的。卡片里内置了射频天线以及芯片。
通过和配套的读卡器近距离触碰。卡片里的芯片通过天线获得电能和信号来工作的。
需要准备一张IC卡及读卡器芯片板RC522。并将读卡器板通过杜邦线线和Arduino连接。
RC522读卡器板及空白IC卡在某宝上很容易买到。
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 不接
这次,我们直接使用国外大哥写的库。
先在工具->管理库,然后搜索RC522。
稍等一会,等库安装好,我们就可以开始写程序了。
IC卡有很多扇区可以写数据。读数据需要A密码,修改数据需要B密码。
如果密码不对,是无法读到卡里的数据的,也无法修改卡的数据。
A密码和B密码都是长度为6个字节的数组。
还好,新买的IC卡空卡。A密码和B密码都为默认值,即0xFFFFFFFFFFFF。
我们就使用默认密码进行操作,就不修改密码了。
PS:非空白卡,比如饭卡,公交卡啥的。设备厂家已经对数据进行了加密,即修改了密码,使用默认密码是无法读写数据的。各位就不要想着自己给自己饭卡、公交卡充值了。
就算破解了密码,饭卡和公交卡的数据一般也都存在云端。卡只是做一个认证。
我们程序就做个简单点的功能,模拟一下给卡充值。
/**
/*程序 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 = ""; //接收数据完成,将接收数据缓存清空
}
}
我们就使用串口来观看界面,并输入充值数额。
打开工具->串口监视器。
波特率设置为9600,并设置为没有结束符。
将我们的射频卡贴到读卡器板卡上。
可以看到,有字出来了。识别到卡片,并将卡内的余额打印出来。(这里的余额是我之前测试的时候写进去的)
然后在输入框中输入200后,点击发送。即将卡内金额改写为200。
然后,我们可以看到,金额改写成功了。
这个金额有没有被正确的充值到卡里呢?我们把读卡器重新断电,然后再上电。
再将卡片放在读卡器上查看。
确实在断电重启读卡器后,可以看到卡的金额就是我们之前刚写进去的。
应为简单起见,我只使用了1个字节存储数据。1个字节的范围为0~255。所以不可以改写超过255的数。
如果想存更大的数,可以使用多个字节来存储数据。
金额当然不可以有字符啦。
Arduino RC522射频卡 模拟充值https://www.zhihu.com/video/1103786769341878272