Recents in Beach


Receba o meu conteúdo GRATUITAMENTE


ESP32 com RFID: Controle de Acesso


Que tal um método de identificação automática através de sinais de rádio que pode lhe trazer segurança e controlar o acesso de pessoas a um determinado local? Isso é possível através da identificação por radiofrequência ou RFID, do inglês Radio Frequency Identification. E é a montagem desse sistema que vou lhe ensinar hoje.
Esse sistema funciona com um cartão ou também pode ser um chaveiro que possui um chip em seu interior. Por meio da identificação dos dados deste cartão ou chip é que é possível fazer o controle de acesso, método bastante utilizado em registros de pontos de funcionários, transporte público, bibliotecas, entre outros.
Nosso objetivo, portanto, é criar um programa, no qual poderemos tanto fazer a leitura de um cartão (ou tag) RFID quanto gravar os dados nele. Utilizamos um WiFi NodeMCU-32S e um módulo RFID-RC522.
Importante destacar que podemos armazenar e recuperar dados nestes chips ou cartões remotamente através de dispositivos, já que estes chegam a ter 1k de memória.


Funcionamento

Um sistema RFID é composto basicamente de um transceptor com decodificador e uma antena e um transponder. E como funciona? Esses cartões têm uma bobina dentro deles. Quando você aproxima-os do leitor, eles emitem um sinal de radiofrequência através das antenas conectadas ao leitor. O tag energizado, que é o cartão, modula as informações gravadas em sua memória e envia esses dados ao leitor. Esse cartão, então, entra no campo de leitura e recebe energia do leitor para executar as operações. O leitor do RFID recebe as informações enviadas pelo tag, decodifica e envia os dados para aplicação do servidor.

Memória

Como mencionado, temos 1k de memória dentro deste tipo de chip. E, a memória EEPROM está organizada da seguinte maneira: são 16 setores de 4 blocos. Cada bloco contém 16 bytes. Lembrando que, dentro do código fonte, você só faz referência ao número do bloco.

Circuito

Nesta imagem nós temos um chaveiro que possui um chip de RFID e nós temos o tradicional cartão, além da nossa montagem. E como que funciona esse circuito? Bom, na internet, você vai encontrar o módulo RFID-RC522 sendo muito utilizado com o Arduino, mas o problema é que esse Arduino, seja, Mega, Nano, independente do modelo, ele não tem comunicação, como rede WiFi, Ethernet, entre outras. Portanto, nós usamos aqui o ESP32. Ele já conta com Bluetooth, RF, ou seja, fácil comunicação. Destaco aqui, então, que quase tudo que funciona com o Arduino também funciona com o ESP32.
Voltando ao circuito, quando, durante a análise de um cartão ou chip, acender o led verde, isso quer dizer que a identificação foi feita e o acesso é liberado. Quando acender o led vermelho quer dizer que o dado não foi autenticado.


WiFi NodeMCU-32S ESP-WROOM-32


RFID-RC522

Aqui temos imagens do cartão e do chaveiro, bem como a antena do RFID. Um detalhe importante é que a Interface dele é SPI.


Montagem

Na nossa montagem nós temos o ESP32 alimentado pela USB e também ligado na serial da IDE Arduino, dois leds para indicar se a leitura foi bem sucedida ou não, e o leitor de RFID, o RC522. Temos o chaveiro com chip e o cartão.
Colocando o chaveiro sobre o leitor aparece a opção de 0 para leitura de dados e, 1, para gravação destes dados. Fazemos um exemplo que mostra que, após a leitura do chip ou cartão, se acender o led verde é que o leitor reconheceu o número. Em caso de acender o led vermelho, quer dizer que ocorreu algum tipo de erro e não foi efetuada a autenticação.
No exemplo, ainda mostro como gravar dados no tag, o que será explicado mais abaixo.

Bibliotecas

Adicione a seguinte biblioteca “MFRC522”.
Basta acessar “Sketch >> Incluir Bibliotecas >> Gerenciar Bibliotecas...”

Código fonte

Nosso programa funcionará da seguinte maneira: após iniciar, o programa ficará esperando que um cartão ou tag seja identificado. Após isso, um menu surgirá para que o usuário escolha entre fazer uma leitura ou gravar algo. Em seguida a operação será realizada.

Setup

Nesta parte tratamos da inclusão das bibliotecas e definimos os tamanhos do buffer e dos dados do bloco. Criamos objetos e inicializamos os pinos, bem como a serial, a comunicação SPI, os leds e o serviço da antena. Já começo a incluir também mensagens no serial monitor.

#include <mfrc522.h> //biblioteca responsável pela comunicação com o módulo RFID-RC522
#include <SPI.h> //biblioteca para comunicação do barramento SPI

#define SS_PIN    21
#define RST_PIN   22

#define SIZE_BUFFER     18
#define MAX_SIZE_BLOCK  16

#define pinVerde     12
#define pinVermelho  32

//esse objeto 'chave' é utilizado para autenticação
MFRC522::MIFARE_Key key;
//código de status de retorno da autenticação
MFRC522::StatusCode status;

// Definicoes pino modulo RC522
MFRC522 mfrc522(SS_PIN, RST_PIN); 

void setup() {
  // Inicia a serial
  Serial.begin(9600);
  SPI.begin(); // Init SPI bus

  pinMode(pinVerde, OUTPUT);
  pinMode(pinVermelho, OUTPUT);
  
  // Inicia MFRC522
  mfrc522.PCD_Init(); 
  // Mensagens iniciais no serial monitor
  Serial.println("Aproxime o seu cartao do leitor...");
  Serial.println();

}

Loop

No Loop nós aguardamos a aproximação do cartão e selecionamos o mesmo. No menu, ofertamos as opções de ler ou gravar dados. Instruímos nesta parte quando o dispositivo deve deixar o estado ACTIVE para o estado de PARADA. Temos que utilizar tal método para possibilitar novas leituras.

void loop() 
{
   // Aguarda a aproximacao do cartao
  if ( ! mfrc522.PICC_IsNewCardPresent()) 
  {
    return;
  }
  // Seleciona um dos cartoes
  if ( ! mfrc522.PICC_ReadCardSerial()) 
  {
    return;
  }

  //chama o menu e recupera a opção desejada
  int opcao = menu();
  
  if(opcao == 0) 
    leituraDados();
  else if(opcao == 1) 
    gravarDados();
  else {
    Serial.println(F("Opção Incorreta!"));
    return;
  }
  // instrui o PICC quando no estado ACTIVE a ir para um estado de "parada"
  mfrc522.PICC_HaltA(); 
  // "stop" a encriptação do PCD, deve ser chamado após a comunicação com autenticação, caso contrário novas comunicações não poderão ser iniciadas
  mfrc522.PCD_StopCrypto1();  
}

Leitura

Nesta parte tratamos a leitura dos dados do cartão/tag. Temos que preparar todas as chaves, tratar do tamanho do buffer e fazer a autenticação do bloco que vamos operar. Por fim, definimos a impressão dos dados lidos.

//faz a leitura dos dados do cartão/tag
void leituraDados()
{
  //imprime os detalhes tecnicos do cartão/tag
  mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); 

  //Prepara a chave - todas as chaves estão configuradas para FFFFFFFFFFFFh (Padrão de fábrica).
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  //buffer para colocar os dados ligos
  byte buffer[SIZE_BUFFER] = {0};

  //bloco que faremos a operação
  byte bloco = 1;
  byte tamanho = SIZE_BUFFER;


  //faz a autenticação do bloco que vamos operar
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, bloco, &key, &(mfrc522.uid)); //line 834 of MFRC522.cpp file
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Authentication failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    digitalWrite(pinVermelho, HIGH);
    delay(1000);
    digitalWrite(pinVermelho, LOW);
    return;
  }

  //faz a leitura dos dados do bloco
  status = mfrc522.MIFARE_Read(bloco, buffer, &tamanho);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Reading failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    digitalWrite(pinVermelho, HIGH);
    delay(1000);
    digitalWrite(pinVermelho, LOW);
    return;
  }
  else{
      digitalWrite(pinVerde, HIGH);
      delay(1000);
      digitalWrite(pinVerde, LOW);
  }

  Serial.print(F("\nDados bloco ["));
  Serial.print(bloco);Serial.print(F("]: "));

  //imprime os dados lidos
  for (uint8_t i = 0; i < MAX_SIZE_BLOCK; i++)
  {
      Serial.write(buffer[i]);
  }
  Serial.println(" ");
}

Gravação

Para gravar dados no cartão/tag temos que seguir alguns passos. A partir do momento que escolhermos a opção de gravação, temos 30 segundos para fazer a entrada de dados via serial. Inserirmos os dados a serem gravados com o caractere “#” e preparamos a chave. Será preciso zerar o buffer e fazer a gravação no bloco 1, já que no bloco 0 temos gravado o número do cartão, que já vem de fábrica. Portanto, não mexemos no bloco 0.
Tratamos na sequência do tamanho de dados e inserimos um comando para autenticação e habilitação de uma comunicação segura. Também colocamos mensagens de erro iguais a da parte da leitura para exibição em caso de dado não autenticado. Gravamos os dados no bloco devido.
//faz a gravação dos dados no cartão/tag
void gravarDados()
{
  //imprime os detalhes tecnicos do cartão/tag
  mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); 
  // aguarda 30 segundos para entrada de dados via Serial
  Serial.setTimeout(30000L) ;     
  Serial.println(F("Insira os dados a serem gravados com o caractere '#' ao final\n[máximo de 16 caracteres]:"));

  //Prepara a chave - todas as chaves estão configuradas para FFFFFFFFFFFFh (Padrão de fábrica).
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  //buffer para armazenamento dos dados que iremos gravar
  byte buffer[MAX_SIZE_BLOCK] = "";
  byte bloco; //bloco que desejamos realizar a operação
  byte tamanhoDados; //tamanho dos dados que vamos operar (em bytes)

  //recupera no buffer os dados que o usuário inserir pela serial
  //serão todos os dados anteriores ao caractere '#'
  tamanhoDados = Serial.readBytesUntil('#', (char*)buffer, MAX_SIZE_BLOCK);
  //espaços que sobrarem do buffer são preenchidos com espaço em branco
  for(byte i=tamanhoDados; i < MAX_SIZE_BLOCK; i++)
  {
    buffer[i] = ' ';
  }
 
  bloco = 1; //bloco definido para operação
  String str = (char*)buffer; //transforma os dados em string para imprimir
  Serial.println(str);

  //Authenticate é um comando para autenticação para habilitar uma comuinicação segura
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A,
                                    bloco, &key, &(mfrc522.uid));

  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    digitalWrite(pinVermelho, HIGH);
    delay(1000);
    digitalWrite(pinVermelho, LOW);
    return;
  }
  //else Serial.println(F("PCD_Authenticate() success: "));
 
  //Grava no bloco
  status = mfrc522.MIFARE_Write(bloco, buffer, MAX_SIZE_BLOCK);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    digitalWrite(pinVermelho, HIGH);
    delay(1000);
    digitalWrite(pinVermelho, LOW);
    return;
  }
  else{
    Serial.println(F("MIFARE_Write() success: "));
    digitalWrite(pinVerde, HIGH);
    delay(1000);
    digitalWrite(pinVerde, LOW);
  }
 
}

Menu

Aqui programamos o Menu. O monitor expõe todas as opções e aguarda o envio de dados. Quando uma opção é selecionada, ele retira 48 do valor lido, que é o 0 da tabela Ascii. Essa tabela é antiga e não utilizada no PC, mas no Arduino e em microcontroladores vocês vão precisar lidar com ela. Se você não conhece, dá uma pesquisada na internet para saber do que se trata.

//menu para escolha da operação
int menu()
{
  Serial.println(F("\nEscolha uma opção:"));
  Serial.println(F("0 - Leitura de Dados"));
  Serial.println(F("1 - Gravação de Dados\n"));

  //fica aguardando enquanto o usuário nao enviar algum dado
  while(!Serial.available()){};

  //recupera a opção escolhida
  int op = (int)Serial.read();
  //remove os proximos dados (como o 'enter ou \n' por exemplo) que vão por acidente
  while(Serial.available()) {
    if(Serial.read() == '\n') break; 
    Serial.read();
  }
  return (op-48);//do valor lido, subtraimos o 48 que é o ZERO da tabela ascii
}



Faça download dos arquivos:







Postar um comentário

23 Comentários

  1. Olá! No meu ESP não roda e dá esta mensagem na IDE do Arduino: AVISO: a biblioteca MFRC522 alega rodar em arquitetura(s) [avr e pode ser incompatível com sua placa atual, que roda em arquitetura(s) STM32F1.

    ResponderExcluir
    Respostas
    1. Essa é apenas uma mensagem de Warning!
      Para desabilitá-la, edite o arquivo "library.properties" alterando a linha:

      architectures=avr,STM32F1,teensy,esp8266

      para

      architectures=*

      Excluir
  2. Alguém tentou em vez de gravar os dados digitados gravar uma string? estou obtendo dificuldade em fazer a conversão, poderiam me ajudar por favor?

    ResponderExcluir
    Respostas
    1. Olá, seguindo o código que temos no exemplo temos que transformar a String em um array de char, para isso utilize os seguintes comandos:

      String str = "teste";
      byte buff[MAX_SIZE_BLOCK];
      str.toCharArray((char*)buff, str.length()+1);

      a partir daí o buff já contém o conteúdo da String.

      Excluir
    2. Fiz tudo certo mais não deu certo !

      Excluir
  3. Eh necessário duas protoboard mesmo? tem como fazer so com uma?

    ResponderExcluir
  4. Estou tendo erro PCD_Authenticate() failed: Timeout in communication pesquisei na internet e encontrei informação que é pq meu cartão ta encryptado, que pode ter alguma coisa gravado nele. Alguem saberia me ajudar?

    ResponderExcluir
    Respostas
    1. Eu tive o mesmo problema, assim se vc colocar o cartão e retirar, e depois apertar o 0 para a leitura, vai dar esse erro, vc tem que deixar o cartão proximo ao leitor e apertar o 0 com ele ainda proximo para autenticar corretamente, se retirar o cartão antes de apertar o 0, ele não vai conseguir autenticar e vai dar o erro.

      Excluir
  5. Ainda com problema nesse codigo...srs.. a minha pergunta anterior nao encontrei resposta, mas gostaria de saber o seguinte:Para eu complicar o codigo eu pressiono o botao boot para conectar, mas quando tento executar esse codigo para aparece o texto eu estou tendo que pressionar o botão En no esp32. Alguem saberia me dizer o pq estou tendo que apertar o botão En?

    ResponderExcluir
  6. Olá Fernando, quando tentamos compilar o código está dando um erro.

    stray'\302'in program

    Você sabe que tipo de erro é este?

    Abraços!

    ResponderExcluir
  7. Não entendi onde fica o controle de acesso no código. Qualquer cartão que eu coloque ele aceita.

    ResponderExcluir
  8. Oi, é possível fazer exatamente esse circuito mas com o ESP8266?

    ResponderExcluir
  9. Erro : AVISO: a biblioteca MFRC522 alega rodar em arquitetura(s) (avr, STM32F1, teensy, esp8266, samd) e pode ser incompatível com sua placa atual, que roda em arquitetura(s) (esp32).
    isso pode prejudicar? carrego o codigo e abro a serial , mas nada de opcoes

    ResponderExcluir
  10. Gostei muito do projecto e fiz o mesmo funciona normalmente, mas só que não consigo enviar dados lido de cartão para base de dados???

    ResponderExcluir
  11. ola teria como apagar os dados salvo no RFID pois eu não estou conseguindo

    ResponderExcluir
  12. Preciso fazer o projeto em uma placa, mas para isso preciso alterar os pinos do RFID, como mudo os pinos dele que vão no ESP?

    ResponderExcluir
  13. Boa noite FernandoK.
    Hoje tentei utilizar um RFID com ESP32 (modulo de desenvolvimento ESP32-ESPDUINO-32/HW-707) , respeitando as conexões de seu tutorial (GPIOs),usando IDE/Ferramentas:
    Placa "ESP32 Dev Module"
    Upload Speed:115200
    CPU Frequency: 240 MHZ
    Flash Frequency: 80 MHZ
    Flash Mode: "QIO"
    Flash Size: "4MB(32Mb)"
    Partion Scheme: "Default 4MB with spiffs (1.2 MB APP/1.5 SPIFFS)"
    PSRAM: "Disabled"

    A transferencia é feita mas no monitor serial só aparece as configurações do ESP sem apresentar o MENU.
    Alguma observação ?
    Obrigado

    ResponderExcluir
  14. Olá tudo bem?

    É possível usar dois leitor de RFID no mesmo ESP32?

    ResponderExcluir
  15. Olá, pessoal.
    Usei este código para alguns testes, até que eu fiz uma alteração e não consegui fazer mais nada no cartão.
    O que fiz:
    1 - Alterei a função gravarDados() para gravarDados(byte bloco) e, ainda dentro dessa função, excluí as linhas "byte bloco;" e "bloco = 1;".
    2 - Na função loop, alterei o trecho abaixo:
    if(opcao == 0)
    leituraDados();
    else if(opcao == 1)
    gravarDados();
    else {
    Serial.println(F("Opção Incorreta!"));
    return;
    }

    Ficando desta forma:
    if(opcao == 0)
    leituraDados();
    else if(opcao == 1)
    for (byte i = 1; i < 8; i++){
    gravarDados(i);
    }
    else {
    Serial.println(F("Opção Incorreta!"));
    return;
    }

    Minha intenção com isso era escrever nos blocos 1, 2, 3, 4, 5, 6 e 7. A gravação ocorreu sem problemas, mas depois disso não consigo mais ler o cartão.
    Alguém sabe o que fiz de errado?

    Muito obrigado.

    ResponderExcluir
  16. Boa Noite Fernando,

    Tudo bem?

    Como eu faço para excluir um tag gravado?

    Obrigado.
    Henrique Bonatelli

    ResponderExcluir