HUM: PN532 NFC + RFID

HUM: PN532 NFC + RFID-Uncategorized

You are a beginner with Dasduino. Or electronics? A specific module caught your eye, but you do not know how to use it? Do not worry, HUM is here for you! How to Use Module (HUM) is a blog tutorial series by soldered where you will find all you need in order to begin working with your favorite module. Tutorials include technical characteristics, work principles, instructions on how to connect the module with Dasduino, and the basic code. Everything else is left to your imagination.

INTRODUCTION

In this tutorial, you will find out more about the PN532 module which enables NFC and RFID communication. We have already talked about RFID communication, in the tutorial for the RDM6300 module, and we know that we can read card codes using it. Below you will see what is the difference with NFC communication and how to use the module.

HOW DOES IT WORK?

RFID is a type of one-way communication that allows reading the code stored in the chip on the card (tag) from the card or the tag. NFC does not differ much from RFID communication, but one of the most important differences is that with this type of communication we can, in addition to reading the UID code of the card, also write/read messages on the card (tag).
This module works like any RFID or NFC module. On the board, there is a built-in antenna that is marked with a white line around the edge of the board, and when using it, we must make sure that all communication or power lines go vertically to the antenna so that they do not interfere. The cards and tags also have antennas and chips inside them, and they are powered by and communicate with the RFID/NFC module using these. When we bring the card close enough to the module, it is activated (through the antenna, the chip receives power in it) and the RFID/NFC module can communicate with it.
The PN532 module allows reading RFID and NFC cards, as well as write and read messages on NFC cards which we will see in the code examples.

HOW TO CONNECT?

The module is very practical for connecting to a microcontroller because it supports I2C, HSU (High-Speed ​​UART), and SPI communication, and we can choose which communication suits us best for a particular use. To select the communication, it is necessary to move the switches located on the module. In the example, we will go through all three modes of connecting the module and give an example code for all three communications, and finally, we will go through writing and reading messages on the NFC card. For SPI communication we use an 8-pin header (we connect 6 pins), and we connect the necessary pins to a microcontroller as shown in the example. For I2C and HSU communication, we use 4-pin headers on which we have GND, VCC, TXD (SDA), and RXD (SCL) pins, and as you can see, the same pins are used for HSU and I2C (labels for HSU are on the back, and for I2C on the front of the module).

Let us begin with going through HSU and SPI communication with a simple code example to read the UID code from RFID cards, after that, we will test NFC communication, and for that application, we will connect the module to Dasduino via I2C communication.

ARDUINO CODE

To use the module, we need to download the library from the link. When we download the zip file, we need to unzip it and add all the folders (there are 6 of them) to the Arduino library folder. If you don’t know where the Arduino library folder is, see the tutorial on how to install a new library.

RFID

HSU (HIGH-SPEED UART)

The module is adjusted for HSU communication (both switches should be in position 0), so we will make the first example with this type of communication between the module and Dasduino. We connect the module according to the scheme and transfer the given code to Dasduino, so we should be able to read the UID code from the card or tag depending on what we are using.

//including the SoftwareSerial library that implements serial communication on certain pins
#include <SoftwareSerial.h>
 
//including the library for software HSU(High-speed UART) and library for the PN532 module
#include <PN532_SWHSU.h>
#include <PN532.h>
 
SoftwareSerial SWSerial( 10, 11 );//(RX,TX) constructor for our SoftwareSerial library, in which we define the pins to which we will connect the module
//constructors for libraries that are used for communication with the module
PN532_SWHSU pn532swhsu( SWSerial );//constructor for High-speed UART
PN532 nfc( pn532swhsu ); //constructor for the PM532 library
 
void setup(void) {
 Serial.begin(115200);////serial communication initialization (speed 115200 baud)
 Serial.println("Hello!");//displaying a greeting message on the Serial monitor 
 nfc.begin();//initialization of communication with the module
 uint32_t versiondata = nfc.getFirmwareVersion(); //requesting the Firmware version and saving it to the versiondata variable
 //if we have not gotten a Firmware version from the module, displaying that the module was not found on the Serial monitor, staying in the indefinite while loop
 if (! versiondata) {
 Serial.print("PN532 module not found..Check how it is connected");
 while (1);
 }
 //if communication is established, displaying the Firmware version
 Serial.print("PN5 module found"); Serial.println((versiondata>>24) & 0xFF, HEX);
 Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
 Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
 //configuring the module
 nfc.SAMConfig();
 //displaying a message that we need to press the card
 Serial.println("Press the card or tag...");
}
 
void loop(void) {
 boolean success;
 uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; //buffer to which we save the code from the card
 uint8_t uidLength; //writing the UID code length (4 or 7 bytes)
//requesting the module to read the card (in the success variable, it saves whether there is a card, and if there is, saving the card code to the uid variable
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
 
//if the module has read the card, displaying the lenght of the code on the card (4 or 7 bytes) and after that, the card code
 if (success) {
 Serial.println("Card found!");
 Serial.print("UID code length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
 Serial.print("UID Code: ");
 //displaying the code from the card in HEX form
 for (uint8_t i=0; i < uidLength; i++)
 {
 Serial.print(" 0x");Serial.print(uid[i], HEX);
 }
 Serial.println("");
 
 delay(1000);//1 second pause before the next reading
 }
//if the card is not found, displaying the message about waiting for the card
 else
 {
 Serial.println("Time is up.. Waiting for the card");
 delay(500);//half second pause so that the message if there is no card is not displayed constantly
 }
}

SPI COMMUNICATION

As we already know, for SPI communication we need 4 lines + 2 more for the power supply, but despite having more lines, this communication has a higher baud rate than the I2C and HSU communication. In order for the module to know how to use SPI, it is necessary to leave the first switch in position 0, and move the second to position 1, which is shown in the previous part of the tutorial. In the wiring scheme, it is shown how to connect the module to the microcontroller and which pins we need. After connecting the module to Dasduino, according to the given scheme, it is necessary to transfer the code example for SPI communication to the Dasduino board. Just like the previous code, this one only allows reading the UID code from cards or tags.

//including the SPI library that is used for SPI communication 
 #include <SPI.h>
//including the library for SPI communication with the module and the library for PN532 module
 #include <PN532_SPI.h>
 #include "PN532.h"
//constructors for libraries that are used for communication with the module
 PN532_SPI pn532spi(SPI, 10); //constructor for SPI communication with the module
 PN532 nfc(pn532spi); //constructor for PM532 library
 
void setup(void) {
 Serial.begin(115200);////serial communication initialization (speed 115200 baud)
 Serial.println("Hello!");//displaying a greeting message on the Serial monitor 
 nfc.begin();//initialization of communication with the module
 uint32_t versiondata = nfc.getFirmwareVersion(); //requesting the Firmware version and saving it to the versiondata variable
 //if we have not gotten a Firmware version from the module, displaying that the module was not found on the Serial monitor, staying in the indefinite while loop
 if (! versiondata) {
 Serial.print("PN532 module not found..Check how it is connected");
 while (1);
 }
 //if communication is established, displaying the Firmware version
 Serial.print("Module PN5 found"); Serial.println((versiondata>>24) & 0xFF, HEX);
 Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
 Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
 //configuring the module
 nfc.SAMConfig();
 //displaying a message that we need to press the card
 Serial.println("Press the card or tag...");
}
 
void loop(void) {
 boolean success;
 uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; //buffer to which we save the code from the card
 uint8_t uidLength; //writing the UID code length (4 or 7 bytes)
//requesting the module to read the card (in the success variable, it saves whether there is a card, and if there is, saving the card code to the uid variable
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
//if the module has read the card, displaying the lenght of the code on the card (4 or 7 bytes) and after that, the card code
 if (success) {
 Serial.println("Card found!");
 Serial.print("UID code length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
 Serial.print("UID Code: ");
 //displaying the code from the card in HEX form
 for (uint8_t i=0; i < uidLength; i++)
 {
 Serial.print(" 0x");Serial.print(uid[i], HEX);
 }
 Serial.println("");
 delay(1000);//1 second pause before the next reading
 }
//if the card is not found, displaying the message about waiting for the card
 else
 {
 Serial.println("Time is up.. Waiting for the card");
 delay(500);//half second pause so that the message if there is no card is not displayed constantly 
 }
}

 

 

NFC

I2C COMMUNICATION

I2C communication is slightly easier to connect and use, and we will use it in the following examples. Below is the image of the wiring scheme, as well as the layout of switches for this type of communication.

As we saw earlier, NFC differs from RFID in the fact that, in addition to reading the UID code from cards, it allows reading and writing messages on a card or tag. First of all, let us explain how, in order for us to be able to write a message on it, the card must be of a certain format. That format is NDEF, and since the cards are not pre-formatted, we must first do the formatting so that we can write on the cards.
To format the card, you simply need to transfer the card formatting code (tag) to Dasduino and place the card on the PN532 module, and a message that the card is formatted will be displayed on the Serial monitor. If the card has already been formatted, a message stating that the formatting failed is displayed.

THE CODE FOR FORMATTING THE CARD
//including the library for I2C communication
#include <Wire.h>
 
//including the library for I2C communication with the PN532 module, library for the PN532 module and the library for the NFC
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>
 
//constructors for the library for I2C communication with the module and for the NFC
PN532_I2C pn532_i2c(Wire);
NfcAdapter nfc = NfcAdapter(pn532_i2c);
 
void setup(void) {
 Serial.begin(115200);////serial communication initialization (speed 115200 baud)
 Serial.println("NDEF Formatting.");//displaying that we are using the module for NDEF formatting on the Serial monitor 
 nfc.begin();//initialization of communication with the module
}
 
void loop(void) {
 //displaying that we need to press the unformatted card on the Serial monitor
 Serial.println("\nPress the unformatted card or tag against the module");
 if (nfc.tagPresent()) {//checking whether the card is pressed, if it is, we format the card
 bool success = nfc.format();//command for formatting the card that returns data about whether the card is formatted or not 
 if (success) {
 //if the card is formatted, displaying a message about successful formatting on the Serial monitor 
 Serial.println("\nThe card (tag) successfully formatted in the NTAG.");
 } else {
 //if formatting was not successful, displaying an error message
 Serial.println("\nUnsuccessful formatting.");
 }
 }
 delay(2000);//2 seconds pause so that the messages are not displayed constantly
}

Once we format the card we can write and read messages from the card. Since the card has just been formatted, there is an empty message on it, which we can see if we read the card with an example of a reading code. To write something on the card you need to transfer the writing code to Dasduino. In the code, you need to change what you want to write on the card, and then just transfer the code and press the card. If everything is done correctly, you should get a note that the message was successfully written and read it with a reader or a mobile phone (newer mobile phones support NFC communication, so you can test whether you can read the message with your phone).

 

THE CODE FOR “WRITING” ON THE CARD
//including the library for I2C communication
#include <Wire.h>
//including the library for I2C communication with the PN532 module, library for the PN532 module and the library for the NFC
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>
 
//constructors for the library for I2C communication with the module and for the NFC
PN532_I2C pn532_i2c(Wire);
NfcAdapter nfc = NfcAdapter(pn532_i2c);
 
void setup() {
 Serial.begin(115200);////serial communication initialization (speed 115200 baud)
 Serial.println("NDEF Writer");//displaying that the module saves a message that is defined in the code to the card
 nfc.begin();//initialization of communication with the module
}
 
void loop() {
 Serial.println("\nPress the formatted card against the reader.");
 if (nfc.tagPresent()) {
 NdefMessage message = NdefMessage(); //creating a variable of NdefMessage type
 //depending on whether we want to write a certain text or url, we need to comment or uncomment the corresponding line of the code
 //message.addTextRecord("Hello, Arduino!");//adding text to the message variable
 message.addUriRecord("http://arduino.cc");//adding url to the message variable
  
 //writing the message variable on the card as a message, the function returns data about whether writing is successful or not
 bool success = nfc.write(message);
 if (success) {
 //if writing was successful, displaying a message about it
 Serial.println("Successful. Try reading the message using reader or mobile phone.");
 } else {
 //if writing was not successful, displaying that there was an error
 Serial.println("Writing unsuccessful.");
 }
 }
 //2 seconds pause
 delay(2000);
}

When a message is written on the card, it is useless if we cannot read it, so there is an example of a code for reading NFC cards that, in addition to the UID code, also displays a message that we previously wrote on the card.

THE CODE FOR READING THE CARD
//including the library for I2C communication
#include <Wire.h>
//including the library for I2C communication with the PN532 module, library for the PN532 module and the library for the NFC
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>
 
//constructors for the library for I2C communication with the module and for the NFC
PN532_I2C pn532_i2c(Wire);
NfcAdapter nfc = NfcAdapter(pn532_i2c);
 
void setup(void) {
 Serial.begin(115200);////serial communication initialization (speed 115200 baud)
 Serial.println("NDEF Citac"); //displaying a message that the module works as NDEF reader
 nfc.begin();//initialization of communication with the module
}
 
void loop(void) {
 Serial.println("\nSearching for NFC card/tag\n");
 if (nfc.tagPresent())//if we have pressed a card, we are reading a message from it and displaying this message immediately on the Serial monitor.
 {
 NfcTag tag = nfc.read(); //reading the NFC card or tag
 tag.print(); //displaying data from the card/tag
 }
 //2 seconds pause so that the read data is not displayed constantly
 delay(2000);
}

If for some reason we do not want the message to remain on the card, we can simply erase the card, i.e. the message from the card, and then the card will have an empty message as the one we had when the card was formatted.

THE CODE FOR DELETING THE MESSAGE
//including the library for I2C communication
#include <Wire.h>
 
//including the library for I2C communication with the PN532 module, library for the PN532 module and the library for the NFC
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>
 
//constructors for the library for I2C communication with the module and for the NFC
PN532_I2C pn532_i2c(Wire);
NfcAdapter nfc = NfcAdapter(pn532_i2c);
 
void setup(void) {
 Serial.begin(115200);////serial communication initialization (speed 115200 baud)
 Serial.println("NFC Deleting data from the card");
 nfc.begin();//initialization of communication with the module
}
 
void loop(void) {
 //displaying a message that the module is deleting data from the pressed card
 Serial.println("\nPress the card you want to delete.");
 //checking whether the card is pressed and if it is, calling the function for erasing the card.
 if (nfc.tagPresent()) {
 bool success = nfc.erase();//the function for erasing the card that returns whether the card has been erased or not
 if (success) {
 //displaying a message whether data has been deleted
 Serial.println("\nSuccessful, data deleted from the card.");
 } else {
 //displaying that deleting was not successful
 Serial.println("\nUnsuccessful data deletion.");
 }
 }
 //2 seconds pause so that checking whether the card is pressed does not continue
 delay(2000);
}

Of course, sometimes we will do something wrong and we will need a new card without messages that is not formatted to the NDEF format. That is why there is a code that clears the card and returns it to the default settings. After we transfer this code to Dasduino and press the card against the module, the message will be deleted from it and the card will be returned to the default settings. If we want to write messages on the card again after clearing it, we need to format it beforehand.

 

THE CODE FOR CLEARING THE CARD
//including the library for I2C communication
#include <Wire.h>
 
//including the library for I2C communication with the PN532 module, library for the PN532 module and the library for the NFC
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>
 
//constructors for the library for I2C communication with the module and for the NFC
PN532_I2C pn532_i2c(Wire);
NfcAdapter nfc = NfcAdapter(pn532_i2c);
 
void setup(void) {
 Serial.begin(115200);////serial communication initialization (speed 115200 baud)
 Serial.println("NFC Tag Cleaner");//displaying that the module is clearing the pressed card, i.e. returning it to default settings 
 nfc.begin();//initialization of communication with the module
}
 
void loop(void) {
 //displaying the message to press the card you want to clear
 Serial.println("\nPress the card you want to clear.");
 //checking whether the card has been pressed and if it is, we call the function to clear the card
 if (nfc.tagPresent()) {
 bool success = nfc.clean();//function for clearing the card that returns the data about whether the card is cleared or not
 if (success) {
 //if the card is cleared, displaying the message that it is returned to the default settings
 Serial.println("\nSuccessful, the card is returned to the default settings.");
 } else {
 //if we did not manage to clear the card, displaying the message that an error occured
 Serial.println("\nError, clearing the card is unsuccessful.");
 }
 }
 //2 seconds pause so that checking whether the card is pressed does not continue
 delay(2000);
}