6042|2

1

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

新人小白求教,89C51对RC522进行操作,无法休眠mifire S50卡,就是操作卡后无法休眠。 [复制链接]

extern void SendData(unsigned char dat);
extern void SendString(char *s);
extern unsigned char data RC522_Buffer[20];  
#define MAXRLEN 18

unsigned char code DefaultKey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
unsigned char data MLastSelectedSnr[4];
unsigned char data ucComMF522Buf[MAXRLEN];

unsigned char SPI_LOOP(unsigned char Dat)
{
  unsigned char data i;
  ACC = Dat;
  i = 8;
SPI_LOOP:  
  CY = ACC & 0x80;
  RC522_MOSI = CY;
  RC522_SCLK = 1;
  CY = RC522_MISO;
  RC522_SCLK = 0;
  i--;
  if(i)goto SPI_LOOP;
  CY = ACC & 0x80;
  return ACC;
}
/////////////////////////////////////////////////////////////////////
//功  能:读RC632寄存器
//参数说明:Address[IN]:寄存器地址
//返  回:读出的值
/////////////////////////////////////////////////////////////////////
unsigned char ReadRawRC(unsigned char Address)
{
  RC522_SCLK = 0;
  RC522_NSS = 0;
  ACC = ((Address<<1)&0x7E)|0x80;
  //
  SPI_LOOP(ACC);
  ACC = SPI_LOOP(0);
  RC522_NSS = 1;
  return ACC;
}

/////////////////////////////////////////////////////////////////////
//功  能:写RC632寄存器
//参数说明:Address[IN]:寄存器地址
//    value[IN]:写入的值
/////////////////////////////////////////////////////////////////////
void WriteRawRC(unsigned char Address, unsigned char value)
{  
  RC522_SCLK = 0;
  RC522_NSS = 0;
  ACC = ((Address<<1)&0x7E);  // 地址高位为0表示写,地位必须为0
  //
  SPI_LOOP(ACC);
  SPI_LOOP(value);
  RC522_NSS = 1;
  RC522_SCLK = 1;
}
/////////////////////////////////////////////////////////////////////
//功  能:置RC522寄存器位
//参数说明:reg[IN]:寄存器地址
//    mask[IN]:置位值
/////////////////////////////////////////////////////////////////////
void SetBitMask(unsigned char reg,unsigned char mask)  
{
  WriteRawRC(reg, ReadRawRC(reg) | mask);  // set bit mask
}
/////////////////////////////////////////////////////////////////////
//功  能:清RC522寄存器位
//参数说明:reg[IN]:寄存器地址
//    mask[IN]:清位值
/////////////////////////////////////////////////////////////////////
void ClearBitMask(unsigned char reg,unsigned char mask)  
{
  WriteRawRC(reg, ReadRawRC(reg) & ~mask);  // clear bit mask
}

/////////////////////////////////////////////////////////////////////
//功  能:通过RC522和ISO14443卡通讯
//参数说明:Command[IN]:RC522命令字
//    pInData[IN]:通过RC522发送到卡片的数据
//    InLenByte[IN]:发送数据的字节长度
//    pOutData[OUT]:接收到的卡片返回数据
//    *pOutLenBit[OUT]:返回数据的位长度
///////PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen)//////////////////////////////////////////////////////////////
char PcdComMF522(unsigned char Command,
            unsigned char pInData,
            unsigned char InLenByte,
            unsigned char pOutData,
            unsigned char pOutLenBit)
{
  char data status = MI_ERR;
  unsigned char data irqEn  = 0x00;
  unsigned char data waitFor = 0x00;
  unsigned char data lastBits;
  volatile unsigned char data n,_i;
  unsigned int data i;
  unsigned short idata T0;
  bit bdata command_bit;
  switch (Command)
  {
    case PCD_AUTHENT:   // 验证密钥
    {
      irqEn  = 0x12;
      waitFor = 0x10;
      command_bit = 0;
      break;
    }   
    case PCD_TRANSCEIVE:  // 发送并接收数据
    {
      irqEn  = 0x77;
      waitFor = 0x30;
      command_bit = 1;
      break;
    }
    default:break;
  }
  //
  WriteRawRC(ComIEnReg,irqEn|0x80); // ComIEnReg:中断请求的使能位。验证密钥:(10010010)位7:管脚IRQ与Status1Reg的IRq反相。位4:允许空闲中断请求(IdleIRq位)传递到IRQ管脚上。位1:允许错误中断请求(ErrIRq位)传递到IRQ管脚上。
              //          发送并接收数据:(11110111)除高位中断请求外,其他都能传到IRQ管脚上
  ClearBitMask(ComIrqReg,0x80);  // ComIrqReg的屏蔽位清零
   WriteRawRC(CommandReg,PCD_IDLE);  // CommandReg低4位写0000B,处于空闲模式
  SetBitMask(FIFOLevelReg,0x80);  // FIFOLevelReg中FlushBuffer位置1,表示缓冲区读和写指针清除,即缓冲区无数据,用来存放一下批数据,ErrReg的BufferOvfl清除
  //
  _i = InLenByte;
loop1:
  WriteRawRC(FIFODataReg, *(unsigned char data*)pInData);
  pInData ++;
  _i --;
  if(_i)goto loop1;
  //
  WriteRawRC(CommandReg, Command);  // 验证密钥 or 发送并接收数据
  //
  if(command_bit)
  {
    SetBitMask(BitFramingReg,0x80);  // 启动数据的发送
  }
  //
  i = 300;
//  TR0 = 1;
loop2:
  n = ReadRawRC(ComIrqReg);
  if( (n & 0x01) || (n & waitFor))goto loop2_end;
  i --;
  if(i)goto loop2;
loop2_end:

  ClearBitMask(BitFramingReg,0x80);  // StartSend位清零
  //  
  if (i!=0)
  {  
    if((ReadRawRC(ErrorReg)&0x1B))  // FIFO没有溢出、接收器启动并完成接收之后:(没冲突)、(CRC没出错)、(没有SOF错误)、(验证时接受字节数没错)
    {
      status = MI_ERR;  // 验证错误
    }
    else
    {
      status = MI_OK;
      if (n & irqEn & 0x01)     // 发送并接收数据、定时器减到0
      {
        status = MI_NOTAGERR;   // 没有找到目标错误
      }
      if (Command == PCD_TRANSCEIVE)
      {       
        n = ReadRawRC(FIFOLevelReg);  // 读FIFO保存的字节数
                        }//        n = 0x02;
      lastBits = ReadRawRC(ControlReg) & 0x07;  // 最后一个接收的字节的有效位数(0则表示8位都有效)
                        //         
                        if (lastBits)
      {
        *(unsigned short data*)pOutLenBit = (n-1)*8 + lastBits;  
      }
      else
      {
        *(unsigned short data*)pOutLenBit = n*8;  
      }
      if (n == 0)        {n = 1;}
      if (n > MAXRLEN){n = MAXRLEN;}
        //
        _i = n;
    loop3:
      *(unsigned char data*)pOutData = ReadRawRC(FIFODataReg);
      pOutData ++;
      _i --;
      if(_i)goto loop3;         
    }
  }
  SetBitMask(ControlReg,0x80);     // stop timer now
  WriteRawRC(CommandReg,PCD_IDLE);    // 空闲
  return status;
}

////////////////////////////////////////////////////////////////////
//开启天线  
//每次启动或关闭天险发射之间应至少有1ms的间隔
/////////////////////////////////////////////////////////////////////
void PcdAntennaOn()
{
  SetBitMask(TxControlReg, 0x03);  // Tx1和Tx2管脚的输出信号调制到13.56MHz的载波上
}

/////////////////////////////////////////////////////////////////////
//关闭天线
/////////////////////////////////////////////////////////////////////
void PcdAntennaOff()
{
  ClearBitMask(TxControlReg, 0x03);
}
//////////////////////////////////////////////////////////////
//功  能:寻卡                                                                          t
//参数说明: 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(unsigned char req_code,unsigned char pTagType)
{
  char data status;  
  unsigned int data unLen;
  ClearBitMask(Status2Reg,0x08);  // 清MFCrypto1On,只能通过软件清零,该位用来指示Crypto1的接通情况,MFAuthent(验证密钥)命令成功执行后置1
  WriteRawRC(BitFramingReg,0x07); // TxLastBits([2-0])表示发送的最后一个字节7位发送

  SetBitMask(TxControlReg,0x03); // TxControlReg低2位(Tx2RFEn和Tx1RFEn)置1,Tx2和Tx1管脚输出信号调制在13.56MHz的载波上

  ucComMF522Buf[0] = req_code;
  status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);  // PCD_TRANSCEIVE == 0x0c发送并接收数据

  if ((status == MI_OK) && (unLen == 0x10))  // 发送成功并且接收16位数据
  {
    *(unsigned char data*)pTagType  = ucComMF522Buf[0];
    pTagType ++;
    *(unsigned char data*)pTagType = ucComMF522Buf[1];  // 接收的卡片类型保存在pTagType中
  }
  else
  {
    status = MI_ERR;  
  }
  return status;
}

void ASCII(unsigned char bytes,unsigned char pBuffer,unsigned char ASCIIBuffer)
{
  unsigned char data i;
  unsigned char data p;
  p = ASCIIBuffer;
  //
  i = bytes;
loop_hex_sep:
  *(unsigned char data*)p = *(unsigned char data*)pBuffer >> 4;
  p ++;
  *(unsigned char data*)p = *(unsigned char data*)pBuffer & 0x0f;
  p ++;
  pBuffer ++;
  i --;
  if(i)goto loop_hex_sep;
  //
  i = bytes << 1;
  p = ASCIIBuffer;
loop_ASCII:
  *(unsigned char data*)p |= 0x30;
  CY = 0;
  ACC = *(unsigned char data*)p - 0x39;
  if( CY )
  {
    *(unsigned char data*)p += 0x07;
  }
  p ++;
  i -- ;
  if(i)goto loop_ASCII;
  //
  *(unsigned char data*)p = 0x00;
}

/////////////////////////////////////////////////////////////////////
//功  能:防冲撞
//参数说明: pSnr[OUT]:卡片序列号,4字节
//返  回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////  
char PcdAnticoll(unsigned char pSnr)
{
  char data status;
  unsigned char data i,snr_check=0;
  unsigned int  data unLen;
  
  unsigned char data *p ;
  p = ucComMF522Buf;

  ClearBitMask(Status2Reg,0x08);   // 清MFCrypto1On,只能通过软件清零,该位用来指示Crypto1的接通情况,MFAuthent(验证密钥)命令成功执行后置1
  WriteRawRC(BitFramingReg,0x00);    // TxLastBits([2-0])表示发送的最后一个字节的所有位都发送
  ClearBitMask(CollReg,0x80);     // 高位置0,所有接收的位在冲突后清除
  ucComMF522Buf[0] = PICC_ANTICOLL1;  // 防冲撞(0x93)
  ucComMF522Buf[1] = 0x20;
  status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);
  //
  if (status == MI_OK)
  {
   i = 4;
loop_checksum:
   snr_check ^= *(unsigned char data*)p;
   *(unsigned char data*)pSnr = *(unsigned char data*)p;
   pSnr ++;
   p ++;
   i --;
   if(i)goto loop_checksum;
   //
   if (snr_check != *(unsigned char data*)p) status = MI_ERR;
  }
  SetBitMask(CollReg,0x80);  // 置1,回归正常
  return status;
}

/////////////////////////////////////////////////////////////////////
//功  能:选定卡片
//参数说明: pSnr[IN]:卡片序列号,4字节
//返  回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdSelect(unsigned char pSnr)
{
  data char status;
  unsigned char data i;
  unsigned int  data unLen;
  
  unsigned char data *p;
  p = ucComMF522Buf + 2;
  
  ucComMF522Buf[0] = PICC_ANTICOLL1;  // 防冲撞
  ucComMF522Buf[1] = 0x70;
  ucComMF522Buf[6] = 0;
  //
  i = 4;
loop_set:
  *p = *(unsigned char data*)pSnr;
  ucComMF522Buf[6]  ^= *(unsigned char data*)pSnr;
  p ++;
  pSnr ++;
  i --;
  if(i)goto loop_set;

  CalculateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);  // CRC校验卡片序列号
  
  ClearBitMask(Status2Reg,0x08);  // 清MFCrypto1On,只能通过软件清零,该位用来指示Crypto1的接通情况,MFAuthent(验证密钥)命令成功执行后置1

  status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);  // 发送卡片的序列号及其校验码
  
  if ((status == MI_OK) && (unLen == 0x18))  // 接收24位
  {  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(unsigned char auth_mode,
                  unsigned char addr,
                  unsigned short pKey,
                  unsigned char pSnr)
{
  char data status;
  unsigned int data unLen;
  unsigned char data i;
  unsigned char data *p;
//  data unsigned char _pKey[] = "0xff,0xff,0xff,0xff,0xff,0xff";
  p = ucComMF522Buf + 2;

  ucComMF522Buf[0] = auth_mode;  // 验证模式
  ucComMF522Buf[1] = addr;   // 块地址
  //
  i = 6;
loop_1:
  *p = *(unsigned char code*)pKey;//this is worked
  pKey ++;
  //*p = 0xff;//this would be more efficient
  p ++;
  
  i --;
  if(i)goto loop_1;// 密码
  //////////
  i = 4;
loop_2:
  *p = *(unsigned char data*)pSnr;// 防冲撞卡号
  p ++;
  pSnr ++;
  i --;
  if(i)goto loop_2;
  ////////
  status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
  if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08)))
  {  status = MI_ERR;  }  
  return status;
}

/////////////////////////////////////////////////////////////////////
//功  能:读取M1卡一块数据
//参数说明: addr[IN]:块地址
//    pData[OUT]:读出的数据,16字节
//返  回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdRead(unsigned char addr,unsigned char pData)
{
  char data status;
  unsigned int data unLen;
  unsigned char data i;
  unsigned char data *p;
  p = ucComMF522Buf;
  ucComMF522Buf[0] = PICC_READ;  // 0x30,读块
  ucComMF522Buf[1] = addr;
  CalculateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);  // 计算CRC,存放在ucComMF522Buf[2]和ucComMF522Buf[3]中
  
  status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);  // 将4个字节放松出去,并接收数据
  if ((status == MI_OK) && (unLen == 0x90))  // 接收144位(18字节)
  {
    i = 16;
  loop_read_out:
    *(unsigned char data*)pData = *p;
    p ++;
    pData ++;
    i --;
    if(i)goto loop_read_out;// 将前16字节读出
  }
  else
  {  status = MI_ERR;  }
  
  return status;
}

/////////////////////////////////////////////////////////////////////
//功  能:写数据到M1卡一块
//参数说明: addr[IN]:块地址
//    pData[IN]:写入的数据,16字节
//返  回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////      
char PcdWrite(unsigned char addr,unsigned char pData)
{
  char data status;
  unsigned int data unLen;
  unsigned char data i;
  unsigned char data *p;
  p = ucComMF522Buf;
  
  ucComMF522Buf[0] = PICC_WRITE;  // 0xa0 写块
  ucComMF522Buf[1] = addr;
  CalculateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);  // 计算CRC

  status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);  // 发送写命令和地址

  if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)) // 接收低四位为1010
  {  status = MI_ERR;  }
   
  if (status == MI_OK)
  {
    i = 16;
  loop_read_out:
    *p = *(unsigned char data*)pData;
    p ++;
    pData ++;
    i --;
    if(i)goto loop_read_out;
    // 将前16字节写入
    CalculateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);
    // 两位CRC计算字节
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);  // 发送18字节
    if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)) // 返回低四位为1010
    {  
      status = MI_ERR;  
    }
  }
  return status;
}
////////////////////////////////////////////////////////
////重点问题区
//////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//功  能:命令卡片进入休眠状态
//返  回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdHalt(void)
{
  unsigned char data unLen;
  ucComMF522Buf[0] = PICC_HALT;  // 0x50,休眠
  ucComMF522Buf[1] = 0;
  CalculateCRC(ucComMF522Buf , 2 , &ucComMF522Buf[2]);//计算校验位
  PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen); // 发送
  return MI_OK;
}

/*********************************************************************
* 用MF522计算CRC16函数
*********************************************************************/
void CalculateCRC(unsigned char pIndata,
            unsigned char length,
            unsigned char pOutData)
{
  unsigned char data i;
  ClearBitMask(DivIrqReg,0x04);  // CRCIRQ清零
  WriteRawRC(CommandReg,PCD_IDLE); // 空闲命令
  WriteRawRC(FIFOLevelReg,0x80);
  // FIFOLevelReg中FlushBuffer位置1,表示缓冲区读和写指针清除,即缓冲区无数据,用来存放一下批数据,ErrReg的BufferOvfl清楚
  i = length;
loop_i1:
  WriteRawRC(FIFODataReg, *(unsigned char data*)pIndata);
  pIndata ++;
  i--;
  if(i)goto loop_i1;
  //
  WriteRawRC(CommandReg, PCD_CALCCRC);
  i = 255;
loop_i2:
  if( ReadRawRC(DivIrqReg) & 0x04 ) goto loop_end;
  i--;
  if(i)goto loop_i2;   
  // CRCIRQ置位,当CRC有效且所有数据被处理则需要置1,退出循环,或者是执行了127次读取认为完成CRC也退出循环
loop_end:
  *(unsigned char data*)pOutData = ReadRawRC(CRCResultRegL);
  pOutData ++;
  *(unsigned char data*)pOutData = ReadRawRC(CRCResultRegM);  
  // 计算结果输出到pOutData中  
}

////////////////////////////////////////////////////////////////////////////////////////////
unsigned char ICcardCodeInit()//
{
  unsigned char data status;
  unsigned char data CardSetNum[2];
  unsigned char data ASCIIBuffer[33];
  status= PcdRequest(PICC_REQIDL , CardSetNum);
  if(status!=0)
  {       
    status= PcdRequest(PICC_REQIDL , CardSetNum);
    if(status!=0)                               
    {               
     return status;
    }
  }

  status = PcdAnticoll(MLastSelectedSnr);
  if(status!=0)
  {
    return status;
  }
  
  status=PcdSelect(MLastSelectedSnr);
  if(status!=MI_OK)
  {
    return status;
  }
  
  return 0;
}
unsigned char ICcardCodeEepromRead(unsigned char block,unsigned char *_data)
{
  unsigned char data status;
  unsigned char data ASCIIBuffer[33];

        if(status = PcdAuthState(0x61, block, DefaultKey, MLastSelectedSnr))// 校验卡密码
        {
                return status;
        }
                               
        if(status = PcdRead(block,_data))
        {
            return status;
        }
        return 0;
}
unsigned char ICcardCodeEepromWrite(unsigned char block,unsigned char *_data)
{
        unsigned char data status;
        //0x60:A密钥验证
        //0x61:B密钥验证
        if(status = PcdAuthState(0x61, block, DefaultKey, MLastSelectedSnr))  // 校验卡密码
        {
                  return status;
        }
       
        if(status = PcdWrite(block,_data))//        写入块
        {
                return status;
        }
        return 0;
}
unsigned char ICcardCodeHalt()
{
        return (PcdHalt());
}

/////////////////////////////////////////////////////////////////////
//系统初始化
/////////////////////////////////////////////////////////////////////
void Rc522IOInit()
{
  RC522_POWER_CONTROL     = 0;
  RC522_RESET             = 0;
  RC522_MISO              = 0;
  RC522_MOSI              = 0;
  RC522_SCLK              = 0;
  RC522_NSS               = 0;
  RC522_IRQ               = 0;//   INT0  
//        P_AM1815=0;
//        NRF24L01_POWER_CONTROL=0;
}

void Rc522InitializeSystem()
{

  RC522_RESET=0;  // 复位
  RC522_RESET=1;
  //WriteRawRC(CommandReg,PCD_RESETPHASE); // 0x0F,软件复位
  
  WriteRawRC(ModeReg,0x3D);    // 和Mifare卡通讯,CRC初始值0x6363
  WriteRawRC(TReloadRegL,30);    // 48
  WriteRawRC(TReloadRegH,0);
  WriteRawRC(TModeReg,0x8D);     // 10001101(141):发送完开始计时,接收时停止计时,自动重装
  WriteRawRC(TPrescalerReg,0x3E);   // 00111110(62),3390  定时时间:3391*49/6.78=24.5ms
  WriteRawRC(TxAutoReg,0x40);    // 控制驱动天线
  ClearBitMask(Status2Reg,0x08);

  WriteRawRC(RxSelReg,0x86);//84  // 内部模拟部分的调制信号作为非接触式UART输入,发送后接收器启动延时6个位时钟
  WriteRawRC(RFCfgReg,0x7F);  //4F  // 接收信号电压增益23dB
  PcdAntennaOn();
}




此帖出自无线连接论坛

最新回复

等于没有提出问题  详情 回复 发表于 2016-7-19 16:53
点赞 关注
 

回复
举报

2万

帖子

74

TA的资源

管理员

沙发
 


>> 如何提问更容易获得答案


此帖出自无线连接论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

2万

帖子

341

TA的资源

版主

板凳
 
等于没有提出问题
此帖出自无线连接论坛
 
 
 

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

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
快速回复 返回顶部 返回列表