社区导航

 

搜索
查看: 172|回复: 0

[分享] RFID射频识别

[复制链接]

3218

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2019-6-17 08:49 | 显示全部楼层 |阅读模式

1、MFRC522是高度集成的非接触式(13.56MHz)读写卡芯片。此发送模块利用调制和解调的原理,并将它们完全集成到各种非接触式通信方法和协议中。MFRC522的内部发送器部分可驱动读写器天线与ISO14443A/MIFARE卡和应答机的通信,无需其它的电路。接收器部分提供一个功能强大和高效的解调和译码电路,用来处理兼容ISO14443A/MIFARE卡和应答机的信号。

2、RC522支持SPI、I2C和UART接口,本实验使用的是SPI接口。RC522的SPI总线接口有其自身的时序要求。它只能工作于从模式,最高传输速率为10 Mbps,数据与时钟相位关系满足“空闲态时钟为低电平,在时钟上升沿同步接收和发送数据,在下降沿数据转换”的约束关系。简化MRFC522框图:

360截图20190617084815426.jpg

 模拟接口用来处理模拟信号的调制和解调。非接触式UART用来处理与主机通信时的协议要求。FIFO缓冲区快速而方便地实现了主机和非接触式UART之间数据传输。

3、IC卡特点:

容量为8K位EEPROM
分为16个扇区,每个扇区为4块,每块16个字节,以块为存取单位
每个扇区有独立的一组密码及访问控制
每张卡有唯一序列号,为32位
具有防冲突机制,支持多卡操作
无电源,自带天线,内含加密控制逻辑和通讯逻辑电路
数据保存期为10年,可改写10万次,读无限次
工作温度:-20℃~50℃(湿度为90%)
工作频率:13.56MHZ
通信速率:106 KBPS
读写距离:10 cm以内(与读写器有关)
卡片的电气部分只由一个天线和ASIC组成。

天线:卡片的天线是只有几组绕线的线圈,很适于封装到IS0卡片中。

ASIC:卡片的ASIC由一个高速(106KB波特率)的RF接口,一个控制单元和一个 8K位EEPROM组成。

工作原理:读写器向M1卡发一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其频率与读写器发射的频率相同,在电磁波的激励下,LC谐振电路产生共振,从而使电容内有了电荷,在这个电容的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内储存,当所积累的电荷达到2V时,此电容可做为电源为其它电路提供工作电压,将卡内数据发射出去或接取读写器的数据。

4、M1射频卡与MFRC522的通讯:

20190413151209297.png

5、

复位应答:

M1射频卡的通讯协议和通讯波特率是定义好的,当有卡片进入读写器的操作范围时,读写器以特定的协议与它通讯,从而确定该卡是否为M1射频卡,即验证卡片的卡型。

防冲突机制:

当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作,未选中的则处于空闲模式等待下一次选卡,该过程会返回被选卡的序列号。

选择卡片:

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

三次互相确认:

选定要处理的卡片之后,读写器就确定要访问的扇区号,并对该扇区密码进行密码校验,在三次相互认证之后就可以通过加密流进行通讯。(在选择另一扇区时,则必须进行另一扇区密码校验。)

读数据块的操作:

读(Read):读一个块;
写(Write):写一个块;
加(Increment):对数值块进行加值;
减(Decrement):对数值块进行减值;
存储(Restore):将块中的内容存到数据寄存器中;
传输(Transfer):将数据寄存器中的内容写入块中;
中止(Halt):将卡置于暂停工作状态;
6、 RFID.c

#include "RFID.h"
#include "delay.h"
#include "SPI.h"

/*****************************************
*功    能:读RC522寄存器
*参数说明:Address[IN]:寄存器地址
*返    回:读出的值
******************************************/
uint8_t ReadRawRC(uint8_t   Addr)
{
    uint16_t ReData = 0;
    uint16_t TempAddr = 0;
//    uint8_t i = 0;
    
    SPI_CS_Status(LOW);
        
    delay_us(10);
                                                                                
    TempAddr = ((Addr << 1) | 0x80) & 0xfe ;            
                                                                                              
    SPI_Send_Data(TempAddr);
    ReData = SPI_Get_Data();
    
    delay_us(10);
    SPI_CS_Status(HIGH);
    delay_us(10);
    return    ReData;
}

/****************************************
*功    能:写RC522寄存器
*参数说明:Address[IN]:寄存器地址
*          value[IN]:写入的值
*****************************************/
void WriteRawRC(uint8_t   Addr, uint8_t  Data)
{  
    uint8_t TempAddr = 0;
    SPI_CS_Status(LOW);    

    delay_us(10);                                                                                                                                                                                
    TempAddr = ((Addr << 1) & 0x7e);                                        
    
    SPI_Send_Data(TempAddr);
    SPI_Send_Data(Data);
    
    delay_us(10);
    SPI_CS_Status(HIGH);
    delay_us(10);
}


/*对RCC522芯片进行复位*/
int8_t PcdReset(void)
{
    delay_us(1);
    WriteRawRC(CommandReg,PCD_RESETPHASE);
        WriteRawRC(CommandReg,PCD_RESETPHASE);
    delay_us(3000);
    
    WriteRawRC(ModeReg,0x3D);           
    WriteRawRC(TReloadRegL,30);           
    WriteRawRC(TReloadRegH,0);
    WriteRawRC(TModeReg,0x8D);
    WriteRawRC(TPrescalerReg,0x3E);
    
        WriteRawRC(TxASKReg,0x40);//±?D?òa
   
    return MI_OK;
}

/*打开天线*/
void PcdAntennaOn(void)
{
    uint8_t   i;
    i = ReadRawRC(TxControlReg);
    if (!(i & 0x03))
    {
        SetBitMask(TxControlReg, 0x03);
    }
}

/*关闭天线*/
void PcdAntennaOff(void)
{
    ClearBitMask(TxControlReg, 0x03);
}

/*针对ISO14443A型卡进行初始化*/
int8_t M500PcdConfigISOType(uint8_t   type)
{
    if (type == 'A')                     
  { 
        ClearBitMask(Status2Reg,0x08);
        WriteRawRC(ModeReg,0x3D);
        WriteRawRC(RxSelReg,0x86);
        WriteRawRC(RFCfgReg,0x7F);   
        WriteRawRC(TReloadRegL,30);
        WriteRawRC(TReloadRegH,0);
        WriteRawRC(TModeReg,0x8D);
        WriteRawRC(TPrescalerReg,0x3E);
        delay_us(1000);
        PcdAntennaOn();
  }
  else{ return 1; }
   
   return MI_OK;
}

/*初始化RC522*/
void InitRc522(void)
{
  Rc522_spi_lowlevel_init();    /*SPI初始化*/
  PcdReset();                                    /*对RC522芯片进行复位*/
  PcdAntennaOff();                      /*关闭天线*/
  PcdAntennaOn();                            /*打开天线*/
  M500PcdConfigISOType( 'A' );/*针对ISO14443A型卡进行初始化*/
}


/************************************
*功    能:置RC522寄存器位
*参数说明:reg[IN]:寄存器地址
*          mask[IN]:置位值
*************************************/
void SetBitMask(uint8_t   reg,uint8_t   mask)  
{
    int8_t   tmp = 0x0;
    tmp = ReadRawRC(reg);
    WriteRawRC(reg,tmp | mask);  
}

/***********************************
*功    能:清RC522寄存器位
*参数说明:reg[IN]:寄存器地址
*          mask[IN]:清位值
************************************/
void ClearBitMask(uint8_t   reg,uint8_t   mask) 
{
    int8_t   tmp = 0x0;
    tmp = ReadRawRC(reg);
    WriteRawRC(reg, tmp & ~mask);  // clear bit mask

/***********************************************
*功    能:通过RC522和ISO14443卡通讯
*参数说明:Command[IN]:RC522命令字
*          pInData[IN]:通过RC522发送到卡片的数据
*          InLenByte[IN]:发送数据的字节长度
*          pOutData[OUT]:接收到的卡片返回数据
*          *pOutLenBit[OUT]:返回数据的位长度
************************************************/
int8_t PcdComMF522(uint8_t   Command, 
                 uint8_t *pIn , 
                 uint8_t   InLenByte,
                 uint8_t *pOut , 
                 uint32_t *pOutLenBit)
{
    int8_t   status = MI_ERR;
    uint8_t   irqEn   = 0x00;
    uint8_t   waitFor = 0x00;
    uint8_t   lastBits;
    uint8_t   n;
    uint32_t   i;
    switch (Command)
    {
        case PCD_AUTHENT:
            irqEn   = 0x12;
            waitFor = 0x10;
            break;
        case PCD_TRANSCEIVE:
            irqEn   = 0x77;
            waitFor = 0x30;
            break;
        default:
            break;
    }
   
    WriteRawRC(ComIEnReg,irqEn|0x80);
    ClearBitMask(ComIrqReg,0x80);    
    WriteRawRC(CommandReg,PCD_IDLE);
    SetBitMask(FIFOLevelReg,0x80);         
    
    for (i=0; i<InLenByte; i++)
    {   WriteRawRC(FIFODataReg, pIn );    }
    WriteRawRC(CommandReg, Command);      
//        n = ReadRawRC(CommandReg);
    
    if (Command == PCD_TRANSCEIVE)
    {    SetBitMask(BitFramingReg,0x80);  }     
                                             
        i = 500;
    do 
    {
        n = ReadRawRC(ComIrqReg);
        i--;
    }
    while ((i!=0) && !(n&0x01) && !(n&waitFor));
    ClearBitMask(BitFramingReg,0x80);

    if (i!=0)
    {    
        if(!(ReadRawRC(ErrorReg)&0x1B))
        {
            status = MI_OK;
            if (n & irqEn & 0x01)
            {   status = MI_NOTAGERR;   }
            if (Command == PCD_TRANSCEIVE)
            {
                   n = ReadRawRC(FIFOLevelReg);
                  lastBits = ReadRawRC(ControlReg) & 0x07;
                if (lastBits)
                {   *pOutLenBit = (n-1)*8 + lastBits;   }
                else
                {   *pOutLenBit = n*8;   }
                if (n == 0)
                {   n = 1;    }
                if (n > MAXRLEN)
                {   n = MAXRLEN;   }
                for (i=0; i<n; i++)
                {   pOut = ReadRawRC(FIFODataReg);    }
            }
        }
        else
        {   status = MI_ERR;   }
        
    }
   

    SetBitMask(ControlReg,0x80);          
    WriteRawRC(CommandReg,PCD_IDLE); 
    return status;
}

/*************************************************************
*功    能:寻卡
*参数说明: req_code[IN]:寻卡方式
*                0x52 = 寻感应区内所有符合14443A标准的卡
*                0x26 = 寻未进入休眠状态的卡
*          pTagType[OUT]:卡片类型代码
*                0x4400 = Mifare_UltraLight
*                0x0400 = Mifare_One(S50)
*                0x0200 = Mifare_One(S70)
*                0x0800 = Mifare_Pro(X)
*                0x4403 = Mifare_DESFire
*返    回: 成功返回MI_OK
**************************************************************/
int8_t PcdRequest(uint8_t   req_code,uint8_t  *pTagType)
{
  char status; 
  unsigned int unLen;
  unsigned char ucComMF522Buf[MAXRLEN];
 
  ClearBitMask(Status2Reg,0x08);//寄存器包含接收器和发送器和数据模式检测器的状态标志
  WriteRawRC(BitFramingReg,0x07);//不启动数据发送
  SetBitMask(TxControlReg,0x03);//TX1、TX2输出信号将传递经发送数据调制的13.56MHz的能量载波信号。
  ucComMF522Buf[0] = req_code;    //将寻卡命令填入到数组
  status =PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);//通过522发送req_code命令,并接收返回数据,存到ucComMF522Buf中
  if ((status == MI_OK) && (unLen== 0x10))//这个为啥是0x10,因为是2个字节共16bit
  {   
     *pTagType     =ucComMF522Buf[0];
     *(pTagType+1) =ucComMF522Buf[1];//获取卡类型
  }
  else
  {  
     status = MI_ERR;  
  }
  
  return status;
}

/**************************************************************
*功    能:防冲撞
*参数说明: pSnr[OUT]:卡片序列号,4字节
*返    回: 成功返回MI_OK
***************************************************************/ 
int8_t PcdAnticoll(uint8_t *pSnr)
{
    char status;
    unsigned char i,snr_check=0;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN];
   
    ClearBitMask(Status2Reg,0x08); //寄存器包含接收器和发送器和数据模式检测器的状态标志
    WriteRawRC(BitFramingReg,0x00);//不启动数据发送,接收的LSB位存放在位0,接收到的第二位放在位1,定义发送的最后一个字节的位数为8
    ClearBitMask(CollReg,0x80);//所有接收的位在冲突后将被清除。
 
    ucComMF522Buf[0] = PICC_ANTICOLL1;    //0x93表明串联级别1
    ucComMF522Buf[1] = 0x20;            //表明PCD发送字节数为整两个字节
 
    status =PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);
 
    if (status == MI_OK)
         {
                   for (i=0; i<4; i++)
                   {  
                            *(pSnr+i)  = ucComMF522Buf;
                            snr_check ^=ucComMF522Buf;
                   }
                   if (snr_check !=ucComMF522Buf)//返回四个字节,最后一个字节为校验位
                   {  
                            status =MI_ERR;   
                   }
    }
    SetBitMask(CollReg,0x80);
    return status;
}


/*读ID函数*/
uint32_t Rc522_read_uid(void)
{
    uint8_t status = 0;
    uint8_t car_type[2];
    uint8_t uid[4];
    
    status=PcdRequest(0x52,car_type);
    if(status==MI_OK) 
    {
        status = PcdAnticoll(uid);  
    }
    if(status==MI_OK) 
    {
        return ((uid[0] << 24) | (uid[1] << 16) | (uid[2] << 8) | (uid[3]));
    }
    return 0;
}


7、RFID.h


#ifndef __BSP_RFID_H_
#define __BSP_RFID_H_

#ifdef __cplusplus
 extern "C" {
#endif
    


    #include "stm32f0xx.h"    
    #include <string.h>
    
    #define Rc522_spi_lowlevel_init()        SPI_Gpio_Init()


    #define MAXRLEN        18
    #define MIN_STRENGTH  228

    #define DEF_FIFO_LENGTH             64           


    #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计算   


    #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        //休眠   


    #define  RFU00                 0x00    
    #define  CommandReg            0x01    //停止和启动命令的执行
    #define  ComIEnReg             0x02    
    #define  DivlEnReg             0x03    
    #define  ComIrqReg             0x04    
    #define  DivIrqReg             0x05
    #define  ErrorReg              0x06    
    #define  Status1Reg            0x07    
    #define  Status2Reg            0x08   //包含接收器、发送器和数据模式检测器的状态位
    #define  FIFODataReg           0x09
    #define  FIFOLevelReg          0x0A
    #define  WaterLevelReg         0x0B
    #define  ControlReg            0x0C
    #define  BitFramingReg         0x0D
    #define  CollReg               0x0E
    #define  RFU0F                 0x0F
    // PAGE 1  
    #define  RFU10                 0x10
    #define  ModeReg               0x11            //定义发送和接受的常用模式
    #define  TxModeReg             0x12
    #define  RxModeReg             0x13
    #define  TxControlReg          0x14            //控制天线驱动器管脚Tx1和Tx2的逻辑操作
    #define  TxASKReg              0x15            //保留为将来用的寄存器
    #define  TxSelReg              0x16
    #define  RxSelReg              0x17            //选择内部接收器设置
    #define  RxThresholdReg        0x18
    #define  DemodReg              0x19
    #define  RFU1A                 0x1A
    #define  RFU1B                 0x1B
    #define  MifareReg             0x1C
    #define  RFU1D                 0x1D
    #define  RFU1E                 0x1E
    #define  SerialSpeedReg        0x1F
    // PAGE 2    
    #define  RFU20                 0x20  
    #define  CRCResultRegM         0x21
    #define  CRCResultRegL         0x22
    #define  RFU23                 0x23
    #define  ModWidthReg           0x24
    #define  RFU25                 0x25
    #define  RFCfgReg              0x26        //配置接收器增益
    #define  GsNReg                0x27
    #define  CWGsCfgReg            0x28
    #define  ModGsCfgReg           0x29
    #define  TModeReg              0x2A        //定义内部定时器的设置,该寄存器分为2个8位寄存器
    #define  TPrescalerReg         0x2B        //定义内部定时器的设置
    #define  TReloadRegH           0x2C        //描述16位长的定时器重装值,该寄存器分为2个8位寄存器
    #define  TReloadRegL           0x2D        //描述16位长的定时器重装值
    #define  TCounterValueRegH     0x2E
    #define  TCounterValueRegL     0x2F
    // PAGE 3      
    #define     RFU30                 0x30
    #define     TestSel1Reg           0x31
    #define     TestSel2Reg           0x32
    #define     TestPinEnReg          0x33
    #define     TestPinValueReg       0x34
    #define     TestBusReg            0x35
    #define     AutoTestReg           0x36
    #define     VersionReg            0x37
    #define     AnalogTestReg         0x38
    #define     TestDAC1Reg           0x39  
    #define     TestDAC2Reg           0x3A   
    #define     TestADCReg            0x3B   
    #define     RFU3C                 0x3C   
    #define     RFU3D                 0x3D   
    #define     RFU3E                 0x3E   
    #define     RFU3F                                  0x3F


    #define MI_ERR                      0xFE 


    #define MI_OK                          0 
    #define MI_CHK_OK                      0 
    #define MI_CRC_ZERO                    0 

    #define MI_CRC_NOTZERO                 1 

    #define MI_NOTAGERR                 0xFF 
    #define MI_CHK_FAILED               0xFF 
    #define MI_CRCERR                   0xFE 
    #define MI_CHK_COMPERR              0xFE 
    #define MI_EMPTY                    0xFD 
    #define MI_AUTHERR                  0xFC 
    #define MI_PARITYERR                0xFB 
    #define MI_CODEERR                  0xFA 

    #define MI_SERNRERR                 0xF8 
    #define MI_KEYERR                   0xF7 
    #define MI_NOTAUTHERR               0xF6 
    #define MI_BITCOUNTERR              0xF5 
    #define MI_BYTECOUNTERR             0xF4 
    #define MI_IDLE                     0xF3 
    #define MI_TRANSERR                 0xF2 
    #define MI_WRITEERR                 0xF1 
    #define MI_INCRERR                  0xF0 
    #define MI_DECRERR                  0xEF 
    #define MI_READERR                  0xEE 
    #define MI_OVFLERR                  0xED 
    #define MI_POLLING                  0xEC 
    #define MI_FRAMINGERR               0xEB 
    #define MI_ACCESSERR                0xEA 
    #define MI_UNKNOWN_COMMAND          0xE9 
    #define MI_COLLERR                  0xE8 
    #define MI_RESETERR                 0xE7 
    #define MI_INITERR                  0xE7 
    #define MI_INTERFACEERR             0xE7 
    #define MI_ACCESSTIMEOUT            0xE5 
    #define MI_NOBITWISEANTICOLL        0xE4 
    #define MI_QUIT                     0xE2 

    #define MI_RECBUF_OVERFLOW          0xCF 
    #define MI_SENDBYTENR               0xCE 

    #define MI_SENDBUF_OVERFLOW         0xCC 
    #define MI_BAUDRATE_NOT_SUPPORTED   0xCB 
    #define MI_SAME_BAUDRATE_REQUIRED   0xCA 

    #define MI_WRONG_PARAMETER_VALUE    0xC5 

    #define MI_BREAK                    0x9E 
    #define MI_NY_IMPLEMENTED           0x9D 
    #define MI_NO_MFRC                  0x9C 
    #define MI_MFRC_NOTAUTH             0x9B 
    #define MI_WRONG_DES_MODE           0x9A 
    #define MI_HOST_AUTH_FAILED         0x99 

    #define MI_WRONG_LOAD_MODE          0x97 
    #define MI_WRONG_DESKEY             0x96 
    #define MI_MKLOAD_FAILED            0x95 
    #define MI_FIFOERR                  0x94 
    #define MI_WRONG_ADDR               0x93 
    #define MI_DESKEYLOAD_FAILED        0x92 

    #define MI_WRONG_SEL_CNT            0x8F 
    #define MI_RC531_WRONG_READVALUE    0x8E 
    #define MI_WRONG_TEST_MODE          0x8C 
    #define MI_TEST_FAILED              0x8B 
    #define MI_TOC_ERROR                0x8A 
    #define MI_COMM_ABORT               0x89 
    #define MI_INVALID_BASE             0x88 
    #define MI_MFRC_RESET               0x87 
    #define MI_WRONG_VALUE              0x86 
    #define MI_VALERR                   0x85

    #define                HIGH            1
    #define                LOW                0

    uint8_t    charPcdRequest(unsigned char req_code,unsigned char *pTagType);    //寻卡函数
    void SetBitMask(uint8_t   reg,uint8_t   mask);
    void    ClearBitMask(uint8_t reg,uint8_t mask);
    uint8_t ReadRawRC(uint8_t Addr);
    void WriteRawRC(uint8_t   Addr, uint8_t  Data);
    
    uint8_t charPcdAnticoll(unsigned char *pSnr);
    int8_t PcdComMF522(uint8_t   Command, 
                 uint8_t *pIn , 
                 uint8_t   InLenByte,
                 uint8_t *pOut , 
                 uint32_t *pOutLenBit);
    int8_t PcdReset(void);
    void InitRc522(void);
    int8_t M500PcdConfigISOType(uint8_t   type);
    void PcdAntennaOff(void);
    void PcdAntennaOn(void);
    
    uint32_t Rc522_read_uid(void);
    

#ifdef __cplusplus
}
#endif

#endif

此帖出自RF/无线论坛


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 /1 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2019-7-16 06:24 , Processed in 0.080329 second(s), 17 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表