arduino

Leer y escribir en etiquetas RFID con MFRC522 (RFID-RC522)

En este post te voy a mostrar cómo guardar información en las tarjetas o etiquetas RFID usando el lector MFRC522 y un Arduino o NodeMCU ESP8266.

Leer y escribir RFID – Almacenamiento de datos

Anteriormente ya te mostré cómo leer el serial de estas etiquetas, pero ahora te voy a enseñar a escribir y leer información dentro de ellas.

Gracias a esto puedes crear infinidad de aplicaciones como una tarjeta de crédito, monedero electrónico, control de entrada para el transporte público, etcétera.

Te voy a mostrar cómo leer y escribir datos usando la NodeMCU ESP8266 pero teóricamente puedes usar cualquier Arduino, ya sea el UNO, Mega, etcétera; lo único que cambia es la conexión, pues el código se queda casi intacto.

Sobre la seguridad

En mi caso siempre utilizo mis proyectos como un pasatiempo, aunque bien esto se puede llevar a la práctica. Solo te recomiendo algo: cambia la clave de las tarjetas, así solo tú la vas a conocer y nadie podrá modificar los datos.

Por otro lado, yo no guardaría datos en la RFID, solo asociaría el serial al servidor, y llevaría el dato (ya sea saldo, crédito restante, etcétera) en el servidor, de modo que no se pueda modificar directamente en la tarjeta.

Al final queda todo en ti, pero te aviso las posibles implicaciones. De igual modo es más simple guardar y escribir datos en la tarjeta, que tener una autenticación con el servidor y cosas de esas.

También te invito a leer lo que dice el autor de la librería que permite usar estas tarjetas.

Almacenar información en tarjetas RFID

Vamos a usar las funciones MIFARE_Write y MIFARE_Read para escribir y leer información respectivamente, usando la librería para el lector MMFRC522 también conocido como RFID-RC522.

Esta operación puede ser ejecutada al presionar un botón, recibir una petición HTTP, etcétera. Para ejemplos simples, en los ejemplos voy a escribir y leer tan pronto la tarjeta se acerque al lector. El circuito queda así:

Conexión lector RFID con NodeMCU ESP8266 – Circuito

Te repito: puedes usar un Arduino si quieres, solo cambia la conexión y ya.

Por cierto, te invito encarecidamente a que primero leas el tutorial sobre cómo leer el serial de las etiquetas RFID; está más detallado y contiene pasos que me saltaré aquí por simplicidad.

Setup

En el setup del código vamos a iniciar el lector y preparar la clave. Si tú ya cambiaste la clave entonces cámbiala en el código.

void setup()
{
  Serial.begin(9600);
  while (!Serial)
  {
    // Esperar serial. Nota: la tarjeta NO HARÁ NADA hasta que haya comunicación Serial (es decir, que el monitor serial sea abierto)
    // si tú no quieres esto, simplemente elimina todas las llamadas a Serial
  }
  // Iniciar lector
  SPI.begin();
  lector.PCD_Init();
  // Preparar la clave para leer las tarjetas RFID
  for (byte i = 0; i < 6; i++)
  {
    clave.keyByte[i] = 0xFF;
  }
  Serial.println("Iniciado correctamente");
}

Leer datos de RFID

Leer etiqueta RFID con ESP8266 y RFID-RC522

Veamos cómo leer los datos almacenados. La primera vez puede que encuentres bytes raros o cadenas raras. Para que el uso sea fácil, escribí una función que escribe una cadena en el bloque.

bool leer(char mensaje[LONGITUD_BYTES])
{
  if (!lector.PICC_IsNewCardPresent())
  {
    return false;
  }
  if (!lector.PICC_ReadCardSerial())
  {
    Serial.println("Error leyendo serial");
    return false;
  }
  byte bloque = 1; // El bloque que leemos
  byte longitud = LONGITUD_BYTES;
  byte buferLectura[LONGITUD_BYTES];

  MFRC522::StatusCode estado;
  estado = lector.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, bloque, &clave, &(lector.uid));
  if (estado != MFRC522::STATUS_OK)
  {
    Serial.println("Error autenticando");
    Serial.println(lector.GetStatusCodeName(estado));
    return false;
  }
  estado = lector.MIFARE_Read(bloque, buferLectura, &longitud);
  if (estado != MFRC522::STATUS_OK)
  {
    Serial.println("Error leyendo bloque");
    Serial.println(lector.GetStatusCodeName(estado));
    return false;
  }

  for (uint8_t i = 0; i < LONGITUD_BYTES - 2; i++)
  {
    mensaje[i] = buferLectura[i];
  }
  // Ya pueden retirar la tarjeta

  lector.PICC_HaltA();
  lector.PCD_StopCrypto1();
  return true;
}

¿Por qué una cadena? fácil, de este modo puedes guardar cualquier tipo de dato. Por ejemplo, si quisieras guardar el saldo o dinero de un usuario simplemente convertirías el número a cadena con snprintf y luego guardarías esa cadena. Lo mismo para el proceso inverso.

No olvides que las cadenas (al menos en C) usan un byte extra para guardar el byte de terminación \0, por lo que la cadena “Hola” en realidad pesa 5 bytes. Te digo esto porque el límite de escritura es de 16 bytes, así que solo puedes guardar 15 caracteres por bloque.

La función va a devolver false en caso de que no haya podido leer (esto puede ser porque no hay tarjeta presente, por ejemplo) y true en caso de que todo sea exitoso.

El modo de uso es:

char contenidoRfid[LONGITUD_BYTES] = "";
bool lecturaExitosa = leer(contenidoRfid);
if (lecturaExitosa)
{
  Serial.println("Lo que hay escrito es:");
  Serial.println(contenidoRfid);
}
else
{
  Serial.println("Error leyendo. Tal vez no hay RFID presente");
}

Fíjate en que primero declaro la cadena y luego se la paso a la función, esto es debido a que la función que lee los datos de RFID no devolverá la información que se haya guardado, sino que va a colocar la información dentro de la cadena que le pasemos.

Escribir datos RFID

Guardar información en tarjeta RFID con MFRC522

Ahora veamos cómo escribir. En este caso la función recibe igualmente una cadena para escribirla. Queda así:

bool escribir(char cadena[LONGITUD_BYTES_ESCRITURA])
{

  if (!lector.PICC_IsNewCardPresent())
  {
    return false;
  }
  if (!lector.PICC_ReadCardSerial())
  {
    Serial.println("Error leyendo serial");
    return false;
  }

  byte bloque = 1;
  byte buferEscritura[LONGITUD_BYTES_ESCRITURA];
  // Copiar cadena al búfer
  for (uint8_t i = 0; i < LONGITUD_BYTES_ESCRITURA; i++)
  {
    buferEscritura[i] = cadena[i];
  }
  MFRC522::StatusCode estado;
  estado = lector.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, bloque, &clave, &(lector.uid));
  if (estado != MFRC522::STATUS_OK)
  {
    Serial.println("Error autenticando");
    Serial.println(lector.GetStatusCodeName(estado));
    return false;
  }
  estado = lector.MIFARE_Write(bloque, buferEscritura, LONGITUD_BYTES_ESCRITURA);
  if (estado != MFRC522::STATUS_OK)
  {
    Serial.println("Error escribiendo bloque");
    Serial.println(lector.GetStatusCodeName(estado));
    return false;
  }
  // Ya pueden retirar la tarjeta

  lector.PICC_HaltA();
  lector.PCD_StopCrypto1();
  return true;
}

De manera parecida, la función devolverá un booleano. El modo de uso es:

char mensaje[] = "parzibyte";
bool escrituraExitosa = escribir(mensaje);
if (escrituraExitosa)
{
  Serial.println("Escrito ok");
}
else
{
  Serial.println("Error escribiendo. Tal vez no hay RFID presente");
}

Primero estoy declarando la cadena en el estilo de C (si quieres declarar la cadena vacía hazlo con char mensaje[] = ""). Luego invoco a la función y dependiendo de ello indico si todo ha ido bien.

Te repito que esta función devolverá false si hay errores de autenticación o si la tarjeta no está presente en el lector.

Poniendo todo junto

El código completo que muestra ejemplos de cómo escribir y leer información en tarjetas RFID usando el MFRC522 y Arduino o ESP8266 lo dejo en GitHub. El loop queda así:

void loop()
{
  if (MODO == MODO_LECTURA)
  {

    char contenidoRfid[LONGITUD_BYTES] = "";
    bool lecturaExitosa = leer(contenidoRfid);
    if (lecturaExitosa)
    {
      Serial.println("Lo que hay escrito es:");
      Serial.println(contenidoRfid);
    }
    else
    {
      Serial.println("Error leyendo. Tal vez no hay RFID presente");
    }
  }
  else if (MODO == MODO_ESCRITURA)
  {
    char mensaje[] = "parzibyte";
    bool escrituraExitosa = escribir(mensaje);
    if (escrituraExitosa)
    {
      Serial.println("Escrito ok");
    }
    else
    {
      Serial.println("Error escribiendo. Tal vez no hay RFID presente");
    }
  }
  delay(1000);
}

Estoy comparando los dos modos solo para ejemplificar; obviamente en la vida real tú puedes invocar esas funciones en donde prefieras.

Por cierto, el delay es para que el mensaje de error no aparezca varias veces en caso de que no haya tarjeta presente.

Para terminar te dejo con más tutoriales de Arduino y Electrónica.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

1 semana hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 semanas hace

Esta web usa cookies.