NFC初步开发详解

一款芯片的开发,我觉得首先要去研读数据手册,大致了解它的硬件设计,各项参数,重点了解其内部的寄存器以及软件开发流程。
芯片的开发肯定是离不开驱动的编写的,但说实话目前作为一个嵌入式开发的小白,很多时候自己辛辛苦苦看数据手册写出来的驱动却不能用或则很不稳定。我相信这也是很多跟我一样的嵌入式开发初学者遇到的问题。其实像这样成熟的芯片,驱动网上是一大堆,并且很稳定。很多时候,其实我们应该更加去注重项目也好,芯片开发也好其中的业务逻辑,或则简单点说就是实现功能的流程。先能套用别人的,将功能实现再说,然后再来研读别人的代码,刚开始我也觉得这样跟搬运工有啥区别,但事实上,再看了一些大牛的成长历程后,会发现确实是搬运-改装-重组-创新的这么一个过程。
       说了一堆,下面开发NFC卡的开发讲解。我这次只是实现了一个简单的像分别属于不同扇区的三个块写数据,然后读出数据到串口的过程。
       首先来说一下NFC卡的存储结构。
      
     如上图所示nfc卡分为16个扇区,每个扇区4个块,一个块16个字节。每个扇区的块3(即第四块)也称作尾块,包含了该扇区的密码A(6个字节)、存取控制(4个字节)、密码B(6个字节)。其余三个块是一般的数据块。扇区0的块0是特殊的块,包含了厂商代码信息,在生产卡片时写入,不可改写。简单点说就是第0块和每个扇区的最后一块是不能改写的。我用了下面一段代码块来屏蔽这些块区:
int index = 0;
 for (int i = 1; i < 31; i++)
 {
  if (((i + 1) % 4) == 0)
  {
   i += 1;
  }
  m_CradAdd[index] = i;
  index++;
 };其中m_CradAdd[index]是最终可操作的块,i从1开始,从而屏蔽了第一块,if((i + 1) % 4) == 0),由于块区从0开始数,那么每个扇区的最后一块就分别是3,6,9........i加1能整除4就代表这一块是不可操作的了,然后i +=1用来除去这一块的计数。代码很简单,稍微分析一下就应该能理解了。
接下来是nfc卡的驱动问题了,首先nfc卡的是spi通信模式,至于spi的通信协议,时序以及模式等,在网上有很多,我就不详细说明了,如果自己不写驱动的话,在网上找一个写的比较好的驱动移植过来就可以了,需要注意的是spi的通信频率不能超过10mhz。这里我重点介绍nfc卡读写寄存器开发的总体流程以及注意事项:
大体流程为:初始化-寻卡-防冲突-选卡-读/写卡
1.初始化:
bool Rc522::Rc522Init()
{
  PcdReset();                                     //复位rc522
  PcdAntennaOff();
  wait_ms(2); 
  PcdAntennaOn();                            //天线开启
 memset(KEY,0xFF,6);
 //memset(m_CradKey, 0xFF, 6);
 return true;
}
2.寻卡
stat = PcdRequest(PICC_REQALL,CardQueue);
其中CardQueue是自己定义的一个用来存放卡号的数组,寻卡成功后会放在这个数组里,PICC_REQALL在驱动中由定义,如下
3.防冲突
  stat = PcdAnticoll(CardQueue);
对于多张复旦卡同时去感应的时候,用来防止读写卡分不清楚。
4.选卡
stat = PcdSelect(CardQueue);
5.加解密验证
stat = PcdAuthState(0x60,addr,KEY,CardQueue)
0x60参数说明在驱动中如下:
addr为复旦卡的读写块地址,就是之前说的简单的计数值,KEY为自己随机定义的初始密码,一般定义为6个0xff(memset(KEY,0xFF,6);)
这个加解密验证的过程主要是为了验证,复旦卡和读写卡的加解密过程是否正常。
下面是我写的一个基本的前期操作流程:
void Rc522::Rc522Process()
{
 int i = 0;
 char stat = MI_ERR;
 Rc522Init();
 stat = PcdRequest(0x52,CardQueue);//Ñ°¿¨
 if(stat == MI_OK)
 {
  stat = MI_ERR;
  stat = PcdAnticoll(CardQueue);//·À³åײ
  if(stat == MI_OK)
  {
   stat = MI_ERR;
   //put.printf("CardQueue");
   stat = PcdSelect(CardQueue);
   if(stat == MI_OK)
   { 
      stat = MI_ERR; 
     /*
       stat = PcdAuthState(0x60,0x04, KEY, CardQueue);
       if(stat == MI_OK)
       {
        stat = MI_ERR;
       }
     */
    }
   }
  }  
}
6.写数据
在驱动中有块写和寄存器写两种函数,这里我用块写做一个简单的说明
sta = PcdWrite(m_CradAdd[5+i],write_data);   
这里一定要注意的是,根据参考数据手册,每次读写之前都需要对块所在的扇区中的任何一个块进行加解密验证,这样看了,有的人觉得麻烦,就想我一次性,用一个循环对所有扇区都验证不就得了。刚开始我也是这样想的,淡事实上,每次连续验证后,,其实最终只是将最后一个操作的块验证了。所以还是老实点来吧,我暂时也没找到好的方法
好了,基本的操作就这些了,当然还有如设置加密啊,钱包操作啊,等等,我也没做深入研究。
写的不好,有不对的地方大家喷完之后还麻烦指出来,我改正。

附上stm32的nfc卡驱动:
头文件:

/////////////////////////////////////////////////////////////////////
//MF522命令字
/////////////////////////////////////////////////////////////////////
#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               //休眠
/////////////////////////////////////////////////////////////////////
//MF522 FIFO长度定义
/////////////////////////////////////////////////////////////////////
#define DEF_FIFO_LENGTH       64                 //FIFO size=64byte
#define MAXRLEN  18
/////////////////////////////////////////////////////////////////////
//MF522寄存器定义
/////////////////////////////////////////////////////////////////////
// PAGE 0
#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
#define     TxAutoReg             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
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#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
/////////////////////////////////////////////////////////////////////
//和MF522通讯时返回的错误代码
/////////////////////////////////////////////////////////////////////
#define  MI_OK                 0
#define  MI_NOTAGERR           (1)
#define  MI_ERR                (2)
#define SHAQU1 0X01
#define KUAI4 0X04
#define KUAI7 0X07
#define REGCARD 0xa1
#define CONSUME 0xa2
#define READCARD 0xa3
#define ADDMONEY 0xa4
//
//#define  spi_cs 1;
//sbit  spi_ck=P0^6;
//sbit  spi_mosi=P0^7;
//sbit  spi_miso=P4^1;
//sbit  spi_rst=P2^7;
#define SPIReadByte() SPIWriteByte(0)
u8 SPIWriteByte(u8 byte);
void SPI2_Init(void);
#define SET_SPI_CS  (GPIOB->BSRR=0X01)
#define CLR_SPI_CS  (GPIOB->BRR=0X01)

#define SET_RC522RST  GPIOB->BSRR=0X02
#define CLR_RC522RST  GPIOB->BRR=0X02
void InitRc522(void);
void ClearBitMask(u8   reg,u8   mask);
void WriteRawRC(u8   Address, u8   value);
void SetBitMask(u8   reg,u8   mask);
char PcdComMF522(u8   Command,
                 u8 *pIn ,
                 u8   InLenByte,
                 u8 *pOut ,
                 u8  *pOutLenBit);
void CalulateCRC(u8 *pIn ,u8   len,u8 *pOut );
u8 ReadRawRC(u8   Address);
void PcdAntennaOn(void);
char PcdReset(void);
char PcdRequest(unsigned char req_code,unsigned char *pTagType);
void PcdAntennaOn(void);
void PcdAntennaOff(void);
char M500PcdConfigISOType(unsigned char type);
char PcdAnticoll(unsigned char *pSnr);
char PcdSelect(unsigned char *pSnr);
char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr);
char PcdWrite(unsigned char addr,unsigned char *pData);
char PcdRead(unsigned char addr,unsigned char *pData);
char PcdHalt(void);
void Reset_RC522(void);



实现文件:
//#include "include.h"
#include "sys.h"
#include "rc522.h"
void delay_ns(u32 ns)
{
  u32 i;
  for(i=0;i<ns;i++)
  {
    __nop();
    __nop();
    __nop();
  }
}
u8 SPIWriteByte(u8 Byte)
{
 while((SPI2->SR&0X02)==0);  //等待发送区空  
 SPI2->DR=Byte;   //发送一个byte  
 while((SPI2->SR&0X01)==0);//等待接收完一个byte 
 return SPI2->DR;                //返回收到的数据   
}
void SPI2_Init(void) 
{
// SPI_InitTypeDef  SPI_InitStructure;
 //GPIO_InitTypeDef GPIO_InitStructure;
 
 //配置SPI2管脚
 RCC->APB2ENR|=1<<0;
 RCC->APB2ENR|=1<<3;
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB, ENABLE);
 GPIOB->CRH&=0X000FFFFF;
 GPIOB->CRH|=0XB8B00000;
 GPIOB->CRL&=0XFFFFFF00;   //PB.1 复位
 GPIOB->CRL|=0X00000033;  //PB.0 片选 推挽输出
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
// GPIO_Init(GPIOB, &GPIO_InitStructure);
//
// GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_14;   
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
// GPIO_Init(GPIOB, &GPIO_InitStructure); 
 RCC->APB1ENR|=1<<14;

 SPI2->CR1|=0<<10;//全双工模式 
 SPI2->CR1|=1<<9; //软件nss管理
 SPI2->CR1|=1<<8; 
 
 SPI2->CR1|=1<<2; //SPI主机
 SPI2->CR1|=0<<11;//8bit数据格式 
 SPI2->CR1&=~0x02; //空闲模式下SCK为0 CPOL=0
 SPI2->CR1&=~0x01; //数据采样从第一个时间边沿开始,CPHA=0 
 SPI2->CR1|=7<<3; //Fsck=Fcpu/4
 SPI2->CR1|=0<<7; //MSBfirst  
 SPI2->CR1|=1<<6; //SPI设备使能
 //SPIx_ReadWriteByte(0xff);//启动传输  
}
void InitRc522(void)
{
  SPI2_Init();
  PcdReset();
  PcdAntennaOff(); 
  PcdAntennaOn();
  M500PcdConfigISOType( 'A' );
}
void Reset_RC522(void)
{
 PcdReset();
  PcdAntennaOff(); 
  PcdAntennaOn();
}                        
/////////////////////////////////////////////////////////////////////
//功    能:寻卡
//参数说明: 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
/////////////////////////////////////////////////////////////////////
char PcdRequest(u8   req_code,u8 *pTagType)
{
 char   status; 
 u8   unLen;
 u8   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;
}
/////////////////////////////////////////////////////////////////////
//功    能:防冲撞
//参数说明: pSnr[OUT]:卡片序列号,4字节
//返    回: 成功返回MI_OK
///////////////////////////////////////////////////////////////////// 
char PcdAnticoll(u8 *pSnr)
{
    char   status;
    u8   i,snr_check=0;
    u8   unLen;
    u8   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];
             snr_check ^= ucComMF522Buf[i];
         }
         if (snr_check != ucComMF522Buf[i])
         {   status = MI_ERR;    }
    }
   
    SetBitMask(CollReg,0x80);
    return status;
}
/////////////////////////////////////////////////////////////////////
//功    能:选定卡片
//参数说明: pSnr[IN]:卡片序列号,4字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdSelect(u8 *pSnr)
{
    char   status;
    u8   i;
    u8   unLen;
    u8   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;
}
/////////////////////////////////////////////////////////////////////
//功    能:验证卡片密码
//参数说明: auth_mode[IN]: 密码验证模式
//                 0x60 = 验证A密钥
//                 0x61 = 验证B密钥
//          addr[IN]:块地址
//          pKey[IN]:密码
//          pSnr[IN]:卡片序列号,4字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////              
char PcdAuthState(u8   auth_mode,u8   addr,u8 *pKey,u8 *pSnr)
{
    char   status;
    u8   unLen;
    u8   i,ucComMF522Buf[MAXRLEN];
    ucComMF522Buf[0] = auth_mode;
    ucComMF522Buf[1] = addr;
//    for (i=0; i<6; i++)
//    {    ucComMF522Buf[i+2] = *(pKey+i);   }
//    for (i=0; i<6; i++)
//    {    ucComMF522Buf[i+8] = *(pSnr+i);   }
    memcpy(&ucComMF522Buf[2], pKey, 6);
    memcpy(&ucComMF522Buf[8], pSnr, 4);
   
    status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
    if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08)))
    {   status = MI_ERR;   }
   
    return status;
}
/////////////////////////////////////////////////////////////////////
//功    能:读取M1卡一块数据
//参数说明: addr[IN]:块地址
//          p [OUT]:读出的数据,16字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdRead(u8   addr,u8 *p )
{
    char   status;
    u8   unLen;
    u8   i,ucComMF522Buf[MAXRLEN];
    ucComMF522Buf[0] = PICC_READ;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
  
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    if ((status == MI_OK) && (unLen == 0x90))
 //   {   memcpy(p , ucComMF522Buf, 16);   }
    {
        for (i=0; i<16; i++)
        {    *(p +i) = ucComMF522Buf[i];   }
    }
    else
    {   status = MI_ERR;   }
   
    return status;
}
/////////////////////////////////////////////////////////////////////
//功    能:写数据到M1卡一块
//参数说明: addr[IN]:块地址
//          p [IN]:写入的数据,16字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////                 
char PcdWrite(u8   addr,u8 *p )
{
    char   status;
    u8   unLen;
    u8   i,ucComMF522Buf[MAXRLEN];
   
    ucComMF522Buf[0] = PICC_WRITE;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
    {   status = MI_ERR;   }
       
    if (status == MI_OK)
    {
        //memcpy(ucComMF522Buf, p , 16);
        for (i=0; i<16; i++)
        {   
         ucComMF522Buf[i] = *(p +i);  
        }
        CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);
        status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);
        if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
        {   status = MI_ERR;   }
    }
   
    return status;
}
/////////////////////////////////////////////////////////////////////
//功    能:命令卡片进入休眠状态
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdHalt(void)
{
    u8   status;
    u8   unLen;
    u8   ucComMF522Buf[MAXRLEN];
    ucComMF522Buf[0] = PICC_HALT;
    ucComMF522Buf[1] = 0;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    return MI_OK;
}
/////////////////////////////////////////////////////////////////////
//用MF522计算CRC16函数
/////////////////////////////////////////////////////////////////////
void CalulateCRC(u8 *pIn ,u8   len,u8 *pOut )
{
    u8   i,n;
    ClearBitMask(DivIrqReg,0x04);
    WriteRawRC(CommandReg,PCD_IDLE);
    SetBitMask(FIFOLevelReg,0x80);
    for (i=0; i<len; i++)
    {   WriteRawRC(FIFODataReg, *(pIn +i));   }
    WriteRawRC(CommandReg, PCD_CALCCRC);
    i = 0xFF;
    do
    {
        n = ReadRawRC(DivIrqReg);
        i--;
    }
    while ((i!=0) && !(n&0x04));
    pOut [0] = ReadRawRC(CRCResultRegL);
    pOut [1] = ReadRawRC(CRCResultRegM);
}
/////////////////////////////////////////////////////////////////////
//功    能:复位RC522
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdReset(void)
{
 //PORTD|=(1<<RC522RST);
 SET_RC522RST;
    delay_ns(10);
 //PORTD&=~(1<<RC522RST);
 CLR_RC522RST;
    delay_ns(10);
 //PORTD|=(1<<RC522RST);
 SET_RC522RST;
    delay_ns(10);
    WriteRawRC(CommandReg,PCD_RESETPHASE);
 WriteRawRC(CommandReg,PCD_RESETPHASE);
    delay_ns(10);
   
    WriteRawRC(ModeReg,0x3D);            //和Mifare卡通讯,CRC初始值0x6363
    WriteRawRC(TReloadRegL,30);          
    WriteRawRC(TReloadRegH,0);
    WriteRawRC(TModeReg,0x8D);
    WriteRawRC(TPrescalerReg,0x3E);
 
 WriteRawRC(TxAutoReg,0x40);//必须要
  
    return MI_OK;
}
//////////////////////////////////////////////////////////////////////
//设置RC632的工作方式
//////////////////////////////////////////////////////////////////////
char M500PcdConfigISOType(u8   type)
{
   if (type == 'A')                     //ISO14443_A
   {
       ClearBitMask(Status2Reg,0x08);
       WriteRawRC(ModeReg,0x3D);//3F
       WriteRawRC(RxSelReg,0x86);//84
       WriteRawRC(RFCfgReg,0x7F);   //4F
       WriteRawRC(TReloadRegL,30);//tmoLength);// TReloadVal = 'h6a =tmoLength(dec)
    WriteRawRC(TReloadRegH,0);
       WriteRawRC(TModeReg,0x8D);
    WriteRawRC(TPrescalerReg,0x3E);
    delay_ns(1000);
       PcdAntennaOn();
   }
   else{ return 1; }
  
   return MI_OK;
}
/////////////////////////////////////////////////////////////////////
//功    能:读RC632寄存器
//参数说明:Address[IN]:寄存器地址
//返    回:读出的值
/////////////////////////////////////////////////////////////////////
u8 ReadRawRC(u8   Address)
{
    u8   ucAddr;
    u8   ucResult=0;
 CLR_SPI_CS;
    ucAddr = ((Address<<1)&0x7E)|0x80;
 
 SPIWriteByte(ucAddr);
 ucResult=SPIReadByte();
 SET_SPI_CS;
   return ucResult;
}
/////////////////////////////////////////////////////////////////////
//功    能:写RC632寄存器
//参数说明:Address[IN]:寄存器地址
//          value[IN]:写入的值
/////////////////////////////////////////////////////////////////////
void WriteRawRC(u8   Address, u8   value)

    u8   ucAddr;
// u8 tmp;
 CLR_SPI_CS;
    ucAddr = ((Address<<1)&0x7E);
 SPIWriteByte(ucAddr);
 SPIWriteByte(value);
 SET_SPI_CS;
// tmp=ReadRawRC(Address);
//
// if(value!=tmp)
//  printf("wrong\n");
}
/////////////////////////////////////////////////////////////////////
//功    能:置RC522寄存器位
//参数说明:reg[IN]:寄存器地址
//          mask[IN]:置位值
/////////////////////////////////////////////////////////////////////
void SetBitMask(u8   reg,u8   mask) 
{
    char   tmp = 0x0;
    tmp = ReadRawRC(reg);
    WriteRawRC(reg,tmp | mask);  // set bit mask
}
/////////////////////////////////////////////////////////////////////
//功    能:清RC522寄存器位
//参数说明:reg[IN]:寄存器地址
//          mask[IN]:清位值
/////////////////////////////////////////////////////////////////////
void ClearBitMask(u8   reg,u8   mask) 
{
    char   tmp = 0x0;
    tmp = ReadRawRC(reg);
    WriteRawRC(reg, tmp & ~mask);  // clear bit mask
}
/////////////////////////////////////////////////////////////////////
//功    能:通过RC522和ISO14443卡通讯
//参数说明:Command[IN]:RC522命令字
//          pIn [IN]:通过RC522发送到卡片的数据
//          InLenByte[IN]:发送数据的字节长度
//          pOut [OUT]:接收到的卡片返回数据
//          *pOutLenBit[OUT]:返回数据的位长度
/////////////////////////////////////////////////////////////////////
char PcdComMF522(u8   Command,
                 u8 *pIn ,
                 u8   InLenByte,
                 u8 *pOut ,
                 u8 *pOutLenBit)
{
    char   status = MI_ERR;
    u8   irqEn   = 0x00;
    u8   waitFor = 0x00;
    u8   lastBits;
    u8   n;
    u16   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);   //清FIFO缓存
   
    for (i=0; i<InLenByte; i++)
    {   WriteRawRC(FIFODataReg, pIn [i]);    }
    WriteRawRC(CommandReg, Command);  
//     n = ReadRawRC(CommandReg);
   
    if (Command == PCD_TRANSCEIVE)
    {    SetBitMask(BitFramingReg,0x80);  }  //开始传送
              
    //i = 600;//根据时钟频率调整,操作M1卡最大等待时间25ms
 i = 100000;
    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 [i] = ReadRawRC(FIFODataReg);    }
            }
        }
        else
        {   status = MI_ERR;   }
       
    }
  
    SetBitMask(ControlReg,0x80);           // stop timer now
    WriteRawRC(CommandReg,PCD_IDLE);
    return status;
}
/////////////////////////////////////////////////////////////////////
//开启天线 
//每次启动或关闭天险发射之间应至少有1ms的间隔
/////////////////////////////////////////////////////////////////////
void PcdAntennaOn(void)
{
    u8   i;
    i = ReadRawRC(TxControlReg);
    if (!(i & 0x03))
    {
        SetBitMask(TxControlReg, 0x03);
    }
}

/////////////////////////////////////////////////////////////////////
//关闭天线
/////////////////////////////////////////////////////////////////////
void PcdAntennaOff(void)
{
 ClearBitMask(TxControlReg, 0x03);
}
/////////////////////////////////////////////////////////////////////
//功    能:扣款和充值
//参数说明: dd_mode[IN]:命令字
//               0xC0 = 扣款
//               0xC1 = 充值
//          addr[IN]:钱包地址
//          pValue[IN]:4字节增(减)值,低位在前
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////                
/*char PcdValue(u8 dd_mode,u8 addr,u8 *pValue)
{
    char status;
    u8  unLen;
    u8 ucComMF522Buf[MAXRLEN];
    //u8 i;
 
    ucComMF522Buf[0] = dd_mode;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
    {   status = MI_ERR;   }
       
    if (status == MI_OK)
    {
        memcpy(ucComMF522Buf, pValue, 4);
        //for (i=0; i<16; i++)
        //{    ucComMF522Buf[i] = *(pValue+i);   }
        CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);
        unLen = 0;
        status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);
  if (status != MI_ERR)
        {    status = MI_OK;    }
    }
   
    if (status == MI_OK)
    {
        ucComMF522Buf[0] = PICC_TRANSFER;
        ucComMF522Buf[1] = addr;
        CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
  
        status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
        if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
        {   status = MI_ERR;   }
    }
    return status;
}*/
/////////////////////////////////////////////////////////////////////
//功    能:备份钱包
//参数说明: sourceaddr[IN]:源地址
//          goaladdr[IN]:目标地址
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
/*char PcdBakValue(u8 sourceaddr, u8 goaladdr)
{
    char status;
    u8  unLen;
    u8 ucComMF522Buf[MAXRLEN];
    ucComMF522Buf[0] = PICC_RESTORE;
    ucComMF522Buf[1] = sourceaddr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
    {   status = MI_ERR;   }
   
    if (status == MI_OK)
    {
        ucComMF522Buf[0] = 0;
        ucComMF522Buf[1] = 0;
        ucComMF522Buf[2] = 0;
        ucComMF522Buf[3] = 0;
        CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);
 
        status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);
  if (status != MI_ERR)
        {    status = MI_OK;    }
    }
   
    if (status != MI_OK)
    {    return MI_ERR;   }
   
    ucComMF522Buf[0] = PICC_TRANSFER;
    ucComMF522Buf[1] = goaladdr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
    {   status = MI_ERR;   }
    return status;
}*/

猜你喜欢

转载自blog.csdn.net/rlyhaha/article/details/53893515
NFC