Review: Shield NFC para Arduino PN532 ISP

NFC es una tecnología de comunicación inalámbrica que a través de la inducción de un campo magnético permite la comunicación entre dos dispositivos.

Esta tecnología es una variante de la RFID que quizás nos suene mas no por su nombre si no por los usos que se le ha dado. Por ejemplo podemos encontrarla en tarjetas como método de pago para el transporte urbano, para las máquinas expendedoras de la oficina, en los chips implantados en los perros que almacenan los datos del can y su dueño, etc.

Pues bien, esta variante indica que la frecuencia de los dispositivos ha de ser de 13.56 Mhz y que su distancia máxima a cubrir será de 10 cm en el mejor de los casos, aunque esto último depende de las antenas de los dispositivos.

Últimamente con los smartphones de gama alta se está poniendo de moda ya que permiten darles bastantes usos. El principal de todos ellos era/es el de realizar pagos en tiendas físicas, sin embargo no es algo que haya proliferado aquí, aunque si en otros países, otros usos son el de programación de perfiles para el móvil, de modo que dependiendo de qué etiqueta/tag/llavero NFC leas el móvil se configure de determinada forma.

Ahora que ya tenemos una idea de que es y que usos se les puede dar vamos a lo que realmente nos ocupa, que es la revisión de una Shield NFC para Arduino cedida por dealextreme.com

Shield NFC para Arduino

La shield o placa de expansión, que en adelante la nombrare como la placa, a revisar está fabricada por ElecFreaks, el mismo fabricante que el Freaduino revisado hace un tiempo. Dealextreme vende muchos de sus productos, entre ellos esta placa que puede comprarse desde aquí: Shield NFC para Arduino.

La placa viene en una caja de cartón junto a los elementos imprescindibles para hacerla funcionar, en este caso la propia placa, un dispositivo NFC con forma de tarjeta de crédito y unos conectores hembra que necesitaremos soldar si queremos poder pinchar otras shields encima de esta.

La placa al tener una forma entandar, la de shield de expansión para Arduino, la hace compatible también con otras plataformas de desarrollo, ya sean los Arduinos oficiales, los compatibles como el Freaduino, los netDuino, etc. Esta es la apariencia que tiene en alguno de ellos:

Puede observarse como la placa una vez conectada queda expuesta hacia el exterior, eso aunque queda un poco anti estético es necesario por si conectamos otras shields encima ya que de lo contrario la antena NFC de la placa quedaría oculta e imposibilitaría su uso.

La placa NFC esta compuesta de toda la circuitería necesaria para funcionar, esto incluye el controlador PN532 capaz de soportar los protocolos ISP, I2C y UART Serial, la antena NFC que permite leer dispositivos hasta un máximo de 5 cm, dos leds que indican el estado, el cristal de cuarzo del controlador, condensadores, resistencias, etc.

Esta placa para funcionar hace uso del protocolo ISP, aunque teóricamente mediante unos "jumpers" que tiene puede cambiarse para usar el I2C o UART, y para realizar la conexión es tan sencillo como pinchar la placa sobre el Arduino. La he probado en un Arduino Duemilanove/Uno y en un moDuino basado en un Arduino Mega, en ambas ha funcionado correctamente.

Librería para usar la Shield NFC

Con la placa no se incluye ningún CD con las librerías necesarias para su uso en Arduino pero si que están tanto en la descripción del producto de dealextreme como en la página del fabricante.
Además como la placa se basa en el chip PN532, que es bastante común, nos encontramos que hay muchas librerías por internet, la gran mayoría están basadas en la de Adafruit y luego han sido modificadas para soportar un protocolo de comunicación concreto y para quitar o añadir funcionalidades.

Por ejemplo la librería del fabricante nos permite obtener el número identificativo único de cada dispositivo NFC (su ID), además de leer y escribir en la memoria EEPROM que suelen tener estos dispositivos. Pero no incluye la funcionalidad de comunicación entre dos shields NFC o entre la placa y un móvil. Otras librerías sí que incluyen algunas funcionalidades de esas, pero como digo su funcionamiento depende del protocolo de comunicación, así que si necesitamos algo "raro" será mejor que nos informemos antes de si es posible darle ese uso.

Para todos los ejemplos que se verán más adelante yo he usado la librería original, aunque la he modificado ya que tal y como viene tenia algunos detalles que no me gustaban nada:

  • De serie solo es compatible con el IDE viejo de Arduino, así que le añadí compatibilidad con la versión 1.x
  • No viene nada de documentación sobre cómo usar sus métodos o qué parámetros se les ha de pasar, por ello extraje la información de otras librerías e incluí toda la que pude.
  • La librería tiene un modo debugger que hace que se imprima por pantalla determinada información, había alguna información que aun teniendo desactivado ese modo se imprimía igual, así que arregle eso ya que puede darnos problemas si quisiéramos enviar datos por el Serial ya que el pc podría leer la basura metida por la librería.
  • He añadido dos métodos para poder leer y escribir la totalidad de la memoria EEPROM de forma consecutiva, esto permite escribir texto o estructuras de datos.
  • Y por último ordene el código que estaba muy mal formateado.

Enlace a la librería modificada por mí

Tarjetas, llaveros y otros dispositivos NFC

Con la placa se incluye un dispositivo NFC con forma de tarjeta de crédito, de hecho su tamaño y grosor son idénticos así que podemos llevarlo en el hueco para tarjetas de la cartera/monedero. Esta incorpora en su interior un espacio de memoria EEPROM en el que podemos leer y escribir los datos que queramos, aunque para hacerlo hay que tomar unas precauciones que explico en el siguiente punto.

A parte de la tarjeta existen muchos otros dispositivos NFC, en ebay mismo venden llaveros NFC como los de la foto y que revise aquí, o algunos otros mas curiosos con apariencia de llavero o como pegatinas.

Precauciones a tener en cuenta

A la hora de leer el ID del dispositivo NFC no hay más que usar el método de lectura que nos devuelve su número identificativo. Sin embargo para leer o escribir la memoria EEPROM hay que tomar unas precauciones ya que no es nada sencillo de usar y de hacerlo incorrectamente podemos dejar inservible parte de la memoria o incluso su totalidad.

Los dispositivos NFC que permiten almacenar información en su memoria siguen determinados protocolos para el almacenamiento, su acceso y protección. En el caso de la tarjeta y de los llaveros este es Mifare, que indica cómo se he de trabajar con la memoria, en el enlace a la Wikipedia lo explican pero voy a intentarlo hacer yo aquí:

  • La memoria se divide en sectores, bloques y bytes. Los sectores son llamados en esta librería como Sector Trailer y los bloques como Data Block.

  • En este caso la memoria tiene 16 sectores, cada uno de ellos tiene 4 bloques y a su vez estos contienen 16 bytes de información.

  • De esos 4 bloques el primero de ellos contiene una clave de acceso para acceder a los tres bloques de datos de ese sector. Eso quiere decir que si queremos leer o escribir información por ejemplo del bloque 29 deberemos antes introducir la clave del bloque 27...

  • Y el problema viene en si modificamos alguno de los bloques que almacenan la clave de acceso, la cual por defecto tiene el valor: FF FF FF FF FF FF, aunque luego el bloque contiene: 0 0 0 0 0 0 FF 7 80 69 FF FF FF FF FF FF . La teoria dice que si modificamos la clave por otra luego bastara con acceder al bloque con la nueva clave, pero lo cierto es que hice la prueba y después de tres horas y de intentarlo todo no hubo forma de recuperar la memoria. La prueba la realice con el sector 31 y fue a partir de ahí desde donde la memoria se quedó inservible. En un último intento de desesperación hice otra prueba con otro sector y se quedó inservible igualmente. Al final el llavero solo se puede usar para obtener su ID que no se vio afectado.

Para hacernos una mejor idea de lo que he explicado, la librería incluye un ejemplo llamado readAllMemoryBlocks que al ejecutarlo nos imprime en el monitor serial del IDE todo el contenido del dispositivo NFC, obteniendo algo así:

Hello!
Found chip PN532
Firmware ver. 1.6
Supports 7
Read card #1833064998

6D 42 5A 26 53 8  4  0  62 63 64 65 66 67 68 69 | Block  0 | Manufacturer Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block  1 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block  2 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block  3 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block  4 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block  5 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block  6 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block  7 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block  8 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block  9 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 10 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 11 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 12 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 13 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 14 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 15 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 16 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 17 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 18 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 19 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 20 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 21 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 22 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 23 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 24 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 25 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 26 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 27 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 28 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 29 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 30 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 31 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 32 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 33 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 34 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 35 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 36 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 37 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 38 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 39 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 40 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 41 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 42 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 43 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 44 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 45 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 46 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 47 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 48 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 49 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 50 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 51 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 52 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 53 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 54 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 55 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 56 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 57 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 58 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 59 | Sector Trailer
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 60 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 61 | Data Block
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  | Block 62 | Data Block
0  0  0  0  0  0  FF 7  80 69 FF FF FF FF FF FF | Block 63 | Sector Trailer

Si nos fiamos en el contenido que se nos imprime veremos los sectores y bloques de memoria con sus 16 bytes por fila, además de un bloque especial llamado Manufacturer Block que contiene información sobre el dispositivo.

Siempre y cuando leamos y escribamos en los Data Block no tendremos problemas, sin embargo que la memoria este dividida en bloques y sectores hace que no sea nada fácil trabajar con ella, al menos de forma transparente. Porque guardar en alguno de los bloques un dato especifico, por ejemplo el número de veces que hemos pasado la tarjeta por el lector, es muy sencillo de hacer. Ahora si en vez de eso queremos guardar cadenas de texto, estructuras de datos, etc. entonces la cosa cambia.

Ejemplos de uso:

En esta sección he incluido unos cuantos ejemplos de cada. Los primeros son sencillos y solo hacen uso del ID del dispositivo para que después el Arduino haga una u otra cosa según se lo hayamos programado. Los segundos hacen uso de la memoria EEPROM y son bastante mas complejos aunque al ser ejemplos bastante didácticos creo que se entiende bien como se ha de usar la memoria

Mostrar la información del chip de la Shield

/**
 * Author:     Alberto Gil Tesa
 * WebSite:    http://giltesa.com
 * License:    CC BY-NC-SA 3.0
 *
 * Description:
 *   ARDUINO SHIELD NFC PN532 ISP
 *
 *   Ejemplo de uso de la shield NFC con chip PN532.
 *   Imprime la informacion de la placa a traves del monitor serial.
 */


#include <PN532.h>

#define SCK  13
#define MOSI 11
#define SS   10
#define MISO 12

PN532 nfc(SCK, MISO, MOSI, SS);


void setup()
{
   // Inicia la comunicacion serie:
   Serial.begin(9600);
   Serial.println("Hi!");

   // Inicia la Shield NFC:
   nfc.begin();

   // Obtiene los datos sobre el chip controlador:
   uint32_t versiondata = nfc.getFirmwareVersion();

   // Si los datos es un numero distinto (o mayor) de 0 significa que se ha podido realizar la conexion satisfactoriamente.
   // Si siempre usamos la misma shield podemos obviar este paso ya que siempre sera correcta la conexion.
   if( !versiondata ) // if( versiondata == 0 )
   {
      Serial.print("No se ha encontrado ninguna placa con chip PN53x");
      return; // Exit
   }


   // Ahora se pasa a imprimir los numeros, estos estan mezclados en "versiondata" asi que hay que separarlos mediante operadores binarios:
   Serial.print("Modelo del chip controlador: PN5");
   Serial.println((versiondata>>24) & 0xFF, HEX);

   Serial.print("Version del Firmware: ");
   Serial.print((versiondata>>16) & 0xFF, DEC);
   Serial.print('.');
   Serial.println((versiondata>>8) & 0xFF, DEC);

   Serial.print("Supports ");
   Serial.println(versiondata & 0xFF, HEX);
}


void loop()
{
}

Mostrar el ID del dispositivo NFC leído

/**
 * Author:     Alberto Gil Tesa
 * WebSite:    http://giltesa.com
 * License:    CC BY-NC-SA 3.0
 *
 * Description:
 *   ARDUINO SHIELD NFC PN532 ISP
 *
 *   Ejemplo de uso de la shield NFC con chip PN532.
 *   Imprime el numero de identificacion unico de la tarjeta/llavero.
 */


#include <PN532.h>

#define SCK  13
#define MOSI 11
#define SS   10
#define MISO 12

PN532 nfc(SCK, MISO, MOSI, SS);


void setup()
{
   Serial.begin(9600);
   nfc.begin();

   // Configura la Shield para leer etiquetas RFID:
   nfc.SAMConfig();

   Serial.println("Placa preparada para leer!");
}


void loop()
{
   uint32_t id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A);

   if( id != 0 )
   {
      Serial.print("ID= "); Serial.println(id);
      delay(1000);
   }
}

Mostrar mediante texto que dispositivo NFC se ha leído

/**
 * Author:     Alberto Gil Tesa
 * WebSite:    http://giltesa.com
 * License:    CC BY-NC-SA 3.0
 *
 * Description:
 *   ARDUINO SHIELD NFC PN532 ISP
 *
 *   Ejemplo de uso de la shield NFC con chip PN532.
 *   Lee un llavero NFC he indica de que color es sabiendo
 *   previamente que color corresponde a cada ID.
 */


#include <PN532.h>

#define SCK       13
#define MOSI      11
#define SS        10
#define MISO      12

#define LIMA      4256651814
#define VERDE     766139942
#define AZUL      2906087206
#define ROJO      1564564006
#define AMARILLO  4249704998
#define GRIS      1833064998

PN532 nfc(SCK, MISO, MOSI, SS);


void setup()
{
   Serial.begin(9600);
   nfc.begin();
   nfc.SAMConfig();

   Serial.println("Placa preparada para leer!");
}


void loop()
{
   uint32_t id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A);

   if( id > 0 )
   {
      switch(id)
      {
         case LIMA     : Serial.println("Lima");        delay(1000); break;
         case VERDE    : Serial.println("Verde");       delay(1000); break;
         case AZUL     : Serial.println("Azul");        delay(1000); break;
         case ROJO     : Serial.println("Rojo");        delay(1000); break;
         case AMARILLO : Serial.println("Amarillo");    delay(1000); break;
         case GRIS     : Serial.println("Gris");        delay(1000); break;
         default       : Serial.println("Desconocido"); delay(1000); break;
      }
   }

}

Encender o apagar un led al leer determinado dispositivo NFC

/**
 * Author:     Alberto Gil Tesa
 * WebSite:    http://giltesa.com
 * License:    CC BY-NC-SA 3.0
 *
 * Description:
 *   ARDUINO SHIELD NFC PN532 ISP
 *
 *   Ejemplo de uso de la shield NFC con chip PN532.
 *   Enciende o apaga un LED conectado al pin "LED" cada vez que se lee la tarjeta
 *   indicada en la constante "ID_TARJETA"
 *
 *   Nota: No puede usarse el led del Arduino ya que ese pin se usa para la Shield.
 */


#include <PN532.h>

#define SCK         13
#define MOSI        11
#define SS          10
#define MISO        12

#define LED         8
#define ID_TARJETA  2864817847

PN532 nfc(SCK, MISO, MOSI, SS);


void setup()
{
   Serial.begin(9600);
   nfc.begin();
   nfc.SAMConfig();

   pinMode(LED, OUTPUT);

   Serial.println("Placa preparada para leer!");
}


void loop()
{
   uint32_t id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A);

   // Si el ID leido coincide con el de la constante "ID_TARJETA"...
   if( id == ID_TARJETA )
   {
      digitalWrite( LED , !digitalRead(LED) ); // Si el led esta encendido lo apaga, si esta apagado lo enciende.
      delay(1000);
   }
}

Cambiar el color de un led RGB según la llave NFC leída

/**
 * Author:     Alberto Gil Tesa
 * WebSite:    http://giltesa.com
 * License:    CC BY-NC-SA 3.0
 *
 * Description:
 *   ARDUINO SHIELD NFC PN532 ISP
 *
 *   Ejemplo de uso de la shield NFC con chip PN532.
 *   Lee llaveros NFC y enciende un Led RGB en el
 *   mismo color que el llavero.
 */


#include <PN532.h>

// Shield NFC:
#define SCK         13
#define MOSI        11
#define SS          10
#define MISO        12

// Pines LED RGB:
#define LED_AZUL    2
#define LED_VERDE   3
#define LED_ROJO    4

// IDs llaveros NFC:
#define LIMA        4256651814
#define AZUL        2906087206
#define ROJO        1564564006
#define AMARILLO    4249704998
#define BLANCO      2864817847
#define GRIS_OFF    1833064998


PN532 nfc(SCK, MISO, MOSI, SS);


void setup()
{
   Serial.begin(9600);
   nfc.begin();
   nfc.SAMConfig();

   pinMode( LED_AZUL  , OUTPUT );
   pinMode( LED_VERDE , OUTPUT );
   pinMode( LED_ROJO  , OUTPUT );
}


void loop()
{
   uint32_t id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A);

   if( id > 0 )
   {
      switch(id)
      {
         //                      ROJO , VERDE , AZUL
         case LIMA     : ledRGB(    0 ,   255 ,   0 ); break;
         case AZUL     : ledRGB(    0 ,     0 , 255 ); break;
         case ROJO     : ledRGB(  204 ,     0 ,   0 ); break;
         case AMARILLO : ledRGB(  160 ,   255 ,   0 ); break;
         case BLANCO   : ledRGB(  255 ,   255 , 255 ); break;
         case GRIS_OFF : ledRGB(    0 ,     0 ,   0 ); break;
      }
   }
}


void ledRGB( byte rojo, byte verde, byte azul )
{
   analogWrite( LED_ROJO  , rojo  );
   analogWrite( LED_VERDE , verde );
   analogWrite( LED_AZUL  , azul  );
}

A partir de aquí comienzan los ejemplos de uso de la memoria EEPROM, todos ellos han sido probados y funcionan correctamente. En cualquier caso no me hago responsable de lo que pueda suceder con ellos y los dispositivos NFC.

Almacenar en la memoria cuantas veces se ha leído una llave

/**
 * Author:     Alberto Gil Tesa
 * WebSite:    http://giltesa.com
 * License:    CC BY-NC-SA 3.0
 *
 * Description:
 *   ARDUINO SHIELD NFC PN532 ISP
 *
 *   Ejemplo de uso de la shield NFC con chip PN532:
 *   Contabiliza el numero de veces que se lee la llave.
 *   Con cada lectura se suma 1 al contador de la EEPROM de
 *   la llave y se imprime el resultado por el monitor serial.
 */


#include <PN532.h>

// Shield NFC:
#define SCK        13
#define MOSI       11
#define SS         10
#define MISO       12


PN532 nfc(SCK, MISO, MOSI, SS);


void setup()
{
   Serial.begin(9600);
   nfc.begin();
   nfc.SAMConfig();
}


void loop()
{
   // Contador es un array de bytes de tamaño 1, es necesario crear la variable de este modo ya que el metodo que escribe la informacion espera recibir un puntero hacia el dato.
   byte contador[1];

   // Es la clave de acceso necesaria para acceder a cada sector de la memoria:
   byte keys[]= {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};


   uint32_t id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A);

   // Si se obtuvo un ID...
   if( id > 0 )
   {
      // Antes de hacer uso de la memoria es necesario autenticarse con la clave de acceso, para ello se le pasa como parametro:
      // - El tipo de tarjeta, pudiendo elegir entre 1 o 2.
      // - El ID de dispositivo NFC al que queremos acceder a su memoria.
      // - La direccion de memoria del bloque en el que queremos autenticarnos, no se le indica el bloque que contiene la clave, si no al que se quiere acceder. El solo se apaña para encontrar la clave correspondiente al bloque.
      // - El tipo de clave, se puede elegir entre KEY_A o KEY_B.
      // - La clave de arriba.
      if( nfc.authenticateBlock(1, id ,0x08, KEY_A, keys) )
      {
         // Una vez autenticados se lee en el bloque 0x08, 1 byte de memoria.
         if( nfc.readMemoryBlock(1, 0x08, contador) )
         {
            // Cada 255 lecturas de la tarjeta se resetea el contador:
            if( contador[0] >= 255)
               contador[0] = 0;

            // Se suma 1 al contador cada vez que se hace una lectura con la Shield:
            contador[0] += 1;

            Serial.print("Contador= "); Serial.println(contador[0]);

            // Se escribe el nuevo valor del contador en el bloque 0x08:
            nfc.writeMemoryBlock(1, 0x08, contador);
         }
      }
      else
      {
         Serial.println("Clave incorrecta o error de lectura");
      }

   }

}

Almacenar en la memoria un texto de 447 bytes

/**
 * Author:     Alberto Gil Tesa
 * WebSite:    http://giltesa.com
 * License:    CC BY-NC-SA 3.0
 *
 * Description:
 *   ARDUINO SHIELD NFC PN532 ISP
 *
 *   Ejemplo de uso de la shield NFC con chip PN532:
 *   En este otro ejemplo mediante los metodos "readAllMemory" y "writeAllMemory" añadidos por mi
 *   se puede leer o escribir en la memoria de forma consecutiva sin tener que preocuparnos por los
 *   bloques de autenticacion.
 *   Podemos almacenar los datos que queramos siempre y cuando sean arrays de bytes.
 *   Eso quiere decir que se pueden almacenar cadenas o estructuras de datos Union.
 *
 *   En concreto este ejemplo guarda un parrafo de texto de 447 caracteres/bytes.
 */


#include <PN532.h>

// Shield NFC:
#define SCK  13
#define MOSI 11
#define SS   10
#define MISO 12
PN532 nfc(SCK, MISO, MOSI, SS);


byte texto[] = "El hardware consiste en una placa con un microcontrolador Atmel AVR y puertos de entrada/salida. Los microcontroladores mas usados son el Atmega168, Atmega328, Atmega1280, ATmega8 por su sencillez y bajo coste que permiten el desarrollo de multiples disenios. Por otro lado el software consiste en un entorno de desarrollo que implementa el lenguaje de programacion Processing/Wiring y el cargador de arranque (boot loader) que corre en la placa.";
byte textoTag[sizeof(texto)];
boolean escrito = false;


void setup()
{
   Serial.begin(9600);
   nfc.begin();
   nfc.SAMConfig();
}


void loop()
{
   uint32_t id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A);

   if( id > 0 )
   {
      // Escribe por primera vez el texto en la memoria EEPROM de la Tag:
      if( !escrito )
      {
         if( !nfc.writeAllMemory( id , texto, sizeof(texto) ) )
            Serial.println("Error de escritura");
         else
         {
            escrito = true;
            Serial.println("Escritura realizada correctamente");
         }
      }


      // Le el contenido de la memoria EEPROM:
      if( escrito )
      {
         if( ! nfc.readAllMemory(id , textoTag , sizeof(textoTag)) )
            Serial.println("Error de lectura");
         else
         {
            for( int i=0 ; i<sizeof(textoTag) ; i++ )
               Serial.print( (char)textoTag[i] );

            Serial.println("\n");
            delay(2000);
         }
      }

   }

}

Almacenar estructuras de datos con las variables que queramos

Este ejemplo se compone de dos ficheros o sub-ejemplos, el primero es solo de escritura y el segundo de lectura.
Lo que hace el ejemplo de escritura es escribir en la EEPROM una estructura de datos Union, que contiene en su interior una estructura de datos Struct y que a su vez contiene 3 variables de tipo byte que almacenan el valor de luminosidad de los colores rojo, verde y azul. De este modo solo hay que pasarle la estructura Union al método writeAllMemory para que la escriba entera con todas las variables que hayamos metido en su interior, es realmente cómodo!

/**
 * Author:     Alberto Gil Tesa
 * WebSite:    http://giltesa.com
 * License:    CC BY-NC-SA 3.0
 *
 * Description:
 *   ARDUINO SHIELD NFC PN532 ISP
 *
 *   Ejemplo de uso de la shield NFC con chip PN532.
 *   Escribe en la memoria EEPROM de la llave NFC
 *   la configuracion de colores de un LED RGB
 */


struct DATOS{
   byte rojo;
   byte verde;
   byte azul;
};

union MEMORIA{
   DATOS color;
   byte  b[sizeof(DATOS)];
}
rgb;


#include <PN532.h>

// Shield NFC:
#define SCK        13
#define MOSI       11
#define SS         10
#define MISO       12
boolean escrito = false;


PN532 nfc(SCK, MISO, MOSI, SS);


void setup()
{
   Serial.begin(9600);
   nfc.begin();
   nfc.SAMConfig();
}


void loop()
{
   uint32_t id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A);

   if( id > 0  &&  !escrito )
   {
      // Segun el color del Tag (del plastico) deberemos de descomentar la linea que se corresponda
      // para que tenga coherencia con la configuracion que almacena:

      rgb.color.rojo  = 0;   rgb.color.verde = 255; rgb.color.azul  = 0;   // Lima
      // rgb.color.rojo  = 0;   rgb.color.verde = 0;   rgb.color.azul  = 255; // Azul
      // rgb.color.rojo  = 204; rgb.color.verde = 0;   rgb.color.azul  = 0;   // Rojo
      // rgb.color.rojo  = 160; rgb.color.verde = 255; rgb.color.azul  = 0;   // Amarillo
      // rgb.color.rojo  = 255; rgb.color.verde = 255; rgb.color.azul  = 255; // Blanco
      // rgb.color.rojo  = 0;   rgb.color.verde = 0;   rgb.color.azul  = 0;   // GRIS == OFF

      if( !nfc.writeAllMemory( id , rgb.b, sizeof(rgb.b) ) )
         Serial.println("Error de escritura");
      else
      {
         escrito = true;
         Serial.println("Escritura realizada correctamente");
      }

   }
}

Lo mismo sucede con el segundo ejemplo que en este caso su funcion es leer la configuración grabada en la EEPROM y encender el Led RGB en los colores/tonalidades que hayamos indicado.

Como siempre recomiendo leer las respectivas entradas de estructuras Union y Struct para entender como funcionan.

/**
 * Author:     Alberto Gil Tesa
 * WebSite:    http://giltesa.com
 * License:    CC BY-NC-SA 3.0
 *
 * Description:
 *   ARDUINO SHIELD NFC PN532 ISP
 *
 *   Ejemplo de uso de la shield NFC con chip PN532.
 *   Lee en la memoria EEPROM de la llave NFC
 *   la configuracion de colores de un LED RGB
 *   para encenderlo segun corresponda.
 */


struct DATOS{
   byte rojo;
   byte verde;
   byte azul;
};

union MEMORIA{
   DATOS color;
   byte  b[sizeof(DATOS)];
}
rgb;


#include <PN532.h>

// Shield NFC:
#define SCK        13
#define MOSI       11
#define SS         10
#define MISO       12

// Pines LED RGB:
#define LED_AZUL    2
#define LED_VERDE   3
#define LED_ROJO    4


PN532 nfc(SCK, MISO, MOSI, SS);


void setup()
{
   Serial.begin(9600);
   nfc.begin();
   nfc.SAMConfig();

   pinMode( LED_AZUL  , OUTPUT );
   pinMode( LED_VERDE , OUTPUT );
   pinMode( LED_ROJO  , OUTPUT );
}


void loop()
{
   uint32_t id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A);

   if( id > 0 )
   {
      if( !nfc.readAllMemory(id , rgb.b , sizeof(rgb.b)) )
         Serial.println("Error de lectura");
      else
      {
         analogWrite( LED_ROJO  , rgb.color.rojo  );
         analogWrite( LED_VERDE , rgb.color.verde );
         analogWrite( LED_AZUL  , rgb.color.azul  );
         delay(1000);
      }
   }
}

Y con los ejemplos se termina esta review. Si te ha gustado puedes compartirla para que mas gente pueda leerla :slight_smile:

Edit:
Bendita limitación de caracteres -_-

giltesa, pedazo post y contribucion. Genial y buen trabajo!

Genial, fantastico post!!!!!

Esta genial. Menuda currada.

Un post genial...Muchas gracias Giltesa!!!!!

Es posible modificar el código nfc que transmite una llave?

hay nfc grabables y otras fijas, no es mas que un codigo

maxid:
hay nfc grabables y otras fijas, no es mas que un codigo

Y suponiendo que tengo una grabable, se puede clonar el codigo entero de otra en esa que es grabable? Es decir para que acabe siendo "la misma clave"

si, busca en atmel tienen los chips. Despues en ebay, dx y demas encuentras de todo
Estas se usan para lugares donde hay visitas, hoteles y le dan una llave de acceso, el cual le cambian el codigo. Es mas simple cambiar el codigo de la tarjeta que reprogramar el lector. En realidad es un problema de seguridad que debes auditar.

maxid:
si, busca en atmel tienen los chips. Despues en ebay, dx y demas encuentras de todo
Estas se usan para lugares donde hay visitas, hoteles y le dan una llave de acceso, el cual le cambian el codigo. Es mas simple cambiar el codigo de la tarjeta que reprogramar el lector. En realidad es un problema de seguridad que debes auditar.

Llaveros NFC programables para móvil, Arduino, etc. - el blog de giltesa
Recomendaciones para ti - DealeXtreme

entonces que funcion de la librería debería usar para pasar toda la información de una llave a otra y así tenerla duplicada. Mi idea es leer de una llave y pasar toda esa información a una que permita escritura para poder tenerla "por duplicado"

Esta shield funciona también con Arduino Leonardo o hay que hacer alguna modificación?

karlospv94:

maxid:
si, busca en atmel tienen los chips. Despues en ebay, dx y demas encuentras de todo
Estas se usan para lugares donde hay visitas, hoteles y le dan una llave de acceso, el cual le cambian el codigo. Es mas simple cambiar el codigo de la tarjeta que reprogramar el lector. En realidad es un problema de seguridad que debes auditar.

Llaveros NFC programables para móvil, Arduino, etc. - el blog de giltesa
Recomendaciones para ti - DealeXtreme

entonces que funcion de la librería debería usar para pasar toda la información de una llave a otra y así tenerla duplicada. Mi idea es leer de una llave y pasar toda esa información a una que permita escritura para poder tenerla "por duplicado"

En la libreria que puse, y modifique, tienes añadidos dos metodos para leer y escribir toda la informacion de golpe... pero necesitas las claves de acceso a cada bloque de memoria. Los metodos estan adaptados para que funcionen con las compradas por ebay.

karlospv94:
Esta shield funciona también con Arduino Leonardo o hay que hacer alguna modificación?

Si, funciona sin problemas en el Leonardo.

giltesa:

karlospv94:

maxid:
si, busca en atmel tienen los chips. Despues en ebay, dx y demas encuentras de todo
Estas se usan para lugares donde hay visitas, hoteles y le dan una llave de acceso, el cual le cambian el codigo. Es mas simple cambiar el codigo de la tarjeta que reprogramar el lector. En realidad es un problema de seguridad que debes auditar.

Llaveros NFC programables para móvil, Arduino, etc. - el blog de giltesa
Recomendaciones para ti - DealeXtreme

entonces que funcion de la librería debería usar para pasar toda la información de una llave a otra y así tenerla duplicada. Mi idea es leer de una llave y pasar toda esa información a una que permita escritura para poder tenerla "por duplicado"

En la libreria que puse, y modifique, tienes añadidos dos metodos para leer y escribir toda la informacion de golpe... pero necesitas las claves de acceso a cada bloque de memoria. Los metodos estan adaptados para que funcionen con las compradas por ebay.

karlospv94:
Esta shield funciona también con Arduino Leonardo o hay que hacer alguna modificación?

Si, funciona sin problemas en el Leonardo.

vale ya entiendo. Es decir, en el código de la librería s epresupone que la clave es 0xFF.... pero si quisiese leer un bloque de otra tarjeta debería poner la clave real de esa tarjeta para cada bloque para poder leer, verdad?

karlospv94:

giltesa:

karlospv94:

maxid:
si, busca en atmel tienen los chips. Despues en ebay, dx y demas encuentras de todo
Estas se usan para lugares donde hay visitas, hoteles y le dan una llave de acceso, el cual le cambian el codigo. Es mas simple cambiar el codigo de la tarjeta que reprogramar el lector. En realidad es un problema de seguridad que debes auditar.

Llaveros NFC programables para móvil, Arduino, etc. - el blog de giltesa
Recomendaciones para ti - DealeXtreme

entonces que funcion de la librería debería usar para pasar toda la información de una llave a otra y así tenerla duplicada. Mi idea es leer de una llave y pasar toda esa información a una que permita escritura para poder tenerla "por duplicado"

En la libreria que puse, y modifique, tienes añadidos dos metodos para leer y escribir toda la informacion de golpe... pero necesitas las claves de acceso a cada bloque de memoria. Los metodos estan adaptados para que funcionen con las compradas por ebay.

karlospv94:
Esta shield funciona también con Arduino Leonardo o hay que hacer alguna modificación?

Si, funciona sin problemas en el Leonardo.

vale ya entiendo. Es decir, en el código de la librería s epresupone que la clave es 0xFF.... pero si quisiese leer un bloque de otra tarjeta debería poner la clave real de esa tarjeta para cada bloque para poder leer, verdad?

Eso es, en este caso la clave de estas tarjetas (de todos los llaveros y de la tarjeta con forma de tarjeta de credito) es:
uint8_t keys[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}
Pero en otras llaves podria ser distinta.

Y hay que tener cuidado con no escribir en la memoria donde se guarda la clave o perderas ese bloque y los siguientes.

giltesa:

karlospv94:

giltesa:

karlospv94:

maxid:
si, busca en atmel tienen los chips. Despues en ebay, dx y demas encuentras de todo
Estas se usan para lugares donde hay visitas, hoteles y le dan una llave de acceso, el cual le cambian el codigo. Es mas simple cambiar el codigo de la tarjeta que reprogramar el lector. En realidad es un problema de seguridad que debes auditar.

Llaveros NFC programables para móvil, Arduino, etc. - el blog de giltesa
Recomendaciones para ti - DealeXtreme

entonces que funcion de la librería debería usar para pasar toda la información de una llave a otra y así tenerla duplicada. Mi idea es leer de una llave y pasar toda esa información a una que permita escritura para poder tenerla "por duplicado"

En la libreria que puse, y modifique, tienes añadidos dos metodos para leer y escribir toda la informacion de golpe... pero necesitas las claves de acceso a cada bloque de memoria. Los metodos estan adaptados para que funcionen con las compradas por ebay.

karlospv94:
Esta shield funciona también con Arduino Leonardo o hay que hacer alguna modificación?

Si, funciona sin problemas en el Leonardo.

vale ya entiendo. Es decir, en el código de la librería s epresupone que la clave es 0xFF.... pero si quisiese leer un bloque de otra tarjeta debería poner la clave real de esa tarjeta para cada bloque para poder leer, verdad?

Eso es, en este caso la clave de estas tarjetas (de todos los llaveros y de la tarjeta con forma de tarjeta de credito) es:
uint8_t keys[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}
Pero en otras llaves podria ser distinta.

Y hay que tener cuidado con no escribir en la memoria donde se guarda la clave o perderas ese bloque y los siguientes.

De acuerdo, gracias! Ahora ya se me han aclarado unas dudas que tenía :slight_smile:
No hay ninguna forma entonces de modificar la clave de cada sector? Porque sino cualquier persona que conozca mi tarjeta sabrá cual es la clave y podría leer toda la info de ella...

Yo la intente modificar en una pero no sé si lo hice mal o que pero el caso es que brickee los bloques de memoria y no supe restaurar la clave original ni nada. No probé con más llaveros pues no quería cargarme más...

En cualquier caso, la información que grabes dentro la puedes guardar cifrada con algún algoritmo asi que lo de la clave de acceso a los bloques de memoria es lo de menos, por mucho que lean la informacion si no la saben descifrar no les va a servir para nada.