STM32(三十八)RFID介绍-使用SPI对RFID标签进行读写
一、概述
特点:
- 自动识别技术的一种。
- 通过无线射频方式进行非接触双向数据通信
- 利用无线射频方式对记录媒体(电子标签或射频卡)进行读写,从而达到识别目标和数据交换的目的。
典型的RFID系统主要包括两部分:射频卡/标签(Tag)和读写器( Reader) 。其系统结构和基本工作原理如图1所示。当前RFID技术研究主要集中在工作频率选择、天线设计、防冲突技术和安全与隐私保护等方面。
标签适用于对象身份识别,对象可以是人或物体。标签的主要模块集成在一个芯片中,完成与读写器通信的功能;芯片上有内存用来存储ID或其他数据,其容量从几个比特到几千个比特;芯片外围连接天线或电池。
RFID标签依据发送射频信号的方式不同,分为主动式(Active)和被动式( Passive)两种,
主动式标签特点:
- 能主动向读写器发送射频信号,
- 通常由内置电池供电,又称为有源标签,
- 通信距离远,其价格相对较高,主要应用于贵重物品远距离检测等应用领域。
被动式标签特点:
- 被动式标签不带电池,又称为无源标签,
- 从读写器的询问信号中获取能量工作,具有价格便宜的优势。
- 工作距离短、存储容量有限,主要用于近距离识别系统。
读写器主要由一个RF模块和控制单元组成,通常有内置天线,通过射频信号与标签通信。读写器可以通过有线连接或无线连接与计算机系统相连,把接收到的标签信息送到主机进行相应处理。
二、RFID模块介绍
1、 芯片特点:
- 高度集成的非接触式(13.56MHz)读写卡芯片,此发送模块利用调制和调节的原理,并将它们完全集成到各种非接触式通信方法和协议中。
- 它支持ISO14443A/MIFARE。
- 支持I2C、SPI、串口通信接口。
- 只能工作于从模式,最高传输速率为10 Mbps
2、 参数介绍:
3、接口说明
4、RFID卡识别过程:
(1)寻卡
(2)防冲突
在很多应用场合,读写器要在很短时间内尽快识别多个标签。由于读写器和标签通信共享无线信道,读写器或标签的信号可能发生冲突,使读写器不能正确识别标签,即发生了碰撞(Collision),
(3)选卡
选择被选中的卡的序列号,并同时返回卡的容量代码。
(4)操作卡
选定要处理的卡片之后,读写器就确定要访问的扇区号,并对该扇区密码进行密码校验,在三次相互认证之后就可以通过加密流进行通讯。(在选择另一扇区时,则必须进行另一扇区密码校验。)
三、S50非接触式IC卡性能简介
1、 主要指标
- 容量为8K位EEPROM
- 分为16个扇区,每个扇区为4块,每块16个字节,以块为存取单位
- 每个扇区有独立的一组密码及访问控制
- 每张卡有唯一序列号,为32位
- 具有防冲突机制,支持多卡操作
- 无电源,自带天线,内含加密控制逻辑和通讯逻辑电路
- 数据保存期为10年,可改写10万次,读无限次
- 工作温度:-20℃~50℃(湿度为90%)
- 工作频率:13.56MHZ
- 通信速率:106 KBPS
- 读写距离:10 cm以内(与读写器有关)
2、 存储结构
(1)M1卡分为16个扇区,每个扇区由4块(块0、块1、块2、块3)组成,(我们也将16个扇区的64个块按绝对地址编号为0~63,存贮结构如下图所示:
|
|
|
|
|
|
块0 |
|
数据块 |
0 |
扇区0 |
块1 |
|
数据块 |
1 |
|
块2 |
|
数据块 |
2 |
|
块3 |
密码A 存取控制 密码B |
控制块 |
3 |
|
块0 |
|
数据块 |
4 |
扇区1 |
块1 |
|
数据块 |
5 |
|
块2 |
|
数据块 |
6 |
|
块3 |
密码A 存取控制 密码B |
控制块 |
7 |
|
|
∶ ∶ ∶
|
|
|
|
0 |
|
数据块 |
60 |
扇区15 |
1 |
|
数据块 |
61 |
|
2 |
|
数据块 |
62 |
|
3 |
密码A 存取控制 密码B |
控制块 |
63 |
(2)第0扇区的块0(即绝对地址0块),它用于存放厂商代码,已经固化,不可更改。
(3)每个扇区的块0、块1、块2为数据块,可用于存贮数据。
数据块可作两种应用:
★ 用作一般的数据保存,可以进行读、写操作。
★ 用作数据值,可以进行初始化值、加值、减值、读值操作。
(4)每个扇区的块3为控制块,包括了密码A、存取控制、密码B。具体结构如下:
A0 A1 A2 A3 A4 A5 FF 07 80 69 B0 B1 B2 B3 B4 B5密码A(6字节) 存取控制(4字节) 密码B(6字节)
(5)每个扇区的密码和存取控制都是独立的,可以根据实际需要设定各自的密码及存取控制。存取控制为4个字节,共32位,扇区中的每个块(包括数据块和控制块)的存取条件是由密码和存取控制共同决定的,在存取控制中每个块都有相应的三个控制位,
定义如下:
块0: C10 C20 C30
块1: C11 C21 C31
块2: C12 C22 C32
块3: C13 C23 C33
三个控制位以正和反两种形式存在于存取控制字节中,决定了该块的访问权限(如 进行减值操作必须验证KEY A,进行加值操作必须验证KEY B,等等)。三个控制 位在存取控制字节中的位置,以块0为例:
对块0的控制:
bit 7 6 5 4 3 2 1 0
字节6 |
|
|
|
C20_b |
|
|
|
C10_b |
字节7 |
|
|
|
C10 |
|
|
|
C30_b |
字节8 |
|
|
|
C30 |
|
|
|
C20 |
字节9 |
|
|
|
|
|
|
|
|
( 注: C10_b表示C10取反 )
存取控制(4字节,其中字节9为备用字节)结构如下所示:
bit 7 6 5 4 3 2 1 0
字节6 |
C23_b |
C22_b |
C21_b |
C20_b |
C13_b |
C12_b |
C11_b |
C10_b |
字节7 |
C13 |
C12 |
C11 |
C10 |
C33_b |
C32_b |
C31_b |
C30_b |
字节8 |
C33 |
C32 |
C31 |
C30 |
C23 |
C22 |
C21 |
C20 |
字节9 |
|
|
|
|
|
|
|
|
( 注: _b表示取反 )
(6)数据块(块0、块1、块2)的存取控制如下:
控制位(X=0..2)
|
访 问 条 件 (对数据块 0、1、2) |
|||||
C1X |
C2X |
C3X |
Read |
Write |
Increment |
Decrement, transfer, Restore |
0 |
0 |
0 |
KeyA|B |
KeyA|B |
KeyA|B |
KeyA|B |
0 |
1 |
0 |
KeyA|B |
Never |
Never |
Never |
1 |
0 |
0 |
KeyA|B |
KeyB |
Never |
Never |
1 |
1 |
0 |
KeyA|B |
KeyB |
KeyB |
KeyA|B |
0 |
0 |
1 |
KeyA|B |
Never |
Never |
KeyA|B |
0 |
1 |
1 |
KeyB |
KeyB |
Never |
Never |
1 |
0 |
1 |
KeyB |
Never |
Never |
Never |
1 |
1 |
1 |
Never |
Never |
Never |
Never |
(KeyA|B 表示密码A或密码B,Never表示任何条件下不能实现)
例如:当块0的存取控制位C10 C20 C30=1 0 0时,验证密码A或密码B正确后可读;
验证密码B正确后可写;不能进行加值、减值操作。
(7)控制块块3的存取控制与数据块(块0、1、2)不同,它的存取控制如下:
|
|
|
密码A |
存取控制 |
密码B |
|||
C13 |
C23 |
C33 |
Read |
Write |
Read |
Write |
Read |
Write |
0 |
0 |
0 |
Never |
KeyA|B |
KeyA|B |
Never |
KeyA|B |
KeyA|B |
0 |
1 |
0 |
Never |
Never |
KeyA|B |
Never |
KeyA|B |
Never |
1 |
0 |
0 |
Never |
KeyB |
KeyA|B |
Never |
Never |
KeyB |
1 |
1 |
0 |
Never |
Never |
KeyA|B |
Never |
Never |
Never |
0 |
0 |
1 |
Never |
KeyA|B |
KeyA|B |
KeyA|B |
KeyA|B |
KeyA|B |
0 |
1 |
1 |
Never |
KeyB |
KeyA|B |
KeyB |
Never |
KeyB |
1 |
0 |
1 |
Never |
Never |
KeyA|B |
KeyB |
Never |
Never |
1 |
1 |
1 |
Never |
Never |
KeyA|B |
Never |
Never |
Never |
例如:当块3的存取控制位C13 C23 C33=1 0 0时,表示:
密码A:不可读,验证KEYA或KEYB正确后,可写(更改)。
存取控制:验证KEYA或KEYB正确后,可读、可写。
密码B:验证KEYA或KEYB正确后,可读、可写。
3、工作原理
卡片的电气部分只由一个天线和ASIC组成。
天线:卡片的天线是只有几组绕线的线圈,很适于封装到IS0卡片中。
ASIC:卡片的ASIC由一个高速(106KB波特率)的RF接口,一个控制单元和一个8K位EEPROM组成。
原理:读写器向M1卡发一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其频率与读写器发射的频率相同,在电磁波的激励下,LC谐振电路产生共振,从而使电容内有了电荷,在这个电容的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内储存,当所积累的电荷达到2V时,此电容可做为电源为其它电路提供工作电压,将卡内数据发射出去或接取读写器的数据。
4、M1射频卡与读写器的通讯
- 复位应答(Answer to request)
M1射频卡的通讯协议和通讯波特率是定义好的,当有卡片进入读写器的操作范围时,读写器以特定的协议与它通讯,从而确定该卡是否为M1射频卡,即验证卡片的卡型。
- 防冲突机制 (Anticollision Loop)
当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作,未选中的则处于空闲模式等待下一次选卡,该过程会返回被选卡的序列号。
- 选择卡片(Select Tag)
选择被选中的卡的序列号,并同时返回卡的容量代码。
- 三次互相确认(3 Pass Authentication)
选定要处理的卡片之后,读写器就确定要访问的扇区号,并对该扇区密码进行密码校验,在三次相互认证之后就可以通过加密流进行通讯。(在选择另一扇区时,则必须进行另一扇区密码校验。)
5、对数据块的操作
- 读(Read):读一个块;
- 写 (Write):写一个块;
- 加(Increment):对数值块进行加值;
- 减(Decrement):对数值块进行减值;
- 存储(Restore):将块中的内容存到数据寄存器中;
- 传输(Transfer):将数据寄存器中的内容写入块中;
- 中止(Halt):将卡置于暂停工作状态;
三、模块连接

RFID使用SPI接口时,要使用到七个管脚,分别为VCC、GND、SDA(CS)、SCK、MOSI、MISO、RST.对应连接到STM32F407主板的U13接口的2、1、4、5、6、7、8。


四、代码编写
功能要求:
(1)读出RFID标签卡的序号和校验码。
(2)显示卡容量。
(3)向卡中写入数据,并读出数据查看写入是否正确。
SPI模式分析:
由RC522规格书可知SPI接口只支持模式3:

(1)main函数
1 2 3 4 5 6 7 | while (1) { MFRC522_Initializtion(); MFRC522Test(); delay_s(1); } |
(2)MFRC522的初始化
主要做gpio初始化,复位、定时器计数器设置、模块启动和打开天线的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | void MFRC522_Initializtion( void ) { STM32_SPI1_Init(); MFRC522_Reset(); //Timer: TPrescaler*TreloadVal/6.78MHz = 0xD3E*0x32/6.78=25ms Write_MFRC522(TModeReg,0x8D); //TAuto=1为自动计数模式,受通信协议影向。低4位为预分频值的高4位 //Write_MFRC522(TModeReg,0x1D); //TAutoRestart=1为自动重载计时,0x0D3E是0.5ms的定时初值//test Write_MFRC522(TPrescalerReg,0x3E); //预分频值的低8位 Write_MFRC522(TReloadRegL,0x32); //计数器的低8位 Write_MFRC522(TReloadRegH,0x00); //计数器的高8位 Write_MFRC522(TxAutoReg,0x40); //100%ASK Write_MFRC522(ModeReg,0x3D); //CRC初始值0x6363 Write_MFRC522(CommandReg,0x00); //启动MFRC522 //Write_MFRC522(RFCfgReg, 0x7F); //RxGain = 48dB调节卡感应距离 AntennaOn(); //打开天线 } |
(3)MFRC522测试函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | u8 mfrc552pidbuf[18]; u8 card_pydebuf[2]; u8 card_numberbuf[5]; u8 card_key0Abuf[6]={0xff,0xff,0xff,0xff,0xff,0xff}; u8 card_writebuf[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; u8 card_readbuf[18]; //MFRC522测试函数 void MFRC522Test( void ) { u8 i,status,card_size; //0x52 = 寻感应区内所有符合 14443A 标准的卡 //0x26 = 寻未进入休眠状态的卡 status=MFRC522_Request(0x52, card_pydebuf); //寻卡 // if (status==0) //如果读到卡 { status=MFRC522_Anticoll(card_numberbuf); //防撞处理 card_size=MFRC522_SelectTag(card_numberbuf); //选卡 status=MFRC522_Auth(0x60, 4, card_key0Abuf, card_numberbuf); //验卡 status=MFRC522_Write(4, card_writebuf); //写卡(写卡要小心,特别是各区的块3) status=MFRC522_Read(4, card_readbuf); //读卡 //MFRC522_Halt();//使卡进入休眠状态 //卡类型显示 printf ( "card_pydebuf:%02X %02X\r\n" ,card_pydebuf[0],card_pydebuf[1]); //卡序列号显示,最后一字节为卡的校验码 printf ( "Card Number:" ); for (i=0;i<5;i++) printf ( "%02X " ,card_numberbuf[i]); printf ( "\r\n" ); //卡容量显示,单位为Kbits printf ( "Card Size:%xkbits\r\n" ,card_size); //读卡状态显示,正常为0 printf ( "Card Status:%d\r\n" ,status); //读一个块的数据显示 printf ( "Read data:" ); for (i=0;i<18;i++) printf ( "%02X " ,card_readbuf[i]); printf ( "\r\n" ); PFout(8)=1; delay_ms(100); PFout(8)=0; delay_ms(100); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2019-07-18 十进制负数转换为二进制、八进制、十六进制的知识分享