STM32(三十八)RFID介绍-使用SPI对RFID标签进行读写

一、概述

射频识别(RFID)是 Radio Frequency Identification 的缩写。
  其原理为阅读器与标签之间进行非接触式的数据通信,达到识别目标的目的。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的接口分别有: VCC、RST、GND、IRQ、MISO、MOSI、SCK、SDA。
由RC522的规格书可知,模块支持三种串口接口类型,当使用SPI接口时,SDA为片选线NSS.

 

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

由原理图可知SCK-->PB3、MISO--->PB4、MOSI---->PB5、CS--->PG7、IRQ(RST)--->PG8

 

 

 

 四、代码编写

功能要求:

  (1)读出RFID标签卡的序号和校验码。

      (2)显示卡容量。

  (3)向卡中写入数据,并读出数据查看写入是否正确。

SPI模式分析:

由RC522规格书可知SPI接口只支持模式3:

 

 

 由时序图可以看出,NSS空闲时,SCK为低电平(CPOL=0),SCK的第一个时钟跳变沿采样(CPHA=0),故为模式0。
代码分析:
(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);     
    }  
}

 

  

 

 
 
 
posted @   轻轻的吻  阅读(4291)  评论(0编辑  收藏  举报
编辑推荐:
· 基于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 十进制负数转换为二进制、八进制、十六进制的知识分享
点击右上角即可分享
微信分享提示