Arduino 控制RFID读写器读写 IC卡

您所在的位置:网站首页 rfid射频模块代码 Arduino 控制RFID读写器读写 IC卡

Arduino 控制RFID读写器读写 IC卡

2023-08-12 05:09| 来源: 网络整理| 查看: 265

Arduino 控制RFID读写器读写 IC卡 一、IC卡的认识

  IC卡可以通过频段进行划分,低频(125KHz~134kHz,典型工作频率是12KHz)、高频(13.56MHz)和超高频(860-960MHz)。

  今天的主角是高频卡即咱的M1卡,当然高频卡还有其他类型的卡,M1卡的芯片主要有s50和s70,即Philips Mifare 1 S50/S70芯片。区别是前者存储区只有1KB,后者4KB。 协议遵循ISO 14443 和ISO 10536。

  M1 S50卡共分为16个扇区,每个扇区分为4个块,每个块16个字节,所以总共16X4X16=1024字节,即1KB。

  每个扇区的最后一个块,也就是块三,控制着整个扇区的数据读写权限,数据可进行增加和减少等等,具体显示如下。

FF FF FF FF FFFF 07 80 69FF FF FF FF FF密码A控制权限密码B

  控制字节的前三个字节为有效字节,最后一个字节为备用字节,通过位的组合来进行多种控制的选择,

  比如第二个字节的第四位X、第三个字节的第一位Y和第三个字节的第四位Z组成一个0-7 的数据,每个数据代表一种控制方式,控制着块0的读写及数据加减操作。

76543210字节1 (FF)Y3_bY2_bY1_bY_bX3_bX2_bX1_bX_b字节2 (07)X3X2X1XZ3_bZ2_bZ1_bZ_b字节3 (80)Z3Z2Z1ZY3Y2Y1Y字节4(69备用) 控制位控制位控制位访问条件访问条件访问条件访问条件XYZ读数据写数据数据增加+数据减少000KEYA/BKEYA/BKEYA/BKEYA/B001KEYA/BXXX010KEYA/BKEYBXX011KEYA/BKEYBKEYBKEYA/B100KEYA/BXXKEYA/B101KEYBKEYBXX110KEYBXXX111XXXX

  ** KEYA/B 表示验证AB密码均可 ,X表示没有该权限 无法进行该操作。

  X_b表示X的反码。

  比如上面的控制权限 为000 即验证A或者B任意密码均可以进行读写加减数据等操作,属于安全性较低的一种控制权限。

  然后块1和块2的读写权限也如上图所示,是由X1 ,Y1,Z1和X2、Y2和Z2来控制。

  块3的读写权限,与块012有所不同。

控制位控制位控制位A密码访问条件A密码访问条件存取控制访问条件存取控制访问条件B密码访问条件B密码访问条件X3Y3Z3读数据写数据读数据写数据读数据写数据000XKEYA/BKEYA/BXKEYA/BKEYA/B001XXKEYA/BXKEYA/BX010XKEYBKEYA/BXXKEYB011XXKEYA/BXXX100XKEYA/BKEYA/BKEYA/BKEYA/BKEYA/B101XKEYBKEYA/BKEYBXKEYB110XXKEYA/BKEYBXX111XXKEYA/BXXX

  普通的M1白卡块0的前四位是UID号,代表着该卡唯一ID,不可以随意修改,因此许多门禁卡将其作为身份的识别,但是也有不少人想复制别人的卡,意思就是将自己卡的UID改成与别人的卡的UID一致。

#块0 16字节数据解释 D9 B2 20 09: 4字节卡号(即UID) 41 : XOR卡号校验 08 : 卡容量 04 00 : 卡类型 00 00 00 00: 其它 00 00 00 00: 其它

  普通的M1白卡无法修改,就出现了一种特殊的M1卡,UID卡,也称为魔术卡,UID可以更改,但是不可以直接通过读写更改,需要特殊的指令才可以修改,可以更改多次,但是无法绕过读写器的防火墙,会响应读写器后指令,被发现为复制卡。 在这里插入图片描述 在这里插入图片描述

  于是乎又出现了一种CUID卡,可以直接通过读写指令多次更改0扇区,方便了很多,同时会屏蔽后指令,绕过防火墙,但是其ID可能被其他读写更改,可能导致失效。

在这里插入图片描述 在这里插入图片描述

  于是乎又出现了一种FUID卡,可更改一次UID,之后将变成普通的UID卡,防火墙检测也可以绕过,只能读写一次。还有一种UFUID卡,如果执行封卡操作,则变成普通的M1卡,如果不执行封卡操作,就是CUID卡,可以反复读写,是FUID和CUID的组合版,可能就是比较贵。

在这里插入图片描述 在这里插入图片描述

二、Arduino读写IC卡取及UID号

  笔者使用的Arduino套件中的RFID读写器,芯片采用NXP公司的RC522,SPI通信,由于Arduino中自带SPI和RFID的库,所以很方便的调用来初始化芯片,以及读取卡片信息。 在这里插入图片描述 在这里插入图片描述 MCU芯片采用arduino uno r3套件,其芯片是Atmel 公司的AVR系列中的ATmega 328p微控制器,是RISC 指令单片机。 在这里插入图片描述

读取IC卡的信息步骤:

0、初始化RC522

1、是否有新卡处于空闲状态,自动忽略睡眠的卡,会唤醒卡

2、发送选择指令选择 一张卡,

3、串口输出卡的存储转储文件信息。(dump文件)

/* 【Arduino】108种传感器模块系列实验(资料+代码+图形+仿真) 实验一百零二:MFRC-522 RFID射频 IC卡感应模块读卡器S50复旦卡钥匙扣 1、工具-管理库-搜索“MFRC522”库-安装 2、项目:使用MFRC522 RFID和Arduino读写标签 3、RFID与Arduino Uno的连线 SDA------------------------Digital 10 SCK------------------------Digital 13 MOSI----------------------Digital 11 MISO----------------------Digital 12 IRQ------------------------不用连接 GND-----------------------GND RST------------------------Digital 9 3.3V------------------------3.3V (千万不要连接到5V接口!!!) */ #include #include #define SS_PIN 10 #define RST_PIN 9 MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. void setup() { Serial.begin(9600); // Initialize serial communications with the PC SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 card Serial.println("Scan PICC to see UID and type..."); } void loop() { // Look for new cards if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } // Select one of the cards if ( ! mfrc522.PICC_ReadCardSerial()) { return; } // Dump debug info about the card. PICC_HaltA() is automatically called. mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); }

在这里插入图片描述

  Arduino 读写IC卡内容的程序,主要是验证扇区AB密码、读块数据和写块数据,具体流程如下:

0、初始化RC522,定义要写入的数据等

1、察看是否有新卡

2、选择一张卡

3、显示卡片UID和类型

4、验证密钥,并读取整个扇区数据,具体验证A还是B密钥,需要知道卡的控制类型,根据上面知道的其实000,即验证AB密码均可。

5、验证秘钥,写入对应扇区对应块的数据。

6、检测写入的数据是否正确,先读出数据,然后和源数据做比较,

/* 【Arduino】108种传感器模块系列实验(资料+代码+图形+仿真) 实验一百零二:MFRC-522 RFID射频 IC卡感应模块读卡器S50复旦卡钥匙扣 1、安装库:IDE-工具-管理库-搜索“MFRC522”库-安装 2、项目三:RC522 模块的读写操作 3、RFID与Arduino Uno的连线 SDA------------------------Digital 10 SCK------------------------Digital 13 MOSI----------------------Digital 11 MISO----------------------Digital 12 IRQ------------------------不用连接 GND-----------------------GND RST------------------------Digital 9 3.3V------------------------3.3V (千万不要连接到5V接口!!!) */ #include #include #define RST_PIN 9 // 配置针脚 #define SS_PIN 10 MFRC522 mfrc522(SS_PIN, RST_PIN); // 创建新的RFID实例 MFRC522::MIFARE_Key key; void setup() { Serial.begin(9600); // 设置串口波特率为9600 while (!Serial); // 如果串口没有打开,则死循环下去不进行下面的操作 SPI.begin(); // SPI开始 mfrc522.PCD_Init(); // Init MFRC522 card for (byte i = 0; i MFRC522::StatusCode status; // 寻找新卡 if ( ! mfrc522.PICC_IsNewCardPresent()) return; // 选择一张卡 if ( ! mfrc522.PICC_ReadCardSerial()) return; // 显示卡片的详细信息 Serial.print(F("卡片 UID:")); dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); //将uid格式化成字符串, Serial.println(); Serial.print(F("卡片类型: ")); MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); Serial.println(mfrc522.PICC_GetTypeName(piccType)); // 检查兼容性 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; } // 我们使用第0个扇区 // 修改块1 byte sector = 0; byte blockAddr = 1; byte dataBlock[] = { 0x01, 0x02, 0x03, 0x04, // 1, 2, 3, 4, 0x04, 0x06, 0x07, 0x08, // 5, 6, 7, 8, 0x0A, 0x0B, 0x0C, 0x0D, // 0,0,0,0 0x0E, 0x0F, 0x09, 0x10 // 0,0,0,0 };//写入的数据定义 byte trailerBlock = 1; 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)); 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(); //开始进行写入准备 Serial.println(F("开始进行写入的准备...")); 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; } // 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 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(); } /** 将字节数组转储为串行的十六进制值 */ void dump_byte_array(byte *buffer, byte bufferSize) { for (byte i = 0; i Serial.begin(9600); // 设置串口波特率为9600 while (!Serial); // 如果串口没有打开,则死循环下去不进行下面的操作 SPI.begin(); // SPI开始 mfrc522.PCD_Init(); // Init MFRC522 card for (byte i = 0; i MFRC522::StatusCode status; // 寻找新卡 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)); // 检查兼容性 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; } //开始进行写入准备 Serial.println(F("开始进行写入的准备...")); status = mfrc522.PICC_HaltA(); //休眠 if(status != MFRC522::STATUS_OK) { Serial.print(F("休眠失败... ")); return; } Serial.println(F("休眠成功... ")); //第一条指令、 byte buffer_send[4]={0x40,0x00,0x00,0x00}; byte receive= 0x01; byte rec_len = 1; byte validbits = 0x07; mfrc522.PCD_SetRegisterBitMask(MFRC522::BitFramingReg,validbits); status = mfrc522.PCD_TransceiveData(buffer_send,1,&receive,&rec_len,&validbits,0,false); if(status != MFRC522::STATUS_OK) { Serial.println(F("0x40 发送失败... ")); Serial.println(status); return; } Serial.println(receive); buffer_send[0] = 0x43; validbits = 8; mfrc522.PCD_ClearRegisterBitMask(MFRC522::BitFramingReg,0x07); status = mfrc522.PCD_TransceiveData(buffer_send,1,&receive,&rec_len,nullptr,0,false); if(status != MFRC522::STATUS_OK) { Serial.println(F("0x43 发送失败... ")); return; } Serial.println(receive); //第一条指令、 buffer_send[0] = 0xa0; buffer_send[1] = 0x00; buffer_send[2] = 0x5f; buffer_send[3] = 0xb1; validbits = 8; status = mfrc522.PCD_TransceiveData(buffer_send,4,&receive,&rec_len,nullptr,0,false); if(status != MFRC522::STATUS_OK) { Serial.println(F("块0 发送失败... ")); return; } Serial.println(receive); //第三条指令、 byte data[20]={ 0x21, 0xB7, 0x7F, 0xE2, // 1, 2, 3, 4, 0x9C, 0x08, 0x04, 0x00, // 5, 6, 7, 8, 0x00, 0x00, 0x00, 0x00, // 0, 0, 0, 0 0x00, 0x00, 0x00, 0x00 // 0, 0, 0, 0 }; byte i=0; byte Value = 0; for(i=0;i Serial.println(F("块0 发送失败... ")); return; } Serial.println(receive); byte sector = 0; //0扇区 byte blockAddr = 0; //0块 byte buffer[18]; byte size = sizeof(buffer); // 再次读取卡中数据,这次是写入之后的数据 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 Serial.println(F("验证成功!")); } else { Serial.println(F("失败,数据不匹配")); Serial.println(F("也许写入的内容不恰当")); } Serial.println(); // 停止 PICC mfrc522.PICC_HaltA(); //停止加密PCD mfrc522.PCD_StopCrypto1(); } /** 将字节数组转储为串行的十六进制值 */ void dump_byte_array(byte *buffer, byte bufferSize) { for (byte i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3