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.

Prima di inserire un commento, per favore, leggi il regolamento

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

13 pings

Skip to comment form

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

Lascia un commento

Your email address will not be published.

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