门锁系统——卡片识别

接上篇3.门锁系统——指纹识别_only_print的博客-CSDN博客

这一篇我们来学习使用RC522——卡片识别模块,这部分遇到的问题比之前多得多,有一些很奇怪的问题,直到现在都没有解决,我只是基本上完成了功能的实现,也有可能是我这个模块的问题,如果您有更好的解决方法,可以给我留言,帮助我解决这块的问题。谢谢各位大佬!

接下来进入今天的模块认识

认识RC522

MFRC522是高度集成的非接触式(13.56MHz)读写卡芯片。此发送模块利用调制和解调的原理,并将它们完全集成到各种非接触式通信方法和协议中。MFRC522利用了先进的调制和解调概念,完全集成了在13.56MHz下所有类型的被动非接触式通信方式和协议,支持 ISO14443A的多层应用。其内部发送器部分可驱动读写器天线与ISO14443A/MIFARE卡和应答机的通信,无需其它的电路。接收器部分提供一个坚固而有效的解调和解码电路,用于处理ISO14443A兼容的应答器信号。数字部分处理ISO14443A帧和错误检测(奇偶&CRC)。此外,它还支持快速CRYPTO1加密算法,用于验证MIFARE系列产品。MFRC522支持MIFARE更高速的非接触式通信,双向数据传输速率高达424kbit/s

它的引脚信息:

单片机和卡片识别模块通信方式为SPI方式,这里附上我的接线引脚:

RC522引脚

单片机引脚

3.3V

电源VCC

RST—硬件复位引脚

PB0

GND

地GND

IRQ

浮空(不用接)

MISO

PA6

MOSI

PA7

SCK

PA5

SDA

PA4(片选信号)

其中,数据收发信号和时钟信号是SPI中开启的,剩下的引脚需要自己在GPIO处配置。

CobeMX设置

先看GPIO的配置:

然后选择开启SPI1,模式设置为:Full-Duplex Master(全双工主机模式)。分频设置为8~256都行,这样随之波特率也会改变,波特率越小通信速度越快。剩下的都不用修改,具体配置如图:

然后就可以在freertos中生成新的任务了,具体任务配置如图:

配置完成后就可以生成程序了。

程序部分

程序部分还是和之前一样,创建相应的文件夹和对应的RC522.c和RC522.h文件,将其加入文件中,这部分的.h文件中需要加入RC522中的所有寄存器的位置:

/

//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



#define     REQ_ALL               0x52

#define     KEYA                  0x60

#define     KEYB                  0x61

这部分都是一样的,可以直接复制。

我们需要使用软件方式实现SPI的通信,所以需要在RC522.c文件中实现SPI的收发数据:

/*

 * 函数名:SPI_RC522_SendByte

 * 描述  :向RC522发送1 Byte 数据

 * 输入  :byte,要发送的数据

 * 返回  : RC522返回的数据

 * 调用  :内部调用

 */

void SPI_RC522_SendByte ( uint8_t byte )

{

    uint8_t counter;



    for(counter=0; counter<8; counter++)

    {

        if ( byte & 0x80 )

            RC522_MOSI_1 ();

        else

            RC522_MOSI_0 ();



        RC522_DELAY();

        RC522_SCK_0 ();

        RC522_DELAY();

        RC522_SCK_1();

        RC522_DELAY();



        byte <<= 1;

    }

}





/*

 * 函数名:SPI_RC522_ReadByte

 * 描述  :从RC522发送1 Byte 数据

 * 输入  :无

 * 返回  : RC522返回的数据

 * 调用  :内部调用

 */

uint8_t SPI_RC522_ReadByte ( void )

{

    uint8_t counter;

    uint8_t SPI_Data;



    for(counter=0; counter<8; counter++)

    {

        SPI_Data <<= 1;



        RC522_SCK_0 ();



        RC522_DELAY();



        if ( RC522_MISO_GET() == 1)

            SPI_Data |= 0x01;



        RC522_DELAY();



        RC522_SCK_1 ();



        RC522_DELAY();

    }



//    printf("****%c****",SPI_Data);

    return SPI_Data;

}

完成后就可以实现对RC522的寄存器进行读写操作了:

/*

 * 函数名:ReadRawRC

 * 描述  :读RC522寄存器

 * 输入  :ucAddress,寄存器地址

 * 返回  : 寄存器的当前值

 * 调用  :内部调用

 */

uint8_t ReadRawRC ( uint8_t ucAddress )

{

    uint8_t ucAddr, ucReturn;



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



    RC522_CS_Enable();



    SPI_RC522_SendByte ( ucAddr );



    ucReturn = SPI_RC522_ReadByte ();



    RC522_CS_Disable();



    return ucReturn;

}
/*

 * 函数名:WriteRawRC

 * 描述  :写RC522寄存器

 * 输入  :ucAddress,寄存器地址

 *         ucValue,写入寄存器的值

 * 返回  : 无

 * 调用  :内部调用

 */

void WriteRawRC ( uint8_t ucAddress, uint8_t ucValue )

{

    uint8_t ucAddr;



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



    RC522_CS_Enable();



    SPI_RC522_SendByte ( ucAddr );



    SPI_RC522_SendByte ( ucValue );



    RC522_CS_Disable();

}





/*

 * 函数名:SetBitMask

 * 描述  :对RC522寄存器置位

 * 输入  :ucReg,寄存器地址

 *         ucMask,置位值

 * 返回  : 无

 * 调用  :内部调用

 */

void SetBitMask ( uint8_t ucReg, uint8_t ucMask )

{

    uint8_t ucTemp;



    ucTemp = ReadRawRC ( ucReg );



    WriteRawRC ( ucReg, ucTemp | ucMask );         // 置位

}





/*

 * 函数名:ClearBitMask

 * 描述  :对RC522寄存器清位

 * 输入  :ucReg,寄存器地址

 *         ucMask,清位值

 * 返回  : 无

 * 调用  :内部调用

 */

void ClearBitMask ( uint8_t ucReg, uint8_t ucMask )

{

    uint8_t ucTemp;



    ucTemp = ReadRawRC ( ucReg );



    WriteRawRC ( ucReg, ucTemp & ( ~ ucMask) );  // 清除Bit位

}


现在这些基本函数都实现完成了,可以利用这些函数进行对卡片的操作了:

/*

 * 函数名:PcdAntennaOn

 * 描述  :开启天线

 * 输入  :无

 * 返回  : 无

 * 调用  :内部调用

 */

void PcdAntennaOn ( void )

{

    uint8_t uc;



    uc = ReadRawRC ( TxControlReg );



    if ( ! ( uc & 0x03 ) )

        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 );



    while ( ReadRawRC ( CommandReg ) & 0x10 );



    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 ( uint8_t ucType )

{

    if ( ucType == '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_us ( 2 );



        PcdAntennaOn ();//开天线

    }

             

}





/*

 * 函数名:PcdComMF522

 * 描述  :通过RC522和ISO14443卡通讯

 * 输入  :ucCommand,RC522命令字

 *         pInData,通过RC522发送到卡片的数据

 *         ucInLenByte,发送数据的字节长度

 *         pOutData,接收到的卡片返回数据

 *         pOutLenBit,返回数据的位长度

 * 返回  : 状态值

 *         = MI_OK,成功

 * 调用  :内部调用

 */

char PcdComMF522 ( uint8_t ucCommand, uint8_t * pInData, uint8_t ucInLenByte, uint8_t * pOutData, uint32_t * pOutLenBit )

{

    char cStatus = MI_ERR;

    uint8_t ucIrqEn   = 0x00;

    uint8_t ucWaitFor = 0x00;

    uint8_t ucLastBits;

    uint8_t ucN;

    uint32_t 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 )

    {

//                  printf("%x\r\n",ReadRawRC ( ErrorReg ));

        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("%d",ErrorReg);

    }



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

    WriteRawRC ( CommandReg, PCD_IDLE );



    return cStatus;

}

这些函数实现后,我们需要对其进行封装以便于我们进行操作.对卡片模块的封装基本都是:寻卡->防冲突->选卡->操作卡这四步,在我们门禁卡这块,只需要使用到寻卡和防冲突这部分就足够了,其中防冲突部分可以读取到卡的卡号(卡号为卡片自带,所有卡的卡号都是不同的),

// 初始化射频卡模块

void RC522_Init ( void )

{



    RC522_Reset_Disable();



    RC522_CS_Disable();



    PcdReset ();



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



}

/*

 * 函数名: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 ( uint8_t ucReq_code, uint8_t * pTagType )

{

      

    char cStatus;

    uint8_t ucComMF522Buf [ MAXRLEN ];

    uint32_t 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 ( uint8_t * pSnr )

{

    char cStatus;

    uint8_t uc, ucSnr_check = 0;

    uint8_t ucComMF522Buf [ MAXRLEN ];

    uint32_t ulLen;



    ClearBitMask ( Status2Reg, 0x08 );              //清MFCryptol On位 只有成功执行MFAuthent命令后,该位才能置位

    WriteRawRC ( BitFramingReg, 0x00);          //清理寄存器 停止收发

    ClearBitMask ( CollReg, 0x80 );                    //清ValuesAfterColl所有接收的位在冲突后被清除



    /*

    参考ISO14443协议:https://blog.csdn.net/wowocpp/article/details/79910800

    PCD 发送 SEL = ‘93’,NVB = ‘20’两个字节

    迫使所有的在场的PICC发回完整的UID CLn作为应答。

    */

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

    ucComMF522Buf [ 1 ] = 0x20;



    // 发送并接收数据 接收的数据存储于ucComMF522Buf

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



    if ( cStatus == MI_OK)             //通信成功

    {

        // 收到的UID 存入pSnr

        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 ( uint8_t * pIndata, uint8_t ucLen, uint8_t * pOutData )

{

    uint8_t 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 );

}

这样对整个卡的开发基本就完成了,在上面的代码中有些宏定义和函数声明,我们需要在.h文件中声明,以下是RCC522.h的所有代码(其中包括之前的寄存器部分):

#include "main.h"

#include "gpio.h"

#include "spi.h"

#include "touch.h"

#define CARD_PARA_SAVED      'C'    //表示这个地方存在一张卡片

#define   CARD_ID_ADDR        24    //卡片ID在24C02中的首地址,必须是页的起始地址,也就是8的整数倍

#define   RC522_DELAY()  Delay_us(20)



/

//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



#define     REQ_ALL               0x52

#define     KEYA                  0x60

#define     KEYB                  0x61



/

//和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

// 使用软件模拟SPI工作方式

/***********************RC522 接口函数宏定义**********************/

#define          RC522_CS_Enable()         HAL_GPIO_WritePin(RC522_NSS_GPIO_Port, RC522_NSS_Pin,GPIO_PIN_RESET)

#define          RC522_CS_Disable()        HAL_GPIO_WritePin(RC522_NSS_GPIO_Port, RC522_NSS_Pin,GPIO_PIN_SET)



#define          RC522_Reset_Enable()      HAL_GPIO_WritePin( RC522_RST_GPIO_Port, RC522_RST_Pin,GPIO_PIN_RESET )

#define          RC522_Reset_Disable()     HAL_GPIO_WritePin ( RC522_RST_GPIO_Port, RC522_RST_Pin ,GPIO_PIN_SET)



#define          RC522_SCK_0()             HAL_GPIO_WritePin( GPIOA, GPIO_PIN_5,GPIO_PIN_RESET )

#define          RC522_SCK_1()             HAL_GPIO_WritePin ( GPIOA, GPIO_PIN_5,GPIO_PIN_SET )



#define          RC522_MOSI_0()            HAL_GPIO_WritePin( GPIOA, GPIO_PIN_7 ,GPIO_PIN_RESET)

#define          RC522_MOSI_1()            HAL_GPIO_WritePin ( GPIOA, GPIO_PIN_7 ,GPIO_PIN_SET)



#define          RC522_MISO_GET()          HAL_GPIO_ReadPin ( GPIOA, GPIO_PIN_6 )



// 复位RC522

void PcdReset ( void );

// 设置RC522的工作方式

void M500PcdConfigISOType ( u8 ucType );

// 初始化射频卡模块

void RC522_Init ( void );

// 寻卡

char PcdRequest ( u8 ucReq_code, u8 * pTagType );

// 防冲撞

char PcdAnticoll ( u8 * pSnr );

到这里整个函数配置就完成了,剩下的就是实现功能了.进入freertos.c文件中,进入我们新添加的任务IDCard中,完成主函数部分:

void IDCard(void *argument)

{

  /* USER CODE BEGIN IDCard */

  // 初始化射频卡模块

  RC522_Init();

       vTaskDelay(300);

       RC522_Init();

       uint8_t CardType[4] = {0};

       uint8_t i;

       // 定义一个用来存储卡片类型的数组

       uint8_t CARD_ID[10] = {0};

  /* Infinite loop */

  for(;;)

  {

             

              vTaskDelay(10);

              i = PcdRequest(PICC_REQALL,CardType);

              if(i == MI_OK)

              {

                     for(uint8_t j = 0;j<4;j++)

                     {

                            printf("%X",CardType[j]);

                     }

                     printf("\r\n");

              }

              i = PcdAnticoll(CardType);

              if(i == MI_OK)

              {

                     for(uint8_t j = 0;j<4;j++)

                     {

                            printf("%X",CardType[j]);

                     }

                     printf("\r\n");

                     //处理卡号数据

                     sprintf(CARD_ID,"%x%x%x%x",CardType[0],CardType[1],CardType[2],CardType[3]);

//                  // 写入卡ID,暂时使用这个方法存储卡ID

//                  EP24C_WriteInOnePage(CARD_ID_ADDR, CardType,1);



                     // 读取储存在EEPROM中的卡ID

                     EP24C_ReadBytes(CARD_ID_ADDR,&CARD_ID[0],1);

                     // 判断刚才接触的卡是否是存储在数组中的卡

                     if(CARD_ID[0] == CardType[0])

                     {

                            printf("卡正确,开锁成功");

                           

                     }

                     else

                     {

                            printf("未储存此卡");

                     }

              }

              vTaskDelay(200);



  }

  /* USER CODE END IDCard */

}

在主函数中可以实现对卡片的识别.

最后我们还需要完成之前在bsp_lcd.c中的对卡片的操作:

// 定义一个用来存储卡片类型的数组

uint8_t CardID[4] = {0};

// 卡片设置

void IDCard_Set(void)

{

       LCD_Fill(0, 0, 280, 100, WHITE);

       // 查看卡片

       LCD_ShowString(10,0, 240,16,16,(uint8_t*)"[1] View the IDCard");

       // 删除卡片

       LCD_ShowString(10,20,240,16,16, (uint8_t*)"[2] Delete the IDCard");

       // 添加卡片

       LCD_ShowString(10,40,240,16,16, (uint8_t*)"[3] Add a IDCard");

       // 重置卡片

       LCD_ShowString(10,60, 240,16,16,(uint8_t*)"[4] Reset the IDCard");

       uint8_t i = 1;

       uint8_t num = 0;

       HAL_Delay(100);

       while(i)

       {

              curKey=ScanKeys(KEY_WAIT_ALWAYS);

              switch(curKey)

              {

                     case  KEY0:

                            break;

                     case       KEY1:// 查看卡片

                     {

                            printf("查看卡片");

                            // 创建一个循环,最大放七个卡片

                            for(uint8_t j = 0;j<7;j++)

                            {

                                   EP24C_ReadBytes(CARD_ID_ADDR, CardID, sizeof(CardID));

                                   if(CardID != 0)

                                   {

                                          printf("%d存在卡片,卡号:",j+1);

                                          for(uint8_t   k = 0;k<4;k++)

                                          {

                                                 printf("%X",CardID[k]);

                                          }

                                          printf("\r\n");

                                         

                                   }

                                  

                            }

                            i = 0;

                            break;

                     }

                     case       KEY2:// 删除卡片

                     {

                            printf("删除卡片");

                            while(i)

                            {

                                   num = Touch_Num();

                                   if(num != 0)

                                   {

                                          // 将选定的位置清0

                                          EP24C_WriteInOnePage((CARD_ID_ADDR+((num-1)*8)), 0, 8);

                                         

                                         

                                   }

                                   i = 0;

                            }

                            break;

                     }

                     case       KEY3:// 添加卡片

                     {

                            // 功能测试出错

                            // 定义一个用来存储卡片类型的数组

                            uint8_t CARD_ID[10] = {0};

                            printf("添加卡片");

//                                num = Touch_Num();

                                   // 延时消抖

                            HAL_Delay(200);

//                                printf("请放卡片");

                            while(i)

                            {

                                   // 判断有无卡靠近

                                   i = PcdRequest(PICC_REQALL,CARD_ID);

                                   if(i == MI_OK)

                                   {

                                          for(uint8_t j = 0;j<4;j++)

                                          {

                                                 printf("%X",CARD_ID[j]);

                                          }

                                          printf("\r\n");

                                   }

                                   i = PcdAnticoll(CARD_ID);

                                   if(i == MI_OK)

                                   {

                                          for(uint8_t j = 0;j<4;j++)

                                          {

                                                 printf("%X",CARD_ID[j]);

                                          }

                                          printf("\r\n");

                                          // 写入卡ID

                                          EP24C_WriteInOnePage(CARD_ID_ADDR, CARD_ID,1);

                                          printf("卡片添加成功\r\n");

                                          i = 0;

                                   }     

                                   HAL_Delay(200);

                            }                                 

                           

                            break;

                     }

                     case       KEY4:// 重置卡片

                     {

                            printf("重置卡片");

                            for(uint8_t j = 0;j<7;j++)

                            {

                                   // 将这些卡片的位置全部清0

                                   EP24C_WriteInOnePage((CARD_ID_ADDR+(j*8)), CardID, 8);

                            }

                            i = 0;

                            break;

                     }

              }//end switch     

       }

      

      

       // 操作完成后显示主界面

       LCD_Fill(0, 0, 280, 100, WHITE);

       Bsp_Lcd_Init();

}

这样就完成了整个卡片操作的开发,但是就在这中间,在bsp_lcd.c中的增添卡操作却怎么都无法实现,所以只能暂时在主函数中完成添加卡的工作,主函数中有:

//                  // 写入卡ID,暂时使用这个方法存储卡ID

//                  EP24C_WriteInOnePage(CARD_ID_ADDR, CardType,1);

将这句的注释解除然后将想要添加的卡放置在识别卡的区域就可以将这张卡添加到rom中.如果需要添加多张卡就需要更改地址,然后在对应的寻找rom内部的卡号处添加新的地址就可以了.

最后,非常重要的一点!!!!!!!!!在生成代码后,自动生成的spi.c文件中,生成的初始化代码中:

相关软件:链接: https://pan.baidu.com/s/1SpKRupfnRLsEY9Yoo3IUfA?pwd=4rre 提取码: 4rre 复制这段内容后打开百度网盘手机App,操作更方便哦

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值