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:
23 Comentários
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.
ResponderExcluirMesmo problema aqui.
ExcluirEssa é apenas uma mensagem de Warning!
ExcluirPara desabilitá-la, edite o arquivo "library.properties" alterando a linha:
architectures=avr,STM32F1,teensy,esp8266
para
architectures=*
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?
ResponderExcluirOlá, seguindo o código que temos no exemplo temos que transformar a String em um array de char, para isso utilize os seguintes comandos:
ExcluirString 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.
Fiz tudo certo mais não deu certo !
ExcluirEh necessário duas protoboard mesmo? tem como fazer so com uma?
ResponderExcluirEstou 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?
ResponderExcluirEu 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.
ExcluirAinda 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?
ResponderExcluirOlá Fernando, quando tentamos compilar o código está dando um erro.
ResponderExcluirstray'\302'in program
Você sabe que tipo de erro é este?
Abraços!
Não entendi onde fica o controle de acesso no código. Qualquer cartão que eu coloque ele aceita.
ResponderExcluirOi, é possível fazer exatamente esse circuito mas com o ESP8266?
ResponderExcluirÉ sim!
ExcluirErro : 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).
ResponderExcluirisso pode prejudicar? carrego o codigo e abro a serial , mas nada de opcoes
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???
ResponderExcluirola teria como apagar os dados salvo no RFID pois eu não estou conseguindo
ResponderExcluirPreciso 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?
ResponderExcluirbarramento spi achei aqui
ExcluirBoa noite FernandoK.
ResponderExcluirHoje 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
Olá tudo bem?
ResponderExcluirÉ possível usar dois leitor de RFID no mesmo ESP32?
Olá, pessoal.
ResponderExcluirUsei 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.
Boa Noite Fernando,
ResponderExcluirTudo bem?
Como eu faço para excluir um tag gravado?
Obrigado.
Henrique Bonatelli