打印
[其他ST产品]

驱动RFID-RC522模块

[复制链接]
363|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
慢醇|  楼主 | 2022-12-24 14:18 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
S50(M1)卡介绍1.S50(M1)卡基础知识

1.每张卡有唯一的序列号,32位
2.卡的容量是8Kbit的EEPROM
3.分为16个扇区,每个扇区分为4块,每块16个字节,以块为存取单位
4.每个扇区都有独立的一组密码和访问控制

2.内部信息

扇区0的块0用来固化厂商代码;

每个扇区的块3作为控制块,存放:密码A(6字节)、存取控制(4字节)、密码B(6字节)


每个扇区的块0、1、2作为数据块,其作用如下:

1.作为一般的数据存储,可以对其中的数据进行读写操作

2.用作数据值,可以进行初始化值、加值、减值、读值操作


3.存取控制

每个扇区的密码和存取控制都是独立的,存取控制是4个字节,即32位(在块3中)。

每个块都有存取条件,存取条件是由密码和存取控制共同决定的。



使用特权

评论回复
沙发
慢醇|  楼主 | 2022-12-24 14:25 | 只看该作者
每个块都有相应的三个控制位,这三个控制位存在于存取控制字节中,相应的控制位决定了该块的访问权限,控制位如图:

使用特权

评论回复
板凳
慢醇|  楼主 | 2022-12-24 14:29 | 只看该作者
就是说,每个扇区的所有块的存取条件控制位,都放在了该扇区的块3中,如图:

使用特权

评论回复
地板
慢醇|  楼主 | 2022-12-24 14:41 | 只看该作者
数据块的存取控制
对数据块,与就是块0、1、2的存取控制是由对应块的控制位来决定的:

使用特权

评论回复
5
慢醇|  楼主 | 2022-12-24 14:43 | 只看该作者
从表中得知:对数据块的存取控制,由于存取控制由三个控制位所决定,所以相应的访问条件就产生了9种。
要想对数据块进行操作,首先要看该数据块的控制位是否允许对数据块的操作,如果允许操作,再看需要验证什么密码,只有验证密码正确后才可以对该数据块执行相应操作。
一般密码A的初始值都是0xFF…

使用特权

评论回复
6
慢醇|  楼主 | 2022-12-24 14:45 | 只看该作者
控制块的存取控
块3(控制块)的存取操作与数据块不同,如图:

使用特权

评论回复
7
慢醇|  楼主 | 2022-12-24 14:54 | 只看该作者
工作原理
电气部分:
卡片的电气部分由一个天线和一个ASIC组成。
天线:就是几组绕线的线圈,体积小,已经封装在卡片内
ASIC:ASIC即专用集成电路,是指应特定用户要求和特定电子系统的需要而设计、制造的集成电路。 目前用CPLD(复杂可编程逻辑器件)和 FPGA(现场可编程逻辑阵列)来进行ASIC设计是最为流行的方式之一,它们的共性是都具有用户现场可编程特性,都支持边界扫描技术,但两者在集成度、速度以及编程方式上具有各自的特点,这样理解,ASIC就是卡片特点的一个集成电路。
卡片的ASIC包含了一个高速(106KB)的RF接口、一个控制单元、一个8K的EEPROM

使用特权

评论回复
8
慢醇|  楼主 | 2022-12-24 15:00 | 只看该作者
工作过程:
读卡器会向M1卡发送一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其工作频率与读卡器发送的电磁波频率相同,遂在电磁波的激励下,LC串联谐振电路会发生共振,从而使电容内产生电荷,在电容的另一端接有一个单向导电的电子泵,电子泵将产生的电荷转移到另一个电容中存储。当存储电容中的电荷达到2V的时候,此时电容就作为电源为其他电路提供工作电压,所以卡片就可以向读卡器发送数据,或者从读卡器接收数据,实现了读卡器与卡片的通信。

使用特权

评论回复
9
慢醇|  楼主 | 2022-12-24 15:01 | 只看该作者
M1与读卡器的通信
通信的流程图如示:

使用特权

评论回复
10
慢醇|  楼主 | 2022-12-24 15:02 | 只看该作者
复位应答(Request)
M1卡的通信协议和通信波特率是定义好的,当有卡片进入读卡器的工作范围时,读卡器要以特定的协议与卡片通信,从而确定卡片的卡型。

防冲突机制(Anticollision Loop)
当有多张卡片进入读写器操作范围时,会从中选择一张卡片进行操作,并返回选中卡片的序列号。

选择卡片(Select Tag)
选择被选中的卡的序列号,并同时返回卡的容量代码。

使用特权

评论回复
11
慢醇|  楼主 | 2022-12-24 15:03 | 只看该作者
三次相互确认(3 Pass Authentication)
选定要处理的卡片后,读写器就要确定访问的扇区号,并且对扇区密码进行密码校验。在三次互相认证后就可以通过加密流进行通信。每次在选择扇区的时候都要进行扇区的密码校验。

使用特权

评论回复
12
慢醇|  楼主 | 2022-12-24 15:08 | 只看该作者
对数据块的操作
读(Read):读一个块的数据;
写(Write):在一个块中写数据;
加(Increment):对数据块中的数值进行加值;
减(Decrement):对数据块中的数值进行减值;
传输(Transfer):将数据寄存器中的内容写入数据块中;
中止(Halt):暂停卡片的工作;

使用特权

评论回复
13
慢醇|  楼主 | 2022-12-24 15:10 | 只看该作者
RC522工程代码详解
1.RC522与M1通信
用户通过单片机初始化RC522,然后通过单片机控制RC522与M1通信,那单片机是怎样与RC522通信的呢?
RC522通过SPI接口与单片机(STM32)通信,单片机向RC522内的寄存器写入特定的指令,RC522会根据寄存器中的值来执行相关操作,并与M1通信。所以要控制RC522,就必须了解RC522的寄存器和一些相关指令,这些东西厂家都会提供,所以我们只需要复制粘贴到我们的工程中使用即可。下面分享一下相关寄存器的地址和指令:

使用特权

评论回复
14
慢醇|  楼主 | 2022-12-24 15:11 | 只看该作者
/
//RC522命令字
/
#define PCD_IDLE              0x00               //取消当前命令
#define PCD_AUTHENT           0x0E               //验证密钥
#define PCD_RECEIVE           0x08               //接收数据
#define PCD_TRANSMIT          0x04               //发送数据
#define PCD_TRANSCEIVE        0x0C               //发送并接收数据
#define PCD_RESETPHASE        0x0F               //复位
#define PCD_CALCCRC           0x03               //CRC计算

/
//Mifare_One卡片命令字
/
#define PICC_REQIDL           0x26               //寻天线区内未进入休眠状态
#define PICC_REQALL           0x52               //寻天线区内全部卡
#define PICC_ANTICOLL1        0x93               //防冲撞
#define PICC_ANTICOLL2        0x95               //防冲撞
#define PICC_AUTHENT1A        0x60               //验证A密钥
#define PICC_AUTHENT1B        0x61               //验证B密钥
#define PICC_READ             0x30               //读块
#define PICC_WRITE            0xA0               //写块
#define PICC_DECREMENT        0xC0               //扣款
#define PICC_INCREMENT        0xC1               //充值
#define PICC_RESTORE          0xC2               //调块数据到缓冲区
#define PICC_TRANSFER         0xB0               //保存缓冲区中数据
#define PICC_HALT             0x50               //休眠

/* RC522  FIFO长度定义 */
#define DEF_FIFO_LENGTH       64                 //FIFO size=64byte
#define MAXRLEN  18


/* RC522寄存器定义 */
// PAGE 0
#define     RFU00                 0x00    //保留
#define     CommandReg            0x01    //启动和停止命令的执行
#define     ComIEnReg             0x02    //中断请求传递的使能(Enable/Disable)
#define     DivlEnReg             0x03    //中断请求传递的使能
#define     ComIrqReg             0x04    //包含中断请求标志
#define     DivIrqReg             0x05    //包含中断请求标志
#define     ErrorReg              0x06    //错误标志,指示执行的上个命令的错误状态
#define     Status1Reg            0x07    //包含通信的状态标识
#define     Status2Reg            0x08    //包含接收器和发送器的状态标志
#define     FIFODataReg           0x09    //64字节FIFO缓冲区的输入和输出
#define     FIFOLevelReg          0x0A    //指示FIFO中存储的字节数
#define     WaterLevelReg         0x0B    //定义FIFO下溢和上溢报警的FIFO深度
#define     ControlReg            0x0C    //不同的控制寄存器
#define     BitFramingReg         0x0D    //面向位的帧的调节
#define     CollReg               0x0E    //RF接口上检测到的第一个位冲突的位的位置
#define     RFU0F                 0x0F    //保留
// PAGE 1     
#define     RFU10                 0x10    //保留
#define     ModeReg               0x11    //定义发送和接收的常用模式
#define     TxModeReg             0x12    //定义发送过程的数据传输速率
#define     RxModeReg             0x13    //定义接收过程中的数据传输速率
#define     TxControlReg          0x14    //控制天线驱动器管教TX1和TX2的逻辑特性
#define     TxAutoReg             0x15    //控制天线驱动器的设置
#define     TxSelReg              0x16    //选择天线驱动器的内部源
#define     RxSelReg              0x17    //选择内部的接收器设置
#define     RxThresholdReg        0x18    //选择位译码器的阈值
#define     DemodReg              0x19    //定义解调器的设置
#define     RFU1A                 0x1A    //保留
#define     RFU1B                 0x1B    //保留
#define     MifareReg             0x1C    //控制ISO 14443/MIFARE模式中106kbit/s的通信
#define     RFU1D                 0x1D    //保留
#define     RFU1E                 0x1E    //保留
#define     SerialSpeedReg        0x1F    //选择串行UART接口的速率
// PAGE 2   
#define     RFU20                 0x20    //保留
#define     CRCResultRegM         0x21    //显示CRC计算的实际MSB值
#define     CRCResultRegL         0x22    //显示CRC计算的实际LSB值
#define     RFU23                 0x23    //保留
#define     ModWidthReg           0x24    //控制ModWidth的设置
#define     RFU25                 0x25    //保留
#define     RFCfgReg              0x26    //配置接收器增益
#define     GsNReg                0x27    //选择天线驱动器管脚(TX1和TX2)的调制电导
#define     CWGsCfgReg            0x28    //选择天线驱动器管脚的调制电导
#define     ModGsCfgReg           0x29    //选择天线驱动器管脚的调制电导
#define     TModeReg              0x2A    //定义内部定时器的设置
#define     TPrescalerReg         0x2B    //定义内部定时器的设置
#define     TReloadRegH           0x2C    //描述16位长的定时器重装值
#define     TReloadRegL           0x2D    //描述16位长的定时器重装值
#define     TCounterValueRegH     0x2E   
#define     TCounterValueRegL     0x2F    //显示16位长的实际定时器值
// PAGE 3      
#define     RFU30                 0x30    //保留
#define     TestSel1Reg           0x31    //常用测试信号配置
#define     TestSel2Reg           0x32    //常用测试信号配置和PRBS控制
#define     TestPinEnReg          0x33    //D1-D7输出驱动器的使能管脚(仅用于串行接口)
#define     TestPinValueReg       0x34    //定义D1-D7用作I/O总线时的值
#define     TestBusReg            0x35    //显示内部测试总线的状态
#define     AutoTestReg           0x36    //控制数字自测试
#define     VersionReg            0x37    //显示版本
#define     AnalogTestReg         0x38    //控制管脚AUX1和AUX2
#define     TestDAC1Reg           0x39    //定义TestDAC1的测试值
#define     TestDAC2Reg           0x3A    //定义TestDAC2的测试值
#define     TestADCReg            0x3B    //显示ADCI和Q通道的实际值
#define     RFU3C                 0x3C    //保留
#define     RFU3D                 0x3D    //保留
#define     RFU3E                 0x3E    //保留
#define     RFU3F                                          0x3F    //保留

/* 和RC522通信时返回的错误代码 */
#define         MI_OK                 0x26
#define         MI_NOTAGERR           0xcc
#define         MI_ERR                0xbb

使用特权

评论回复
15
慢醇|  楼主 | 2022-12-24 15:14 | 只看该作者
既然RC522是通过SPI与单片机通信的,所以就会有相应的引脚配置,下面给出相关引脚的配置和一些引脚操作宏定义:
/* RC522引脚连接说明(SPI1的引脚) :
CS:PA4( 接的SDA引脚 )
SCK:PA5
MISO:PA6
MOSI:PA7
RST:PB0
*/
void RC522_GPIO_Init( void )
{
        GPIO_InitTypeDef GPIO_InitStructure;
       
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE );
       
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
        GPIO_Init( GPIOA, &GPIO_InitStructure );
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
        GPIO_Init( GPIOA, &GPIO_InitStructure );
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
        GPIO_Init( GPIOA, &GPIO_InitStructure );
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_Init( GPIOB, &GPIO_InitStructure );
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_Init( GPIOA, &GPIO_InitStructure );
}

/* IO口操作函数 */
#define   RC522_CS_Enable()         GPIO_ResetBits ( GPIOA, GPIO_Pin_4 )
#define   RC522_CS_Disable()        GPIO_SetBits ( GPIOA, GPIO_Pin_4 )

#define   RC522_Reset_Enable()      GPIO_ResetBits( GPIOB, GPIO_Pin_0 )
#define   RC522_Reset_Disable()     GPIO_SetBits( GPIOB, GPIO_Pin_0 )

#define   RC522_SCK_0()             GPIO_ResetBits( GPIOA, GPIO_Pin_5 )
#define   RC522_SCK_1()             GPIO_SetBits( GPIOA, GPIO_Pin_5 )

#define   RC522_MOSI_0()            GPIO_ResetBits( GPIOA, GPIO_Pin_7 )
#define   RC522_MOSI_1()            GPIO_SetBits( GPIOA, GPIO_Pin_7 )

#define   RC522_MISO_GET()          GPIO_ReadInputDataBit( GPIOA, GPIO_Pin_6 )

使用特权

评论回复
16
慢醇|  楼主 | 2022-12-24 15:16 | 只看该作者
我是通过软件模拟SPI与RC522通信的,SPI发送接收字节的代码如下(高位先行):
/* 软件模拟SPI发送一个字节数据,高位先行 */
void RC522_SPI_SendByte( uint8_t byte )
{
        uint8_t n;
        for( n=0;n<8;n++ )
        {
                if( byte&0x80 )
                        RC522_MOSI_1();
                else
                        RC522_MOSI_0();
               
                Delay_us(200);
                RC522_SCK_0();
                Delay_us(200);
                RC522_SCK_1();
                Delay_us(200);
               
                byte<<=1;
        }
}

/* 软件模拟SPI读取一个字节数据,先读高位 */
uint8_t RC522_SPI_ReadByte( void )
{
        uint8_t n,data;
        for( n=0;n<8;n++ )
        {
                data<<=1;
                RC522_SCK_0();
                Delay_us(200);
               
                if( RC522_MISO_GET()==1 )
                        data|=0x01;
               
                Delay_us(200);
                RC522_SCK_1();
                Delay_us(200);
               
               
        }
        return data;
}

使用特权

评论回复
17
慢醇|  楼主 | 2022-12-24 15:20 | 只看该作者
单片机和RC522之间的通信基础机制就建立起来了,下一步就是建立在通信基础上的操作了。

使用特权

评论回复
18
慢醇|  楼主 | 2022-12-24 15:21 | 只看该作者
STM32对RC522寄存器的操作
上面说了,单片机是向RC522的寄存器操作来驱动RC522的,所以会有这几种基本操作:

读取RC522指定寄存器的值
向RC522指定寄存器中写入指定的数据
置位RC522指定寄存器的指定位
清位RC522指定寄存器的指定位

使用特权

评论回复
19
慢醇|  楼主 | 2022-12-24 15:23 | 只看该作者
下面给出这些操作的函数实现:
/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  :读取RC522指定寄存器的值
        * @param  :Address:寄存器的地址
  * @retval :寄存器的值
*/

知道了对RC522寄存器的操作,就可以结合相关的指令,对RC522写入指令控制RC522了,下面接收一下RC522的基本操作。
uint8_t RC522_Read_Register( uint8_t Address )
{
        uint8_t data,Addr;
       
        Addr = ( (Address<<1)&0x7E )|0x80;
       
        RC522_CS_Enable();
        RC522_SPI_SendByte( Addr );
        data = RC522_SPI_ReadByte();//读取寄存器中的值
        RC522_CS_Disable();
       
        return data;
}

/**
  * @brief  :向RC522指定寄存器中写入指定的数据
  * @param  :Address:寄存器地址
                                      data:要写入寄存器的数据
  * @retval :无
*/
void RC522_Write_Register( uint8_t Address, uint8_t data )
{
        uint8_t Addr;
       
        Addr = ( Address<<1 )&0x7E;
       
        RC522_CS_Enable();
        RC522_SPI_SendByte( Addr );
        RC522_SPI_SendByte( data );
        RC522_CS_Disable();
       
}

/**
  * @brief  :置位RC522指定寄存器的指定位
  * @param  :Address:寄存器地址
                                      mask:置位值
  * @retval :无
*/
void RC522_SetBit_Register( uint8_t Address, uint8_t mask )
{
        uint8_t temp;
        /* 获取寄存器当前值 */
        temp = RC522_Read_Register( Address );
        /* 对指定位进行置位操作后,再将值写入寄存器 */
        RC522_Write_Register( Address, temp|mask );
}

/**
  * @brief  :清位RC522指定寄存器的指定位
  * @param  :Address:寄存器地址
                      mask:清位值
  * @retval :无
*/
void RC522_ClearBit_Register( uint8_t Address, uint8_t mask )
{
        uint8_t temp;
        /* 获取寄存器当前值 */
        temp = RC522_Read_Register( Address );
        /* 对指定位进行清位操作后,再将值写入寄存器 */
        RC522_Write_Register( Address, temp&(~mask) );
}

使用特权

评论回复
20
慢醇|  楼主 | 2022-12-24 15:24 | 只看该作者
STM32对RC522的基础通信
上面说了寄存器、指令、对寄存器的操作,这里介绍一些对RC522的基本操作,包括:

开启天线
关闭天线
复位RC522
设置RC522工作方式

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

115

主题

1183

帖子

4

粉丝