• 正文
    • 一模塊來(lái)源
    • 二規(guī)格參數(shù)
    • 三移植過(guò)程
    • 四移植驗(yàn)證
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

【CW32模塊使用】RC522射頻IC卡識(shí)別模塊

01/15 09:18
1035
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

近場(chǎng)通信(NEAR FIELD COMMUNICATION, NFC),又稱近距離無(wú)線通信,是一種短距離的高頻無(wú)線通信技術(shù),允許電子設(shè)備之間進(jìn)行非接觸式點(diǎn)對(duì)點(diǎn)數(shù)據(jù)傳輸(在十厘米內(nèi))交換數(shù)據(jù)。這個(gè)技術(shù)由免接觸式射頻識(shí)別(RFID)演變而來(lái),并向下兼容RFID,最早由SONY和PHILIPS各自開發(fā)成功,主要用于手機(jī)等手持設(shè)備中提供M2M(MACHINE TO MACHINE)的通信。

由于近場(chǎng)通訊具有天然的安全性,因此,NFC技術(shù)被認(rèn)為在手機(jī)支付等領(lǐng)域具有很大的應(yīng)用前景。同時(shí),NFC也因?yàn)槠湎啾扔谄渌?a class="article-link" target="_blank" href="/tag/%E6%97%A0%E7%BA%BF%E9%80%9A%E8%AE%AF/">無(wú)線通訊技術(shù)較好的安全性被中國(guó)物聯(lián)網(wǎng)校企聯(lián)盟比作機(jī)器之間的“安全對(duì)話”。

模塊來(lái)源

模塊實(shí)物展示:

資料鏈接:https://pan.baidu.com/s/1pGSaohXnOi8tu6M3i3KFcQ

資料提取碼:suah

規(guī)格參數(shù)

工作電壓:3.3V

工作電流:10-26mA

模塊尺寸:40mm×60mm

支持的卡類型:mifare1 S50、mifare1 S70、mifare UltraLight、mifare Pro、mifare Desfire

控制方式:SPI

以上信息見(jiàn)廠家資料文件

移植過(guò)程

我們的目標(biāo)是將例程移植至CW32F030C8T6開發(fā)板上【能夠識(shí)別IC卡的ID并進(jìn)行讀寫的功能】。首先要獲取資料,查看數(shù)據(jù)手冊(cè)應(yīng)如何實(shí)現(xiàn)讀取數(shù)據(jù),再移植至我們的工程。

3.1查看資料

S50非接觸式IC卡,分為16個(gè)扇區(qū),每個(gè)扇區(qū)由4塊(塊0、塊1、塊2、塊3)組成,(我們也將16個(gè)扇區(qū)的64個(gè)塊按絕對(duì)地址編號(hào)為0~63,存貯結(jié)構(gòu)如下圖所示:

第0扇區(qū)的塊0(即絕對(duì)地址0塊),它用于存放廠商代碼,已經(jīng)固化,不可更改。

每個(gè)扇區(qū)的塊0、塊1、塊2為數(shù)據(jù)塊,可用于存貯數(shù)據(jù)。數(shù)據(jù)塊可作兩種應(yīng)用:

用作一般的數(shù)據(jù)保存,可以進(jìn)行讀、寫操作。

用作數(shù)據(jù)值,可以進(jìn)行初始化值、加值、減值、讀值操作。

每個(gè)扇區(qū)的塊3為控制塊,包括了密碼A、存取控制、密碼B。具體結(jié)構(gòu)如下:

每個(gè)扇區(qū)的密碼和存取控制都是獨(dú)立的,可以根據(jù)實(shí)際需要設(shè)定各自的密碼及存取控制。存取控制為4個(gè)字節(jié),共32位,扇區(qū)中的每個(gè)塊(包括數(shù)據(jù)塊和控制塊)的存取條件是由密碼和存取控制共同決定的,在存取控制中每個(gè)塊都有相應(yīng)的三個(gè)控制位,定義如下:

塊0:C10   C20   C30塊1:C11   C21   C31塊2:C12   C22   C32塊3:C13   C23   C33

三個(gè)控制位以正和反兩種形式存在于存取控制字節(jié)中,決定了該塊的訪問(wèn)權(quán)限(如進(jìn)行減值操作必須驗(yàn)證KEY A,進(jìn)行加值操作必須驗(yàn)證KEY B,等等)。

三個(gè)控制位在存取控制字節(jié)中的位置,以塊0為例(對(duì)塊0的控制):

數(shù)據(jù)塊(塊0、塊1、塊2)的存取控制如下:

(KeyA|B 表示密碼A或密碼B,Never表示任何條件下不能實(shí)現(xiàn))

例如:當(dāng)塊0的存取控制位C10 C20 C30=1 0 0時(shí),驗(yàn)證密碼A或密碼B正確后可讀;驗(yàn)證密碼B正確后可寫;不能進(jìn)行加值、減值操作。

控制塊塊3的存取控制與數(shù)據(jù)塊(塊0、1、2)不同,它的存取控制如下:

例如:當(dāng)塊3的存取控制位C13 C23 C33=1 0 0時(shí),表示:

       密碼A:不可讀,驗(yàn)證KEYA或KEYB正確后,可寫(更改)。
       存取控制:驗(yàn)證KEYA或KEYB正確后,可讀、可寫。
       密碼B:驗(yàn)證KEYA或KEYB正確后,可讀、可寫。

M1射頻卡與讀寫器的通訊

3.2引腳選擇

模塊接線圖

3.3移植至工程

移植步驟中的導(dǎo)入.c和.h文件與【CW32模塊使用】DHT11溫濕度傳感器相同,只是將.c和.h文件更改為bsp_rc522.c與bsp_rc522.h。這里不再過(guò)多講述,移植完成后面修改相關(guān)代碼。

在文件bsp_rc522.c中,編寫如下代碼。

/* * Change Logs: * Date           Author       Notes * 2024-06-21     LCKFB-LP    first version */#include "bsp_rc522.h"
/****************************************************************** * 函 數(shù) 名 稱:RC522_Init * 函 數(shù) 說(shuō) 明:IC卡感應(yīng)模塊配置 * 函 數(shù) 形 參:無(wú) * 函 數(shù) 返 回:無(wú) * 作       者:LC * 備       注:******************************************************************/void RC522_Init(void){        //開啟GPIO時(shí)鐘        RCC_GPIO_ENABLE();
        GPIO_InitTypeDef  GPIO_InitStructure;
        // SDA SCK MOSI RST        GPIO_InitStructure.Pins = GPIO_CS|GPIO_SCK|GPIO_MOSI|GPIO_RST;        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;        GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;        GPIO_Init(PORT_GPIO, &GPIO_InitStructure);        GPIO_WritePin(PORT_GPIO, GPIO_CS|GPIO_SCK|GPIO_MOSI|GPIO_RST, GPIO_Pin_SET);
        // MISO        GPIO_InitStructure.Pins = GPIO_MISO;        GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;        GPIO_Init(PORT_GPIO, &GPIO_InitStructure);}


////////////////軟件模擬SPI與RC522通信////////////////////////////////////////////* 軟件模擬SPI發(fā)送一個(gè)字節(jié)數(shù)據(jù),高位先行 */void RC522_SPI_SendByte( uint8_t byte ){        uint8_t n;        for( n=0;n<8;n++ )        {                if( byte&0x80 )                        RC522_MOSI_1();                else                        RC522_MOSI_0();
                delay_us(200);                RC522_SCK_0();                delay_us(200);                RC522_SCK_1();                delay_us(200);
                byte<<=1;        }}
/* 軟件模擬SPI讀取一個(gè)字節(jié)數(shù)據(jù),先讀高位 */uint8_t RC522_SPI_ReadByte( void ){        uint8_t n,data;        for( n=0;n<8;n++ )        {                data<<=1;                RC522_SCK_0();                delay_us(200);
                if( RC522_MISO_GET()==1 )                        data|=0x01;
                delay_us(200);                RC522_SCK_1();                delay_us(200);

        }        return data;}
//////////////////////////STM32對(duì)RC522寄存器的操作///////////////////////////////////*  讀取RC522指定寄存器的值    向RC522指定寄存器中寫入指定的數(shù)據(jù)    置位RC522指定寄存器的指定位    清位RC522指定寄存器的指定位*/
/**  * @brief  :讀取RC522指定寄存器的值        * @param  :Address:寄存器的地址  * @retval :寄存器的值*/uint8_t RC522_Read_Register( uint8_t Address ){        uint8_t data,Addr;
        Addr = ( (Address<<1)&0x7E )|0x80;
        RC522_CS_Enable();        RC522_SPI_SendByte( Addr );        data = RC522_SPI_ReadByte();//讀取寄存器中的值        RC522_CS_Disable();
        return data;}
/**  * @brief  :向RC522指定寄存器中寫入指定的數(shù)據(jù)  * @param  :Address:寄存器地址                                      data:要寫入寄存器的數(shù)據(jù)  * @retval :無(wú)*/void RC522_Write_Register( uint8_t Address, uint8_t data ){        uint8_t Addr;
        Addr = ( Address<<1 )&0x7E;
        RC522_CS_Enable();        RC522_SPI_SendByte( Addr );        RC522_SPI_SendByte( data );        RC522_CS_Disable();
}
/**  * @brief  :置位RC522指定寄存器的指定位  * @param  :Address:寄存器地址                                      mask:置位值  * @retval :無(wú)*/void RC522_SetBit_Register( uint8_t Address, uint8_t mask ){        uint8_t temp;        /* 獲取寄存器當(dāng)前值 */        temp = RC522_Read_Register( Address );        /* 對(duì)指定位進(jìn)行置位操作后,再將值寫入寄存器 */        RC522_Write_Register( Address, temp|mask );}
/**  * @brief  :清位RC522指定寄存器的指定位  * @param  :Address:寄存器地址                      mask:清位值  * @retval :無(wú)*/void RC522_ClearBit_Register( uint8_t Address, uint8_t mask ){        uint8_t temp;        /* 獲取寄存器當(dāng)前值 */        temp = RC522_Read_Register( Address );        /* 對(duì)指定位進(jìn)行清位操作后,再將值寫入寄存器 */        RC522_Write_Register( Address, temp&(~mask) );}
///////////////////STM32對(duì)RC522的基礎(chǔ)通信////////////////////////////////////*    開啟天線    關(guān)閉天線    復(fù)位RC522    設(shè)置RC522工作方式*/
/**  * @brief  :開啟天線  * @param  :無(wú)  * @retval :無(wú)*/void RC522_Antenna_On( void ){        uint8_t k;        k = RC522_Read_Register( TxControlReg );        /* 判斷天線是否開啟 */        if( !( k&0x03 ) )                RC522_SetBit_Register( TxControlReg, 0x03 );}
/**  * @brief  :關(guān)閉天線  * @param  :無(wú)  * @retval :無(wú)*/void RC522_Antenna_Off( void ){        /* 直接對(duì)相應(yīng)位清零 */        RC522_ClearBit_Register( TxControlReg, 0x03 );}

/**  * @brief  :復(fù)位RC522  * @param  :無(wú)  * @retval :無(wú)*/void RC522_Rese( void ){        RC522_Reset_Disable();        delay_us ( 1 );        RC522_Reset_Enable();        delay_us ( 1 );        RC522_Reset_Disable();        delay_us ( 1 );        RC522_Write_Register( CommandReg, 0x0F );        while( RC522_Read_Register( CommandReg )&0x10 )                ;
        /* 緩沖一下 */        delay_us ( 1 );        RC522_Write_Register( ModeReg, 0x3D );       //定義發(fā)送和接收常用模式        RC522_Write_Register( TReloadRegL, 30 );     //16位定時(shí)器低位        RC522_Write_Register( TReloadRegH, 0 );      //16位定時(shí)器高位        RC522_Write_Register( TModeReg, 0x8D );      //內(nèi)部定時(shí)器的設(shè)置        RC522_Write_Register( TPrescalerReg, 0x3E ); //設(shè)置定時(shí)器分頻系數(shù)        RC522_Write_Register( TxAutoReg, 0x40 );     //調(diào)制發(fā)送信號(hào)為100%ASK}

/**  * @brief  :設(shè)置RC522的工作方式  * @param  :Type:工作方式  * @retval :無(wú)  M500PcdConfigISOType*/void RC522_Config_Type( char Type ){        if( Type=='A' )        {                RC522_ClearBit_Register( Status2Reg, 0x08 );                RC522_Write_Register( ModeReg, 0x3D );                RC522_Write_Register( RxSelReg, 0x86 );                RC522_Write_Register( RFCfgReg, 0x7F );                RC522_Write_Register( TReloadRegL, 30 );                RC522_Write_Register( TReloadRegH, 0 );                RC522_Write_Register( TModeReg, 0x8D );                RC522_Write_Register( TPrescalerReg, 0x3E );                delay_us(2);                /* 開天線 */                RC522_Antenna_On();        }}
/////////////////////////STM32控制RC522與M1卡的通信////////////////////////////////////////*    通過(guò)RC522和M1卡通訊(數(shù)據(jù)的雙向傳輸)    尋卡    防沖突    用RC522計(jì)算CRC16(循環(huán)冗余校驗(yàn))    選定卡片    校驗(yàn)卡片密碼    在M1卡的指定塊地址寫入指定數(shù)據(jù)    讀取M1卡的指定塊地址的數(shù)據(jù)    讓卡片進(jìn)入休眠模式*/
/**  * @brief  :通過(guò)RC522和ISO14443卡通訊* @param  :ucCommand:RC522命令字 *          pInData:通過(guò)RC522發(fā)送到卡片的數(shù)據(jù) *          ucInLenByte:發(fā)送數(shù)據(jù)的字節(jié)長(zhǎng)度 *          pOutData:接收到的卡片返回?cái)?shù)據(jù) *          pOutLenBit:返回?cái)?shù)據(jù)的位長(zhǎng)度  * @retval :狀態(tài)值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認(rèn)證          ucIrqEn   = 0x12;                //允許錯(cuò)誤中斷請(qǐng)求ErrIEn  允許空閑中斷IdleIEn          ucWaitFor = 0x10;                //認(rèn)證尋卡等待時(shí)候 查詢空閑中斷標(biāo)志位          break;
       case PCD_TRANSCEIVE:                //接收發(fā)送 發(fā)送接收          ucIrqEn   = 0x77;                //允許TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEn          ucWaitFor = 0x30;                //尋卡等待時(shí)候 查詢接收中斷標(biāo)志位與 空閑中斷標(biāo)志位          break;
       default:         break;
    }
    RC522_Write_Register ( ComIEnReg, ucIrqEn | 0x80 );                //IRqInv置位管腳IRQ與Status1Reg的IRq位的值相反    RC522_ClearBit_Register ( ComIrqReg, 0x80 );                        //Set1該位清零時(shí),CommIRqReg的屏蔽位清零    RC522_Write_Register ( CommandReg, PCD_IDLE );                //寫空閑命令    RC522_SetBit_Register ( FIFOLevelReg, 0x80 );                        //置位FlushBuffer清除內(nèi)部FIFO的讀和寫指針以及ErrReg的BufferOvfl標(biāo)志位被清除
    for ( ul = 0; ul < ucInLenByte; ul ++ )                  RC522_Write_Register ( FIFODataReg, pInData [ ul ] );                    //寫數(shù)據(jù)進(jìn)FIFOdata
    RC522_Write_Register ( CommandReg, ucCommand );                                        //寫命令

    if ( ucCommand == PCD_TRANSCEIVE )                        RC522_SetBit_Register(BitFramingReg,0x80);                                  //StartSend置位啟動(dòng)數(shù)據(jù)發(fā)送 該位與收發(fā)命令使用時(shí)才有效
    ul = 1000;//根據(jù)時(shí)鐘頻率調(diào)整,操作M1卡最大等待時(shí)間25ms
    do                                                                                                                 //認(rèn)證 與尋卡等待時(shí)間    {         ucN = RC522_Read_Register ( ComIrqReg );                                                        //查詢事件中斷         ul --;    } while ( ( ul != 0 ) && ( ! ( ucN & 0x01 ) ) && ( ! ( ucN & ucWaitFor ) ) );                //退出條件i=0,定時(shí)器中斷,與寫空閑命令
    RC522_ClearBit_Register ( BitFramingReg, 0x80 );                                        //清理允許StartSend位
    if ( ul != 0 )    {        if ( ! ( RC522_Read_Register ( ErrorReg ) & 0x1B ) )                        //讀錯(cuò)誤標(biāo)志寄存器BufferOfI CollErr ParityErr ProtocolErr        {        cStatus = MI_OK;
        if ( ucN & ucIrqEn & 0x01 )                                        //是否發(fā)生定時(shí)器中斷          cStatus = MI_NOTAGERR;
        if ( ucCommand == PCD_TRANSCEIVE )        {                ucN = RC522_Read_Register ( FIFOLevelReg );                        //讀FIFO中保存的字節(jié)數(shù)
                ucLastBits = RC522_Read_Register ( ControlReg ) & 0x07;        //最后接收到得字節(jié)的有效位數(shù)
                if ( ucLastBits )                        * pOutLenBit = ( ucN - 1 ) * 8 + ucLastBits;           //N個(gè)字節(jié)數(shù)減去1(最后一個(gè)字節(jié))+最后一位的位數(shù) 讀取到的數(shù)據(jù)總位數(shù)                else                        * pOutLenBit = ucN * 8;                                           //最后接收到的字節(jié)整個(gè)字節(jié)有效
                if ( ucN == 0 )        ucN = 1;
                if ( ucN > MAXRLEN )                        ucN = MAXRLEN;
                for ( ul = 0; ul < ucN; ul ++ )                  pOutData [ ul ] = RC522_Read_Register ( FIFODataReg );                }        }        else        cStatus = MI_ERR;    }
   RC522_SetBit_Register ( ControlReg, 0x80 );           // stop timer now   RC522_Write_Register ( CommandReg, PCD_IDLE );
   return cStatus;}


/**  * @brief  :尋卡* @param  ucReq_code,尋卡方式*                      = 0x52:尋感應(yīng)區(qū)內(nèi)所有符合14443A標(biāo)準(zhǔn)的卡 *                     = 0x26:尋未進(jìn)入休眠狀態(tài)的卡 *         pTagType,卡片類型代碼 *                   = 0x4400:Mifare_UltraLight *                   = 0x0400:Mifare_One(S50) *                   = 0x0200:Mifare_One(S70) *                   = 0x0800:Mifare_Pro(X)) *                   = 0x4403:Mifare_DESFire  * @retval :狀態(tài)值MI_OK,成功*/char PcdRequest ( uint8_t ucReq_code, uint8_t * pTagType ){   char cStatus;   uint8_t ucComMF522Buf [ MAXRLEN ];   uint32_t ulLen;
   RC522_ClearBit_Register ( Status2Reg, 0x08 );        //清理指示MIFARECyptol單元接通以及所有卡的數(shù)據(jù)通信被加密的情況   RC522_Write_Register ( BitFramingReg, 0x07 );        //        發(fā)送的最后一個(gè)字節(jié)的 七位   RC522_SetBit_Register ( TxControlReg, 0x03 );        //TX1,TX2管腳的輸出信號(hào)傳遞經(jīng)發(fā)送調(diào)制的13.46的能量載波信號(hào)
   ucComMF522Buf [ 0 ] = ucReq_code;                //存入尋卡方式        /* PCD_TRANSCEIVE:發(fā)送并接收數(shù)據(jù)的命令,RC522向卡片發(fā)送尋卡命令,卡片返回卡的型號(hào)代碼到ucComMF522Buf中 */   cStatus = PcdComMF522 ( PCD_TRANSCEIVE,        ucComMF522Buf, 1, ucComMF522Buf, & ulLen );        //尋卡
   if ( ( cStatus == MI_OK ) && ( ulLen == 0x10 ) )        //尋卡成功返回卡類型   {                 /* 接收卡片的型號(hào)代碼 */       * pTagType = ucComMF522Buf [ 0 ];       * ( pTagType + 1 ) = ucComMF522Buf [ 1 ];   }   else     cStatus = MI_ERR;     return cStatus;}


/**  * @brief  :防沖突        * @param  :Snr:卡片序列,4字節(jié),會(huì)返回選中卡片的序列  * @retval :狀態(tài)值MI_OK,成功*/char PcdAnticoll ( uint8_t * pSnr ){    char cStatus;    uint8_t uc, ucSnr_check = 0;    uint8_t ucComMF522Buf [ MAXRLEN ];          uint32_t ulLen;
    RC522_ClearBit_Register ( Status2Reg, 0x08 );                //清MFCryptol On位 只有成功執(zhí)行MFAuthent命令后,該位才能置位    RC522_Write_Register ( BitFramingReg, 0x00);                //清理寄存器 停止收發(fā)    RC522_ClearBit_Register ( CollReg, 0x80 );                        //清ValuesAfterColl所有接收的位在沖突后被清除
    ucComMF522Buf [ 0 ] = 0x93;        //卡片防沖突命令    ucComMF522Buf [ 1 ] = 0x20;
          /* 將卡片防沖突命令通過(guò)RC522傳到卡片中,返回的是被選中卡片的序列 */    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;    }    RC522_SetBit_Register ( CollReg, 0x80 );    return cStatus;}


/** * @brief   :用RC522計(jì)算CRC16(循環(huán)冗余校驗(yàn))        * @param  :pIndata:計(jì)算CRC16的數(shù)組 *            ucLen:計(jì)算CRC16的數(shù)組字節(jié)長(zhǎng)度 *            pOutData:存放計(jì)算結(jié)果存放的首地址  * @retval :狀態(tài)值MI_OK,成功*/void CalulateCRC ( uint8_t * pIndata, u8 ucLen, uint8_t * pOutData ){    uint8_t uc, ucN;

    RC522_ClearBit_Register(DivIrqReg,0x04);    RC522_Write_Register(CommandReg,PCD_IDLE);    RC522_SetBit_Register(FIFOLevelReg,0x80);
    for ( uc = 0; uc < ucLen; uc ++)            RC522_Write_Register ( FIFODataReg, * ( pIndata + uc ) );
    RC522_Write_Register ( CommandReg, PCD_CALCCRC );
    uc = 0xFF;
    do    {        ucN = RC522_Read_Register ( DivIrqReg );        uc --;    } while ( ( uc != 0 ) && ! ( ucN & 0x04 ) );
    pOutData [ 0 ] = RC522_Read_Register ( CRCResultRegL );    pOutData [ 1 ] = RC522_Read_Register ( CRCResultRegM );
}


/**  * @brief   :選定卡片  * @param  :pSnr:卡片序列號(hào),4字節(jié)  * @retval :狀態(tài)值MI_OK,成功*/char PcdSelect ( uint8_t * pSnr ){    char ucN;    uint8_t uc;          uint8_t ucComMF522Buf [ MAXRLEN ];    uint32_t  ulLen;    /* PICC_ANTICOLL1:防沖突命令 */    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 ] );
    RC522_ClearBit_Register ( 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;
}


/**  * @brief   :校驗(yàn)卡片密碼  * @param  :ucAuth_mode:密碼驗(yàn)證模式  *                     = 0x60,驗(yàn)證A密鑰  *                     = 0x61,驗(yàn)證B密鑰  *           ucAddr:塊地址  *           pKey:密碼  *           pSnr:卡片序列號(hào),4字節(jié)  * @retval :狀態(tài)值MI_OK,成功*/char PcdAuthState ( uint8_t ucAuth_mode, uint8_t ucAddr, uint8_t * pKey, uint8_t * pSnr ){    char cStatus;          uint8_t uc, ucComMF522Buf [ MAXRLEN ];    uint32_t ulLen;
    ucComMF522Buf [ 0 ] = ucAuth_mode;    ucComMF522Buf [ 1 ] = ucAddr;          /* 前倆字節(jié)存儲(chǔ)驗(yàn)證模式和塊地址,2~8字節(jié)存儲(chǔ)密碼(6個(gè)字節(jié)),8~14字節(jié)存儲(chǔ)序列號(hào) */    for ( uc = 0; uc < 6; uc ++ )            ucComMF522Buf [ uc + 2 ] = * ( pKey + uc );
    for ( uc = 0; uc < 6; uc ++ )            ucComMF522Buf [ uc + 8 ] = * ( pSnr + uc );    /* 進(jìn)行冗余校驗(yàn),14~16倆個(gè)字節(jié)存儲(chǔ)校驗(yàn)結(jié)果 */    cStatus = PcdComMF522 ( PCD_AUTHENT, ucComMF522Buf, 12, ucComMF522Buf, & ulLen );          /* 判斷驗(yàn)證是否成功 */    if ( ( cStatus != MI_OK ) || ( ! ( RC522_Read_Register ( Status2Reg ) & 0x08 ) ) )      cStatus = MI_ERR;
    return cStatus;
}

/**  * @brief   :在M1卡的指定塊地址寫入指定數(shù)據(jù)  * @param  :ucAddr:塊地址  *           pData:寫入的數(shù)據(jù),16字節(jié)  * @retval :狀態(tài)值MI_OK,成功*/char PcdWrite ( uint8_t ucAddr, uint8_t * pData ){    char cStatus;          uint8_t uc, ucComMF522Buf [ MAXRLEN ];    uint32_t ulLen;
    ucComMF522Buf [ 0 ] = PICC_WRITE;//寫塊命令    ucComMF522Buf [ 1 ] = ucAddr;//寫塊地址
          /* 進(jìn)行循環(huán)冗余校驗(yàn),將結(jié)果存儲(chǔ)在& ucComMF522Buf [ 2 ] */    CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
        /* PCD_TRANSCEIVE:發(fā)送并接收數(shù)據(jù)命令,通過(guò)RC522向卡片發(fā)送寫塊命令 */    cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
                /* 通過(guò)卡片返回的信息判斷,RC522是否與卡片正常通信 */    if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )      cStatus = MI_ERR;
    if ( cStatus == MI_OK )    {                        //memcpy(ucComMF522Buf, pData, 16);                        /* 將要寫入的16字節(jié)的數(shù)據(jù),傳入ucComMF522Buf數(shù)組中 */      for ( uc = 0; uc < 16; uc ++ )                          ucComMF522Buf [ uc ] = * ( pData + uc );                        /* 冗余校驗(yàn) */      CalulateCRC ( ucComMF522Buf, 16, & ucComMF522Buf [ 16 ] );      /* 通過(guò)RC522,將16字節(jié)數(shù)據(jù)包括2字節(jié)校驗(yàn)結(jié)果寫入卡片中 */      cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf, & ulLen );                        /* 判斷寫地址是否成功 */                        if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )        cStatus = MI_ERR;    }    return cStatus;}

/**  * @brief   :讀取M1卡的指定塊地址的數(shù)據(jù)  * @param  :ucAddr:塊地址  *           pData:讀出的數(shù)據(jù),16字節(jié)  * @retval :狀態(tài)值MI_OK,成功*/char PcdRead ( uint8_t ucAddr, uint8_t * pData ){    char cStatus;          uint8_t uc, ucComMF522Buf [ MAXRLEN ];    uint32_t ulLen;
    ucComMF522Buf [ 0 ] = PICC_READ;    ucComMF522Buf [ 1 ] = ucAddr;          /* 冗余校驗(yàn) */    CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );    /* 通過(guò)RC522將命令傳給卡片 */    cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
          /* 如果傳輸正常,將讀取到的數(shù)據(jù)傳入pData中 */    if ( ( cStatus == MI_OK ) && ( ulLen == 0x90 ) )    {                        for ( uc = 0; uc < 16; uc ++ )        * ( pData + uc ) = ucComMF522Buf [ uc ];    }    else      cStatus = MI_ERR;
    return cStatus;
}

/**  * @brief   :讓卡片進(jìn)入休眠模式  * @param  :無(wú)  * @retval :狀態(tài)值MI_OK,成功*/char PcdHalt( void ){        uint8_t ucComMF522Buf [ MAXRLEN ];        uint32_t  ulLen;
  ucComMF522Buf [ 0 ] = PICC_HALT;  ucComMF522Buf [ 1 ] = 0;
  CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );         PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
  return MI_OK;
}

在文件bsp_rc522.h中,編寫如下代碼。

/* * Change Logs: * Date           Author       Notes * 2024-06-21     LCKFB-LP    first version */
#ifndef _BSP_RC522_H#define _BSP_RC522_H
#include "board.h"
#ifndef u8#define u8 uint8_t#endif
#ifndef u16#define u16 uint16_t#endif
#ifndef u32#define u32 uint32_t#endif

#define RCC_GPIO_ENABLE()   __RCC_GPIOA_CLK_ENABLE()#define PORT_GPIO           CW_GPIOA//SDA#define GPIO_CS             GPIO_PIN_1//SCK#define GPIO_SCK            GPIO_PIN_2//MOSI#define GPIO_MOSI           GPIO_PIN_3//RST#define GPIO_RST            GPIO_PIN_5//MISO#define GPIO_MISO           GPIO_PIN_4


/* IO口操作函數(shù) */#define   RC522_CS_Enable()         GPIO_WritePin(PORT_GPIO, GPIO_CS,GPIO_Pin_RESET)#define   RC522_CS_Disable()        GPIO_WritePin(PORT_GPIO, GPIO_CS,GPIO_Pin_SET)
#define   RC522_Reset_Enable()      GPIO_WritePin(PORT_GPIO, GPIO_RST,GPIO_Pin_RESET)#define   RC522_Reset_Disable()     GPIO_WritePin(PORT_GPIO, GPIO_RST,GPIO_Pin_SET)
#define   RC522_SCK_0()             GPIO_WritePin(PORT_GPIO, GPIO_SCK,GPIO_Pin_RESET)#define   RC522_SCK_1()             GPIO_WritePin(PORT_GPIO, GPIO_SCK,GPIO_Pin_SET)
#define   RC522_MOSI_0()            GPIO_WritePin(PORT_GPIO, GPIO_MOSI,GPIO_Pin_RESET)#define   RC522_MOSI_1()            GPIO_WritePin(PORT_GPIO, GPIO_MOSI,GPIO_Pin_SET)
#define   RC522_MISO_GET()          GPIO_ReadPin(PORT_GPIO, GPIO_MISO)

//RC522命令字#define PCD_IDLE              0x00               //取消當(dāng)前命令#define PCD_AUTHENT           0x0E               //驗(yàn)證密鑰#define PCD_RECEIVE           0x08               //接收數(shù)據(jù)#define PCD_TRANSMIT          0x04               //發(fā)送數(shù)據(jù)#define PCD_TRANSCEIVE        0x0C               //發(fā)送并接收數(shù)據(jù)#define PCD_RESETPHASE        0x0F               //復(fù)位#define PCD_CALCCRC           0x03               //CRC計(jì)算
//Mifare_One卡片命令字#define PICC_REQIDL           0x26               //尋天線區(qū)內(nèi)未進(jìn)入休眠狀態(tài)#define PICC_REQALL           0x52               //尋天線區(qū)內(nèi)全部卡#define PICC_ANTICOLL1        0x93               //防沖撞#define PICC_ANTICOLL2        0x95               //防沖撞#define PICC_AUTHENT1A        0x60               //驗(yàn)證A密鑰#define PICC_AUTHENT1B        0x61               //驗(yàn)證B密鑰#define PICC_READ             0x30               //讀塊#define PICC_WRITE            0xA0               //寫塊#define PICC_DECREMENT        0xC0               //扣款#define PICC_INCREMENT        0xC1               //充值#define PICC_RESTORE          0xC2               //調(diào)塊數(shù)據(jù)到緩沖區(qū)#define PICC_TRANSFER         0xB0               //保存緩沖區(qū)中數(shù)據(jù)#define PICC_HALT             0x50               //休眠
/* RC522  FIFO長(zhǎng)度定義 */#define DEF_FIFO_LENGTH       64                 //FIFO size=64byte#define MAXRLEN  18

/* RC522寄存器定義 */// PAGE 0#define     RFU00                 0x00    //保留#define     CommandReg            0x01    //啟動(dòng)和停止命令的執(zhí)行#define     ComIEnReg             0x02    //中斷請(qǐng)求傳遞的使能(Enable/Disable)#define     DivlEnReg             0x03    //中斷請(qǐng)求傳遞的使能#define     ComIrqReg             0x04    //包含中斷請(qǐng)求標(biāo)志#define     DivIrqReg             0x05    //包含中斷請(qǐng)求標(biāo)志#define     ErrorReg              0x06    //錯(cuò)誤標(biāo)志,指示執(zhí)行的上個(gè)命令的錯(cuò)誤狀態(tài)#define     Status1Reg            0x07    //包含通信的狀態(tài)標(biāo)識(shí)#define     Status2Reg            0x08    //包含接收器和發(fā)送器的狀態(tài)標(biāo)志#define     FIFODataReg           0x09    //64字節(jié)FIFO緩沖區(qū)的輸入和輸出#define     FIFOLevelReg          0x0A    //指示FIFO中存儲(chǔ)的字節(jié)數(shù)#define     WaterLevelReg         0x0B    //定義FIFO下溢和上溢報(bào)警的FIFO深度#define     ControlReg            0x0C    //不同的控制寄存器#define     BitFramingReg         0x0D    //面向位的幀的調(diào)節(jié)#define     CollReg               0x0E    //RF接口上檢測(cè)到的第一個(gè)位沖突的位的位置#define     RFU0F                 0x0F    //保留// PAGE 1#define     RFU10                 0x10    //保留#define     ModeReg               0x11    //定義發(fā)送和接收的常用模式#define     TxModeReg             0x12    //定義發(fā)送過(guò)程的數(shù)據(jù)傳輸速率#define     RxModeReg             0x13    //定義接收過(guò)程中的數(shù)據(jù)傳輸速率#define     TxControlReg          0x14    //控制天線驅(qū)動(dòng)器管教TX1和TX2的邏輯特性#define     TxAutoReg             0x15    //控制天線驅(qū)動(dòng)器的設(shè)置#define     TxSelReg              0x16    //選擇天線驅(qū)動(dòng)器的內(nèi)部源#define     RxSelReg              0x17    //選擇內(nèi)部的接收器設(shè)置#define     RxThresholdReg        0x18    //選擇位譯碼器的閾值#define     DemodReg              0x19    //定義解調(diào)器的設(shè)置#define     RFU1A                 0x1A    //保留#define     RFU1B                 0x1B    //保留#define     MifareReg             0x1C    //控制ISO 14443/MIFARE模式中106kbit/s的通信#define     RFU1D                 0x1D    //保留#define     RFU1E                 0x1E    //保留#define     SerialSpeedReg        0x1F    //選擇串行UART接口的速率// PAGE 2#define     RFU20                 0x20    //保留#define     CRCResultRegM         0x21    //顯示CRC計(jì)算的實(shí)際MSB值#define     CRCResultRegL         0x22    //顯示CRC計(jì)算的實(shí)際LSB值#define     RFU23                 0x23    //保留#define     ModWidthReg           0x24    //控制ModWidth的設(shè)置#define     RFU25                 0x25    //保留#define     RFCfgReg              0x26    //配置接收器增益#define     GsNReg                0x27    //選擇天線驅(qū)動(dòng)器管腳(TX1和TX2)的調(diào)制電導(dǎo)#define     CWGsCfgReg            0x28    //選擇天線驅(qū)動(dòng)器管腳的調(diào)制電導(dǎo)#define     ModGsCfgReg           0x29    //選擇天線驅(qū)動(dòng)器管腳的調(diào)制電導(dǎo)#define     TModeReg              0x2A    //定義內(nèi)部定時(shí)器的設(shè)置#define     TPrescalerReg         0x2B    //定義內(nèi)部定時(shí)器的設(shè)置#define     TReloadRegH           0x2C    //描述16位長(zhǎng)的定時(shí)器重裝值#define     TReloadRegL           0x2D    //描述16位長(zhǎng)的定時(shí)器重裝值#define     TCounterValueRegH     0x2E#define     TCounterValueRegL     0x2F    //顯示16位長(zhǎng)的實(shí)際定時(shí)器值// PAGE 3#define     RFU30                 0x30    //保留#define     TestSel1Reg           0x31    //常用測(cè)試信號(hào)配置#define     TestSel2Reg           0x32    //常用測(cè)試信號(hào)配置和PRBS控制#define     TestPinEnReg          0x33    //D1-D7輸出驅(qū)動(dòng)器的使能管腳(僅用于串行接口#define     TestPinValueReg       0x34    //定義D1-D7用作I/O總線時(shí)的值#define     TestBusReg            0x35    //顯示內(nèi)部測(cè)試總線的狀態(tài)#define     AutoTestReg           0x36    //控制數(shù)字自測(cè)試#define     VersionReg            0x37    //顯示版本#define     AnalogTestReg         0x38    //控制管腳AUX1和AUX2#define     TestDAC1Reg           0x39    //定義TestDAC1的測(cè)試值#define     TestDAC2Reg           0x3A    //定義TestDAC2的測(cè)試值#define     TestADCReg            0x3B    //顯示ADCI和Q通道的實(shí)際值#define     RFU3C                 0x3C    //保留#define     RFU3D                 0x3D    //保留#define     RFU3E                 0x3E    //保留#define     RFU3F                                          0x3F    //保留
/* 和RC522通信時(shí)返回的錯(cuò)誤代碼 */#define         MI_OK                 0x26#define         MI_NOTAGERR           0xcc#define         MI_ERR                0xbb
/**********************************************************************/
void RC522_Init(void);/* IO口初始化 */////////////////軟件模擬SPI與RC522通信///////////////////////////////////////////void RC522_SPI_SendByte( uint8_t byte );/* 軟件模擬SPI發(fā)送一個(gè)字節(jié)數(shù)據(jù),高位先行 */uint8_t RC522_SPI_ReadByte( void );/* 軟件模擬SPI讀取一個(gè)字節(jié)數(shù)據(jù),先讀高位 */uint8_t RC522_Read_Register( uint8_t Address );//讀取RC522指定寄存器的值void RC522_Write_Register( uint8_t Address, uint8_t data );//向RC522指定寄存器中寫入指定的數(shù)據(jù)void RC522_SetBit_Register( uint8_t Address, uint8_t mask );//置位RC522指定寄存器的指定位void RC522_ClearBit_Register( uint8_t Address, uint8_t mask );//清位RC522指定寄存器的指定位/////////////////////STM32對(duì)RC522的基礎(chǔ)通信///////////////////////////////////void RC522_Antenna_On( void );//開啟天線void RC522_Antenna_Off( void );//關(guān)閉天線void RC522_Rese( void );//復(fù)位RC522void RC522_Config_Type( char Type );//設(shè)置RC522的工作方式/////////////////////////STM32控制RC522與M1的通信///////////////////////////////////////char PcdComMF522 ( uint8_t ucCommand, uint8_t * pInData, uint8_t ucInLenByte, uint8_t * pOutData, uint32_t * pOutLenBit );//通過(guò)RC522和ISO14443卡通訊char PcdRequest ( uint8_t ucReq_code, uint8_t * pTagType );//尋卡char PcdAnticoll ( uint8_t * pSnr );//防沖突void CalulateCRC ( uint8_t * pIndata, u8 ucLen, uint8_t * pOutData );//用RC522計(jì)算CRC16(循環(huán)冗余校驗(yàn))char PcdSelect ( uint8_t * pSnr );//選定卡片char PcdAuthState ( uint8_t ucAuth_mode, uint8_t ucAddr, uint8_t * pKey, uint8_t * pSnr );//校驗(yàn)卡片密碼char PcdWrite ( uint8_t ucAddr, uint8_t * pData );//在M1卡的指定塊地址寫入指定數(shù)據(jù)char PcdRead ( uint8_t ucAddr, uint8_t * pData );//讀取M1卡的指定塊地址的數(shù)據(jù)char PcdHalt( void );//讓卡片進(jìn)入休眠模式

#endif

移植驗(yàn)證

在自己工程中的main主函數(shù)中,編寫如下。

/* * Change Logs: * Date           Author       Notes * 2024-06-21     LCKFB-LP    first version */#include "board.h"#include "stdio.h"#include "bsp_uart.h"#include "bsp_rc522.h"
/* 卡的ID存儲(chǔ),32位,4字節(jié) */u8 ucArray_ID [ 4 ];uint8_t ucStatusReturn;    //返回狀態(tài)
int32_t main(void){    int i = 0;
    uint8_t read_write_data[16]={0};//讀寫數(shù)據(jù)緩存    uint8_t card_KEY[6] ={0xff,0xff,0xff,0xff,0xff,0xff};//默認(rèn)密碼
    board_init();    uart1_init(115200U);
    printf ("Init....rn");    RC522_Init( );//IC卡IO口初始化    RC522_Rese( );//復(fù)位RC522    printf ("Start!rn");
    while(1)    {
        /* 尋卡(方式:范圍內(nèi)全部),第一次尋卡失敗后再進(jìn)行一次,尋卡成功時(shí)卡片序列傳入數(shù)組ucArray_ID中 */        if ( ( ucStatusReturn = PcdRequest ( PICC_REQALL, ucArray_ID ) ) != MI_OK )        {                        ucStatusReturn = PcdRequest ( PICC_REQALL, ucArray_ID );        }
        if ( ucStatusReturn == MI_OK  )        {            /* 防沖突操作,被選中的卡片序列傳入數(shù)組ucArray_ID中 */            if ( PcdAnticoll ( ucArray_ID ) == MI_OK )            {                    //輸出卡ID                    printf("ID: %X %X %X %Xrn", ucArray_ID [ 0 ], ucArray_ID [ 1 ], ucArray_ID [ 2 ], ucArray_ID [ 3 ]);
                     //選卡                    if( PcdSelect(ucArray_ID) != MI_OK )                    {    printf("PcdSelect failurern");         }
                    //校驗(yàn)卡片密碼                    //數(shù)據(jù)塊6的密碼A進(jìn)行校驗(yàn)(所有密碼默認(rèn)為16個(gè)字節(jié)的0xff)                    if( PcdAuthState(PICC_AUTHENT1B, 6, card_KEY,  ucArray_ID) != MI_OK )                    {    printf("PcdAuthState failurern");      }
                    //往數(shù)據(jù)塊4寫入數(shù)據(jù)read_write_data                    read_write_data[0] = 0xaa;//將read_write_data的第一位數(shù)據(jù)改為0xaa                    if( PcdWrite(4,read_write_data) != MI_OK )                    {    printf("PcdWrite failurern");          }
                    //將read_write_data的16位數(shù)據(jù),填充為0(清除數(shù)據(jù)的意思)                    memset(read_write_data,0,16);                    delay_us(8);
                    //讀取數(shù)據(jù)塊4的數(shù)據(jù)                    if( PcdRead(4,read_write_data) != MI_OK )                    {    printf("PcdRead failurern");           }
                    //輸出讀出的數(shù)據(jù)                    for( i = 0; i < 16; i++ )                    {                                                    printf("%x ",read_write_data[i]);                    }                    printf("rn");            }        }    }}

移植現(xiàn)象:串口輸出讀取到的卡ID,然后寫入0xaa,之后將數(shù)據(jù)讀出發(fā)送至串口。

模塊移植成功案例代碼:

鏈接:https://pan.baidu.com/s/1G2mJkPs4eGR7D1eKMDLAPw?pwd=LCKF

提取碼:LCKF

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計(jì)資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

以開放、共享、互助為理念,致力于構(gòu)建武漢芯源半導(dǎo)體CW32系列MCU生態(tài)社區(qū)。無(wú)論是嵌入式MCU小自還是想要攻破技術(shù)難題的工程師,亦或是需求解決方案的產(chǎn)品經(jīng)理都可在CW32生態(tài)社區(qū)汲取營(yíng)養(yǎng)、共同成長(zhǎng)。

B站