无法通过 PN532 从 NTAG213 读取内存

物联网 NFC
2021-06-28 10:45:31

我目前正在尝试将几个字节从 PN532 写入 NTAG213 的用户可编程内存并读回这些字节。当 PN532 检测到 NTAG213 接近时,就会发生写入和读取。我从Adafruits库移植所需的功能在这里的ATxmega32A4U。要扫描和读取 NTAG213 卡,我正在使用以下功能。

// Reads cards, beep and long light flash for good card read, short light flash for no card read, lights mostly on for NFC chip not talking right
void TestNFC_ReadTag (void) {
    bool success;
    uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
    uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
    
    /************************************ Everytime Try Reading a Card ***********************************/
    // Check for a good card read
    success = PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength, 1000);
    // If card read is good then beep and long flash of main lights
    if (success) {
        LIGHT_ON();
        EventTimerCreate(200,1,TestingLightsOff);
        for (int nfcBeep = 0; nfcBeep < 300; nfcBeep++) {
            DACB.CH0DATA = 0x700;
            _delay_us(200);
            DACB.CH0DATA = 0x900;
            _delay_us(200);
        }
        DACB.CH0DATA = 0x800;
        _delay_ms(500);         // Reduced from 1000ms to 500ms to avoid WDT reset - Vinay
    }
    // If valid card read then short light flash no beep
    else {
        LIGHT_ON();
        _delay_ms(10);
        LIGHT_OFF();
    }
}

/**************************************************************************/
/*!
Waits for an ISO14443A target to enter the field

@param  cardBaudRate  Baud rate of the card
@param  uid           Pointer to the array that will be populated
with the card's UID (up to 7 bytes)
@param  uidLength     Pointer to the variable that will hold the
length of the card's UID.

@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
bool PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout)
{
    // read data packet
    if (PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) {
        return 0x0;
    }
    
    // check some basic stuff
    /* ISO14443A card response should be in the following format:

    byte            Description
    -------------   ------------------------------------------
    b0              Tags Found
    b1              Tag Number (only one used in this example)
    b2..3           SENS_RES
    b4              SEL_RES
    b5              NFCID Length
    b6..NFCIDLen    NFCID
    */

    if (pn532_packetbuffer[0] != 1)
    return 0;

    uint16_t sens_res = pn532_packetbuffer[2];
    sens_res <<= 8;
    sens_res |= pn532_packetbuffer[3];

    DMSG("ATQA: 0x");  DMSG_HEX(sens_res);
    DMSG("SAK: 0x");  DMSG_HEX(pn532_packetbuffer[4]);
    DMSG("\r\n");

    /* Card appears to be Mifare Classic */
    *uidLength = pn532_packetbuffer[5];

    for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) {
        uid[i] = pn532_packetbuffer[6 + i];
    }

    return 1;
}
/**************************************************************************/
/*!
@brief  Starts the scan

@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532_StartScan(void)
{
    uint8_t pn532_packetbuffer[2];
    uint8_t ret = 0;
    
    pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
    pn532_packetbuffer[1] = 1;
    pn532_packetbuffer[2] = PN532_MIFARE_ISO14443A;
    
    /* Disable the interrupt */
    PORTA.INT1MASK &= ~(1<<PIN7_bp);
    
    /* Send scan command and read acknowledgments */
    if (PN532_writeCommand(pn532_packetbuffer, 3, NULL, 0))
        ret = 0x0;  // command failed
    else
        ret = 0x01;
    
    /* Enable the interrupt */
    PORTA.INT1MASK |= PIN7_bm;
    
    return(ret);
}

写入和读取 NTAG213 的内存。我使用以下功能。

/**************************************************************************/
/*!
    Tries to write an entire 4-bytes data buffer at the specified page
    address.

    @param  page     The page number to write into.  (0x04..0x27).
    @param  buffer   The byte array that contains the data to write.

    @returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532_writePage (uint8_t page, uint8_t *buffer)
{
     if ((page < NTAG_PAGE_START_ADDRESS) || (page > NTAG_PAGE_END_ADDRESS)) {
         DMSG("Page value out of range\n");
         return 0;
     }
    
    /* Prepare the first command */
    pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;               /* Card number */
    pn532_packetbuffer[1] = 1;                                          
    pn532_packetbuffer[2] = NTAG_CMD_WRITE_USER_EEPROM;                 /* NTAG213 Write cmd = 0xA2 */
    pn532_packetbuffer[3] = page;                                       /* page Number (0x04..0x27) */
    memcpy (pn532_packetbuffer + 4, buffer, 4);                         /* Data Payload */
    
    /* Send command to write to NTAG 213 EEPROM */
    if (PN532_writeCommand(pn532_packetbuffer, 8, NULL, 0))
        return 0;

    /* Read the response packet */
    if(PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), 100) < 0)
        return 0;

    return 1;
}

/**************************************************************************/
/*!
    Tries to read an entire 4-bytes page at the specified address.

    @param  page        The page number ((0x04..0x27 in most cases)
    @param  buffer      Pointer to the byte array that will hold the
                        retrieved data (if any)
*/
/**************************************************************************/
uint8_t PN532_readPage (uint8_t page, uint8_t *buffer)
{
    if ((page < NTAG_PAGE_START_ADDRESS) || (page > NTAG_PAGE_END_ADDRESS)) {
        DMSG("Page value out of range\n");
        return 0;
    }
    
    /* Prepare the command */
    pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
    pn532_packetbuffer[1] = 1;                                  /* Card number */
    pn532_packetbuffer[2] = NTAG_CMD_READ_USER_EEPROM;          /* NTAG Read command = 0x30 */
    pn532_packetbuffer[3] = page;                               /* page Number (0x04..0x27) */

    /* Send the command */
    if (PN532_writeCommand(pn532_packetbuffer, 4, NULL, 0))
        return 0;

     /* Read the response packet */
     //if(PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), 100))
     if(PN532_readResponse(pn532_packetbuffer, 20, 100) < 0)
        return 0;
        
    #ifdef PN532_PGREAD_DBG
        printf("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\r\n",
        pn532_packetbuffer[0], pn532_packetbuffer[1], pn532_packetbuffer[2], pn532_packetbuffer[3],
        pn532_packetbuffer[4], pn532_packetbuffer[5], pn532_packetbuffer[6], pn532_packetbuffer[7],
        pn532_packetbuffer[8], pn532_packetbuffer[9], pn532_packetbuffer[10], pn532_packetbuffer[11],
        pn532_packetbuffer[12], pn532_packetbuffer[13], pn532_packetbuffer[14], pn532_packetbuffer[15],
        pn532_packetbuffer[16], pn532_packetbuffer[17], pn532_packetbuffer[18]);
    #endif

    /* If the status isn't 0x00 we probably have an error */
    if (pn532_packetbuffer[0] == 0x00) {
        /* Copy the 4 data bytes to the output buffer         */
        /* Block content starts at byte 1 of a valid response */
        /* Note that the command actually reads 16 bytes or 4  */
        /* pages at a time ... we simply discard the last 12  */
        /* bytes                                              */
        memcpy (buffer, pn532_packetbuffer + 1, 4);
    } 
    else {
        return 0;
    }
    
    // Return OK signal
    return 1;
}

我正在执行一些测试,并在尝试从 NTAG 读取时遇到了一些问题。

以下测试代码的工作意义: PN532 能够读取卡以及从 NTAG 写入和读回用户数据。

 void TestNFCInterrupt_ReadTag (void){
    static uint8_t flag  = 0;
    
    /* Test code. Always perform read or write prior to getting the uuid */
    if(flag == 0){
        testPN532WritePage();
        flag = 1;
    }
    else{
        testPN532ReadPage();
        flag = 0;
    }
    
    /* Needs to restart the scan to detect the NTAG passively */
    PN532_StartScan();
    TestNFC_ReadTag();
    PN532_StartScan();
    
}

但令人惊讶的是,对于下面的代码,检测到卡,写入工作,但是在检测到卡后进行下一次读取时,我收到状态错误响应 0x27,这表明由于当前上下文,该命令是不可接受的关于 PN532,这可以在PN532 用户手册的第 68 页上看到

void TestNFCInterrupt_ReadTag (void){
    static uint8_t flag  = 0;
    
    TestNFC_ReadTag();

    /* Test code. Always perform read or write prior to getting the uuid */
    if(flag == 0){
        testPN532WritePage();
        flag = 1;
    }
    else{
        testPN532ReadPage();
        flag = 0;
    }
    
    /* Needs to restart the scan to detect the NTAG passively */
    PN532_StartScan();
}

此外,这里是 NTAG213 手册。抱歉帖子内容详尽,但教了以上信息,有必要寻求帮助。如果有人能花一些时间检查代码或提出任何建议,我将不胜感激。

1个回答

经过一段时间的调试和代码检查后,我知道问题的发生是由于在void TestNFC_ReadTag (void)函数中检测/读取新卡时的音频蜂鸣声导致了一些中间延迟读取了 UUID,随后调用了读/写页面 API。因此,要写入或读取 NTAG 用户内存,总是需要发出 INDATAEXCHANGE 命令并在读取标签后立即调用读/写页面因此,我对void TestNFC_ReadTag (void)函数进行了一些细微的更改以满足此要求并且可以正常工作。以下是我所做的更改:

/* Made these as static global variables */
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)



// Reads cards, beep and long light flash for good card read, short light flash for no card read, lights mostly on for NFC chip not talking right
void TestNFC_ReadTag (void) {
    bool success;
    static flag = 0;

    /************************************ Everytime Try Reading a Card ***********************************/
    // Check for a good card read
    success = PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength, 1000);
    
    if (success) {

        if(flag == 0){
           testPN532WritePage();
           flag = 1;
        }
        else{
           testPN532ReadPage();
           flag = 0;
     }

        LIGHT_ON();
        EventTimerCreate(200,1,TestingLightsOff);
        for (int nfcBeep = 0; nfcBeep < 300; nfcBeep++) {
            DACB.CH0DATA = 0x700;
            _delay_us(200);
            DACB.CH0DATA = 0x900;
            _delay_us(200);
        }
        DACB.CH0DATA = 0x800;
        _delay_ms(500);         // Reduced from 1000ms to 500ms to avoid WDT reset - Vinay
    }
    // If Invalid card read then short light flash no beep
    else {
        LIGHT_ON();
        _delay_ms(10);
        LIGHT_OFF();
    }
}

void TestNFCInterrupt_ReadTag (void){

    /* Read the tag and write/read to NTAG213 user memory */
    TestNFC_ReadTag();

    /* Needs to restart the scan to detect the NTAG passively */
    PN532_StartScan();
}

我希望这有帮助!