Automação Residencial

Fechadura Eletrônica com Servo-Motor e RFID

Eletrogate 18 de agosto de 2021

Introdução

Blog-Eletrogate-Fechadura-RFID-1Uma das grandes oportunidades que o Arduino ou qualquer outro sistema IoT que conhecemos nos proporciona é a capacidade de automatizar o nosso dia-a-dia. Por isso, neste post você irá aprender como construir o sistema e o esquema de uma fechadura eletrônica, na qual a tranca será um servo-motor, e a chave será uma tag RFID, tendo integrações com Leds, um display LCD I2C e um mecanismo para cadastrar novas tags.

O RFID é uma tecnologia para identificação sem contato e que é muito utilizado principalmente em sistemas de identificação e em sistemas de segurança. Todo o artigo estará dividido em setores, a fim de proporcionar um maior entendimento, tanto na parte de como capturar a tag RFID, como incluí-la no projeto e como criar o mecanismo que irá adicionar novas tags aos perfis cadastrados no código.

Como projeto final, criaremos um sistema que com as tags RFID cadastradas possamos abrir a fechadura de servo-motor, recebendo, então, uma confirmação via display LCD e leds. Teremos também uma função para incluir novas UIDs RFID aos perfis do código sem uma já cadastrada.


O que é RFID

Blog-Eletrogate-Fechadura-RFID-2RFID é a sigla para “Radio Frequency Identification” (Identificação por radiofrequência) e é o termo dedicado a tecnologias que propiciam a identificação por meio da emissão de ondas de rádio, sejam elas através de um microchip ou de uma tag. Estes basicamente armazenam um número de série que será capturado e decodificado por uma antena, que, no nosso projeto, será a responsável por enviar as informações ao Arduino.

O RFID pode ser utilizado em muitas aplicações, entre elas, nota-se aplicações nas redes hoteleiras (nas chaves dos quartos), em bibliotecas (para o cadastro dos livros), em equipamentos de segurança, identificando animais, entre várias outras aplicações. Como Blog-Eletrogate-Fechadura-RFID-3antes dito, em nosso projeto utilizaremos da aplicação do RFID destinada à abertura de fechaduras.


Estruturando o projeto

Blog-Eletrogate-Fechadura-RFID-4A fim de simplificar todo o desenvolvimento do projeto, este será dividido em algumas partes, visando um final completo para nosso sistema. A primeira parte irá ser destinada a te ensinar como capturar a UID de cada tag RFID e verificar se é igual a outra já cadastrada, a segunda terá como objetivo acionar o servo-motor caso o leitor encontre a UID já cadastrada. A terceira parte será responsável pela confirmação visual via display LCD e pelos leds, a quarta parte irá ensinar a criar o sistema que irá cadastrar novas UIDs, e, por fim, a quinta parte será para resolvermos alguns bugs, incluindo uma mensagem de erro ao sistema.

A cada estágio do desenvolvimento criaremos uma nova sub-rotina no nosso sketch, com o objetivo de organizar e facilitar o entendimento do código, tendo, por fim, o código já pronto e muito bem estruturado.

Para a utilização do leitor e do display serão necessárias bibliotecas extras. Ambas podem ser instaladas pela própria IDE do Arduino, e se chamam “LiquidCrystal_I2C” e “MFRC522”. Todas as outras bibliotecas a serem utilizadas já são nativas, logo, não serão necessários downloads externos.


Materiais Necessários para o Projeto Fechadura Eletrônica com Servo-Motor e RFID

Estes serão os materiais a serem utilizados durante todo o processo de construção do projeto. (Para o tutorial foi utilizado um Arduino Nano visando um sistema compacto, entretanto, um Arduino Uno também pode ser utilizado)


Esquemático

O esquemático abaixo será o esquemático final do nosso projeto, porém, por já estar completo, servirá de base durante todo o nosso desenvolvimento.

Blog-Eletrogate-Fechadura-RFID-5


Parte 1: Descobrindo e Verificando UIDs de Tags RFID

Cada tag RFID possui sua UID própria que será lida pelo leitor, entretanto, para “arquivá-la” dentro do código e compará-la a outras UIDs, deveremos organizar essa leitura, por isso,  através do loop “for” ilustrado abaixo, será formatada a UID no formato “00:AA:11:BB”, sempre adicionando o “0” a numéros de único caractere e sempre mudando as letras para maiúsculas.

#include <SPI.h>                                   //Inclusão das bibliotecas
#include <MFRC522.h>

#define ss 10                                     //Define os pinos ss e rst
#define rst 9 

MFRC522 rfid(ss, rst);

void setup() {
  Serial.begin(9600);                             //Inicia o Monitor Serial
  SPI.begin();                                    //Inicia o SPI
  rfid.PCD_Init();                                //Inicia o leitor
}

void loop() {
  String id = "";                                  //Cria a variável "id"
  
  //Se não houver nenhum cartão, não faz nada
  if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
     return;
  } 
  
  id = le_cartao();                               //Chama a função e imprime a uid lida             
  Serial.println(id)
}

String le_cartao() {  
  String _id = "";                                //Cria a variável "_id"
  for (byte i = 0; i < 4; i++) {                  //Loop for para percorrer os caracteres lidos, seguindo o formato proposto
    _id += (rfid.uid.uidByte[i] < 0x10 ? "0" : "") + String(rfid.uid.uidByte[i], HEX) + (i!=3 ? ":" : "");
  }
    
  _id.toUpperCase();                              //Transforma as letras em caixa alta
  rfid.PICC_HaltA();                              //Para a criptografia
  rfid.PCD_StopCrypto1(); 

  return _id;                                     //Retorna a uid lida
}

Feito isso com suas tags, criaremos agora apenas uma função temporária, ou seja, que não estará no projeto final, a fim de demonstrar como fazer a comparação de UIDs no código. Para isso, será necessário ao menos uma UID salva com você.

#include <SPI.h>                                   //Inclusão das bibliotecas
#include <MFRC522.h>

#define ss 10                                     //Define os pinos ss e rst
#define rst 9 

MFRC522 rfid(ss, rst);

void setup() {
  Serial.begin(9600);                             //Inicia o Monitor Serial
  SPI.begin();                                    //Inicia o SPI
  rfid.PCD_Init();                                //Inicia o leitor
}

void loop() {
  String id = "";                                  //Cria a variável "id"
  
  //Se não houver nenhum cartão, não faz nada
  if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
     return;
  } 
  
  id = le_cartao();                               //Chama a função para ler a uid   

  if (id == "02:DC:A7:34") {                      //Verifica a uid lida (troque o parâmetro de verificação para sua tag antes lida)
    Serial.println("Acesso permitido");           //Imprime a mensagem
  }
}

String le_cartao() {  
  String _id = "";                                //Cria a variável "_id"
  for (byte i = 0; i < 4; i++) {                  //Loop for para percorrer os caracteres lidos, seguindo o formato proposto
    _id += (rfid.uid.uidByte[i] < 0x10 ? "0" : "") + String(rfid.uid.uidByte[i], HEX) + (i!=3 ? ":" : "");
  }
    
  _id.toUpperCase();                              //Transforma as letras em caixa alta
  rfid.PICC_HaltA();                              //Para a criptografia
  rfid.PCD_StopCrypto1(); 

  return _id;                                     //Retorna a uid lida
}

Parte 2: Adicionando o Servo-Motor

Para adicionar o servo-motor seguiremos o código padrão para este tipo de motor, seguindo os comandos da biblioteca “Servo.h”, que já é nativa da IDE do Arduino. No início apenas incluiremos ao nosso código já utilizado as funções do servo, mas estas serão incluídas posteriormente na nossa futura função para a verificação dos usuários. Portanto, o código abaixo será utilizado para a implementação do servo-motor no nosso projeto.

#include <SPI.h>                                   //Inclusão das bibliotecas
#include <MFRC522.h>
#include <Servo.h>

#define ss 10                                     //Define os pinos ss e rst
#define rst 9 

MFRC522 rfid(ss, rst);                            //Cria o objeto do rfid
Servo s;                                          //Cria o objeto do servo-motor

void setup() {
  Serial.begin(9600);                             //Inicia o Monitor Serial
  SPI.begin();                                    //Inicia o SPI
  rfid.PCD_Init();                                //Inicia o leitor

  s.attach(4);                                    //Anexa o servo-motor ao pino 4
  s.write(0);                                     //Inicia o motor na posição 0
}

void loop() {
  String id = "";                                  //Cria a variável "id"
  
  //Se não houver nenhum cartão, não faz nada
  if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
     return;
  } 
  
  id = le_cartao();                               //Chama a função para ler a uid   

  if (id == "02:DC:A7:34") {                      //Verifica a uid lida (troque o parâmetro de verificação para sua tag antes lida)
    Serial.println("Acesso permitido");           //Imprime a mensagem
    s.write(90);                                  //Gira o motor a 90°
    delay(1000);                                  //Delay de 1 segundo
    s.write(0);                                   //Retorna para a posição de 0°
  }
}

String le_cartao() {  
  String _id = "";                                //Cria a variável "_id"
  for (byte i = 0; i < 4; i++) {                  //Loop for para percorrer os caracteres lidos, seguindo o formato proposto
    _id += (rfid.uid.uidByte[i] < 0x10 ? "0" : "") + String(rfid.uid.uidByte[i], HEX) + (i!=3 ? ":" : "");
  }
    
  _id.toUpperCase();                              //Transforma as letras em caixa alta
  rfid.PICC_HaltA();                              //Para a criptografia
  rfid.PCD_StopCrypto1(); 

  return _id;                                     //Retorna a uid lida
}

Parte 3: Adicionando a Confirmação Visual

Para adicionar confirmação visual dividiremos o processo em dois passos. Primeiramente iremos incluir algo para piscar os leds. Como esta será uma função bastante utilizada para as duas cores de led a serem utilizadas, branco e vermelho, criaremos uma sub-rotina para administrá-los, proporcionando uma boa organização no código e uma leitura mais fácil na interpretação deste.

Esta sub-rotina se chamará “pisca” e receberá como parâmetro o pino do led, visto que os mesmos comandos serão utilizados tanto para o led vermelho quanto para o branco. Dentro desta sub-rotina utilizaremos comandos como “digitalWrite()” e delays para ativar os leds. Como o led irá piscar mais de uma vez, utilizaremos o loop “for” para repetir esta ação 5 vezes.

Adicione o código da função abaixo no final do seu código e a função já estará pronta para ser utilizada.

void pisca(byte pino) {                           
  for (byte i = 0; i < 5; i++) {                  //Lopp para repetir a função
    digitalWrite(pino, HIGH);                     //Liga o led
    delay(100);                                   //Espera 100 milissegundos
    digitalWrite(pino, LOW);                      //Desliga o led
    delay(100);                                   //Espera 100 milissegundos
  }
}

Para incluir as mensagens no display lcd utilizaremos os comandos padrão da biblioteca, o “print” e o “setCursor”, que será utilizado, basicamente, para centralizar as mensagens, deixando-as agradáveis visualmente. Serão adicionadas mensagens em várias funções que ainda serão adicionadas, por isso, ao decorrer do projeto, ainda serão vistas novas linhas relacionadas ao display.

Após a inclusão das linhas necessárias para o perfeito funcionamento do display, o atual estado do sketch é esse:

#include <SPI.h>                                   //Inclusão das bibliotecas
#include <MFRC522.h>
#include <Servo.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

#define ss 10                                     //Define os pinos ss e rst
#define rst 9 

LiquidCrystal_I2C lcd(0x27, 16, 2);               //Cria o objeto do display
MFRC522 rfid(ss, rst);                            //Cria o objeto do rfid
Servo s;                                          //Cria o objeto do servo-motor

void setup() {
  Serial.begin(9600);                             //Inicia o Monitor Serial
  SPI.begin();                                    //Inicia o SPI
  rfid.PCD_Init();                                //Inicia o leitor

  lcd.init();                                     //Inicia e liga a luz do display
  lcd.backlight();

  s.attach(4);                                    //Anexa o servo-motor ao pino 4
  s.write(0);                                     //Inicia o motor na posição 0
}

void loop() {
  String id = "";                                  //Cria a variável "id"
  
  //Se não houver nenhum cartão, não faz nada
  if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
     lcd.setCursor(3, 0);                          //Imprime a mensagem centralizada no display
     lcd.print("Aproxime o");
     lcd.setCursor(5, 1);
     lcd.print("cartao");
     return;
  } 
  
  id = le_cartao();                               //Chama a função para ler a uid   

  if (id == "02:DC:A7:34") {                      //Verifica a uid lida (troque o parâmetro de verificação para sua tag antes lida)
    Serial.println("Acesso permitido");           //Imprime a mensagem
    s.write(90);                                  //Gira o motor a 90°
    delay(1000);                                  //Delay de 1 segundo
    s.write(0);                                   //Retorna para a posição de 0°
  }
}

String le_cartao() {  
  String _id = "";                                //Cria a variável "_id"
  for (byte i = 0; i < 4; i++) {                  //Loop for para percorrer os caracteres lidos, seguindo o formato proposto
    _id += (rfid.uid.uidByte[i] < 0x10 ? "0" : "") + String(rfid.uid.uidByte[i], HEX) + (i!=3 ? ":" : "");
  }
    
  _id.toUpperCase();                              //Transforma as letras em caixa alta
  rfid.PICC_HaltA();                              //Para a criptografia
  rfid.PCD_StopCrypto1(); 

  return _id;                                     //Retorna a uid lida
}

void pisca(byte pino) {                           
  for (byte i = 0; i < 5; i++) {                  //Lopp para repetir a função
    digitalWrite(pino, HIGH);                     //Liga o led
    delay(100);                                   //Espera 100 milissegundos
    digitalWrite(pino, LOW);                      //Desliga o led
    delay(100);                                   //Espera 100 milissegundos
  }
}

Parte 4: Adicionando Novas UIDs

Criar um mecanismo para adicionar novas UIDs será uma das partes mais complexas do código, e para ela utilizaremos a seguinte estruturação: existirá uma ordem de pessoas a qual a adição de novas UIDs deverá seguir, quando algum cartão for inserido e for dado como acesso negado, ao pressionar o botão esta UID será adicionado ao próximo usuário da “fila”. 

Esta fila será estruturada em formato de matriz, na qual dentro de um array principal se localizarão outros array, cada um para um usuário, e dentro deste iremos organizar o nome e a UID, se já for cadastrada, dessa pessoa. Segue o exemplo abaixo.

String usuarios[][2] {
  {"Miguel", "02:DC:A7:34"},
  {"Joao", ""},
  {"Maria", ""}
};

Primeiramente iremos desenvolver a função que será responsável por verificar as UIDs de acordo com as dos usuários, já cadastradas na matriz. Para isso, criaremos um loop “for” que irá percorrer todo o nosso array de usuários verificando se a UID deles é igual a lida pelo leitor. A função receberá como parâmetro o valor lido pela nossa função para capturar os dados do leitor. A função está representada no código abaixo.

void verifica_usuario(String id) {
  //Define o número de elementos da matriz
  byte elementos = (sizeof(usuarios) / sizeof(usuarios[0]));
  lcd.clear();                                    //Limpa o display
  
  for (byte i = 0; i < elementos; i++) {      
    if (usuarios[i][1] == id) {                   //Verifica a UID
      lcd.setCursor(3, 0);
      lcd.print("Ola,");                          //Mensagem centralizada exibindo o nome do ususário
      lcd.print(usuarios[i][0]);
      lcd.setCursor(1, 1);
      lcd.print("Seja bem-vindo");
      
      s.write(90);                                //Ativa o servo
      pisca(lb);                                  //Pisca o led branco
      
      delay(3000);
      lcd.clear();
      s.write(0);
      return true;
    }
  }

  lcd.setCursor(3, 0);                            //Mensagem de cartão não reconhecido
  lcd.print("Cartao nao");
  lcd.setCursor(2, 1);
  lcd.print("reconhecido!");
  
  pisca(lv);                                      //Pisca o led vermelho
  delay(3000);
  
  lcd.clear();
  return false;
}

Agora iremos desenvolver a função para adicionar as novas tags, logo, adicionaremos o gatilho dessa função, que será o pressionamento do botão, funcionalidade que será inserida diretamente no “void loop()”. Dentro da nossa função, primeiramente, incluiremos um loop “for” para verificar se a tag já está cadastrada para alguma outra pessoa. 

Após isso será impresso no display o nome do novo dono do cartão, e, posteriormente, a UID será adicionado à matriz dos usuários, imprimindo uma mensagem no display e adicionando uma unidade ao contador, que será o responsável por definir qual será o próximo usuário a receber uma nova UID.

O código abaixo representa o atual estado do nosso projeto.

#include <SPI.h>                                   //Inclusão das bibliotecas
#include <MFRC522.h>
#include <Servo.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

#define ss 10                                     //Define os pinos ss e rst
#define rst 9 

LiquidCrystal_I2C lcd(0x27, 16, 2);               //Cria o objeto do display
MFRC522 rfid(ss, rst);                            //Cria o objeto do rfid
Servo s;                                          //Cria o objeto do servo-motor

void setup() {
  Serial.begin(9600);                             //Inicia o Monitor Serial
  SPI.begin();                                    //Inicia o SPI
  rfid.PCD_Init();                                //Inicia o leitor

  lcd.init();                                     //Inicia e liga a luz do display
  lcd.backlight();

  pinMode(lb, OUTPUT);                            //Define os pinos dos leds como saída e o do botão como saída
  pinMode(lv, OUTPUT);
  pinMode(b, INPUT_PULLUP);

  s.attach(4);                                    //Anexa o servo-motor ao pino 4
  s.write(0);                                     //Inicia o motor na posição 0
}

void loop() {
  String id = "";                                  //Cria a variável "id"
  
  //Se não houver nenhum cartão, não faz nada
  if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
     lcd.setCursor(3, 0);                          //Imprime a mensagem centralizada no display
     lcd.print("Aproxime o");
     lcd.setCursor(5, 1);
     lcd.print("cartao");
     return;
  } 
  
  id = le_cartao();                               //Chama a função para ler a uid   
  verifica_usuario(id);                           //Chama a função para verificar o usuário
}

String le_cartao() {  
  String _id = "";                                //Cria a variável "_id"
  for (byte i = 0; i < 4; i++) {                  //Loop for para percorrer os caracteres lidos, seguindo o formato proposto
    _id += (rfid.uid.uidByte[i] < 0x10 ? "0" : "") + String(rfid.uid.uidByte[i], HEX) + (i!=3 ? ":" : "");
  }
    
  _id.toUpperCase();                              //Transforma as letras em caixa alta
  rfid.PICC_HaltA();                              //Para a criptografia
  rfid.PCD_StopCrypto1(); 

  return _id;                                     //Retorna a uid lida
}

void pisca(byte pino) {                           
  for (byte i = 0; i < 5; i++) {                  //Lopp para repetir a função
    digitalWrite(pino, HIGH);                     //Liga o led
    delay(100);                                   //Espera 100 milissegundos
    digitalWrite(pino, LOW);                      //Desliga o led
    delay(100);                                   //Espera 100 milissegundos
  }
}

void verifica_usuario(String id) {
  //Define o número de elementos da matriz
  byte elementos = (sizeof(usuarios) / sizeof(usuarios[0]));
  lcd.clear();                                    //Limpa o display
  
  for (byte i = 0; i < elementos; i++) {      
    if (usuarios[i][1] == id) {                   //Verifica a UID
      lcd.setCursor(3, 0);
      lcd.print("Ola,");                          //Mensagem centralizada exibindo o nome do ususário
      lcd.print(usuarios[i][0]);
      lcd.setCursor(1, 1);
      lcd.print("Seja bem-vindo");
      
      s.write(90);                                //Ativa o servo
      pisca(lb);                                  //Pisca o led branco
      
      delay(3000);
      lcd.clear();
      s.write(0);
      return true;
    }
  }

  lcd.setCursor(3, 0);                            //Mensagem de cartão não reconhecido
  lcd.print("Cartao nao");
  lcd.setCursor(2, 1);
  lcd.print("reconhecido!");
  
  pisca(lv);                                      //Pisca o led vermelho
  delay(3000);
  
  lcd.clear();
  return false;
}

void adiciona_cartao(int local, String id) {
  //Define o número de elementos da matriz
  byte elementos = (sizeof(usuarios) / sizeof(usuarios[0]));
  
  for (byte i = 0; i < elementos; i++) {          //Loop for para verificar se a UID já foi utilizada
    if (usuarios[i][1] == id) {
      return;
    }
  }
  
  lcd.clear();                                    //Limpa o display
  lcd.setCursor(0, 0);
  lcd.print("Cartao de: ");
  lcd.print(usuarios[local][0]);
  Serial.println(id);
  delay(1000);
  
  usuarios[local][1] = id;                        //Adiciona a UID à matriz
  count += 1;
  delay(3000);                                    //Adiciona uma unidade ao contador

  lcd.clear();
  lcd.setCursor(5, 0);
  lcd.print("Cartao");
  lcd.setCursor(3, 1);
  lcd.print("adicionado");
  pisca(lb);                                      //Pisca os leds brancos
  delay(3000);
  lcd.clear();
}

Parte 5: Mensagem de Erro

Sempre que o leitor verifica a presença de um cartão ele armazena o seu valor no código, e deste jeito podemos cadastrar novas UIDs aos outros usuários, entretanto, no atual estágio de desenvolvimento do código, se pressionarmos o botão antes de passarmos alguma tag pelo leitor, este armazenará um valor de “00:00:00:00” ao usuário, causando um grande problema ao nosso código.

Portanto, nesta etapa do desenvolvimento, iremos inserir na nossa função para adicionar novas UIDs uma condicional que só nos permitirá identificar um novo perfil se a UID registrada for diferente de “00:00:00:00”. A função ficará conforme o código abaixo.

void adiciona_cartao(int local, String id) {
  //Define o número de elementos da matriz
  byte elementos = (sizeof(usuarios) / sizeof(usuarios[0]));
  
  for (byte i = 0; i < elementos; i++) {          //Loop for para verificar se a UID já foi utilizada
    if (usuarios[i][1] == id) {
      return;
    }
  }
  
  lcd.clear();                                    //Limpa o display
  lcd.setCursor(0, 0);
  lcd.print("Cartao de: ");
  lcd.print(usuarios[local][0]);
  Serial.println(id);
  delay(1000);

  if (id != "00:00:00:00") {
    usuarios[local][1] = id;                      //Adiciona a UID à matriz
    count += 1;                                   //Adiciona uma unidade ao contador
    delay(3000);    
 
    lcd.clear();
    lcd.setCursor(5, 0);
    lcd.print("Cartao");
    lcd.setCursor(3, 1);
    lcd.print("adicionado");
    pisca(lb);                                    //Pisca os leds brancos
    delay(3000);
    lcd.clear();
  } else {
    lcd.clear();                                  //Limpa o display
    lcd.setCursor(6, 0);                          //Mensagem de erro centralizada
    lcd.print("ERRO");
    pisca(lv);                                    //Pisca o led vermelho
    delay(3000);
    lcd.clear();
  }
}

Código Completo

O código completo do nosso projeto está ilustrado abaixo.

/*
* Autor: Miguel Sena
* blog.eletrogate.com
*/

#include <SPI.h>                                   //Inclusão das bibliotecas
#include <MFRC522.h>
#include <Servo.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

#define ss 10                                     //Define os pinos ss e rst
#define rst 9 

LiquidCrystal_I2C lcd(0x27, 16, 2);               //Cria o objeto do display
MFRC522 rfid(ss, rst);                            //Cria o objeto do rfid
Servo s;                                          //Cria o objeto do servo-motor

String usuarios[][2] {                            //Matriz dos usuários
  {"Miguel", "02:DC:A7:34"},
  {"Joao", ""},
  {"Maria", ""}
};

byte count = 1;                                   //Contador de usuários

void setup() {
  Serial.begin(9600);                             //Inicia o Monitor Serial
  SPI.begin();                                    //Inicia o SPI
  rfid.PCD_Init();                                //Inicia o leitor

  lcd.init();                                     //Inicia e liga a luz do display
  lcd.backlight();

  pinMode(lb, OUTPUT);                            //Define os pinos dos leds como saída e o do botão como saída
  pinMode(lv, OUTPUT);
  pinMode(b, INPUT_PULLUP);

  s.attach(4);                                    //Anexa o servo-motor ao pino 4
  s.write(0);                                     //Inicia o motor na posição 0
}

void loop() {
  String id = "";                                  //Cria a variável "id"
  
  //Se não houver nenhum cartão, não faz nada
  if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
     lcd.setCursor(3, 0);                          //Imprime a mensagem centralizada no display
     lcd.print("Aproxime o");
     lcd.setCursor(5, 1);
     lcd.print("cartao");

     while (!digitalRead(b)) {                    //Verifica se o botão foi pressionado
      adiciona_cartao(count, le_cartao());
     }
     return;
  } 
  
  id = le_cartao();                               //Chama a função para ler a uid   
  verifica_usuario(id);                           //Chama a função para verificar o usuário
}

String le_cartao() {  
  String _id = "";                                //Cria a variável "_id"
  for (byte i = 0; i < 4; i++) {                  //Loop for para percorrer os caracteres lidos, seguindo o formato proposto
    _id += (rfid.uid.uidByte[i] < 0x10 ? "0" : "") + String(rfid.uid.uidByte[i], HEX) + (i!=3 ? ":" : "");
  }
    
  _id.toUpperCase();                              //Transforma as letras em caixa alta
  rfid.PICC_HaltA();                              //Para a criptografia
  rfid.PCD_StopCrypto1(); 

  return _id;                                     //Retorna a uid lida
}

void pisca(byte pino) {                           
  for (byte i = 0; i < 5; i++) {                  //Lopp para repetir a função
    digitalWrite(pino, HIGH);                     //Liga o led
    delay(100);                                   //Espera 100 milissegundos
    digitalWrite(pino, LOW);                      //Desliga o led
    delay(100);                                   //Espera 100 milissegundos
  }
}

void verifica_usuario(String id) {
  //Define o número de elementos da matriz
  byte elementos = (sizeof(usuarios) / sizeof(usuarios[0]));
  lcd.clear();                                    //Limpa o display
  
  for (byte i = 0; i < elementos; i++) {      
    if (usuarios[i][1] == id) {                   //Verifica a UID
      lcd.setCursor(3, 0);
      lcd.print("Ola,");                          //Mensagem centralizada exibindo o nome do ususário
      lcd.print(usuarios[i][0]);
      lcd.setCursor(1, 1);
      lcd.print("Seja bem-vindo");
      
      s.write(90);                                //Ativa o servo
      pisca(lb);                                  //Pisca o led branco
      
      delay(3000);
      lcd.clear();
      s.write(0);
      return true;
    }
  }

  lcd.setCursor(3, 0);                            //Mensagem de cartão não reconhecido
  lcd.print("Cartao nao");
  lcd.setCursor(2, 1);
  lcd.print("reconhecido!");
  
  pisca(lv);                                      //Pisca o led vermelho
  delay(3000);
  
  lcd.clear();
  return false;
}

void adiciona_cartao(int local, String id) {
  //Define o número de elementos da matriz
  byte elementos = (sizeof(usuarios) / sizeof(usuarios[0]));
  
  for (byte i = 0; i < elementos; i++) {          //Loop for para verificar se a UID já foi utilizada
    if (usuarios[i][1] == id) {
      return;
    }
  }
  
  lcd.clear();                                    //Limpa o display
  lcd.setCursor(0, 0);
  lcd.print("Cartao de: ");
  lcd.print(usuarios[local][0]);
  Serial.println(id);
  delay(1000);

  if (id != "00:00:00:00") {
    usuarios[local][1] = id;                      //Adiciona a UID à matriz
    count += 1;                                   //Adiciona uma unidade ao contador
    delay(3000);    
 
    lcd.clear();
    lcd.setCursor(5, 0);
    lcd.print("Cartao");
    lcd.setCursor(3, 1);
    lcd.print("adicionado");
    pisca(lb);                                    //Pisca os leds brancos
    delay(3000);
    lcd.clear();
  } else {
    lcd.clear();                                  //Limpa o display
    lcd.setCursor(6, 0);                          //Mensagem de erro centralizada
    lcd.print("ERRO");
    pisca(lv);                                    //Pisca o led vermelho
    delay(3000);
    lcd.clear();
  }
}

Resultado Final

Confira abaixo o nosso projeto em pleno funcionamento.


Conclusão

Em síntese, presenciamos todas as etapas do desenvolvimento do projeto, desde uma simples identificação de uma UID RFID, até uma fechadura funcional e com variadas funcionalidades. Se quiser, poderá aprimorar este projeto com a adição de mais formas de customizar os perfis, além de, no lugar do servo-motor, adicionar uma fechadura solenóide, tornando o projeto ainda mais útil. Se tiver alguma dúvida, deixe nos comentários.

Conheça a Metodologia Eletrogate e ofereça aulas de robótica em sua escola!


Sobre o Autor


Miguel Sena
@arduuno

Estudante e hobbista na parte de eletrônica e programação. Gosto de desenvolver projetos no Arduino e ESP-32 voltados á robótica e automação residencial, e de desenvolver projetos em Python, assim como a integração dele com o Arduino.


Eletrogate

18 de agosto de 2021

A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.

Tenha a Metodologia Eletrogate dentro da sua Escola! Conheça nosso Programa de Robótica nas Escolas!

Eletrogate Robô

Cadastre-se e fique por
dentro de novidades!