HUM: PN532 NFC + RFID

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