RFID Shield controllo accessi arduino

I tag RFID ( Identificazione a radio frequenza ) sono sempre più diffusi e forse anche superati da tecnologie più moderne come NFC, poterli utilizzare con la rfid shield  arduino è sempre affascinante.

RFID shield con arduino

Qualche mese fa ti ho scritto un articolo su come assemblare la rfid shield in quanto il kit è da saldare, nulla di complesso, tutti componenti classici.

In questo articolo proverai lo sketch rilasciato dal produttore della shield per:

  • registrare le chiavi Tag in tuo possesso
  • verificare che le chiavi siano correttamente riconosciute
  • cancellare una delle chiavi
  • verificare che solo la chiave registrata sia riconosciuta
  • cancellare entrambe le chiavi

E nei prossimi articoli dedicati ai tag rfid shield analizzerai linea per linea il codice per poterlo adattare al tuo progetto di controllo accessi, allarme, centralina domotica, ecc…

Il materiale necessario: rfid shield e chiavi con tag compatibile

Per realizzare il tuo progetto con i tag rfid shield devi procurarti sia la rfid shield sia almeno due chiavi contenenti un tag compatibile con il lettore.

La rfid shield opera a 125KHz, la forma della chiave o del Tag non influisce sul funzionamento del progetto.

Quindi procurati la rfid shield:

RFID shield ID-12

almeno due chiavi contenenti tag rfid a 125KHz:

RFID shield tag key

ed ovviamente Arduino.

Ho marcato le due chiavi con adesivi colorati uno verde ed uno rosso/violaceo per distinguerle durante la fase di test dello sketch che puoi vedere nel video in basso.

Lo sketch per la rfid shield

Sul sito da cui ho acquistato la rfid shield ho scaricato lo sketch con cui puoi eseguire i primi test:

/*
         LEGENDA CODICI:

        ####################################################################################
        #                             #                      #                             #
        #         TIPO AVVISO         #        BUZZER        #             LED             #
        #                             #                      #                             #
        ####################################################################################
        # Modalità registrazione      # Beep singolo rapido  # Led verde acceso fisso      #
        #                             #                      #                             #
        # Modalità eliminazione       # Beep singolo rapido  # Led rosso acceso fisso      #
        #                             #                      #                             #
        # Tessera già registrara      # Beep singolo rapido  # Led rosso singolo lampeggio #
        #                             #                      #                             #
        # Tessera registrata          # Beep singolo veloce  # Led verde 5 lampeggi veloci #
        #                             #                      #                             #
        # Tessera già cancellata      # 10 Beep molto rapidi # Led rosso 10 lampeggi rapidi#
        #                             #                      #                             #
        # Tessera cancellata          # Beep singolo lento   # Led verde singolo lampeggio #
        #                             #                      #                             #
        # Tessera non corretta        # Beep doppio veloce   # Led rosso singolo lampeggio #
        #                             #                      #                             #
        # Tessera corretta            # Beep singolo lento   # Led verde singolo lampeggio #
        #                             #                      #                             #
        # Memoria cancellata totale   # Beep singolo lungo   # Led rosso e verde accesi poi#
        #                             #                      # beep e lampeggio rapido     #
        #                             #                      #                             #
        # Checksum non corretto       # Beep singolo veloce  # Led rosso singolo lampeggio #
        ####################################################################################
*/

#include <EEPROM.h>
#include <SoftwareSerial.h>

#define PULSANTE   5               //pin relativo al pulsante da premere per entrare in modalità scrittura/cancellazione

#define DATA_PIN       7           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (7 | 8)
#define RELE_PIN       9           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (9 | 10)
#define BUZZ_PIN       3           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (3 | 11)
#define GREEN_LED_PIN  8           //pin relativo al led verde
#define RED_LED_PIN    6           //pin relativo al led rosso

//scegliere cosa fare quando viene letta una scheda

#define RELE     0                 //scegliere '1' per fare in modo che alla lettura di una scheda il relè venga attivato '0' per non fare nulla
#define BUZZER   1                 //scegliere '1' per fare in modo che alla lettura di una scheda il buzzer emetta un suono '0' per non fare nulla
#define LED      1                 //scegliere '1' per fare in modo che alla lettura di una scheda corretta venga acceso il led verde e per una scheda incorretta il led rosso '0' per non fare nulla

#define DURATA_RELE 1000          //scegliere il tempo per il quale deve rimanere acceso il relè (se viene inserito '0' il relè funzionerà in modo bistabile)

boolean check;                    //variabile con la quale eseguo tutti i controlli all'interno dello sketch
int on_off=0;                     //variabile che utilizzo per controllare lo stato del led in modalità bistabile

SoftwareSerial mySerial(DATA_PIN,1);    //inizializzo il pin sul quale leggere i dati trasmessi dall'ID-12
void setup() {

  if(DURATA_RELE>60000)                                                    //controllo che il tempo impostato per la durata di attivazione del relè sia inferiore a 1 minuto
    while(1){                                                              //in caso contrario stampo su seriale un messaggio di errore in un ciclo infinito
        delay(2000);
        Serial.print("Tempo relè non valido, troppo alto");
    }

  pinMode(PULSANTE,INPUT);                                                 //imposto il pin del pulsante in modalità input per verificare quando il pulsante viene premuto
  digitalWrite(PULSANTE,HIGH);                                             //e lo setto alto, in modo tale da attivare la resistenza di pull-up

  if(RELE)                                                                 //controllo se è stato scelto di attivare o meno il relè, nel primo caso, imposto il pin assegnatogli come output
    pinMode(RELE_PIN,OUTPUT);
  if(BUZZER)                                                               //controllo se è stato scelto di attivare o meno il buzzer, nel primo caso, imposto il pin assegnatogli come output
    pinMode(BUZZ_PIN,OUTPUT);
  if(LED){                                                                 //controllo se è stato scelto di attivare o meno i led, nel primo caso, imposto i pin assegnatogli come output
    pinMode(GREEN_LED_PIN,OUTPUT);
    pinMode(RED_LED_PIN,OUTPUT);
  }
  Serial.begin(9600);                                                      //Inizializzo la porta seriale sulla frequenza di 9600 baud
  mySerial.begin(9600);                                                    //inizializzo la seriale sulla quale leggo i dati delle schede a 9600 baud

  if(digitalRead(PULSANTE)==LOW) azzera();                                 //controllo che il il pulsante sia premuto in fase di accensione del dispositivo, in caso affermativo azzero tutta la memoria EEPROM
}

void loop () {

  byte val;                                                          //variabile che utilizzo per leggere i valori dalla tessera appena passata
  byte code[6];                                                      //vettore nel quale salvo il codice letto completo
  byte checksum;                                                     //variabile sulla quale calcolo e salvo il checksum
  byte bytesread;                                                    //variabile che viene utilizzata per per contare quanti byte sono stati letti
  byte tempbyte;                                                     //variabile che mi serve per memorizzare temporaneamente mezzo byte letto

  unsigned long int tempo=0;                                         //variabile che utilizzo per salvare il tempo attuale, per contare i millisecondi passati
  boolean scrivere=false;                                            //variabile che utilizzo per controllare se la tessera appena letta è da salvare o da controllare
  boolean controllo=false;                                           //variabile che utilizzo per controllare se la tessera appena letta è da cancellare oppure no

  if(digitalRead(PULSANTE)==LOW){                                    //controllo se il pulsante è premuto
     tempo=millis();                                                 //se lo è salvo gli attuali millisecondi passati dall'avvio del dispositivo
     while((digitalRead(PULSANTE)==LOW)&&(tempo+3000>millis()));     //quindi mando in esecuzione un ciclo che non fa nulla
     if(millis()>tempo+2999){                                        //controllo dopo la fine del ciclo se esso è stato in esecuzione per 3 secondi, confrontando il tempo iniziale + 3000 con il tempo attuale
       if(LED)
         digitalWrite(GREEN_LED_PIN,HIGH);                           //se così è, accendo il led verde
         Serial.println("Modalità registrazione");                   //e stampo sulla seriale che sono entrato in modalità registrazione
       if(BUZZER){
         analogWrite(BUZZ_PIN,50);
         delay(50);                                                  //e faccio fare un suono di avviso al buzzer
         digitalWrite(BUZZ_PIN,LOW);
       }
         scrivere=true;                                              //e pongo a vero la variabile scrivere
     }
     if(digitalRead(PULSANTE)==LOW){                                 //se dopo ciò il pulsante è ancora premuto
       while((digitalRead(PULSANTE)==LOW)&&(tempo+5000>millis()));   //mando in esecuzione un altro ciclo nullo
       if(millis()>tempo+4999){                                      //se esso è stato in esecuzione per 2 secondi significa che sono entrato in modalita eliminazione
         Serial.println("Modalità eliminazione");                    //quindi lo scrivo sulla seriale
        if(LED){
         digitalWrite(RED_LED_PIN,HIGH);                             //accendo il led rosso
         digitalWrite(GREEN_LED_PIN,LOW);                            //spengo quello verde, precedentemente acceso
        }
        if(BUZZER){
         analogWrite(BUZZ_PIN,50);
         delay(50);                                                  //faccio fare un suono di avviso al buzzer
         digitalWrite(BUZZ_PIN,LOW);
        }
         while(digitalRead(PULSANTE)==LOW);                          //mando in esecuzione un ciclo finchè il pulsante non viene rilasciato
         controllo=true;                                             //e pongo a vero la variabile controllo
       }
     }
  }

//-------------------------------------------------------------------------------------inizio do-while------------------------------------------------------------------------------------------

  do{                                                                //inizio un ciclo che finirà solo quando verrà premuto nuovamente il pulsante

   val = 0;
   checksum = 0;                                                     //azzero le variabili precedentemente dichiarate
   bytesread = 0;
   tempbyte = 0;

  if(mySerial.available() > 0) {                                     //controllo se sulla mia seriale è presente qualche dato
    if((val = mySerial.read()) == 2) {                               //se così è leggo da essa il valore
      bytesread = 0;                                                 //e se è uguale a 2 (carattere di controllo) pongo a 0 la variabile bytesread
      while (bytesread < 12) {                                       //mando in esecuzione un ciclo per 12 volte, in modo da poter leggere tutti i 12 caratteri della tessera (5 byte del codice + 1 del cehcksum
      if( mySerial.available() > 0) {                                //controllo se i dati sono disponibili ad essere letti
          val = mySerial.read();                                     //quindi assegno a 'val' il valore dell'i-esimo carattere
          if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02)) {     //se leggo un carattere 'header' o un carattere di stop
            break;                                                             // fermo la lettura
          }

          if ((val >= '0') && (val <= '9')) {
            val -= '0';
          }                                                                    //traduco in esadecimale il carattere appena letto
          else if ((val >= 'A') && (val <= 'F')) {
            val = 10 + val - 'A';
          }

          //ogni 2 caratteri letti, aggiungo il byte così creato al vettore 'code'

          if (bytesread & 1 == 1) {                                            //se ho letto un solo carattere fin'ora
            code[bytesread >> 1] = (val | (tempbyte << 4));                        //assegno alla seconda parte del byte in posizione bytesread-esima il valore esadecimale del carattere letto

            if (bytesread >> 1 != 5) {                                             //se ho letto l'ultimo byte della scheda calcolo il checksum
              checksum ^= code[bytesread >> 1];                                    //facendo la XOR sull'ultimo byte letto
            };
          } else {
            tempbyte = val;                                                    //altrimenti assegno il valore letto alla variabile tempbyte
          };

          bytesread++;                                                        //mi preparo a leggere il prossimo byte
        }
      }

     if (bytesread == 12) {                                                   //se ho letto tutti i 6 byte
        (code[5]==checksum) ? check = true : check = false ;                  //controllo che il checksum sia corretto
        if(check){                                                            //se lo è passo a controllare se devo salvare o cancellare
            check=false;                                                      //rimetto a false la variabile check per successivi utilizzi
            if(scrivere&&!controllo){                                         //controllo se devo scrivere
                  for(int i=0;i<1021;i+=5){                                   //in caso affermativo eseguo un ciclo che controlla tutta la EEPROM
                        if((EEPROM.read(i)==code[0])&&(EEPROM.read(i+1)==code[1])&&(EEPROM.read(i+2)==code[2])&&(EEPROM.read(i+3)==code[3])&&(EEPROM.read(i+4)==code[4])){
                            check=true;                                        //se trovo il codice della tessera letta già salvato nella EEPROM metto a true la variabile 'check'
                            break;                                             //ed esco dal ciclo
                        }
                  }
                  if(check){                                                   //quindi controllo il valore della variabile check, se è vero, significa che la tessera è già stata registrata
                        Serial.print("Tessera già registrata!");               //quindi lo comunico su seriale
                        stampa_code(code);
                      if(LED)
                        digitalWrite(RED_LED_PIN,HIGH);
                        delay(50);
                      if(BUZZER)
                        analogWrite(BUZZ_PIN,50);                              //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                        delay(50);
                      if(BUZZER)
                        digitalWrite(BUZZ_PIN,LOW);
                      if(LED)
                        digitalWrite(RED_LED_PIN,LOW);
                  }

                  else{                                                        //se la tessera non è stata trovata
                      check=false;                                             //rimetto a false la variabile check per successivi utilizzi
                      for(int i=0;i<1021;i+=5){                                //quindi eseguo un ciclo che controlla tutta la EEPROM in cerca di 5 byte successivi liberi
                        if((EEPROM.read(i)==0xff)&&(EEPROM.read(i+1)==0xff)&&(EEPROM.read(i+2)==0xff)&&(EEPROM.read(i+3)==0xff)&&(EEPROM.read(i+4)==0xff)){
                          for(int j=i;j<i+5;j++)                               //una volta trovati, partendo dal primo, fino al quinto, ci salvo il valore della tessera
                              EEPROM.write(j,code[j-i]);                             //eseguendo un ciclo 5 volte
                          check=true;                                                //pongo a true la variabile check
                          break;                                               //ed esco dal ciclo
                        }
                      }
                      if(check){                                               //se la variabile check è vera, significa che ho salvato con successo, quindi
                          Serial.print("Tessera Salvata");                     //lo stampo su seriale
                          stampa_code(code);
                        if(BUZZER){
                          analogWrite(BUZZ_PIN,50);
                          delay(100);
                          digitalWrite(BUZZ_PIN,LOW);
                        }
                        if(LED){
                          for(int i=0;i<5;i++){
                           digitalWrite(GREEN_LED_PIN,HIGH);                   //e mando un segnale luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                           delay(50);
                           digitalWrite(GREEN_LED_PIN,LOW);
                           delay(50);
                          }
                          digitalWrite(GREEN_LED_PIN,HIGH);
                        }
                      }
                      else{                                                    //se la variabile check non è vera, significa che ho controllato tutta la memoria senza trovare 5 byte sequenziali liberi
                           Serial.println("Memoria piena");                    //quindi spamo su seriale che la memoria è piena
                           for(int i=0;i<5;i++){
                           if(LED)
                             digitalWrite(RED_LED_PIN,HIGH);
                           if(BUZZER)
                             analogWrite(BUZZ_PIN,50);
                           delay(50);                                          //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                           if(LED)
                             digitalWrite(RED_LED_PIN,LOW);
                           if(BUZZER)
                             digitalWrite(BUZZ_PIN,LOW);
                           delay(50);
                          }
                    }
                }
            }
            else if(scrivere&&controllo){                                      //se non bisogna salvare, controllo se bisogna eliminare una tessera
                  int posizione=-1;                                            //quindi inizializzo a -1 la variabile posizione, che mi servirà per salvare la posizione nella EEPROM della tessera
                  for(int i=0;i<1021;i+=5){                                    //ed eseguo un ciclo che controlla tutta la EEPROM per cercare il codice corrispondente
                        if((EEPROM.read(i)==code[0])&&(EEPROM.read(i+1)==code[1])&&(EEPROM.read(i+2)==code[2])&&(EEPROM.read(i+3)==code[3])&&(EEPROM.read(i+4)==code[4])){
                            posizione=i;                                       //se viene trovato salvo la posizione del primo byte nella variabile posizione
                        break;                                                 //ed esco dal ciclo
                        }
                  }
                  if(posizione!=-1){                                           //quindi controllo che la variabile posizione sia diversa da -1 così da sapere se è stato trovato o meno il codice
                      for(int j=posizione;j<posizione+5;j++)                   //eseguo quindi un ciclo partendo dalla posizione 'posizione' nella EEPROM
                              EEPROM.write(j,0xff);                            //sovrascrivendo i 5 byte corrispondenti alla tessera, con il byte di default '0xff'
                      Serial.print("Scheda cancellata");                       //una volta fatto ciò, stampo su seriale l'avvenuta cancellazione
                      stampa_code(code);
                      if(LED){
                        digitalWrite(GREEN_LED_PIN,HIGH);
                        digitalWrite(RED_LED_PIN,HIGH);
                      }
                      if(BUZZER)
                        analogWrite(BUZZ_PIN,50);                              //e mando un segnale luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                      delay(250);
                      if(LED)
                        digitalWrite(GREEN_LED_PIN,LOW);
                      if(BUZZER)
                        digitalWrite(BUZZ_PIN,LOW);
                  }
                  else{                                                        //se la variabile posizione vale -1 significa che non ha trovato in memoria la tessera letta
                      Serial.print("Impossibile cancellare la scheda, non è salvata");  //quindi lo comunico su seriale
                      stampa_code(code);
                      for(int x=0;x<10;x++){
                        if(LED)
                          digitalWrite(RED_LED_PIN,HIGH);
                        if(BUZZER)
                          analogWrite(BUZZ_PIN,50);
                        delay(25);                                             //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                        if(LED)
                          digitalWrite(RED_LED_PIN,LOW);
                        if(BUZZER)
                          digitalWrite(BUZZ_PIN,LOW);
                        delay(25);
                      }
                      if(LED)
                        digitalWrite(RED_LED_PIN,HIGH);
                    }

            }

            check=true;                                                        //rimetto a vero il valore della variabile check siccome il checksum è corretto
            }
            else{                                                              //se il checksum fosse incorretto
                 Serial.print("Checksum incorretto");                          //lo comunico su seriale
                 for(int i=0;i<3;i++){
                    if(LED)
                      digitalWrite(RED_LED_PIN,HIGH);
                    if(BUZZER)
                      analogWrite(BUZZ_PIN,50);
                    delay(30);                                                 //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                    if(LED)
                      digitalWrite(RED_LED_PIN,LOW);
                    if(BUZZER)
                      digitalWrite(BUZZ_PIN,LOW);
                 }
                 if(LED)
                    digitalWrite(RED_LED_PIN,HIGH);
            }

     }
    }
  }
  }
  while((digitalRead(PULSANTE)==HIGH)&&(controllo||scrivere));

//-------------------------------------------------------------------------------------------fine do-while---------------------------------------------------------------------------------------

  if(LED){
    digitalWrite(GREEN_LED_PIN,LOW);                                          //spengo gli eventuali led accesi per conoscere la modalità nella quale ero all'interno del ciclo
    digitalWrite(RED_LED_PIN,LOW);
  }

  if (bytesread == 12) {                                                      //controllo di avere letto tutti i 6 byte della tessera
     if(check){                                                               //controllo che il checksum sia corretto
           if(!scrivere){                                                     //e controllo anche che non ci sia da salvare/scrivere una tessera
                  check=false;                                                //rimetto a false la variabile check per successivi utilizzi
                  for(int i=0;i<1021;i+=5)                                    //eseguo un ciclo che controlla tutta la EEPROM alla ricerca della tessera letta
                        if(EEPROM.read(i)==code[0]&&EEPROM.read(i+1)==code[1]&&EEPROM.read(i+2)==code[2]&&EEPROM.read(i+3)==code[3]&&EEPROM.read(i+4)==code[4]){
                            check=true;                                       //se viene trovata metto a true la variabile check
                            break;                                            //ed esco dal ciclo
                        }

                     if(check){                                               //quindi controllo il valore della variabile check
                       Serial.print("Tessera valida");                        //se è vero, significa che la tessera è stata trovata e quindi è valida, e lo stampo su seriale
                       stampa_code(code);
                       if(LED)
                            digitalWrite(GREEN_LED_PIN,HIGH);
                       if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(200);
                            digitalWrite(BUZZ_PIN,LOW);                       //quindi in base alla selezione dell'utente
                       }                                                      //mando un segnale luminoso e/o sonoro
                       if(RELE){                                              //in più accendo il relè
                            if(DURATA_RELE){                                  //secondo la modalità impostata dall'utente
                               digitalWrite(RELE_PIN,HIGH);
                               tempo=millis();
                               while(tempo+DURATA_RELE>millis());
                               digitalWrite(RELE_PIN,LOW);
                            }
                            else{
                               if(on_off){
                                  digitalWrite(RELE_PIN,LOW);
                                  on_off--;
                               }
                               else{
                                  digitalWrite(RELE_PIN,HIGH);
                                  on_off++;
                               }
                            }
                       }
                    }
                      else{                                                    //se al contrario il valore è falso
                        Serial.print("Tessera non valida!");                   //significa che ho controllato tutta la memoria senza trovare la tessera, quindi lo comunico su seriale
                        stampa_code(code);
                        if(LED)
                            digitalWrite(RED_LED_PIN,HIGH);
                        if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(50);
                            digitalWrite(BUZZ_PIN,LOW);                        //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                            delay(50);
                            analogWrite(BUZZ_PIN,50);
                            delay(50);
                            digitalWrite(BUZZ_PIN,LOW);
                        }
                     }
                    }
                    if(LED){
                      delay(500);
                      digitalWrite(GREEN_LED_PIN,LOW);                         //spegno gli eventuali led rimasti accesi
                      digitalWrite(RED_LED_PIN,LOW);
                    }
     }
     else{                                                                     //se il checksum fosse incorretto
                 Serial.print("Checksum incorretto");                          //lo comunico su seriale
                 for(int i=0;i<3;i++){
                    if(LED)
                      digitalWrite(RED_LED_PIN,HIGH);
                    if(BUZZER)
                      analogWrite(BUZZ_PIN,50);
                    delay(30);                                                 //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                    if(LED)
                      digitalWrite(RED_LED_PIN,LOW);
                    if(BUZZER)
                      digitalWrite(BUZZ_PIN,LOW);
                 }
     }
    }
  bytesread=0;                                                                 //azzero la variabile bytesread per una prossima lettura
}

//--------------------------------------------------------------------------FUNZIONE PER AZZERARE LA MEMORIA EEPROM------------------------------------------------------------------------------

void azzera(){
  if(LED){
    digitalWrite(GREEN_LED_PIN,HIGH);
    digitalWrite(RED_LED_PIN,HIGH);
  }
  for(int i=0;i<1023;i++)
      EEPROM.write(i,0xff);
  Serial.println("Memoria Azzerata!");
  if(BUZZER)
    analogWrite(BUZZ_PIN,50);
  for(int i=0;i<5;i++)
    if(LED){
      digitalWrite(GREEN_LED_PIN,HIGH);
      delay(100);
      digitalWrite(GREEN_LED_PIN,LOW);
      digitalWrite(RED_LED_PIN,HIGH);
      delay(100);
      digitalWrite(RED_LED_PIN,LOW);
    }
  if(BUZZER)
    digitalWrite(BUZZ_PIN,LOW);
}

//--------------------------------------------------------------FUNZIONE PER STAMPARE IL CODICE DELLA TESSERA LETTA SU SERIALE-------------------------------------------------------------------

void stampa_code(byte * code){
        Serial.print(": <");
        for (int i=0; i<5; i++) {
          if (code[i] < 16) Serial.print("0");
          Serial.print(code[i], HEX);
          if(i!=4)
            Serial.print(" ");
        }
        Serial.println(">");
}

in questo primo articolo mi concentro sulle prime linee dello sketch in cui sono impostate molte delle variabili che utilizzerai in tutto lo sketch.

Linee 001-030: riportano il riassunto delle operazioni che puoi eseguire con il pulsante P1;

linea 035: includi la libreria EEPROM con cui potrai leggere e scrivere nella memoria EEPROM di Arduino;

linea 036: includi la libreria SoftwareSerial che ti permette di emulare via software la comunicazione seriale su due pin di arduino differenti dai pin 0 ed 1 che puoi utilizzare per il debug;

linea 038: definisci il pin digitale a cui è collegato il pilsante P1;

linee 040-044: definisci i pin a cui la shield Rfid è collegata. I primi 3 pin puoi sceglierli in funzione dei jumper impostati sulla shield stessa;

linea 048: definisci mediante la costante RELE cosa debba fare il relé presente sulla RFID shield alla lettura di un tag corretto, 0 = non fa nulla, 1 = eccita il relé;

linea 049: definisci mediante la costante BUZZER se far emettere un suono al cicalino presente sulla shield ( 1 ) o se farlo rimanere in silenzio ( 0 );

linea 050: definisci mediante la costante LED se accendere ( 1 ) o spegnere ( 0 ) il led alla lettura di un tag valido;

linea 052: definisci il tempo di eccitazione del relé, l’autore ha riportato nel commento che il valore 0 rende il comportamento del relé bistabile;

linea 057: inizializza l’oggetto mySerial come istanza della classe SoftwareSerial impostando il pin di lettura dati dalla RFID shield, nell’esempio il pin è il 7 se hai posizionato il jumper come nelle figure sopra e lasciato invariata al linea 040;

linee 060-064: imposta un controllo all’interno della funzione setup() il cui scopo è verificare il valore impostato per la costante DURATA_RELE, se tale tempo è superiore al minuro = 60 second = 60000 millisecondi, imposta un ciclo infinito che scrive sul monitor seriale la frase: “Tempo relè non valido, troppo alto” ogni 2 secondi;

linee 066-067: imposta la modalità del pin PULSANTE ( P1 ) a INPUT e attiva la resistenza di pull-up interna ad Arduino inviando un segnale digitale HIGH al pin stesso;

linee 069-076: per ciascuna delle variabili impostate alle linee 048-050 verifica il valore ed imposta la modalità per il pin corrispondente, questa tecnica ti consente di impostare solo i pin che gai realmente deciso di utilizzare per il tuo progetto senza coinvolgere ulteriori pin;

linee 077-078: inizializza le porte seriali, sia quella standard ( pin 0 ed 1 ) sia quella emulata dalla libreria SoftwareSerial;

linea 080: contolla che in fase di accensione il pulsante P1 sia prenuto, in tal caso lancia la funzione azzera() definita alle linee 402-423;

linee 085-093: definisci alcune variabili che ti serviranno durante l’esecuzione del loop(), i commenti a lato chiariscono ciascuna variabile che funzione ha nello sketch;

linea 095: verifica la pressione del PULSANTE;

linea 096: imposta la variabile tempo come l’attuale valore in millisecondi trascorsi dall’avvio dello sketch, questo valore ti servirà per controllare il tempo trascorso dalla pressione del pulsante;

linea 097: avvia un ciclo della durata di 3000 millisecondi ( 3 secondi ) in cui una delle condizioni è che il pulsante P1 sia sempre premuto, se lasci il pulsante o termina il tempo procedi all’operazione successiva;

linea 098: verifica che siano trascorsi più di 3 secondi, sei nella modalità di registrazione dei tag;

linee 99-106: se definita la modalità di accensione del LED, accende il led verde. Se è definita la modalità di emissione suoni con il BUZZER emette un suono per 50 millisecondi;

linea 107: imposta la variabile scrivere a true mettendo in modalità scrittura la EEPROM di Arduino;

linee 109-110: se il pulsante è ancora premuto esegui un nuovo ciclo da 5 secondi simile a quello impostato alla linea 097;

linee 111-124: se sono trascorsi più di 5 secondi accendi il led rosso, spegni quello verde ed emetti un suono con il buzzer della durata di 50 millisecondi. Alla linea 123 imposta la variabile controllo a true;

Nel prossimo articolo analizzerò le linee successive in cui esegui la lettura dei tag rfid e li inserisci nella EEPROM di arduino.

Il video

Ho realizzato un video in cui puoi vedere come funziona sia la fase di registrazione delle chiavi sia la fase di riconoscimento e cancellazione.

Buona visione !!!

  • Questo sito ed i suoi contenuti è fornito "così com'è" e Mauro Alfieri non rilascia alcuna dichiarazione o garanzia di alcun tipo, esplicita o implicita, riguardo alla completezza, accuratezza, affidabilità, idoneità o disponibilità del sito o delle informazioni, prodotti, servizi o grafiche correlate contenute sul sito per qualsiasi scopo.
  • Ti chiedo di leggere e rispettare il regolamento del sito prima di utilizzarlo
  • Ti chiedo di leggere i Termini e Condizioni d'uso del sito prima di utilizzarlo
  • In qualità di Affiliato Amazon io ricevo un guadagno dagli acquisti idonei qualora siano presenti link al suddetto sito.

Permalink link a questo articolo: https://www.mauroalfieri.it/elettronica/rfid-shield-controllo-accessi-arduino.html

41 commenti

1 ping

Vai al modulo dei commenti

  1. Ciao, quanto costa la shield?

    1. Ciao Feghea,
      qualche decina di euro, la trovi on-line cercando con google, è in vendita direttamente on-line.

      Mauro

    • Cosimo il 15 Settembre 2013 alle 11:37
    • Rispondi

    Ciao Mauro,
    volevo sapere se questo codice andrebbe bene per il modulo MFRC-522 RC522

    1. Ciao Cosimo,
      dovresti provarlo io non possiedo questo componente e non l’ho provato.

      Mauro

    • Adriano il 9 Dicembre 2013 alle 20:23
    • Rispondi

    Ciao Mauro,
    bel progetto !

    Io sto eseguendo un semplice progetto che legge delle chiavi elettroniche, usando l’RC522 che cita anche Cosimo.

    Per fare questo ho trovato uno Sketch che potrebbe fare al caso mio, mi sono però schiantato sulla libreria RFID.h . Non riesco a trovarla.

    Hai una qualche idea dove si possa scaricare

    Grazie mille Adriano

    1. Ciao Adriano,
      mi cogli impreparato sull’esistenza di una libreria RFID.h, come hai visto nel progetto io utilizzo una semplice SoftSerial.h
      hai provato a cercare tra i progetti presenti su giyhub? Spesso chi scrive librerie con lo scopo di rilasciarle open-source usa github come repository software.

      Mi piacerebbe poter pubblicare il tuo progetto quando lo avrai ultimato se ti va di condividere con altri appassionati.

      Mauro

    • Salvatore il 6 Gennaio 2014 alle 14:45
    • Rispondi

    Ciao Mauro, se io avessi bisogno solo del modulo RFID, quindi ID-12, mi basta prendere quel modulo e poi collegarlo secondo il suo schema e posso eseguire sia registrazioni che cancellazioni e verifiche dei TAG o c’è bisogno anche altro?

    Grazie.

    1. Ciao Salvatore
      il modulo ID-12, che io sappia, non ha memoria o software per la gestione delle informazioni tipo memorizzazione o cancellazione.
      Queste funzioni io le ho fatte eseguire ad Arduino, come vedrai descritto nell’articolo.

      Mauro

    • Salvatore il 6 Gennaio 2014 alle 22:36
    • Rispondi

    Ciao Mauro,
    quindi prendendo spunto dal tuo progetto, se implementassi anche io nel mio software queste funzioni, mi basterebbe acquistare il modulo ID-12 e i vari TAG. Giusto?

    1. Ciao Salvatore,
      certo, anche se il costo della shield é praticamente per il 90% composto dal componente ID-12 gli altri componenti incidono per pochi euro 🙂

      Mauro

    • Adriano il 8 Marzo 2014 alle 14:52
    • Rispondi

    Ciao Mauro,
    scusa se non ti ho più risposto, ma ultimamente sono stato impegnato in altre faccende che non mi hanno permesso di occuparmi del mio passatempo come vorrei.
    Comunque, nel frattempo sono riuscito a risolvere il mio problema e ti spedirò lo sketc per condividerlo con tutti gli appassionati. È un esempio molto semplice che vorrei ampliare con la memorizzazione di chi si annuncia su una scheda SD.

    Ciao Adriano

    1. Ottimo Adriano 🙂 ricorda di corredarlo di foto, descrizione del progetto e commenti allo sketch stesso.

    • Riccardo il 20 Marzo 2014 alle 15:25
    • Rispondi

    Buongiorno Mauro
    Complimenti per il progetto, veramente interessante.
    Io comincio solo ora ad avvicinarmi ad Arduino e avrei qualche dubbio su due cose:
    Ponendo di utilizzare Arduino uno quanti tag possono essere memorizzati nella sua eeprom? in caso sarebbe possibile utilizzare una SD esterna ?
    Secondo dubbio: secondo te sarebbe possibile memorizzare i tag in un database php residente su pc ?
    Grazie e buon lavoro

    1. Ciao Riccardo,
      innanzitutto i dubbi che mi poni sono 3, ma sono tutti gratis !!!
      Ogni tessera di questo tipo per essere memorizzata si avvale di 5 byte ossia 5 posizioni EEPROM, come leggi nei commenti al codice.
      1. il numero di Tag memorizzabili dipende quindi dalla capienza delle EEPROM, se usi un Arduino Uno R3 è di 1024 posizioni per cui con un rapido calcolo ( 1024/5 ) = 204 tag circa

      2. si, potresti memorizzare i tad su una SD Card, avresti maggiore latenza in fase di scrittura e lettura del dato.

      3. si, puoi memorizzarli anche su un server, il tempo di latenza aumenta ancora ma è fattibile.

        • Riccardo il 20 Marzo 2014 alle 19:28
        • Rispondi

        Grazie dei chiarimenti

        Riccardo

        1. Sono sempre a disposizione per chiarimenti quando sono intelligenti.

    • Giuseppe il 10 Aprile 2014 alle 22:33
    • Rispondi

    Ciao Mauro, innanzitutto grazie per aver messo a disposizione di tutti le tue conoscenze tecniche.
    Ho da poco acquistato il nuovo Arduino Yun ed ho provato, montando sullo Yun un Arduino RFID Shield (alimentato in maniera indipendente visto che lo Yun ha bisogno di 5 volt mentre l’RFID di 12 volt), a far girare lo sketch realizzato da te per il controllo accessi. Qualcosa non va: lo sketch viene caricato senza problemi ma il sistema non funziona.
    Mi daresti una mano a capire come mai?
    Premetto che ho già provato il tuo sketch su un Arduino Uno R3 e tutto funziona perfettamente.
    Grazie mille

    1. Ciao Giuseppe,
      senza sapere cosa non funziona è difficile aiutarti.
      Ti consiglio di leggere attentamente la descrizione dello sketch e di verificare che l’arduino yun utilizzi nello stesso modo i pin di comunicazione con la RFID shield.

    • Matteo il 13 Luglio 2014 alle 11:54
    • Rispondi

    Ciao Mauro, grazie per il progetto, molto interessante!!
    Ho provato a scaricare lo sketch da questa pagina cliccando sul link, ma quando faccio la verifica, il programma mi restituisce degli errori; ho notato che nella riga 33 c’è inserito #include mentre nello sketch visibile nella pagina, alla riga 33 c’è inserito #include .
    Quale delle due righe è corretta per far funzionare lo sketch? Io ho un Arduno Uno Rev 3 e un Arduino Mega 2560.

    Grazie mille!!

    1. Ciao Matteo, purtroppo nei commenti nn viene riportato cosa scrivi dopo l’include perché il carattere “< " e ">” sono eliminati dal browser.
      Dopo l’include devi metterci la libreria RFID che ti occorre per il tuo sketch.

        • Matteo il 14 Luglio 2014 alle 12:15
        • Rispondi

        Ah, scusa!!
        Nel commento scrivevo che se scarico lo sketch cliccando sul link, alla riga 33 è presente la libreria NewSoftSerial.h , dopo aver eseguito la verifica, Arduino mi restituisce degli errori ; mentre se copio lo sketch (quello dove tu descrivi le righe passo passo) presente sulla pagina, alla riga 33 è presente la libreria SoftwareSerial.h , e una volta eseguita la verifica Arduino non da errori.
        La mia domanda è: quale delle due librerie devo usare con Arduino Uno Rev3? Che differenza c’è tra le due librerie?

        Grazie 1000!!!!

    • Alberto il 2 Marzo 2015 alle 13:00
    • Rispondi

    Buon giorno Signor Mauro,
    Sto pensando di realizzare un progetto dove mi servirebbe che un dispositivo RFID (avevo pensato proprio alla shield di arduino del suo articolo) mi potesse comunicare con delle tessere (chiavi tag) e se queste sono riconosciute dal sistema, arduino dovrebbe comunicare ad un LCD il mio nome e cognome e l’ora a cui ho passato la tessera e aprirmi una serratura facendo scattare un relè.
    Quello che vorrei cortesemente domandarLe è:
    dato che questo riconoscimento dovrei farlo con gran numero di schede/chiavi, la shield è in grado di riconoscermi più di due chiavi tag? altrimenti conosce altri dispositivi in grado non solo di riconoscermi le chiavi tag, ma anche di comunicare i dati ad Arduino e farmeli vedere su un display? e pensa sia difficile un interfacciamento chiave-rfid-LCD-relè?
    Le invio il link di un video dove dal minuto 1:56 fino al 2:13 può farsi una idea del progetto di cui parlo. https://www.youtube.com/watch?v=ckdgxHObN8Q#t=152
    Ringraziandola per la cortese attenzione, spero mi risponda appena può.

    1. Ciao Alberto,
      il limite delle chiavi memorizzabili non è dato tanto dalla schield RFID quanto dalla EEPROM arduino, in quanto ogni volta che memorizzi una nuova chiave dovrai salvare il suo TAG in più celle della EEPROM.
      Ognuna delle chiavi mostrate in questo articolo è codificata con 6 byte ( 5 per il codice + 1 di controllo ) e la EEPROM arduino uno è 1024, per cui senza memorizzare altri dati ( nome, cognome, ecc. ) potresti memorizzare 170,66 chiavi.
      Nel tuo caso dovendo memorizzare anche dati relativi a nome e cognome per poterteli restituire sul display e direi che non è semplice valutare quanto lungo potrebbe essere un nome, limitando il numero di chiavi.

      Io opterei per un sistema con SD Card, che può memorizzare molti più dati e sulla quale potresti decidere di mettere anche un log degli accessi.

    • tony il 21 Giugno 2015 alle 07:12
    • Rispondi

    interessante sto cercando un progetto simile ma che faccia almeno 10 tag, che di un impulso negativo o positivo (naturalmente se il tag è stato memorizzato prima.
    ma il lettore tag si piccolo per metterlo all’interno di un frutto

    1. Ciao Tony,
      sul tipo di progetto ce ne sono molti simili a quello che cerchi sul Web o puoi commissionarlo ad uno sviluppatore se non possiedi le capacità per svilupparlo da solo.
      Per la soluzione in un frutto potresti cercare tra i sensori degli allarmi, di solito soluzioni simili sono utilizzate in quell’ambito.

    • Giuseppe il 9 Febbraio 2016 alle 13:25
    • Rispondi

    Salve Mauro,
    avrei bisogno di un consiglio, a fine sketch hai messo la funzione per stampare il codice su seriale, io avrei bisogno di inserirlo su un database sql e stavo pensando di utilizzare il metodo GET, di seguito un esempio:
    strURL = “GET http://localhost/data.php?user_id=“;
    solo che output naturalmente non è il codice della tessera letta ma solo una parte di bit.
    Come posso fare secondo te ad inserire l’intero codice così come esce dal seriale?
    Forse con Pyserial?
    Grazie e complimenti per i bei lavori che ci mostri.

    1. Ciao Giuseppe,
      probabilmente non ho compreso la richiesta che mi poni.
      La GET così come la scrivi dubito riuscirà a tradurre localhost nell’indirizzo del server a cui vuoi inviare il dato.
      L’ultima funzione stampa il codice sulla seriale lettera per lettera, potrai fare la stessa cosa componendo l’URL in modo dinamico prima di eseguire la chiamata in GET.
      Infine non dimenticarti di usare una shield che possa supportare un collegamento HTTP e le librerie che le occorrono per funzionare.

    • Giuseppe il 9 Febbraio 2016 alle 16:16
    • Rispondi

    Grazie per la risposta tempestiva, sto utilizzando la classica shield ethertnet e per l’invio al database non ho problemi mi funziona. La riga che ho scritto è solo una parte, ecco perchè non ti è chiara. Se serve posto tutto il codice In ogni caso potresti farmi un esempio sintattico di come comporre URL in modo dinamico?
    Grazie

    1. Ciao Giuseppe,
      in alcuni articoli dedicati alla Ethernet Shield trovi dettagliato riga per riga un esempio.
      Concettualmente è semplice insieme al Serial.print aggiungi anche il print del medesimo carattere nella stringa dell’url subito prima dell’invio, nella chiamata stessa.

    • Pietro il 9 Marzo 2016 alle 15:10
    • Rispondi

    Buona sera io vorrei usare sia le card e i portachiavi come apertura e chiusura per una serranda carrabile quindi mi serve un doppio contatto ho già il lettore ho già le schede e ho già arduino uno ti ringrazio se potessi aiutarmi cordiali saluti serenata pietro

    1. Ciao Pietro,
      il mio aiuto lo trovi nel blog leggendo tutti gli articoli che ho scritto e comprendendo gli sketch.
      In alternativa puoi leggere la sezione “sostienimi” per comprendere come commissionarmi un progetto.

    • sergio il 6 Luglio 2016 alle 11:02
    • Rispondi

    ciao, mi servirebbe che si potesse cancellare una chiave senza averla fisicamente. anche collegando il computer momentaneamente, è possibile?

    1. Ciao Sergio,
      non penso di aver compreso la tua richiesta. L’RFID che ho descritto in questo tutorial usa tag con id fisso e sei tu lato sw su arduino, o genuino, a decidere quale ID è abilitato e quale no, questo comporta, nel mio esempio, la riprogrammazione dello sketch.
      Se hai gestito in altro modo le autorizzazioni puoi farlo agendo sul codice di autorizzazione.

    • Giovanni il 23 Novembre 2016 alle 10:40
    • Rispondi

    Ciao Mauro ho inserito questo codie è tutto funziona perfettamente, ma vorrei fare un confronto con i byte letti da ogni tag in modo tale che se corrisponde quel codice mi stampa un numero che dico io invece del codice del tag completo.
    E’ possibile fare una conversione da byte a string??? grazie

    byte code[6]; //vettore nel quale salvo il codice letto completo

    if(check){ //se la variabile check è vera, significa che ho salvato

    Serial.print(“Tessera Salvata”); //lo stampo su seriale
    //stampa_code(code);
    Esempio if(code==” “){
    Serial.print(” 1 “);

    Vorrei stampare il numero uno se rileva quel codice e cosi via per gli altri tag con numeri diversi.
    Grazie

    1. Ciao Giovanni,
      puoi scrivere il confronto direttamente in byte if ( code[0] == … && code[1] == … ecc. Come avviene in fase di controllo del tag da parte dello sketch.

    • Giovanni il 24 Novembre 2016 alle 02:28
    • Rispondi

    Ok grazie Mauro, domani farò una prova.
    Gentilissimo come sempre.

    • Giovanni il 29 Novembre 2016 alle 12:48
    • Rispondi

    Ciao Mauro, ho montato la shield con l’arduino mega 2560 ma non mi legge i tag e non capisco il perchè visto he è compatibile con il mega, ho necessità di usare il mega perchè devo registrare tanti tag col controllo di rete, quindi monto su di essa anche una ethernet shield.
    Con l’arduino uno funzionava bene, ma ho finito la memoria e volevo usare il mega.

    Grazie

    Giovanni

    1. Ciao Giovanni,
      il primo suggerimento che mi viene in mente è controllare che la SoftwareSerial.h sia compatibile e funzionante con la MEGA.
      I alternativa prova a scrivere al fornitore, Futura Elettronica, che solitamente risponde ai quesiti rapidamente.

    • Giovanni il 30 Novembre 2016 alle 00:58
    • Rispondi

    Umm capito Mauro, pensavo fosse un problema di piedini del mega, ma può darsi che sia la libreria, domani provo a cambiare libreria nel tuo codice qui postato e controllo se è compatibile.
    Grazie mille

    • Luciano il 3 Maggio 2020 alle 10:05
    • Rispondi

    Buongiorno,
    vorrei sapere come fare per leggere il valore del TAG su seriale, in modo da poterlo vedere sul
    Monitor Seriale
    oltre ai messaggi:
    09:37:02.041 -> Modalità registrazione
    09:37:04.045 -> Modalità eliminazione

    Grazie

    1. Ciao Luciano,
      è un progetto di un po di anni fa, ma se non ricordo male esiste una array “code” che memorizza i valori del codice sia in fase di lettura sia in fase di scrittura.
      Hai provato a farti scrivere sul monitor seriale i valori contenuti in tale array ?

  1. […] corso del precedente articolo dedicato all’Rfid arduino ho iniziato ad analizzare il codice di esempio rilasciato dal […]

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.