RFID-RC522模拟SPI扣款充值都可以,用自带的SPI扣款充值就是不行。

2019-07-20 05:12发布

#include "rc522.h"
#include "delay.h"
#include "usart.h"
#include "spi.h"
//#include <string.h>
//////////////////////////////////////////////////////////
// M1卡分为16个扇区,每个扇区由四个块(块0、块1、块2、块3)组成
// 将16个扇区的64个块按绝对地址编号为:0~63
// 第0个扇区的块0(即绝对地址0块),用于存放厂商代码,已经固化不可更改
// 每个扇区的块0、块1、块2为数据块,可用于存放数据
// 每个扇区的块3为控制块(绝对地址为:块3、块7、块11.....)包括密码A,存取控制、密码B等

/*******************************
*连线说明:
*1--SDA  <----->A4
*2--SCK  <----->A5
*3--MOSI <----->A7
*4--MISO <----->A6
*5--悬空
*6--GND <----->GND
*7--RST <----->B0
*8--VCC <----->VCC
************************************/

/*全局变量*/


/*Recharge[4]充值金额,低字节在前,第一字节满(FF+1)256时,第二字节+1,第二字节满256时,第三字节+1,依次类推*/
unsigned char Recharge[4]={100,0,0,0};

/*money[16]前4个字节为卡片金额,4-7 反码,8-11字节备份金额,后面4个字节为 地址( Adr):
1 字节绝对地址,当进行备份管理时,可用于保存块的地址(即地址不一定与当前的块号相同)。
地址保存四次,两次取反,两次不取反。在 increment、decrement、 restore 和 transfer 操作中,地址保持不变。它只能通过 write*/
unsigned char money[16]={0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x06,0xf9,0x06,0xf9};//初始钱包格式

unsigned char CT[2];  //卡类型
unsigned char SN[4];  //卡号
unsigned char RFID[16];         //存放块数据
unsigned char RFID1[16];        //存放块数据


u8 KEY[6]={0xff,0xff,0xff,0xff,0xff,0xff};                                        //出厂初始密码
u8 mykey[6] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5};        //自己设置的密码
/*只读、扣款,不可充值*/
unsigned char Encryption[16]={0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xff,0x00,0xf0,0x69,0xff,0xff,0xff,0xff,0xff,0xff};//存取控制设置
/*可读可充值、可扣款*/
unsigned char Encryption1[16]={0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xff,0x07,0x80,0x69,0xff,0xff,0xff,0xff,0xff,0xff};//存取控制设置
/*函数声明*/
unsigned char status;
unsigned char s=0x08;
u8 i8;                //my
int  mony=0;//my
#define   RC522_DELAY()  delay_us( 20 )


/*
* 函数名:RorWcar
* 描述  :读或写数据
* 输入  :R_W,    读或写,0写,1读
                                         
* 返回  : 无
* 调用  :外部调用
*/
void RorWcar(u8 R_W)
{
        // 寻卡
        status= PcdRequest( PICC_REQALL , CT );    // REQ_ALL代表寻天线区内所有卡。TagType为返回的卡类型
        if(!status)
        {
                                       
            // 防冲突
            status = PcdAnticoll(SN);
                                       
            if(!status)                                                // 防冲突成功
            {
                // 选卡
                status=PcdSelect(SN);

                if(!status)                                //选卡成功
                {

                    // 认证
                                                                        status=PcdAuthState(0x60,0x07,mykey,SN); // 验证A密钥,块地址,扇区密码,卡序列号 校验1扇区密码,密码位于每一扇区第3块               

                   if(!status)                // 认证成功
                   {
                                                                                                       
                                                                                                        status=PcdRead(0x06,RFID );                                                        //读卡,读取1扇区2块数据
                                                                                                        mony=(int)(RFID[0]|RFID[1]<<8|RFID[2]<<16|RFID[3]<<24);//转换成10进制整数
                                                                                                        if(!status)
                                                                                                        {
                                                                                                        printf(" 卡类型:%02X%02X ",CT[0],CT[1]);
                                                                                                        if(CT[0]==0x04&&CT[1]==0x00)printf("标准卡(S50) ");
                                                                                                        printf(" 卡ID号: %02X%02X%02X%02X ",SN[0],SN[1],SN[2],SN[3]);
                                                                                                        printf(" 当前余额:%d 元 ",mony);                       
                                                                                 
                                                                                                        }
                                                                                                        status=PcdValue(0xc0,0x06, Recharge);//卡片充值0xc1、扣款0xc0       
                                                                                                       
                                                                                                        if(!status)printf(" 充值成功 ");
                                                                                                       
                                                                                                        status=PcdBakValue(0x06, 0x05);//源地址,目标地址
                                                                                                        if(!status)printf(" 备份成功 ");
                                                                                 
                      //读写卡
                                                                                 if(R_W==0)
                                                                                         {
                                                                                                 status = PcdWrite(0x07, Encryption );   // 写卡,将Encryption[0]-Encryption[16]写入1扇区3块,作用:存取控制,不可充值
//                                                                                                 status = PcdWrite(0x07, Encryption1 );   // 写卡,将Encryption[0]-Encryption[16]写入1扇区3块,作用:存取控制,可充值
//                                                                                                 status = PcdWrite(0x06, money);   // 写卡,将write1[0]-write1[16]写入1扇区1块
                                                                                         }
                                                                                         else
                                                                                         {
                                                                                                        status=PcdRead(0x06,RFID );                                                        //读卡,读取1扇区2块数据

                                                                                                        mony=(int)(RFID[0]|RFID[1]<<8|RFID[2]<<16|RFID[3]<<24);//转换成10进制整数
                                                                                                        status=PcdRead(0x05,RFID1 );                                                        //读卡,读取1扇区2块数据
                                                                                         }
                                                                                                       

                       if(!status)
                       {
//                                                                                                 printf(" 写入存取控制成功 ");
                            //读写成功
                                                                                                               
                            printf(" 最新余额为:%d 元 ",mony);
                                                                                                                printf(" 备份的钱包格式为: ");
                                                                                                                for(i8=0;i8<16;i8++)printf("%02x",RFID1[i8]);
                            WaitCardOff();//等待卡离开
                       }
                  }
              }
         }
    }
}


void RC522_Init ( void )
{               
                SPI1_Init();                                           //初始化SPI
                SPI1_SetSpeed(SPI_BaudRatePrescaler_4);                //设置为21M时钟,高速模式
               
    RC522_Reset_Disable();                                //关闭复位RST         GPIOB, GPIO_Pin_0                                my
               
    RC522_CS_Disable();                                                //关闭SDA  GPIOA, GPIO_Pin_4                                                my
       
    PcdReset ();                                                                        //复位RC522                                                                                                                        

    M500PcdConfigISOType ( 'A' );//设置工作方式

}





/*
* 函数名:ReadRawRC
* 描述  :读RC522寄存器
* 输入  :ucAddress,寄存器地址
* 返回  : 寄存器的当前值
* 调用  :内部调用
*/
u8 ReadRawRC ( u8 ucAddress )
{
    u8 ucReturn,ucAddr;
       
                ucAddr = ( ( ucAddress << 1 ) & 0x7E ) | 0x80;

    RC522_CS_Enable();

                SPI1_ReadWriteByte(ucAddr);
       
                ucReturn =SPI1_ReadWriteByte(0);

    RC522_CS_Disable();

    return ucReturn;
}


/*
* 函数名:WriteRawRC
* 描述  :写RC522寄存器
* 输入  :ucAddress,寄存器地址
*         ucValue,写入寄存器的值
* 返回  : 无
* 调用  :内部调用
*/
void WriteRawRC ( u8 ucAddress, u8 ucValue )
{  
    u8 ucAddr;

    ucAddr = ( ucAddress << 1 ) & 0x7E;

    RC522_CS_Enable();

    SPI1_ReadWriteByte(ucAddr);

                SPI1_ReadWriteByte(ucValue);

    RC522_CS_Disable();
}


/*
* 函数名:SetBitMask
* 描述  :对RC522寄存器置位
* 输入  :ucReg,寄存器地址
*         ucMask,置位值
* 返回  : 无
* 调用  :内部调用
*/
void SetBitMask ( u8 ucReg, u8 ucMask )  
{
    u8 ucTemp;

    ucTemp = ReadRawRC ( ucReg );

    WriteRawRC ( ucReg, ucTemp | ucMask );         // set bit mask

}


/*
* 函数名:ClearBitMask
* 描述  :对RC522寄存器清位
* 输入  :ucReg,寄存器地址
*         ucMask,清位值
* 返回  : 无
* 调用  :内部调用
*/
void ClearBitMask ( u8 ucReg, u8 ucMask )  
{
    u8 ucTemp;

    ucTemp = ReadRawRC ( ucReg );

    WriteRawRC ( ucReg, ucTemp & ( ~ ucMask) );  // clear bit mask


}


/*
* 函数名:PcdAntennaOn
* 描述  :开启天线
* 输入  :无
* 返回  : 无
* 调用  :内部调用
*/
void PcdAntennaOn ( void )
{
    u8 uc;

    uc = ReadRawRC ( TxControlReg );

    if ( ! ( uc & 0x03 ) )
                {
                                                printf("开天线");//my
            SetBitMask(TxControlReg, 0x03);
                }
}


/*
* 函数名:PcdAntennaOff
* 描述  :关闭天线
* 输入  :无
* 返回  : 无
* 调用  :内部调用
*/
void PcdAntennaOff ( void )
{

    ClearBitMask ( TxControlReg, 0x03 );

}


/*
* 函数名:PcdRese
* 描述  :复位RC522
* 输入  :无
* 返回  : 无
* 调用  :外部调用
*/
void PcdReset ( void )
{
    RC522_Reset_Disable();
       
    delay_us ( 1 );
               
    RC522_Reset_Enable();
       
    delay_us ( 1 );

    RC522_Reset_Disable();

    delay_us ( 1 );
       
    WriteRawRC ( CommandReg, 0x0f );                                        //执行启动        my
       
    while ( ReadRawRC ( CommandReg ) & 0x10 );//等待启动完成 my
       
    delay_us ( 1 );

    WriteRawRC ( ModeReg, 0x3D );            //定义发送和接收常用模式 和Mifare卡通讯,CRC初始值0x6363

    WriteRawRC ( TReloadRegL, 30 );          //16位定时器低位   
    WriteRawRC ( TReloadRegH, 0 );               //16位定时器高位

    WriteRawRC ( TModeReg, 0x8D );                 //定义内部定时器的设置

    WriteRawRC ( TPrescalerReg, 0x3E );          //设置定时器分频系数

    WriteRawRC ( TxAutoReg, 0x40 );                //调制发送信号为100%ASK


}


/*
* 函数名:M500PcdConfigISOType
* 描述  :设置RC522的工作方式
* 输入  :ucType,工作方式
* 返回  : 无
* 调用  :外部调用
*/
void M500PcdConfigISOType ( u8 ucType )
{
    if ( ucType == 'A')                     //ISO14443_A
  {
        ClearBitMask ( Status2Reg, 0x08 );

        WriteRawRC ( ModeReg, 0x3D );//3F

        WriteRawRC ( RxSelReg, 0x86 );//84      /*选择内部接收器设置 my*/

        WriteRawRC( RFCfgReg, 0x7F );   //4F    /*配置接收器增益 my*/

        WriteRawRC( TReloadRegL, 30 );//定时器重装值,低位my

        WriteRawRC ( TReloadRegH, 0 );//定时器重装值,高位my

        WriteRawRC ( TModeReg, 0x8D );//内部定时器的设置 TPrescaler高4位为1101,F(timer)=6.78MHZ/TPrescaler          my

        WriteRawRC ( TPrescalerReg, 0x3E );//内部定时器的设置,TPrescaler低8位为0011 1110                                                                                         my

        delay_us ( 2 );

        PcdAntennaOn ();//开天线

   }

}


/*
* 函数名:PcdComMF522
* 描述  :通过RC522和ISO14443卡通讯
* 输入  :ucCommand,RC522命令字
*         pInData,通过RC522发送到卡片的数据
*         ucInLenByte,发送数据的字节长度
*         pOutData,接收到的卡片返回数据
*         pOutLenBit,返回数据的位长度
* 返回  : 状态值
*         = MI_OK,成功
* 调用  :内部调用
*/
char PcdComMF522 ( u8 ucCommand, u8 * pInData, u8 ucInLenByte, u8 * pOutData, u32 * pOutLenBit )        
{                                                                                                                                                                                                                                                                                                                        //原u32
    char cStatus = MI_ERR;
    u8 ucIrqEn   = 0x00;
    u8 ucWaitFor = 0x00;
    u8 ucLastBits;
    u8 ucN;
    u32 ul;

    switch ( ucCommand )
    {
       case PCD_AUTHENT:        //Mifare认证
          ucIrqEn   = 0x12;     //允许错误中断请求ErrIEn  允许空闲中断IdleIEn
          ucWaitFor = 0x10;     //认证寻卡等待时候 查询空闲中断标志位
          break;

       case PCD_TRANSCEIVE:     //接收发送 发送接收
          ucIrqEn   = 0x77;     //允许TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEn
          ucWaitFor = 0x30;     //寻卡等待时候 查询接收中断标志位与 空闲中断标志位
          break;

       default:
         break;

    }

    WriteRawRC ( ComIEnReg, ucIrqEn | 0x80 );       //IRqInv置位管脚IRQ与Status1Reg的IRq位的值相反
    ClearBitMask ( ComIrqReg, 0x80 );           //Set1该位清零时,CommIRqReg的屏蔽位清零
    WriteRawRC ( CommandReg, PCD_IDLE );        //写空闲命令
    SetBitMask ( FIFOLevelReg, 0x80 );          //置位FlushBuffer清除内部FIFO的读和写指针以及ErrReg的BufferOvfl标志位被清除

    for ( ul = 0; ul < ucInLenByte; ul ++ )
          WriteRawRC ( FIFODataReg, pInData [ ul ] );           //写数据进FIFOdata

    WriteRawRC ( CommandReg, ucCommand );                   //写命令


    if ( ucCommand == PCD_TRANSCEIVE )
            SetBitMask(BitFramingReg,0x80);                 //StartSend置位启动数据发送 该位与收发命令使用时才有效

    ul = 1000;//根据时钟频率调整,操作M1卡最大等待时间25ms

    do                                                      //认证 与寻卡等待时间   
    {
         ucN = ReadRawRC ( ComIrqReg );                         //查询事件中断
         ul --;
    } while ( ( ul != 0 ) && ( ! ( ucN & 0x01 ) ) && ( ! ( ucN & ucWaitFor ) ) );       //退出条件i=0,定时器中断,与写空闲命令

    ClearBitMask ( BitFramingReg, 0x80 );                   //清理允许StartSend位

    if ( ul != 0 )
    {
        if ( ! (( ReadRawRC ( ErrorReg ) & 0x1B )) )            //读错误标志寄存器BufferOfI CollErr ParityErr ProtocolErr
        {
            cStatus = MI_OK;

            if ( ucN & ucIrqEn & 0x01 )                 //是否发生定时器中断
              cStatus = MI_NOTAGERR;   

            if ( ucCommand == PCD_TRANSCEIVE )
            {
                ucN = ReadRawRC ( FIFOLevelReg );           //读FIFO中保存的字节数

                ucLastBits = ReadRawRC ( ControlReg ) & 0x07;   //最后接收到得字节的有效位数

                if ( ucLastBits )
                    * pOutLenBit = ( ucN - 1 ) * 8 + ucLastBits;    //N个字节数减去1(最后一个字节)+最后一位的位数 读取到的数据总位数
                else
                    * pOutLenBit = ucN * 8;                     //最后接收到的字节整个字节有效

                if ( ucN == 0 )
                    ucN = 1;   

                if ( ucN > MAXRLEN )
                    ucN = MAXRLEN;   

                for ( ul = 0; ul < ucN; ul ++ )
                  pOutData [ ul ] = ReadRawRC ( FIFODataReg );   
            }      
        }
            else
                cStatus = MI_ERR;   
//          printf(ErrorReg);
    }

   SetBitMask ( ControlReg, 0x80 );           // stop timer now
   WriteRawRC ( CommandReg, PCD_IDLE );

   return cStatus;

}


/*
* 函数名:PcdRequest
* 描述  :寻卡
* 输入  :ucReq_code,寻卡方式
*                     = 0x52,寻感应区内所有符合14443A标准的卡
*                     = 0x26,寻未进入休眠状态的卡
*         pTagType,卡片类型代码
*                   = 0x4400,Mifare_UltraLight
*                   = 0x0400,Mifare_One(S50)
*                   = 0x0200,Mifare_One(S70)
*                   = 0x0800,Mifare_Pro(X))
*                   = 0x4403,Mifare_DESFire
* 返回  : 状态值
*         = MI_OK,成功
* 调用  :外部调用
*/
char PcdRequest ( u8 ucReq_code, u8 * pTagType )
{
    char cStatus;  
    u8 ucComMF522Buf [ MAXRLEN ];
    u32 ulLen;

    ClearBitMask ( Status2Reg, 0x08 );  //清理指示MIFARECyptol单元接通以及所有卡的数据通信被加密的情况
    WriteRawRC ( BitFramingReg, 0x07 ); //  发送的最后一个字节的 七位
    SetBitMask ( TxControlReg, 0x03 );  //TX1,TX2管脚的输出信号传递经发送调制的13.56的能量载波信号

    ucComMF522Buf [ 0 ] = ucReq_code;       //存入 卡片命令字

    cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, & ulLen ); //寻卡  

    if ( ( cStatus == MI_OK ) && ( ulLen == 0x10 ) )    //寻卡成功返回卡类型
    {   

       * pTagType = ucComMF522Buf [ 0 ];
       * ( pTagType + 1 ) = ucComMF522Buf [ 1 ];
    }

    else
     cStatus = MI_ERR;

    return cStatus;

}


/*
* 函数名:PcdAnticoll
* 描述  :防冲撞
* 输入  :pSnr,卡片序列号,4字节
* 返回  : 状态值
*         = MI_OK,成功
* 调用  :外部调用
*/
char PcdAnticoll ( u8 * pSnr )
{
    char cStatus;
    u8 uc, ucSnr_check = 0;
    u8 ucComMF522Buf [ MAXRLEN ];
    u32 ulLen;

    ClearBitMask ( Status2Reg, 0x08 );      //清MFCryptol On位 只有成功执行MFAuthent命令后,该位才能置位
    WriteRawRC ( BitFramingReg, 0x00);      //清理寄存器 停止收发
    ClearBitMask ( CollReg, 0x80 );         //清ValuesAfterColl所有接收的位在冲突后被清除

    ucComMF522Buf [ 0 ] = 0x93; //卡片防冲突命令
    ucComMF522Buf [ 1 ] = 0x20;

    cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 2, ucComMF522Buf, & ulLen);//与卡片通信

    if ( cStatus == MI_OK)      //通信成功
    {
        for ( uc = 0; uc < 4; uc ++ )
        {
            * ( pSnr + uc )  = ucComMF522Buf [ uc ];            //读出UID
            ucSnr_check ^= ucComMF522Buf [ uc ];
        }

        if ( ucSnr_check != ucComMF522Buf [ uc ] )
                cStatus = MI_ERR;   

    }

    SetBitMask ( CollReg, 0x80 );

    return cStatus;

}


/*
* 函数名:CalulateCRC
* 描述  :用RC522计算CRC16
* 输入  :pIndata,计算CRC16的数组
*         ucLen,计算CRC16的数组字节长度
*         pOutData,存放计算结果存放的首地址
* 返回  : 无
* 调用  :内部调用
*/
void CalulateCRC ( u8 * pIndata, u8 ucLen, u8 * pOutData )
{
    u8 uc, ucN;

    ClearBitMask(DivIrqReg,0x04);

    WriteRawRC(CommandReg,PCD_IDLE);

    SetBitMask(FIFOLevelReg,0x80);

    for ( uc = 0; uc < ucLen; uc ++)
        WriteRawRC ( FIFODataReg, * ( pIndata + uc ) );   

    WriteRawRC ( CommandReg, PCD_CALCCRC );

    uc = 0xFF;

    do
    {
        ucN = ReadRawRC ( DivIrqReg );
        uc --;
    } while ( ( uc != 0 ) && ! ( ucN & 0x04 ) );

    pOutData [ 0 ] = ReadRawRC ( CRCResultRegL );
    pOutData [ 1 ] = ReadRawRC ( CRCResultRegM );

}


/*
* 函数名:PcdSelect
* 描述  :选定卡片
* 输入  :pSnr,卡片序列号,4字节
* 返回  : 状态值
*         = MI_OK,成功
* 调用  :外部调用
*/
char PcdSelect ( u8 * pSnr )
{
    char ucN;
    u8 uc;
    u8 ucComMF522Buf [ MAXRLEN ];
    u32  ulLen;

    ucComMF522Buf [ 0 ] = PICC_ANTICOLL1;
    ucComMF522Buf [ 1 ] = 0x70;
    ucComMF522Buf [ 6 ] = 0;

    for ( uc = 0; uc < 4; uc ++ )
    {
        ucComMF522Buf [ uc + 2 ] = * ( pSnr + uc );
        ucComMF522Buf [ 6 ] ^= * ( pSnr + uc );
    }

    CalulateCRC ( ucComMF522Buf, 7, & ucComMF522Buf [ 7 ] );

    ClearBitMask ( Status2Reg, 0x08 );

    ucN = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 9, ucComMF522Buf, & ulLen );

    if ( ( ucN == MI_OK ) && ( ulLen == 0x18 ) )
      ucN = MI_OK;  
    else
      ucN = MI_ERR;   

    return ucN;

}


/*
* 函数名:PcdAuthState
* 描述  :验证卡片密码
* 输入  :ucAuth_mode,密码验证模式
*                     = 0x60,验证A密钥
*                     = 0x61,验证B密钥
*         u8 ucAddr,块地址
*         pKey,密码
*         pSnr,卡片序列号,4字节
* 返回  : 状态值
*         = MI_OK,成功
* 调用  :外部调用
*/
char PcdAuthState ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr )
{
    char cStatus;
      u8 uc, ucComMF522Buf [ MAXRLEN ];
    u32 ulLen;

    ucComMF522Buf [ 0 ] = ucAuth_mode;
    ucComMF522Buf [ 1 ] = ucAddr;                                                                                //0-1存入验证A密钥、块地址09

    for ( uc = 0; uc < 6; uc ++ )
        ucComMF522Buf [ uc + 2 ] = * ( pKey + uc ); //2-7存入密码0xff  

    for ( uc = 0; uc < 6; uc ++ )
        ucComMF522Buf [ uc + 8 ] = * ( pSnr + uc ); //8-13存入卡片序列号

    cStatus = PcdComMF522 ( PCD_AUTHENT, ucComMF522Buf, 12, ucComMF522Buf, & ulLen );

    if ( ( cStatus != MI_OK ) || ( ! ( ReadRawRC ( Status2Reg ) & 0x08 ) ) )

        {
//          if(cStatus != MI_OK)
//                  printf("666")   ;      
//          else
//              printf("888");
            cStatus = MI_ERR;
    }

    return cStatus;

}


/*
* 函数名:PcdWrite
* 描述  :写数据到M1卡一块
* 输入  :u8 ucAddr,块地址
*         pData,写入的数据,16字节
* 返回  : 状态值
*         = MI_OK,成功
* 调用  :外部调用
*/
char PcdWrite ( u8 ucAddr, u8 * pData )
{
    char cStatus;
      u8 uc, ucComMF522Buf [ MAXRLEN ];
    u32 ulLen;

    ucComMF522Buf [ 0 ] = PICC_WRITE;
    ucComMF522Buf [ 1 ] = ucAddr;

    CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );

    cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );

    if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
      cStatus = MI_ERR;   

    if ( cStatus == MI_OK )
    {
            //memcpy(ucComMF522Buf, pData, 16);
      for ( uc = 0; uc < 16; uc ++ )
              ucComMF522Buf [ uc ] = * ( pData + uc );  

      CalulateCRC ( ucComMF522Buf, 16, & ucComMF522Buf [ 16 ] );

      cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf, & ulLen );

            if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
        cStatus = MI_ERR;   

    }

    return cStatus;

}


/*
* 函数名:PcdRead
* 描述  :读取M1卡一块数据
* 输入  :u8 ucAddr,块地址
*         pData,读出的数据,16字节
* 返回  : 状态值
*         = MI_OK,成功
* 调用  :外部调用
*/
char PcdRead ( u8 ucAddr, u8 * pData )
{
    char cStatus;
      u8 uc, ucComMF522Buf [ MAXRLEN ];
    u32 ulLen;

    ucComMF522Buf [ 0 ] = PICC_READ;//读块
    ucComMF522Buf [ 1 ] = ucAddr;                //0x08块地址 ,本程序my

    CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );

    cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );

    if ( ( cStatus == MI_OK ) && ( ulLen == 0x90 ) )
    {
            for ( uc = 0; uc < 16; uc ++ )
        * ( pData + uc ) = ucComMF522Buf [ uc ];   
    }

    else
      cStatus = MI_ERR;   

    return cStatus;

}


/*
* 函数名:PcdHalt
* 描述  :命令卡片进入休眠状态
* 输入  :无
* 返回  : 状态值
*         = MI_OK,成功
* 调用  :外部调用
*/
char PcdHalt( void )
{
    u8 ucComMF522Buf [ MAXRLEN ];
    u32  ulLen;

    ucComMF522Buf [ 0 ] = PICC_HALT;
    ucComMF522Buf [ 1 ] = 0;

    CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
    PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );

    return MI_OK;

}


void IC_CMT ( u8 * UID, u8 * KEY, u8 RW, u8 * Dat )                                                                        //no use
{
    u8 ucArray_ID [ 4 ] = { 0 };//先后存放IC卡的类型和UID(IC卡序列号)

    PcdRequest ( 0x52, ucArray_ID );//寻卡

    PcdAnticoll ( ucArray_ID );//防冲撞

    PcdSelect ( UID );//选定卡

    PcdAuthState ( 0x60, 0x10, KEY, UID );//校验

    if ( RW )//读写选择,1是读,0是写
        PcdRead ( 0x10, Dat );

    else
        PcdWrite ( 0x10, Dat );

    PcdHalt ();  

}
//等待卡离开
void WaitCardOff(void)
{
    char          status;

    while(1)
    {
        status = PcdRequest(PICC_REQALL, CT);
        if(status)
        {
            status = PcdRequest(PICC_REQALL, CT);
            if(status)
            {
                status = PcdRequest(PICC_REQALL, CT);
                if(status)
                {
                    return;
                }
            }
        }
        delay_ms(10);
    }
}

//功    能:扣款和充值
//参数说明: dd_mode[IN]:命令字
//               0xC0 = 扣款
//               0xC1 = 充值
//          addr[IN]:钱包地址
//          pValue[IN]:4字节增(减)值,低位在前
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdValue(unsigned char dd_mode,unsigned char addr,unsigned char *pValue)
{
    char status;
    unsigned int  unLen;
    unsigned char i,ucComMF522Buf[MAXRLEN];

    ucComMF522Buf[0] = dd_mode;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);

    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
          //status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);//MY

    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);//原6
        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(unsigned char sourceaddr, unsigned char goaladdr)
{
    char status;
    unsigned int  unLen;
    unsigned char 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;
}


//void ShowID(u16 x,u16 y, u8 *p, u16 charColor, u16 bkColor)  //显示卡的卡号,以十六进制显示        my
//{
//    u8 num[9];
//    u8 i;

//    for(i=0;i<4;i++)
//    {
//        num[i*2]=p[i]/16;
//        num[i*2]>9?(num[i*2]+='7')num[i*2]+='0');
//        num[i*2+1]=p[i]%16;
//        num[i*2+1]>9?(num[i*2+1]+='7')num[i*2+1]+='0');
//    }
//    num[8]=0;

//    LCD_ShowString(6,110,110,16,16,num);
//    printf("ID>>>%s ", num);

//}


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。