NFC
La technologie RFID / NFC fait partie des modes de communication sans contact.
NFC, ou Near Field Communication (Communication dans un champ proche), est une technologie fréquemment utilisée dans des applications de type systèmes de contrôle d’accès sans fil (par exemple des portes sans clé et des verrous), paiements avec smartphones, …
Le circuit émetteur-récepteur (PN532) gère la communication sans fil à 13.56MHz.
Matériel testé : NFC Shield V2.0
Bibliothèques : PN532 (protocole) et NDEF (format de message)
Le NFC Shield de Seeed est une platine d’évaluation conçue pour tester les technologies de communication sans contact de type RFID / NFC en 13.56 MHz.
Ce modèle, basé sur un contrôleur spécialisé de type « PN532 », permet de communiquer avec des cartes MIFARE ou des smartphones.
Dans le présent article, pour utiliserons le format de message NDEF qui permet une approche nettement simplifiée du protocole NFC.
Câblage
Ce modèle est sur un shield, il n’y a donc aucun câblage à réaliser !
Il faut néanmoins savoir que ce shield utilise le port numérique 10 (ou bien le 9 après une légère modification sur la carte). Il n’est donc plus disponible pour d’autres applications.
Programmation
Il faut tout d’abord, si ce n’est pas déjà fait, installer les bibliothèques PN532 et NDEF :
- se rendre sur https://github.com/Seeed-Studio/PN532
- cliquer sur Clone or download, puis Download ZIP
- installer la bibliothèque en copiant les dossiers contenus dans l’archive ZIP (PN532x) dans le dossier {utilisateur}\Documents\Arduino\libraries\
- se rendre sur https://github.com/don/NDEF
- cliquer sur Clone or download, puis Download ZIP
- installer la bibliothèque en copiant tout le contenu de l’archive ZIP dans le dossier {utilisateur}\Documents\Arduino\libraries\NDEF\
Une première approche consiste à utiliser les exemples fournis avec la bibliothèque, ou plus simplement, les exemples suivants :
Obtenir des informations sur un périphérique NFC
#include <SPI.h> #include "PN532_SPI.h" #include "PN532.h" #include "NfcAdapter.h" PN532_SPI interface(SPI, 10); // création de l'interface SPI pour l'adaptateur NFC NfcAdapter nfc = NfcAdapter(interface); // création de l'objet adaptateur NFC void setup(void) { Serial.begin(115200); Serial.println("NDEF Reader"); nfc.begin(); // démarrage de la communication NFC } void loop(void) { Serial.println("\nScanner un peripherique NFC\n"); if (nfc.tagPresent()) // Vérification de la présence d'un périphérique NFC { NfcTag tag = nfc.read(); // lecture du périphérique, renvoie un objet NfcTag tag.print(); // affichage des informations contenues sur le périphérique (type, UID, et message NDEF) } delay(500); }
Informations sur le lecteur :
NDEF Reader Found chip PN532 Firmware ver. 1.6
Avec une carte MIFARE :
Tag is not NDEF formatted. NFC Tag - Mifare Classic UID 9D 4D 55 94 No NDEF Message
Avec un smartphone
Unknown TLV 6E Error. Can't decode message length. NFC Tag - ERROR UID 08 D0 11 D6 No NDEF Message
Utilisation avec des cartes MIFARE
Les cartes à puce sans contact MIFARE comportent un circuit en logique câblée doté d’une petite mémoire permettant de stocker des informations. Elle sont alimentées lorsqu’on les approche d’un lecteur grâce à une petite bobine.
Formater une carte MIFARE
Le message Tag is not NDEF formatted indique que la carte n’est pas au format NDEF : il faut la formater.
La méthode permettant de formater un tag est :
nfc.format()[reveal_link heading= »%image% Exemple d’utilisation : » id= »id1″] [reveal heading= »noheading » id= »id1″]
#include <SPI.h> #include "PN532_SPI.h" #include "PN532.h" #include "NfcAdapter.h" PN532_SPI interface(SPI, 10); // création de l'interface SPI pour l'adaptateur NFC NfcAdapter nfc = NfcAdapter(interface); // création de l'objet adaptateur NFC void setup(void) { Serial.begin(115200); nfc.begin(); // begin NFC comm } void loop(void) { Serial.println("Placer une carte Mifare Classic devant le lecteur pour la formater"); if (nfc.tagPresent()) { bool success = nfc.format(); if (success) { Serial.println("Formatage NDEF reussi !"); } else { Serial.println("Echec du formatage"); } } delay(5000); }[/reveal]
Écrire un message NDEF
Une fois la carte formatée, on peut y écrire des messages, dont la taille dépend de la capacité de mémoire de la carte.
Pour cela, il faut créer un objet « message » …
NdefMessage message = NdefMessage();
… ajouter un ou plusieurs enregistrements à ce message …
message.addUriRecord("Arduino : l'essentiel !");
… et enfin écrire ce message sur la carte …
nfc.write(message);[reveal_link heading= »%image% Exemple d’utilisation : » id= »id2″] [reveal heading= »noheading » id= »id2″]
#include <SPI.h> #include "PN532_SPI.h" #include "PN532.h" #include "NfcAdapter.h" PN532_SPI interface(SPI, 10); // création de l'interface SPI pour l'adaptateur NFC NfcAdapter nfc = NfcAdapter(interface); // création de l'objet adaptateur NFC void setup(void) { Serial.begin(115200); Serial.println("NDEF Reader"); nfc.begin(); } void loop(void) { Serial.println("Placer une carte Mifare Classic devant le lecteur pour y ecrire un message"); if(nfc.tagPresent()) { NdefMessage message = NdefMessage(); message.addUriRecord("Arduino : l'essentiel !"); message.addUriRecord("arduino.blaisepascal.fr"); bool success = nfc.write(message); if(success) { Serial.println("Message ecrit avec succes !"); }else{ Serial.println("Echec de l'ecriture du message"); } } delay(5000); }
Si l’écriture a réussi, l’instruction tag.print() (voir premier programme, plus haut) affichera ceci :
NDEF Message 2 records, 56 bytes NDEF Record TNF 0x1 Well Known Type Length 0x1 1 Payload Length 0x18 24 Type 55 U Payload 00 41 72 64 75 69 6E 6F 20 3A 20 6C 27 65 73 73 65 6E 74 69 65 6C 20 21 .Arduino : l'essentiel ! Record is 28 bytes NDEF Record TNF 0x1 Well Known Type Length 0x1 1 Payload Length 0x18 24 Type 55 U Payload 00 61 72 64 75 69 6E 6F 2E 62 6C 61 69 73 65 70 61 73 63 61 6C 2E 66 72 .arduino.blaisepascal.fr Record is 28 bytes
Pour accéder plus précisément aux enregistrements du message contenu dans la carte, il faut utiliser d’autres méthodes…
[/reveal]Lire un message NDEF
Pour accéder à chaque enregistrement du message contenu dans la carte, il faut utiliser les méthodes suivantes :
récupération du message dans un objet NdefMessage :
NdefMessage message = tag.getNdefMessage()
récupération de l’enregistrement numéro i dans un objet NdefRecord
NdefRecord record = message.getRecord(i);
récupération de la longueur (en octets) de l’enregistrement :
int payloadLength = record.getPayloadLength();
création d’un tableau d’octets pour y stocker l’enregistrement :
byte payload[payloadLength];
récupération de l’enregistrement dans le tableau ainsi créé :
record.getPayload(payload);
Pour afficher l’enregistrement sous la forme d’une chaîne de caractères, il faut utiliser l’instruction suivante :
Serial.write(payload, payloadLength);
[reveal_link heading= »%image% Exemple d’utilisation : » id= »id3″] [reveal heading= »noheading » id= »id3″]
#include <SPI.h> #include "PN532_SPI.h" #include "PN532.h" #include "NfcAdapter.h" PN532_SPI interface(SPI, 10); // création de l'interface SPI pour l'adaptateur NFC NfcAdapter nfc = NfcAdapter(interface); // création de l'objet adaptateur NFC void setup(void) { Serial.begin(115200); Serial.println("NDEF Reader"); nfc.begin(); } void loop(void) { Serial.println("\nScanner un peripherique NFC\n"); if (nfc.tagPresent()) { NfcTag tag = nfc.read(); // lecture du périphérique if(tag.hasNdefMessage()) // vérification de la présence d'un message NDEF { NdefMessage message = tag.getNdefMessage(); // création de l'objet NdefMessage for(int i=0;i<message.getRecordCount();i++) // parcours de tous les enregistrements du message { NdefRecord record = message.getRecord(i); // création de l'objet NdefRecord int payloadLength = record.getPayloadLength(); byte payload[payloadLength]; record.getPayload(payload); Serial.write(payload, payloadLength); // affichage de l'enregistrement Serial.println(); } } } delay(500); }[/reveal]
Applications
Utiliser un périphérique NFC comme une clef
Chaque périphérique NFC possède un identifiant (UID).
Dans le cas d’une carte MIFARE, il s’agit d’un numéro de 4 octets, presque unique (calculer combien de possibilité cela fait !) et non modifiable.
#include <SPI.h> #include "PN532_SPI.h" #include "PN532.h" #include "NfcAdapter.h" String const myUID = "DD 4A 61 94"; // remplacer cet UID par celui qui correspond à la carte "autorisée" int const LedPin = 13; // LED témoin PN532_SPI interface(SPI, 10); NfcAdapter nfc = NfcAdapter(interface); void setup(void) { Serial.begin(115200); Serial.println("NDEF Reader"); nfc.begin(); pinMode(LedPin,OUTPUT); digitalWrite(LedPin,LOW); } void loop(void) { Serial.println("Scanning..."); if (nfc.tagPresent()) // check if an NFC tag is present on the antenna area { NfcTag tag = nfc.read(); // read the NFC tag String scannedUID = tag.getUidString(); // get the NFC tag's UID if( myUID.compareTo(scannedUID) == 0) // comparaison de la clef du périphérique scanné avec la clef "autorisée" { Serial.println("Correct Key"); digitalWrite(LedPin,HIGH); delay(500); }else{ Serial.print("Clef incorrecte : "); Serial.println(scannedUID); // clignotement = digitalWrite(LedPin,HIGH); delay(200); digitalWrite(LedPin,LOW); delay(200); digitalWrite(LedPin,HIGH); delay(200); digitalWrite(LedPin,LOW); delay(200); digitalWrite(LedPin,HIGH); delay(200); digitalWrite(LedPin,LOW); delay(200); digitalWrite(LedPin,HIGH); delay(200); digitalWrite(LedPin,LOW); } } delay(2000); }
Obtenir des informations depuis un Smartphone
Le programme ci-dessous permet d’obtenir des informations de la part d’une application Android.
Pour le faire fonctionner, il faut au préalable activer la fonctionnalité NFC et l’échange des données Android Beam.
Ensuite, approcher le smartphone du shield NFC …
#include "SPI.h" #include "PN532_SPI.h" #include "snep.h" #include "NdefMessage.h" PN532_SPI pn532spi(SPI, 10); SNEP nfc(pn532spi); uint8_t ndefBuf[128]; uint8_t recordBuf[128]; void setup() { Serial.begin(115200); } void loop() { Serial.println("Attente d'un message d'un Android"); int msgSize = nfc.read(ndefBuf, sizeof(ndefBuf)); if (msgSize > 0) { NdefMessage msg = NdefMessage(ndefBuf, msgSize); Serial.println("\nSucces"); NdefRecord record = msg.getRecord(0); int recordLength = record.getPayloadLength(); if (recordLength <= sizeof(recordBuf)) { record.getPayload(recordBuf); Serial.write(recordBuf, recordLength); for (int i = 0; i < 5; i++) { Serial.write('\n'); } delay(2000); } } else { Serial.println("Echec"); } delay(1000); }
sources : https://cedric.cnam.fr/~bouzefra/cours/CoursNFC_Bouzefrane_Decembre2013.pdf