RFID_RC522模块
此模块运用射频识别技术与多种IC卡进行数据交互,并通过SPI与外界通信。
射频识别,又称为无线射频识别,英文简称为RFID(Radio Frequency Identification)。这是一种通信技术,它能够通过无线电讯号识别特定的目标,并且读取和写入相关的数据,无需识别系统和特定目标之间建立物理接触。一套完整的RFID硬件系统由Reader(如RC522)和Transponder(如IC卡)两部分组成。其工作原理是,Transponder接收Reader传送的微波信号,并通过内置的电磁感应线圈获取能量,进而进行信息交换。
MF RC522是一款由NXP公司推出的,应用于13.56MHz非接触式通信的高集成度读写卡芯片,这款芯片具有低电压、低成本、体积小的特点,是智能仪表和便携式手持设备的理想选择。
Mifare One(S50)卡
Mifare One(S50)卡是一种非接触式智能卡,通常简称为S50卡或Mifare 1K。
此卡的存储空间分为16个扇区,每个扇区为4块,每块为16个字节,读写数据以块为单位。每个扇的区前三块为数据块,最后一块控制块。我们也将16个扇区的64个块按绝对地址编号为0~63,存储结构如下图所示:
数据块可用作一般的数据保存,进行读、写操作;还可用作数据值,进行初始化值、加值、减值、读值操作。其中第0扇区的块0(即绝对地址0块),用于存放厂商代码,已经固化,不可更改。
控制块包括了密码A(0~5字节,共6字节)、存取控制码(6~9字节,共4字节)、密码B(10~15字节,共6字节) ,它们共同决定了该扇区数据的读写权限。从这也能看出,每个扇区的数据读写权限,只与自己的块3有关,与其他扇区无关。
存取控制码的具体结构如下:
注:字节9为占位符,无实际作用;Cxx_b是Cxx的取反
每3个对应的Cxx决定了对应块的数据读写权限,具体结构如下:
对于数据块:
注:KeyA|B 表示密码A或密码B,Never表示任何条件下不能实现
如:当块0的存取控制位C10 C20 C30 = 001时,验证密码A或密码B正确后可读,验证密码B正确后可写: 不能进行加值、减值操作。
对于控制块:
如:当块3的存取控制位C13 C23 C33 = 001时,表示:
密码A:不可读,验证KEYA或KEYB正确后,可写
存取控制:验证KEYA或KEYB正确后,可读、可写
密码B:验证KEYA或KEYB正确后,可读、可写
手机APP查看卡信息
下载一个NFC的读卡软件,比如下图那个,先读一张卡,大概了解一下它的存储结构。
多数未使用的IC卡的原始数据都如下图(这里只截了一部分)所示。其中,FF 07 80 69为默认的存取控制位,密码A和B的每一位均为F。这也是这些软件能够在用户不输入密码和存取控制位的情况下,能直接读出卡中数据的原因。
用STM32C8T6最小系统板与RFID_RC522模块通信,以实现对Mifare One(S50)卡的读写
元件:
接线:
STM32 | RFID-RC522 | ST-LINK | USB-TTL |
3V3 | 3.3V | 3.3V | |
PA11 | RST | ||
GND | GND | GND | GND |
PA6 | MISO | ||
PA7 | MOSI | ||
PA5 | SCK | ||
PA4 | SDA | ||
SWDIO | SWDIO | ||
SWCLK | SWCLK | ||
PA10 | TX | ||
PA9 | RX |
注:RFID-RC522的IRQ引脚不接;USB-TTL的VCC和5v接不接无所谓,USB-TTL只用于电脑与模块之间的串口通讯,只需使其知道参考电压(GND)即可(实际上,如果USB-TTL和ST-LINK均插在同一个电脑上,它们就已经共地了)
现象:
流程:
寻找卡片-->防冲撞(防止同时检测到多张卡)-->选择卡片-->验证卡片密码-->将数据写入指定块-->读出指定块的数据
代码:
//main.c
#include "stm32f10x.h"
#include "Serial.h"
#include "RC522.h"
#include "spi_driver.h"
#include "Delay.h"
unsigned char Card_Type[2] = {0x04,0x00}; //Mifare One(S50)卡
unsigned char Card_ID[4];
unsigned char Card_KEY[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; //默认密钥(A和B一样)
unsigned char Write_Block = 0x06; //要写入的块地址
unsigned char Read_Block = 0x06; //要读出的块地址
unsigned char Card_Write_Data[16] = {0x12,0x34,0x56,0x78,0x9a,0xbc,0xde}; //要写入的数据
unsigned char Card_Read_Data[16]; //要读出的数据
unsigned char status; //记录多种状态
int main(void)
{
Serial_Init();
printf("\r\n***************************** 串口测试 ****************************\r\n");
RC522_IO_Init();
PcdReset(); //复位RC522
PcdAntennaOff(); //关闭天线
Delay_ms(100);
PcdAntennaOn(); //开启天线
Delay_ms(100);
printf("\r\n***************************** RC522启动 *****************************\r\n");
while(1)
{
status = PcdRequest(0x52, Card_Type);//寻卡函数,如果成功返回MI_OK
if(status == MI_OK)
{
printf("\r\n");
printf("寻卡成功\r\n");
status = PcdAnticoll(Card_ID);//防冲撞 如果成功返回MI_OK
if(status == MI_OK)
{
printf("卡号:%.2x %.2x %.2x %.2x\r\n",Card_ID[0],Card_ID[1],Card_ID[2],Card_ID[3]);
}
else
{
printf("检测到多张卡片\r\n");
}
status = PcdSelect(Card_ID); //选卡 如果成功返回MI_OK
if(status == MI_OK)
{
printf("选卡成功\r\n");
}
else
{
printf("选卡失败\r\n");
}
status = PcdAuthState(0x60,0x05,Card_KEY,Card_ID); //验证卡片密码
if(status == MI_OK)
{
printf("验证成功\r\n");
}
else
{
printf("验证失败\r\n");
}
status = PcdWrite(Write_Block,Card_Write_Data); //写指定块
if(status == MI_OK)
{
printf("写指定块成功\r\n");
}
else
{
printf("写指定块失败\r\n");
}
status = PcdRead(Read_Block,Card_Read_Data); //读指定块
if(status == MI_OK)
{
printf("读指定块成功");
printf(",0x%.2x块的数据为:%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\r\n",Read_Block,*Card_Read_Data,*(Card_Read_Data+1),*(Card_Read_Data+2),*(Card_Read_Data+3),*(Card_Read_Data+4),*(Card_Read_Data+5),*(Card_Read_Data+6),*(Card_Read_Data+7),*(Card_Read_Data+8),*(Card_Read_Data+9),*(Card_Read_Data+10),*(Card_Read_Data+11),*(Card_Read_Data+12),*(Card_Read_Data+13),*(Card_Read_Data+14),*(Card_Read_Data+15));
}
else
{
printf("读指定块失败\r\n");
}
status = PcdHalt(); //卡片进入休眠状态
if(status == MI_OK)
{
printf("休眠成功\r\n");
}
else
{
printf("休眠失败\r\n");
}
}
else
{
//printf("寻卡失败\r\n");
}
Delay_s(1);
}
}
工程文件:
gitee:RFID_RC522模块: RFID_RC522
csdn:https://download.csdn.net/download/qq_44955826/88694159?spm=1001.2014.3001.5503