Fingerprint Scanner TTL GT-511C3 – seconda parte

Eccoti alla seconda puntata sul lettore di impronte digitali Fingerprint Scanner TTL GT-511C3 introdotto con l’articolo del 25/8:

fingerprint-scanner

Nell’ultimo articolo hai visto come registrare le impronte digitali, stavolta lo complico un po’ (ma non troppo) per:

  • rendere il sensore indipendente dal monitor seriale
  • gestire gli errori di enrollment
  • poter usare, in qualche modo, l’impronta registrata.

L’idea della serratura controllata dal Fingerprint Scanner TTL GT-511C3

L’idea è di simulare (con un led) l’apertura/chiusura di una serratura: led acceso serratura aperta, led spento serratura chiusa.

Il display LCD verrà utilizzato per mostrare messaggi all’utente e per fornire istruzioni su cosa il sistema si aspetta.

Materiale utilizzato

i componenti che ho usato per il progetto Fingerprint Scanner TTL GT-511C3 sono:

Il funzionamento

Come detto il led simula la serratura aperta/chiusa mentre il pulsante simula un pulsante interno all’abitazione che permette di chiudere/aprire la serratura dall’interno senza dover posizionare un altro lettore di impronte, cosa peraltro inutile perché dall’interno devo essere libero facilmente e velocemente di poter aprire/chiudere la serratura.

Assumendo come stato iniziale della serratura = aperta (led acceso), ti chiederà di registrare un’impronta digitale e poi si metterà in stand by.

Alla pressione di uno qualsiasi dei pulsanti del display, uscirà dallo stand by e ti chiederà di fargli leggere la tua impronta.

Se l’impronta è la stessa che hai registrato cambierà lo stato alla serratura (da aperta a chiusa o viceversa) altrimenti restituirà un messaggio d’errore.

Grazie ad un interrupt la pressione del pulsante sulla breadboard cambierà lo stato della serratura senza dover leggere l’impronta (simula il pulsante d’apertura interno) qualsiasi cosa stia facendo in quel momento Arduino.

Collegamento elettrico

Il collegamento elettrico è il seguente:

collegamento 3_FP

Inizio dalle caratteristiche del display: è un display della DFRobot che si impila sopra alla scheda Arduino 1 e riporta alcuni dei pin e l’alimentazione per poterli usare con altre schede/sensori.

Occupa i pin digitali da 4 a 10 e il pin analogico 0 sul quale si può leggere il valore di un eventuale pulsante (di quelli del display) premuto.

Ogni pulsante premuto produce un diverso valore sul pin analogico A0. Quello che ti interessa ora è che se A0 < 1023 un pulsante è premuto altrimenti no.

Nel corso del terzo articolo vedrai come funziona più nel dettaglio.

Gli interrupt

Qualche informazione anche sugli interrupt: un interrupt è “un segnale asincrono che indica il “bisogno di attenzione” da parte di una periferica finalizzata ad una particolare richiesta di servizio”.

In buona sostanza c’è qualcosa che “cambia” e questo attiva una richiesta.

Arduino gestisce parecchi tipi di interrupt ma quelli che ci interessano sono quelli definibili dall’utente.

Possono essere collegati ai pin digitali 2 (interrupt 0) e 3 (interrupt 1) e possono essere attivati dal cambio di stato di uno di questi pin.

Le variazioni di maggior interesse che possono attivare l’interrupt sono:

–          RISING: il pin passa dal valore basso a quello alto

–          FALLING: il pin passa dal valore alto a quello basso.

–          CHANGE: il pin passa da alto a basso o viceversa, cambia valore insomma.

Per questo specifico progetto useremo la variazione FALLING perché, se guardi lo schema elettrico, capirai che il valore del pin è alto se il pulsante non è premuto e diventa basso quando il pulsante viene premuto.

L’unica altra cosa da fare per gestire un interrupt è creare la funzione che esegue il compito quando l’interrupt si verifica e di associarla alla variazione che attiva l’interrupt.

Al verificarsi dell’interrupt arduino interrompe il flusso di esecuzione (da cui interrupt), esegue le istruzioni associate all’interrupt e infine torna al punto in cui si era interrotto.

Trovi maggiori informazioni sugli interrupt in questo articolo: Tutorial: Arduino interrupt

Lo sketch

Ora che ho illustrato gli scopi parliamo dello sketch:

#include <LiquidCrystal.h>
#include "FPS_GT511C3.h"
#include "SoftwareSerial.h"
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
FPS_GT511C3 fps(12, 13);
bool serratura_aperta=true;
int led = 11;


void setup() {
  lcd.begin(16, 2);  
  pinMode (10,OUTPUT);
  Serial.begin(9600);
  fps.Open();
  digitalWrite(10,LOW);
  if (serratura_aperta) digitalWrite(led,HIGH);
  else digitalWrite(led,LOW);
  attachInterrupt(0, apre_chiude, FALLING);
}

void loop() {
  int pulsante;
  if (fps.GetEnrollCount()==0) inizializza();
  pulsante=analogRead(0);
  if (pulsante<1000)
  {
    digitalWrite(10,HIGH);
    fps.SetLED(true);
    lcd.clear();
    lcd.print("Press finger");
    if (put_finger()==1) return;
    fps.CaptureFinger(true);
    int id = fps.Identify1_N();
    if(id < 200)
    {
      fps.SetLED(false);
      apre_chiude();
    }
    else
    {
      lcd.clear();
      lcd.print("Finger not in DB");
      delay(2000);
      fps.SetLED(false);
    }
  }
}

int inizializza()
{
  int ritorno;
  digitalWrite(10,HIGH);
  lcd.clear();
  lcd.print("INIZIALIZATION");
  delay(2000);
  fps.SetLED(true);
  ritorno=Enroll(0);
  while (ritorno != 0) ritorno=Enroll(0);
  fps.SetLED(false);
  digitalWrite(10,LOW);
}

int Enroll(int enrollid){
  bool result;
  int enr_result;
  lcd.clear();
  digitalWrite(10,HIGH);
  lcd.print("Record finger ");
  lcd.print(enrollid);
  enr_result=fps.EnrollStart(enrollid);
  if (enr_result==0)
  {
    while(fps.IsPressFinger() == false) delay(100);
    result = fps.CaptureFinger(true);
    if (result)
    {
      enr_result=fps.Enroll1();
      if (enr_result ==0)
      {
        lcd.clear();
        lcd.print("Remove finger");
        while(fps.IsPressFinger() == true) delay(100);
        lcd.clear();
        lcd.print("Press again");
        while(fps.IsPressFinger() == false) delay(100);
        result = fps.CaptureFinger(true);
        if (result)
        {
          enr_result=fps.Enroll2();
          if (enr_result ==0)
          {
            lcd.clear();
            lcd.print("Remove finger"); 
            while(fps.IsPressFinger() == true) delay(100);
            lcd.clear();
            lcd.print("Press again");
            while(fps.IsPressFinger() == false) delay(100);
            result = fps.CaptureFinger(true);
            if (result)
            {
              lcd.clear();
              lcd.print("Remove finger");
              enr_result = fps.Enroll3();
              if (enr_result == 0)
              {
                lcd.clear();
                lcd.print("Enrolling OK");
                delay(2000);
                return 0;
              }
              else
              {
                lcd.clear();
                lcd.print("Enrolling KO:");
                lcd.setCursor(0,1);
                switch(enr_result)
                {
                  case 1:
                    lcd.print("Generic error");
                    break;
                  case 2:
                    lcd.print("Too bad FPrint");
                    break;
                  case 3:
                    lcd.print("FPrint exists");
                    break;
                }
                delay(2000);
                return 1;
              }
            }
            else
            {
              lcd.clear();
              lcd.print("Failed 3rd read");
              delay(2000);
              return 1;
             }
          }
          else
          {
            lcd.clear();
            lcd.print("Enroll failed:");
            lcd.setCursor(0,1);
            switch(enr_result)
            {
                case 1:
                  lcd.print("Generic error");
                  break;
                case 2:
                  lcd.print("Too bad FPrint");
                   break;
                case 3:
                  lcd.print("FPrint exists");
                  break;
            }
            delay(2000);
            return 1;
          }     
        }
        else       
        {
          lcd.clear();
          lcd.print("Failed 2nd read");
          delay(2000);
          return 1;
        }
      }
      else
      {
        lcd.clear();
        lcd.print("Enroll failed:");
        lcd.setCursor(0,1);
        switch(enr_result)
        {
            case 1:
              lcd.print("Generic error");
              break;
            case 2:
              lcd.print("Too bad FPrint");
               break;
            case 3:
              lcd.print("FPrint exists");
              break;
        }
        delay(2000);
        return 1;
      }
    }
    else
    {
        lcd.clear();
        lcd.print("Failed 1st read");
        delay(2000);
        return 1;
    }
  }
  else
  {
    lcd.clear();
    lcd.print("Enroll failed:");
    lcd.setCursor(0,1);
    switch(enr_result)
    {
        case 1:
          lcd.print("Reader DB full");
          break;
        case 2:
          lcd.print("ID ");
          lcd.print(enrollid);
          lcd.print(" invalid");
          break;
        case 3:
          lcd.print("ID ");
          lcd.print(enrollid);
          lcd.print(" busy");
          break;
    }
    delay(2000);
    return 1;
  }
}

void open_lock()
{
  if (serratura_aperta == false)
  {
    serratura_aperta=true;
    digitalWrite(led,HIGH);
  }
}

void close_lock()
{
  if(serratura_aperta)
  {
    serratura_aperta = false;
    digitalWrite(led,LOW);
  }
}

void apre_chiude()
{
  if (serratura_aperta)
  {
    close_lock();
    serratura_aperta = false;
  }
  else
  {
    open_lock();
    serratura_aperta=true;
  }
}

int put_finger()
{
  int timeout = 0;
  while(fps.IsPressFinger() == false)
  {
    delay(100);
    timeout+=100;
    if (timeout > 3000)
    {
      fps.SetLED(false);
      digitalWrite(10,LOW);
      return 1;
    }
  }
  return 0;
}

int remove_finger()
{
  int timeout = 0;
  while(fps.IsPressFinger() == true)
  {
    delay(100);
    timeout+=100;
    if (timeout > 3000)
    {
      fps.SetLED(false);
      digitalWrite(10,LOW);
      return 1;
    }
  }
  return 0;
}

Alcune parti te le ho illustrate nel precedente articolo, vediamo le differenze.

Righe 1-8: includono le librerie necessarie e creano gli oggetti LCD e FPS. Il pin 11 (variabile led) pilota il led che simula la serratura

Righe 11-20: inizializzano il sistema. In particolare la riga 19 collega un interrupt al pin 2 digitale: ogni volta che il pin digitale 2 (interrupt 0) passa dal valore alto a quello basso (FALLING), cioè quando viene premuto il pulsante, esegue la funzione apre_chiude.

Righe 22-48: funzione loop. Vale la pena evidenziare:

  • Riga 24: utilizza la funzione di libreria GetEnrollCount che restituisce il numero di impronte memorizzate nel sensore. Se c’è almeno un dito memorizzato continua altrimenti richiama la funzione inizializza che permette di valorizzarle
  • Righe 25-26: legge il valore del pulsante del display. Se qualcosa è premuto prosegue altrimenti ricomincia il loop.
  • Riga 28: accende la retroilluminazione dello schermo LCD
  • Righe 30-31: puliscono il display LCD e ci scrivono il messaggio per l’utente
  • Riga 32: richiama la funzione put_finger che restituisce 0 se il dito è premuto sul sensore prima del timeout, 1 se va in timeout (e quindi ricomincia il cilco di loop) serve per non farlo rimanere bloccato sulla richiesta di pressione del dito all’infinito
  • Riga 34: questa è la funzione che permette di confrontare il dito sul sensore con le impronte registrate. Restituisce l’id dello slot se trova l’impronta, 200 se non la trova.
  • Righe 37-38: cambiano lo stato della serratura e spengono il led del sensore (dito identificato)
  • Righe 42-45: dito non identificato. Scrivono l’errore sul display e tornano al
    loop

Righe 50-62: funzione inizializza. Chiamata per memorizzare un’impronta quando il DB delle impronte del sensore è vuoto. Accende la retroilluminazione del display, il led del sensore, fa l’enrollment, spegne la retroilluminazione e spegne il led del sensore. La funzione che fa l’enrollment restituisce 0 se tutto è andato bene 1 altrimenti. Quindi la funzione inizializza continua a chiamare la funzione di enrollment finché il risultato è diverso da 0.

Righe 64-223: Enrollment. Molto simile alla procedura di enrollment del precedente articolo con in più solo la gestione degli errori e la scrittura sul display LCD. In particolare:

  • Righe 71-72 fanno partire l’enrollment. Se il ritorno della funzione è 0 (ok) continua altrimenti va alle righe 200-221 per gestire l’errore restituito dalla funzione. La riga 203 posiziona il cursore alla seconda riga del display LCD (un ritorno a capo in buona sostanza).
  • Riga 75: controlla che la funzione CaptureFinger non restituisca errore
  • Riga 78: primo passo di enrollment. Se la funzione restituisce 0 (ok) prosegue altrimenti gestisce l’errore alle righe 170-189.
  • Per i successivi step dell’enrollment i controlli sono simili.

Righe 225-232: Se la serratura è chiusa cambia lo stato ad aperta e accende il led altrimenti non fa nulla.

Righe 233-240: Se la serratura è aperta cambia lo stato a chiusa e spegne il led altrimenti non fa nulla.

Righe 242-254: questa è la funzione richiamata dall’interrupt (e dal loop). Inverte lo stato della serratua: la apre se chiusa e la chiude se aperta.

Righe 256-271: funzione che attende la pressione del dito sul sensore. Restituisce 0 alla pressione, 1 se va in timeout. Il timeout è gestito nel seguente modo:

  • Riga 258: crea una variabile locale timeout e la imposta a 0
  • Riga 259: controlla se il dito è sul sensore. Se c’è esce restituendo 0 altrimenti:
  • Riga 261-262: attende 100 ms ed incrementa la variabile timeout di 100
  • Riga 263: se timeout > 3000 esce restituendo 1 altrimenti ricomincia il while alla riga 259

Righe 273-288: stesso meccanismo della precedente funzione ma con la rimozione del dito.

Cortesemente, prima di inserire i commenti leggi il regolamento

Permanent link to this article: http://www.mauroalfieri.it/elettronica/fingerprint-scanner-ttl-gt-511c3-seconda-parte.html

12 comments

1 ping

Skip to comment form

    • Antonio on 30 dicembre 2014 at 22:53
    • Reply

    Ciao Michele, come hai potuto leggere dal mio commento nella terza parte della tua guida, ho preferito prendere lo stesso schermo che hai usato tu per il tuo progetto e ti faccio i complimenti per la spiegazione e per le tante opzioni che hai inserito al suo interno. Comunque in questi giorni mi è arrivato lo schermo e sto facendo un paio di prove solo che sto riscontrando dei problemi non so se sono solo inerenti a me o anche ad altri.
    Andiamo a dire quali sono:
    Prima di tutto ti dico che sono partito dal primo capito per fare le cose per bene e ho collegato il lettore di impronte ad arduino caricato lo sketch e tutto andava ok, sullo schermo del pc mi usciva tutto bene.
    I problemi sono sorti con la seconda e terza parte, ho applicato lo sketch della seconda parte ho fatto i collegamenti si vede lo schermo funziona, il led si accende e si spegne con il pulsante ma mi fa fare l’INIZIALIZATION all’infinito, cioè premo il primo dito per 3 volte e mi dice Enrolling OK premo il secondo dito stessa procedura e mi dice Enrolling OK e poi di nuovo INIZIALIZATION e così all’infinito, finche non lo prendo e lo spendo perché oppure lo butto contro al muro :-D, quindi non mi va mai in stan by, non so il perché, pensavo che il sensore non salvasse le mie impronte ma eseguendo la prima parte delle guida se provo a registrare 2 volte lo stesso dito mi dà errore quindi li registra ma allora perché non mi và.

    Dal momento che la seconda parte non mi andava ho provato a vedere se la terza parte partisse o andasse, ma dopo aver fatto tutti i collegamenti come da te indicato e dopo aver caricato lo sketch niente non si vede lo schermo il sensore di impronte è illuminato, ma lo schermo è totalmente spento e il pulsante per accendere e spegnere il led non funziona mentre nella seconda parte della guida funziona quindi non credo che sia un problema di collegamenti oppure anche nella seconda parte non avrebbe funzionato.
    Spero di riuscire a risolvere.

    Grazie e buona serata ( auguri di buona Natale anche se in ritardo e di un buon anno nuovo a te e a Mauro :-D)

    1. Ciao Antonio e auguri,
      innanzitutto scusa per il ritardo ma sono stato fuori per le feste e non è semplice rispondere senza un computer 🙂
      Partiamo dal problema sul secondo sketch: ho incollato la versione sbagliata sul sito. Alla riga 24 sostituisci
      if (fps.GetEnrollCount()>0) inizializza();
      con
      if (fps.GetEnrollCount()==0) inizializza();
      Provvederò a correggere lo sketch quanto prima.
      Per quanto riguarda il problema con l’ultimo sketch è un problema squisitamente di memoria: si satura la memoria dati e vanno in conflitto gli oggetti che gestiscono display e lettore di impronte. Capitava anche a me anche se non in maniera sistematica e sono impazzito a capire i motivi. Ti suggerisco di eliminare alcune funzionalità e/o di ridurre al miminimo le strutture per la memorizzazione delle sequenze. In particolare alla riga 17 sostituisci
      sequenza seq[2];
      con
      sequenza seq[1];
      Se anche così non va evidentemente il tuo Arduino o la tua IDE hanno un comportamento diverso dai miei e devi limare sulle funzionalità ma dobbiamo parlarne perché va modificato per benino lo sketch.
      Spero di esserti stato utile. Fammi sapere.
      Michele

        • Antonio on 7 gennaio 2015 at 11:27
        • Reply

        Ciao Michele e grazie per gli auguri, immaginavo che stavi fuori per questo ho aspettato dopo le vacanze per ricevere una risposta, e ti ringrazio per avermi risposto sei stato gentilissimo e molto disponibile.

        Ho fatto la modifica da te indicata ma dopo averla fatta lo schermo non si vede rimane blu e basta non fa vedere niente e non succede niente, se riporto lo sketch com’era prima il problema è sempre lo stesso :-(, inoltre facendo la modifica neanche più il pulsante mi funziona.

        Lo stesso purtroppo vale per lo sketch 4 niente da fare anche sostituendo la sequenza 2 con 1.

        Comunque io uso arduino uno con cip atmega328p-pu, tu quale hai usato per effettuare questo progetto?

        Comunque il progetto che ho in mente io è molto più semplice del tuo, però volevo prendere spunto dal tuo perché è molto ben fatto e pieno di ottime idee e ti faccio i miei complimenti, però purtroppo non riesco a farlo funzionare in nessun modo sto da diverse settimane ma niente da fare :-(. Comunque quello che voglio fare è far muore un servo tramite l’impronta digitale di una 10 di persone, ovviamente con lo schermo che dà l’ok o no, le sequenze mi attirano però come hai detto pure tu usano spazio e quindi vanno a compromettere tutto il progetto tu che mi consigli?

        Grazie ancore per la tua disponibilità e gentilezza. Ringrazio anche Mauro che ha messo a disposizione il suo blog per aiutare le persone.

        1. Se lo scopo è quello di azionare un servo quando un’impronta è riconosciuta allora puoi limare molto.
          La parte del servo mi era sfuggita quindi immagino tu abbia incluso anche la libreria dei servo con ulteriore consumo di memoria.
          Puoi limitarti ad utilizzare le funzioni di enroll e di riconoscimento accantonando tutta la parte delle sequenze risparmiando parecchio in termini di memoria.
          Inoltre puoi utilizzare solo la memoria del lettore di impronte senza usare le eeprom così risparmi anche una libreria:
          GetEnrollCount() per sapere quante sono le impronte memorizzate.
          Per finire se non ti interessa l’hard reset della scheda puoi anche eliminare le
          #include
          #include
          con i relativi comandi.
          Insomma devi risparmiare memoria.
          Per finire ti consiglio di scriverti uno sketch per ripulire il lettore in cui usi la funzione DeleteAll per cancellare tutte le impronte. Il lettore, infatti, conserva le impronte nella sua memoria che non si cancella con la perdita di alimentazione.
          prendendo spunto dal mio ti consiglio di:
          1) creare lo sketch per ripulire il sensore (sono poche righe: metti il DeleteAll direttamente nel setup mentre il loop è un semplice delay) e ripulirlo
          2) usare una versione semplificata del mio sketch in cui le impronte sostituiscono le sequenze ed eliminando l’hard reset. Se vuoi posso provare a farti uno scheletro dell’applicazione ma mi serve il tuo indirizzo di posta elettronica

            • Antonio on 7 gennaio 2015 at 14:30

            Piche grazie ancora per il tuo aiuto, la mia mail è antony.89@hotmail.it

            Il mio progetto comunque è questo e forse può servire anche ad altri, in poche parole voglio fare una serratura che funzioni con impronte digitali, il servo farà muovere fisicamente la serratura che si aprirà e si chiuderà.

            Ovviamente le cose che non dovrebbero mancare per questo avevo preso in considerazione il tuo progetto sono la possibilità di cancellare le impronte di aggiungerle e di vedere sullo schermo se ci sono errori o altro niente di che.

            Ti ringrazio ancora per l’aiuto.

    • Michele on 2 giugno 2015 at 16:46
    • Reply

    Ciao scusa il disturbo, ho provato a realizzare la seconda parte del tuo progetto ma non riesco a far funzionare il display, lo schermo rimane completamente spento ed anche il led del sensore resta spento, mentre se carico lo stesso programma senza che lo schermo sia collegato il led del sensore si accende.
    Il display dovrebbe essere funzionante datochè ho provato a caricare il programma dedicato solamente al display keypad e lo schermo funziona, l’unico problema è che l’indicazione del tasto premuto mediante i numeri funziona solamente per il tasto “RIGHT”. Volevo sapere se può darmi qualche consiglio utile al fine di realizzare il progetto. Grazie.

    1. Ciao Michele,
      lascio che l’autore del progetto possa darti tutte le delucidazioni che meriti.
      Da come lo descrivi sembra un problema di alimentazione, prova ad alimentare il circuito con una alimentazione esterna al Pc e senza la porta USB collegata.

        • Michele on 9 giugno 2015 at 20:44
        • Reply

        Grazie del consiglio proverò a seguirlo. Comunque analizzandolo nuovamente il programma ho scoperto che i tasti del display funzionano e che il software si ferma sul comando “fps.Open();” e quindi rimane quest’ultimo il problema che non riesco a risolvere.

    • luca on 12 ottobre 2015 at 21:50
    • Reply

    salve Mauro

    ho provato a utilizzare questo sketch ma il processo si blocca dopo che sul display visualizza finger not in db.
    tengo a precisare che il sensore a mia disposizione è il gt511c1 il quale può contenere solo 20 impronte.
    comporta qualche problema per il programma?
    il resto , arduino cablaggi ecc. è tutto uguale.
    attendo un suo riscontro.

    1. Ciao Luca,
      il progetto è stato scritto da Michele, lascio il tuo commento visibile in modo che lui possa aiutarti.

    • David on 1 dicembre 2016 at 10:16
    • Reply

    ciao Michele,

    vorrei anch’io realizzare una piccola serratura comandata del sensore d’impronte. Mi chiedevo se si potesse remotare la procedura di acquisizione delle impronte per avere meno hw possibile. Sto realizzando una “scatola” con quella serratura e lo spazio è poco… Secondo te si potrebbe usare un Arduino nano allo scopo?
    Grazie ancora per i consigli. Spero che non sia troppo tardi!!

    1. Ciao David,
      mi piace l’idea che più appassionati e lettori del blog si scambino consigli.
      Lascio il tuo commento on-line per Michele e chi altro volesse aiutarti.

  1. […] Righe 297-458: Funzione di Enroll, già descritta nel precedente articolo […]

Lascia un commento

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.