RC522读卡器 M1卡学习总结(二)

二、说说RC522读卡器

       我从淘宝里买来的读卡器模块如下:

RC522读卡器 <wbr>M1卡 <wbr>学习总结(二)

它带有一组接口:SDA  SCK  MOSI  MISO  IRQ(NG)  GND  RST  3.3V

读卡器与M1卡之间的通讯,首先要寻卡(Answer To Request),验证卡片类型

                                            ----》防冲突检查(Anticollision Loop)选择一张卡片,返回该卡序列号;

                                           -----》选择卡片(Select Tag),选择被选中的卡的序列号,返回卡的容量代码;

                                           -----》三次互相确认(3 Pass Authentication)通过密码校验之后,三次互相认                                             证                                                   之后可以通讯。

 

M1卡指令:

                 读(Read):读一个块;

                 写(Write):写一个块;

                 加值(Increment):对数值块进行加值;

                 减值(Decrement):对数值块进行减值;

                 存储(Restore):将块中数据保存到数据寄存器中;

                 传输(Transfer):将数据寄存器中内容写入到块中;

                 终止(Halt):将卡置于暂停工作状体。


三、RC522读卡器的使用--硬件部分

       我使用了stm8s103来驱动RC522读卡器,硬件连接如下:

      stm8s103引脚                      RC522接口

      3.3v                    ----------   3.3v

      GND                   ---------    GND

      PC4                    ---------     SDA(NSS)

      PC5(SPI_SCK)    ---------     SCK

      PC6(SPI_MISO) ---------     MISO

      PC7(SPI_MOSI) ---------     MOSI

      至少接这6针。

 

     使用stm8s芯片的spi接口来和rc522通讯,通过相应的寄存器可控制SPI接口的数据传输率、数据时钟相位等通信参数。

     这里使用spi通讯,1/4分频,空闲低电平,第一个时钟周期开始采样,第一个时钟边缘开始数据采样。

注意:片选信号必须保证在写入数据流期间为低电平,而在无数据流写入时为高电平,不得为了省事而一直将NSS置为低电平。


四、单片机stm8s与读卡器RC522通讯----软件部分

      单片机与读卡器的接口

      RC522读卡器提供三种接口,分别是UART,I2C,SPI这三种接口。我们这里选择了spi接口。关于stm8s为主机,rc522读卡器为从机。spi使用4个管脚与从设备相连,MISO,MOSI,SCK,NSS.

       这里有一点需要注意:MOSI管脚相互连接,MISO脚相互连接。这样,数据在主和从之间串行地传输(MSB位在前)。通信总是由主设备发起。主设备通过MOSI脚把数据发送给从设备,从设备通过MISO引脚回传数据。这意味全双工通信的数据输出和数据输入是用同一个时钟信号同步的:时钟信号由主设备通过SCK脚提供。

(1)SPI初始化如下:

void init_SPI_Master(void)
       
        SPI_CR1 = 0x04;          //fMaster/2, 配置为主设备,空闲低电平,第一个时钟周期开始采样
        SPI_CR2 = 0x03;           //内部指定主模式,NSS上电平决定该位值
        SPI_CRCPR = 0x07;
        SPI_ICR = 0x00;            //中断禁止
        SPI_CR1 |= 0x40;          //开启SPI

}

(2)UART初始化,这里为了调试方便,我们使用uart接口来观察执行情况。

void init_UART(void)
{
       UART1_CR2=0x00;//使发送禁用TEN=0;
       UART1_CR1=0x00;//设置M字长,8位数据位
       UART1_CR3=0x00;//1位停止位
 
       UART1_BRR2=0X00;      //波特率9600,分频系数=2000000/9600=208
       UART1_BRR1=0X0D;       //208=0X0D;
       UART1_CR2=0X2C;       //b3=1,允许发送  b2=1,允许接收  b5=1,允许产生接收中断
}

 (3)UART发送数据函数

void UARTSend(uchar aa)
{
  UART1_CR2=0x00;
  UART1_DR=aa;                   

  UART1_CR2=0x08;
  while((UART1_SR & 0x40) ==0);
  UART1_CR2=0x2c;//0x2c;//0x08; 2位 rev使能 3位 发送使能 5--rien 
}

(4)UART接收中断处理函数

@far @interrupt void UART1_RX_IRQHandler(void)  //UART1_Receiver(void)
{
     unsigned char i;
     _asm("sim");    //关总中断
      a=UART1_DR;      //将接收的字符放到a中
     _asm("rim");    //开总中断
    return;
}

(5)SPI接收发送字节

//spi接口在写的时候要先发送,发送不一定要传送内容,只是为了
//给从机提供时钟,因为sck是主机来发出的,所以写函数里面要有发送指令,目的是提供从机写时钟
uchar SPIWriteByte(uchar spiData)
{
   uchar retry=0;
  while((SPI_SR & 0X02)==0)  //等待发送区空
  {
   retry++;
   if(retry>200) return 0;  //防止死机
  }
 
  SPI_DR=spiData;             //发送一个byte
  retry=0;
  while((SPI_SR|0X80)==0X80);  //等待通信结束
 
  while((SPI_SR & 0X01)==0);  //等待接收缓冲区空
  {
     retry++;
    if(retry>200) return 0;
  }
  return SPI_DR;    //返回受到的数
 

}

(6)main.c主程序函数

void main()
{
 uchar i;
 uchar Card_Type1[2];
 uchar Card_ID[4];
 uchar Card_KEY[6] = {0xff,0xff,0xff,0xff,0xff,0xff};  
 uchar Card_Data[16];
 uchar status;
  //fmaster=fcpu=2MHz
 CLK_ECKR=0x00;
 CLK_ICKR=0x01;
 CLK_CMSR=0xe1;
 
 CLK_SWR=0xe1;
 CLK_CKDIVR=0x18;

 init_IO();
 init_UART();
 init_SPI_Master();
 
 _asm("rim");    //开总中断,便于产生串口接收中断

 status=PcdReset();
 PcdAntennaOff();
 delay(20);
 PcdAntennaOn();
 M500PcdConfigISOType( 'A' );
 a=0x63;
 nblock=4;//kuan 0
 t=0;
 while(1)
 {
  

        //    PcdAntennaOff();
        //测试一下接口是否正确
        status = CheckMCURC522interface();
        if(status != MI_OK)
        {
             UARTSend(0x04);
             continue;
        }
    
         status = PcdRequest(PICC_REQALL, g_ucTempbuf);
           if (status != MI_OK)
          {    
              continue;
           }
         //  UARTSend(a);//0x11);
         //  for(i=0;i<8;i++)
         //  UARTSend(g_ucTempbuf[i]);//0400 e52b 0000000000
       

         delay(20);//

         status = PcdAnticoll(g_ucTempbuf);
         if (status != MI_OK)
         {    continue;    }
         //   UARTSend(0x12);
         delay(20);//delay_ms(2);
         status = PcdSelect(g_ucTempbuf);
         if (status != MI_OK)
         {    continue;    }
        //   UARTSend(0x13);
         delay(20);//

       //   UARTSend(nblock);
       //认证卡
         status = PcdAuthState(PICC_AUTHENT1A, nblock, DefaultKey, g_ucTempbuf);
         if (status != MI_OK)
         {    continue;    }
        //   UARTSend(0x14);
        delay(20);//

       if(a==b) continue;
       else b=a;
       UARTSend(a);  //发送执行的命令代码
     switch(a)
     {
     case 0x91://写电子钱包数据到块nblock
       status = PcdWrite(nblock, data1);
         if(status==MI_OK)
       {
        UARTSend(0x88);
        
       }
       else UARTSend(0x44);
       break;
     case 0x92://写普通数据到块nblock
       status = PcdWrite(nblock, data3);
         if(status==MI_OK)
       {
        UARTSend(0x88);
        
       }
       else UARTSend(0x44);
         break;
     case 0x93://从块n中读取数据
       status = PcdRead(nblock, g_ucTempbuf);//PcdRead(2, g_ucTempbuf);
        if (status == MI_OK)
        {   
        UARTSend(0x88);
        for(i=0;i<16;i++)
         UARTSend(g_ucTempbuf[i]);//把写进去的数
        }
        else  UARTSend(0x44);
        break;
     case 0x94://从块n中读取数据
       status = PcdRead(nblock, g_ucTempbuf);//PcdRead(2, g_ucTempbuf);
        if (status == MI_OK)
        {   
        UARTSend(0x88);
        for(i=0;i<16;i++)
         UARTSend(g_ucTempbuf[i]);//把写进去的数
        }
        else  UARTSend(0x44);
        break;
     case 0x95://操作电子钱包
       status = PcdValue(PICC_DECREMENT,nblock,data2);
       if (status == MI_OK)
        
         UARTSend(0x88);
         for(i=0;i<4;i++)
           UARTSend(data2[i]);//
       }
        else  UARTSend(0x44);
       break;
     case 0x96: //备份电子钱包
       status = PcdBakValue(nblock, nblock+1);
        if (status == MI_OK)
        
         UARTSend(0x88);
        
       }
        else  UARTSend(0x44);
        break;
     default:break;
     
     }
    
       
  //    PcdHalt();
  //    PcdAntennaOff();
 }
}

(7)RC522的库函数和网上都基本一样,就不写了。

以上程序本人已经测试过了。

 

(8)本人在学习rc522的过程中参考了很多文章,在此表示感谢!

M1卡介绍  http://wenku.baidu.com/view/62cccb122e3f5727a4e9625c.html

M1卡破解密码控制位及控制规则http://www.docin.com/p-624326551.html

Mifare1技术说明(M1卡说明文档) http://www.docin.com/p-379085837.html

基于非接触式ic卡的读卡器的设计与开发http://www.docin.com/p-906980594.html

      13.56M读卡器开发详解二http://blog.sina.com.cn/s/blog_6754612e0101c0pe.html


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值