MF RC500程序

MF500PICCACTIVATEIDLE ()

激活处于IDLE状态(上电复位和通信失败时卡片都处于这种状态)的一张卡片。

用法:

Mf500PiccActivateIdle ( unsigned char br, unsigned char * atq, unsigned char * sak, unsigned char * uid, unsigned char * uid_len)

描述:

本函数完成了“Request-Idle”,“Anticollision”和“Select”命令序列来激活一张卡片并将它的状态由IDLE改变为ACTIVE状态。多级序列号会被正确地处理。

参数:

br    (输入)针对MIFARE®通信的波特率,为0时速率为106 k

atq   (输出)请求的应答(Answer to Request)

sak (输出)选择的应答(Select acknowledge)

uid   (输出)最多至10字节的UID

uid_len    (输出)UID的总长度(最多三级序列号10字节: 3 + 3 + 4)

返回值:

CCRC, MI_BITCOUNTERR, MI_NOBITWISEANTICOLL, MI_BAUDRATE_NOT_SUPPORTED,

MI_SERNRERR


以下内容为程序代码:

char Mf500PiccActivateIdle(unsigned char br,
    unsigned char *atq,
    unsigned char *sak,
    unsigned char *uid,
    unsigned char *uid_len)
{
    unsigned char cascade_level;
    unsigned char sel_code;
    unsigned char uid_index;
    signed char status;
    unsigned char cmdASEL;

    *uid_len      = 0;    //序列号字节总长度

    //call activation with def. divs
    status = Mf500PcdSetDefaultAttrib();
    if (status == MI_OK)
    {
        status = Mf500PiccCommonRequest(PICC_REQIDL,atq);
    }
    if (status == MI_OK)
    {
        if((atq[0] & 0x1F) == 0x00) //检查返回的ATQ低字节(标签类型信息)低5位看是否有卡片支持位帧防冲撞
        {
            status = MI_NOBITWISEANTICOLL;
        }
    }

    if (status == MI_OK)
    {
        //Get UID in 1 - 3 levels (standard, [double], [triple] )
        //-------
        switch(br)
        {
        case 0:    //防冲撞级别 1 106 kBaud
            cmdASEL = PICC_ANTICOLL1;
            break;
        case 1:    //防冲撞级别 1 212 kBaud
            cmdASEL = PICC_ANTICOLL11;
            break;
        case 2:    //防冲撞级别 1 424 kBaud
            cmdASEL = PICC_ANTICOLL12;
            break;
        case 3:    //防冲撞级别 1 848 kBaud
            cmdASEL = PICC_ANTICOLL13;
            break;
        default:
            status = MI_BAUDRATE_NOT_SUPPORTED;
            break;
        }
    }

    if (status == MI_OK)
    {
        cascade_level = 0;    //UID级数从0开始,最多支持3级
        uid_index     = 0;    //序列号指针
        do
            {
            //Select命令代码依赖于UID的级数
            sel_code   = cmdASEL + (2 * cascade_level);
            cmdASEL = PICC_ANTICOLL1;    //第一层Anticollision和Select可以使用各种波特率的命令代码(93H/92H/94H/98H)
                                        //但是第二层和第三层只能使用唯一的命令代码(95H和97H),因此要将cmdASEL复位为PICC_ANTICOLL1
            //ANTICOLLISION
            status = Mf500PiccCascAnticoll(sel_code, 0, &uid[uid_index]);
            if (status == MI_OK)
            {
                //SELECT
                status = Mf500PiccCascSelect(sel_code, &uid[uid_index], sak);
                if (status == MI_OK)
                {
                    cascade_level++;

                    //通过返回的SAK第2位区别序列号是否结束(是否还有下一级的UID)
                    if (*sak & 0x04)
                    {
                        //UID还有下一级,也就是说返回的4字节UID的第一字节是层叠标签0x88而不是序列号,把它去掉
                        memmove(&uid[uid_index], &uid[uid_index + 1], 3);
                        uid_index += 3;    //序列号指针只移动3字节
                        *uid_len += 3;    //序列号字节总数增3
                    }
                    else
                    {
                        //UID没有下一级了,则返回的4字节都是有效的序列号
                        uid_index += 4;    //序列号指针移动4字节
                        *uid_len += 4;    //序列号字节总数增4
                    }
                }
            }
        }
        while((status == MI_OK)                //当没有错误发生
                && (*sak & 0x04)            //而且UID还有下一级
                && (cascade_level < 3));    //还有UID级数在3以内时继续循环

    }

    if (status == MI_OK)
    {
        //若UID级数已经达到3但SAK还指出有下一层UID时则说明碰到了一张外星卡
        if ((cascade_level == 3) && (*sak & 0x04))
        {
            *uid_len = 0;
            status = MI_CASCLEVEX;
        }
        Mf500PcdSetAttrib(br,br);
    }
    return (status);
}


--  作者:mifarelight
--  发布时间:2007-12-15 15:24:46
--  

MF500PICCAUTHKEY()

直接以微处理器装载的密钥来进行认证

用法:

Mf500PiccAuthKey (unsigned char auth_mode, unsigned char * snr, unsigned char * keys, unsigned char sector )

本函数利用微处理器提供的密钥来认证一个卡片扇区。密钥被装载进读写卡芯片并用于认证指定扇区。为了获得所需的已编码密钥(把六字节密钥编码为MF RC500要求的特定格式12字节),可以使用函数Mf500HostCodeKey

参数:

auth _mode     (输入)选择密钥A或者密钥B(PICC_AUTHENT1A/PICC_AUTHENT1B)

snr   (输入)要认证卡片的4字节序列号

keys        (输入)认证卡片所需的12字节特定格式密钥

block      (输入)用来寻址卡片上要认证的块地址,对于MIFARE®标准卡,块地址由063,对于其它卡片类型,请参考相应的产品说明。

返回值:

CCRC, MI_BITCOUNTERR, MI_KEYERR, MI_AUTHERR

以下内容为程序代码:

char Mf500PiccAuthKey(  unsigned char auth_mode,
    unsigned char *snr,
    unsigned char *keys,
    unsigned char block)
{
    char status     = MI_OK;
    unsigned char i = 0;

    PcdSetTmo(106);
    FlushFIFO();    //清空FIFO
    ResetInfo(MInfo);
    memcpy(MSndBuffer,keys,12);         //12字节用于认证的密钥
    MInfo.nBytesToSend = 12;
    //写入密钥装载命令
    if ((status=PcdSingleResponseCmd(PCD_LOADKEY,MSndBuffer,MRcvBuffer,&MInfo)) == MI_OK)
    {
        //执行认证过程
        status = Mf500PiccAuthState(auth_mode,snr,block);
    }
    return status;
}


可见,它最终调用了函数Mf500PiccAuthState()

以下内容为程序代码:

char Mf500PiccAuthState(   unsigned char auth_mode,
    unsigned char *snr,
    unsigned char block)
{
    char status = MI_OK;
    unsigned char i = 0;

    WriteRC(RegChannelRedundancy,0x07); //禁能RxCRC,使能TxCRC和奇偶校验

    PcdSetTmo(150);
    MSndBuffer[0] = auth_mode;      //认证命令
    MSndBuffer[1] = block;          //要认证的块
    memcpy(MSndBuffer + 2,snr,4);   //4字节的序列号
    ResetInfo(MInfo);
    MInfo.nBytesToSend = 6;         //共6字节

    //认证分两步进行
    if ((status = PcdSingleResponseCmd(PCD_AUTHENT1,
        MSndBuffer,
        MRcvBuffer,
        &MInfo)) == MI_OK)
    {
        if (ReadRC(RegSecondaryStatus) & 0x07) //若RxLastBits不为零则数据传输有误

        {
            status = MI_BITCOUNTERR;
        }
        else
        {
            WriteRC(RegChannelRedundancy,0x03); //禁能RxCRC,TxCRC,使能奇偶校验
            ResetInfo(MInfo);
            MInfo.nBytesToSend = 0;             //第二步不需要数据

            if ((status = PcdSingleResponseCmd(PCD_AUTHENT2,
                MSndBuffer,
                MRcvBuffer,
                &MInfo)) == MI_OK)
            {
                if ( ReadRC(RegControl) & 0x08 ) //若Crypto1位被激活,表示认证成功
                {
                    status = MI_OK;
                }
                else
                {
                    status = MI_AUTHERR;
                }
            }
        }
    }
    return status;
}


--  作者:mifarelight
--  发布时间:2007-12-15 15:29:04
--  

Authent2命令成功,则卡片和MF RC500的认证就过关了。对于这种情况,控制位Crypto1被自动置位。当Crypto1位置位时,所有后续的卡片通讯都是使用Crypto1安全原理加密了的。若Authent2命令失败,则Crypto1被清零。
 注意:Crypto1标志不能由微处理器置位,它只能通过成功执行了Authent2命令置位。微处理器可以清除Crypto1标志来继续和卡片进行明码通讯。

 注意:Authent2命令必须在Authent1命令成功后立即运行。


--  作者:mifarelight
--  发布时间:2007-12-15 15:55:41
--  
卡片(以MIFARE1 S50为例)的状态随着读写模块(以MF RC500为例)所发送的命令转换,读写模块的命令需要严格按照顺序来执行。

REQUEST ALL/IDLE

若一张MIFARE®卡片进入读写卡器的天线区域,则卡片被置于初始状态 - IDLE。处于这种初始状态的MIFARE®卡只能接受的Request命令是两个不同的request命令代码。

所有的卡片均响应“Request All52hex)”命令。

只有未被置于HALT状态的卡才响应“Request Idle26hex)”命令。

MIFARE®卡以它的卡片类型来回应(基于标签类型,根据ISO 14443规定的ATQ)。


ANTICOLLISION

在成功的Request之后,MIFARE®卡接受“Anticollision”命令并返回它的序列号。若读写卡天线区域内有多张卡,MF RC500自动启动一个内部防冲撞过程并最终返回某张卡片的序列号。

ISO 14443非接触接口标准还包括支持多级序列号的另两个Anticollision命令代码(95hex97hex)。

 

SELECT

在成功的“Request”或者“Anticollision”命令之后,MIFARE®卡接受“Select”命令。和“Select”命令有关,只有指定序列号的卡片被选中并和MF RC500继续通信,所有其它未被选中的卡片在之后的通信中都不再被涉及并再次返回初始状态 - IDLE。

Select所指定序列号的卡片以卡片特定代码answer to selectATS)”来响应“Select”命令。ISO 14443非接触接口标准,还包括支持多级序列号的另两个select命令代码(95hex97hex)。

 

AUTHENTICATION

为了访问MIFARE® Classich卡片的EEPROM所保存的数据,卡片必须经过认证。因此,必须完成认证过程。用户选择合适的密钥向卡片提交认证。若这些密钥和保存在卡片扇区尾块的密钥相同,则可以对卡片进行进一步的访问,如读、写、增值、减值等等。

 

READ

通过认证过程之后,“Read”命令读出卡片EEPROM的内容。不同的卡片类型所读出的内容是不一样的,MIFARE Standard IC输出16字节的完整块内容而MIFARE Light IC输出两个4字节的页和8字节伪数据。

如果读取的是扇区的尾块,那么密钥会被卡片屏蔽为全零,因为密钥是不能读出的。

另外,对于有效认证之后的MIFARE Classic卡片,数据只能在该卡片该块的访问条件允许时读出。

 

WRITE

通过认证过程之后,若访问条件允许,则“Write”向卡片EEPROM写入数据。不同的卡片类型所能写入的内容是不一样的,MIFARE Standard IC可以将16字节的完整块内容而MIFARE Light IC可以一个4字节的页写入卡片的EEPROM

 注意:当向扇区尾块写入数据时必须特别小心。该块保存了卡片的密钥和访问条件。在写入卡片的扇区尾块过程中,卡片应该尽量靠近读卡器的天线。

 

INCREMENT

Increment”命令读取MIFARE Standard卡片IC上所寻址的数值块,然后检查读回的数据结构并将数据块的内容加上所传输的数值,接着把结果保存到卡片的内部寄存器中。整个过程不对卡片的EEPROM进行写操作。


DECREMENT

Decrement”命令读取MIFARE Standard卡片IC上所寻址的数值块,然后检查读回的数据结构并将数据块的内容减去所传输的数值,接着把结果保存到卡片的内部寄存器中。整个过程不对卡片的EEPROM进行写操作。

 

RESTORE

Restore”命令读取MIFARE Standard卡片IC上所寻址的数值块,然后检查读回的数据结构并将数据块的内容保存到卡片的内部寄存器中。整个过程不对卡片的EEPROM进行写操作。

 

TRANSFER

Transfer”命令将卡片内部寄存器的内容传送到EEPROM指定的地址处。该命令只能在增值、减值或恢复功能之后调用。

 

HALT

Halt”命令将MIFARE卡置入睡眠状态 - HALT。为了再次激活该MIFARE卡片,必须对卡片重新上电复位(令卡片离开读卡区后重新进入)或者使用“Request All”命令。


--  作者:iccreem
--  发布时间:2008-11-13 9:15:16
--  
小弟是一个大学生,下面是我写的一个用AVR单片机控制RC531的程序,可是总是不能RC531里的寄存器进行访问,是不是读写时的时序不对呢?应该怎样配置AVR的IO寄存器呢?请各位高手帮忙看一下,小弟感激不尽!
其中AD0~AD7是和RC531的数据线连起来的,我用的是独立选通方式中的地址和数据复用方式。

#define GetRegPage(addr) (0x80 | (addr>>3))
///////////////////////////////////////////////////////////////////////
// 往一个地址写一个数据
///////////////////////////////////////////////////////////////////////
void WriteRawIO(unsigned char Address, unsigned char Value)
{
set_bit(PORTB , ALE); //置ALE位,地址锁存有效
DDRA = 0xff;
PORTA = Address; //写入地址,锁存为RC531内部地址

clr_bit(PORTB , ALE); //清ALE位,地址锁存无效
_delay_us(50); //延时50us

clr_bit(PORTB , RC531_CS); //清NCS位,片选有效
clr_bit(PORTB , WR); //清NWR位,写有效
DDRA = 0xff; //设置A口为输出
PORTA = Value; //写入数据
_delay_us(50); //延时50us


set_bit(PORTB , WR); //置NWR,写无效
set_bit(PORTB , RC531_CS); //置NCS位,片选无效
}

///////////////////////////////////////////////////////////////////////
// 从一个地址读出一个数据
///////////////////////////////////////////////////////////////////////
unsigned char ReadRawIO(unsigned char Address)
{
uchar c;
set_bit(PORTB , ALE); //置ALE位,地址锁存有效
DDRA = 0xff;
PORTA = Address; //写入地址,锁存为RC531内部地址

clr_bit(PORTB , ALE); //清ALE位,地址锁存无效
_delay_us(50); //延时50us

clr_bit(PORTB , RC531_CS); //清NCS位,片选有效
clr_bit(PORTB , RD); //清NRD位,读有效
DDRA = 0x00; //设置A口为输入
c = PINA; //读出数据
_delay_us(50); //延时50us

set_bit(PORTB , RD);
//置NRD位,读无效
set_bit(PORTB , RC531_CS); //置NCS位,片选无效

return c;
}

///////////////////////////////////////////////////////////////////////
// 往一个地址写一个数据(EEPROM)
///////////////////////////////////////////////////////////////////////
void WriteIO(unsigned char Address, unsigned char value)
{
WriteRawIO(0x00,GetRegPage(Address));
WriteRawIO(Address,value);
}

///////////////////////////////////////////////////////////////////////
// 从一个地址读出一个数据(EEPROM)
///////////////////////////////////////////////////////////////////////
unsigned char ReadIO(unsigned char Address)
{
WriteRawIO(0x00,GetRegPage(Address));
return ReadRawIO(Address);
}
--  作者:mifarelight
--  发布时间:2008-11-13 20:45:40
--  
 ReadRawIO和WriteRawIO都和你的具体硬件连接有关,你肯定要仔细验证程序是否产生读写MF RC5XX所要求的时序。这是最底层的部分。

原始的读写操作都成功之后,你再尝试读取RC5XX的片上寄存器,把读回的值和芯片的上电复位值相比较,都差不多的话才意味着读写都正确进行了。
原文地址:https://www.cnblogs.com/bingyun84/p/1571422.html