IC卡(M1)RFID-RC522的基本操作

(一)、RFID-RC522用的是典型的SPI通信,比较方便,我在本篇文章采用的是软件模拟的方式,相比于硬件SPI的优势是方便大家的移植,引脚用普通的引脚即可。

(二)、卡和读卡器之间的通信流程如下:

复位应答(Request)
M1卡的通信协议和通信波特率是定义好的,当有卡片进入读卡器的工作范围时,读卡器要以特定的协议与卡片通信,从而确定卡片的卡型。

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

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

三次相互确认(3 Pass Authentication)
选定要处理的卡片后,读写器就要确定访问的扇区号,并且对扇区密码进行密码校验。在三次互相认证后就可以通过加密流进行通信。每次在选择扇区的时候都要进行扇区的密码校验。

对数据块的操作
读(Read):读一个块的数据;
写(Write):在一个块中写数据;
加(Increment):对数据块中的数值进行加值;
减(Decrement):对数据块中的数值进行减值;
传输(Transfer):将数据寄存器中的内容写入数据块中;
中止(Halt):暂停卡片的工作;

(三)、核心代码及解释

相关寄存器的定义比较多,网上也有很多,我在这就不再详细的叙述了。

1、相关引脚初始化

void RC522_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;     
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);        //使能PF端口时钟
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_4;               
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //IO口速度为50MHz
    GPIO_Init(GPIOF, &GPIO_InitStructure);                 
    GPIO_SetBits(GPIOF,GPIO_Pin_1|GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_4);  //拉高

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;      //上拉输入               
    GPIO_Init(GPIOF, &GPIO_InitStructure);                 
}

在RC522中,IRQ 不需要接,MISO引脚与单片机相连的引脚配置成上拉输入或者浮空输入都可,其他除了VCC ,GND引脚都配置成推挽输出。

2、寻卡

char PcdRequest(unsigned char req_code,unsigned char *pTagType)
{
   char status;  
   unsigned int  unLen;
   unsigned char ucComMF522Buf[MAXRLEN]; 

   ClearBitMask(Status2Reg,0x08);
   WriteRawRC(BitFramingReg,0x07);
   SetBitMask(TxControlReg,0x03);
 
   ucComMF522Buf[0] = req_code;

   status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);
   
   if ((status == MI_OK) && (unLen == 0x10))
   {    
       *pTagType     = ucComMF522Buf[0];
       *(pTagType+1) = ucComMF522Buf[1];
   }
   else
   {   status = MI_ERR;  
    }
   
   return status;
}

其中 PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);是M1卡与RFID-RC522进行通信的函数,后面会介绍。

ucComMF522Buf数组里面保存的是卡片的类型,相关类型对应如下:

//                0x4400 = Mifare_UltraLight
//                0x0400 = Mifare_One(S50)
//                0x0200 = Mifare_One(S70)
//                0x0800 = Mifare_Pro(X)
//                0x4403 = Mifare_DESFire

3、防冲撞

char PcdAnticoll(unsigned char *pSnr)
{
    char status;
    unsigned char i,snr_check=0;
    unsigned int  unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    
    ClearBitMask(Status2Reg,0x08);
    WriteRawRC(BitFramingReg,0x00);
    ClearBitMask(CollReg,0x80);
 
    ucComMF522Buf[0] = PICC_ANTICOLL1;
    ucComMF522Buf[1] = 0x20;
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);
 
    if (status == MI_OK)
    {
         for (i=0; i<4; i++)
         {   
             *(pSnr+i)  = ucComMF522Buf[i];       //读出卡片的UID
             snr_check ^= ucComMF522Buf[i];
         }
         if (snr_check != ucComMF522Buf[i])
         {   status = MI_ERR;    }
    }
    
    SetBitMask(CollReg,0x80);
    return status;
}

以上代码中具有将卡片防冲突命令通过RC522传到卡片中,返回的是被选中卡片的32位的卡号

4、选择卡片

char PcdSelect(unsigned char *pSnr)
{
    char status;
    unsigned char i;
    unsigned int  unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0] = PICC_ANTICOLL1;
    ucComMF522Buf[1] = 0x70;
    ucComMF522Buf[6] = 0;
    for (i=0; i<4; i++)
    {
        ucComMF522Buf[i+2] = *(pSnr+i);
        ucComMF522Buf[6]  ^= *(pSnr+i);
    }
    CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);
  
    ClearBitMask(Status2Reg,0x08);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
    
    if ((status == MI_OK) && (unLen == 0x18))
    {   status = MI_OK;  }
    else
    {   status = MI_ERR;    }
 
    return status;
}

参数传入的是32位的卡号

5、计算CRC

//用MF522计算CRC16函数
void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData)
{
    unsigned char i,n;
    ClearBitMask(DivIrqReg,0x04);
    WriteRawRC(CommandReg,PCD_IDLE);
    SetBitMask(FIFOLevelReg,0x80);
    for (i=0; i<len; i++)
    {   WriteRawRC(FIFODataReg, *(pIndata+i));   }
    WriteRawRC(CommandReg, PCD_CALCCRC);
    i = 0xFF;
    do 
    {
        n = ReadRawRC(DivIrqReg);
        i--;
    }
    while ((i!=0) && !(n&0x04));
    pOutData[0] = ReadRawRC(CRCResultReg
    pOutData[1] = ReadRawRC(CRCResultRegM);
}

大家有没有发现以上代码大部分都有用到

unsigned char ReadRawRC(unsigned char Address);

void WriteRawRC(unsigned char Address,unsigned char value);
这2个函数呢,分别是读写相应寄存器,一个方法就是也是用到这2个函数,但是它还调用了底层的SPI读写一个字节;还有一个方法就是直接在这2个函数里面编写读写SPI的函数,我在这里就采用这个方法一步到位了比较简单:代码如下:/
//功    能:读RC632寄存器
//参数说明:Address[IN]:寄存器地址
//返    回:读出的值
/

unsigned char ReadRawRC(unsigned char Address)
{
     unsigned char i, ucAddr;
     unsigned char ucResult=0;

     MF522_SCK = 0;
     MF522_NSS = 0;
     ucAddr = ((Address<<1)&0x7E)|0x80;

     for(i=8;i>0;i--)
     {
         MF522_SI = ((ucAddr&0x80)==0x80);
         MF522_SCK = 1;
         ucAddr <<= 1;
         MF522_SCK = 0;
         delay_us(10);       //STM32需要多加的延时时间。51的不需要加
     }

     for(i=8;i>0;i--)
     {
         MF522_SCK = 1;
         ucResult <<= 1;
         ucResult|=MF522_SO;
         MF522_SCK = 0;
         delay_us(10);      //STM32需要多加的延时时间。51的不需要加
     }

     MF522_NSS = 1;
     MF522_SCK = 1;
     return ucResult;
}

/
//功    能:写RC632寄存器
//参数说明:Address[IN]:寄存器地址
//          value[IN]:写入的值
/

void WriteRawRC(unsigned char Address, unsigned char value)
{  
    unsigned char i, ucAddr;

    MF522_SCK = 0;
    MF522_NSS = 0;
    ucAddr = ((Address<<1)&0x7E);

    for(i=8;i>0;i--)
    {
        MF522_SI = ((ucAddr&0x80)==0x80);
        MF522_SCK = 1;
        ucAddr <<= 1;
        MF522_SCK = 0;
        delay_us(10);       //STM32需要多加的延时时间。51的不需要加
    }

    for(i=8;i>0;i--)
    {
        MF522_SI = ((value&0x80)==0x80);
        MF522_SCK = 1;
        value <<= 1;
        MF522_SCK = 0;
        delay_us(10);     //STM32需要多加的延时时间。51的不需要加
    }
    MF522_NSS = 1;
    MF522_SCK = 1;
}

以上就是本次的全部介绍,欢迎各位大佬和我一起交流!

  • 4
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我是一名语言模型,没有能力提供代码。不过,我可以给您一些参考资料。 RFID-RC522是一种常见的13.56MHz RFID读卡器模块。在Arduino等开发板上使用RFID-RC522模块进行读卡操作需要安装相应的库,例如MFRC522。 以下是使用MFRC522读取RFID卡的代码示例: ``` #include <SPI.h> #include <MFRC522.h> #define SS_PIN 10 #define RST_PIN 9 MFRC522 mfrc522(SS_PIN, RST_PIN); // 创建MFRC522实例 void setup() { Serial.begin(9600); // 初始化串口通信 SPI.begin(); // 初始化SPI通信 mfrc522.PCD_Init(); // 初始化RFID模块 Serial.println("Ready to read RFID cards"); } void loop() { // 检测是否有RFID卡靠近 if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) { // 获取卡片类型获取MFRC522卡片类型 MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); // 输出卡片类型 Serial.print("RFID Card Type: "); Serial.println(mfrc522.PICC_GetTypeName(piccType)); // 输出卡片UID Serial.print("UID: "); for (byte i = 0; i < mfrc522.uid.size; i++) { Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : ""); Serial.print(mfrc522.uid.uidByte[i], HEX); } Serial.println(); // 等待卡片离开 mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); } } ``` 此代码使用Arduino UNO板上数字引脚10和9分别连接RFID-RC522模块的SDA和RST引脚。在程序中初始化并启用MFRC522库,标准SPI通信接口必须在程序初始化时开始。在void loop()函数中,检查是否存在RFID卡,如果检测到,则获取卡片类型,并输出卡片类型和UID。 最后,程序等待卡片被移动走。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值