Programma antifurto

Ciao :slight_smile:
Il mio ultimo progetto che ho intenzione di creare è un piccolo antifurto il quale si attiva tramite un tastierino numerico (nel mio caso 4X4) e rileva i movimenti tramite il sensore di movimento PIR.
Inoltre è presente un display LCD 16X2 per "monitorare visivamente" la situazione dell'antifurto.
Il problema è che non funziona l'input del PIN (di 4 cifre) il quale viene richiesto subito per mettere in azione il sistema.
L'input del sensore PIR è il pin 2 poichè ho deciso di provare ad utilizzare la tecnica dell'interrupt su Arduino UNO.

Ecco il codice:

#include <LiquidCrystal.h> //importo la libreria per gestire LCD
#include <Keypad.h> //importo la libreria per la gestione del tastierino numerico (4*4 in questo caso)

#define buzzer 3 //costante per indicare pin del cicalino
#define pir 2 //costante per definire pin del PIR
#define MAX 5  //costante per definire valore massimo del vettore
char pin[MAX]; //stringa per pin inserito dall'utente
char MioPIN[MAX] = "1234"; //stringa che rappresenta il pin per abilitare antifurto

LiquidCrystal lcd (13,12,11,10,9,8); //imposto pin che comandano display

const byte riga = 4; //constante di tipo byte per identificare grandezza riga
const byte colonna = 4; //constante di tipo byte per identificare grandezza colonna

char matriceTasti[riga][colonna] = 
{
    {'1','2','3','A'},
    {'4','5','6','B'},
    {'7','8','9','C'},
    {'*','0','#','D'}
}; //end vettore multidimensionale per la dichiarazione dei tasti del keypad

byte pinRiga[riga] = {A0,A1,A2,A3}; //vettore per indicare pin riga keypad
byte pinColonna[colonna] = {7,6,5,4}; //vettore per indicare pin colonna keypad

Keypad keypad = Keypad (makeKeymap(matriceTasti), pinRiga, pinColonna, riga, colonna ); //creo variabile di tipo keypad con tutte le caratteristiche 

byte stato = 0; //variabile che indica lo stato
char carattere;
byte conta=0,contaLCD=6;

void allarme(void); //prototipo funzione per far scattare segnalazione allarme


void setup()
{
    lcd.begin(16,2); //imposto grandezza display

    pinMode(pir,INPUT); //imposto il pin2 digitale come input
    pinMode(buzzer,OUTPUT); //imposto il pin3 come output per comandare il cicalino

    /*
     * Interrupt per la gestione del sensore PIR
     * L'interrupt è attivo sul pin 2 (indicato con il valore 0 mentre il pin3 con il valore 1)
     * il quale richiama il sottoprogramma "allarme" 
     * quando si passa da LOW ad HIGH sul pin 2 --> RISING
     */
   attachInterrupt (0,allarme,RISING);
   noInterrupts(); //disabilito interrupt 
 
} //end setup

void loop() 
{
    switch(stato)
    {
       case 0:
      /*
       * Stato di partenza in cui
       * viene richiesto il pin di 4 cifre 
       * e se convalidato si passa allo stato 1 altrimenti si ripete
       */
       
         
        lcd.setCursor(0,0);
        lcd.print("ANTIFURTO OFF");
        lcd.setCursor(0,1);
        lcd.print("Pin: ");
              
      
        carattere  =  keypad.getKey();
        
       if (carattere) // makes sure a key is actually pressed, equal to (customKey != NO_KEY)
        {
           pin[conta] = carattere; // store char into data array
           lcd.setCursor(contaLCD,1); // move cursor to show each new char
           lcd.print(pin[conta]); // print char at said cursor
          
          conta++; 
          contaLCD++; 
       }

     if(conta == MAX-1) // if the array index is equal to the number of expected chars, compare data to master
      {
         lcd.clear();
         lcd.setCursor(0, 0);
   

       if(strcmp(pin, MioPIN)==0)
       {
         lcd.print("PIN CORRETTO");
         stato = 1;
         interrupts();
       }
       else
       {
           lcd.print("PIN SBAGLIATO");
           stato = 0;
       }

          delay(1000);// added 1 second delay to make sure the password is completely shown on screen before it gets cleared.
          lcd.clear();

       while(conta !=0)
       {
         pin[conta--] = 0; //pulizia stringa pin
         contaLCD--;
       }
    
    } //end if
      
      break; 


      case 1:
      /*Stato che indica che l'antifiruto è attivo*/

      //interrupts(); l'interrupt è stato abilitato se la password era corretta
    char letto;
    letto = keypad.getKey(); //lettura di un eventuale carattere 

    if(letto == 'A')
      {
         stato = 0; //stato vale 0 così da tornare in quello di partenza
         /*Lo comunico tramite lcd*/
         lcd.clear(); 
         lcd.setCursor(0,0);
         lcd.print("Disattivazione");
         lcd.setCursor(0,1);
         lcd.print("Allarme!");
         delay(1500); //ritardo di 1 secondo e mezzo
         noInterrupts(); //disabilito interrupt poichè nello stato di partenza(case 0) non è attivo!
      } //end if

      lcd.setCursor(0,0);
      lcd.print("ON - TUTTO OK!");
      lcd.setCursor(0,1);
      lcd.print("A per disattivare");
      delay(30); 
      
     break;

     case 2:
        /*
         * stato in cui si effettua la segnalazione della rilevazione del PIR 
         * tramite display LCD e cicalino  
         */

          noInterrupts(); //disabilita l'interrupt

          lcd.clear(); //pulizia display
          lcd.setCursor(0,0);
          lcd.print("Movimento");
          lcd.setCursor(0,1);
          lcd.print("Rilvevato");

          for(byte i = 0; i < 3; i++)
          {
            digitalWrite(buzzer,HIGH);
            delay(500);
            digitalWrite(buzzer,LOW);
            delay(500);
          } //end for
          
          stato = 1;  //imposto il valore di stato uguale a 1 così da tornare allo stato di controllo
          
         interrupts(); //abilito nuovamente interrupt sul pin2
         
      break; //end case 2

    } //end switch      
} //end loop

/*Funzioni e sottoprogrammi*/

void allarme (void)
{
   stato = 2; //la variabile assume il valore 2 ed entra così nel case per la segnalazione del movimento
}//end allarme()

Ringrazio in anticipo se qualcuno mi potrà aiutare :slight_smile:

coppolino:
Il problema è che non funziona l'input del PIN (di 4 cifre) il quale viene richiesto subito per mettere in azione il sistema.

Ciao coppolino, in che senso non funziona? Hai in ingresso un carattere dal keypad oppure nulla?

Ciao vedi se questo può aiutarti..

#include "Keypad.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include<Servo.h>
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns

LiquidCrystal_I2C lcd(0x3F, 20,4);
byte colPins[COLS] = {5,4,3,2};
byte rowPins[ROWS] = {9,8,7,6};

char Keys[ROWS][COLS]= //creo la matrice dei tasti della tastiera.
{
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

Keypad keyp = Keypad(makeKeymap(Keys), rowPins, colPins,4,4);
Servo myservo;
char key='\0';
int Led_close=12;
int Led_open =13;
long inst_time;
char risp[16];
byte close_val=20;
byte open_val=170;

void setup()
{
  lcd.init();
  lcd.backlight();
  pinMode(Led_close,OUTPUT);
  //analogWrite(lum_pin,0);
  lcd.begin(16, 2);
  pinMode (Led_open,OUTPUT);
  Serial.begin(9600);
  myservo.attach(10);
  myservo.write(close_val);
}

void loop()
{
  lcd.clear();
  lcd.print("Premi il tasto '*'");
  key=keyp.getKey();
  while(key!='*')key=keyp.getKey();
  //analogWrite(lum_pin,255);
  int ans=get_param("Inserire Password","1475",risp,true);
  if(ans==1)
  {
    lcd.print("Apertura porta...");
    digitalWrite(Led_open, HIGH);
    tone(11,220,200);
    delay(1000);
    tone(11,600,400);
    
    myservo.write(open_val);
    
    delay(5000);
    lcd.clear();
    digitalWrite(Led_open, LOW);
    lcd.print("Chiusura porta");
    tone(11,800,400);
    delay(500);
    tone(11,800,400);
    myservo.write(close_val);
    delay(1000);
  }
  else if (ans==2)
  {
    lcd.print("Password errata!");
    tone(11,100,200);
    digitalWrite(Led_close,HIGH);
    delay(2000);
    digitalWrite(Led_close,LOW);
    
  }
  //analogWrite(lum_pin,0);
}

boolean get_param(char* question, char* answer, char* param,boolean isPassword )
{
  byte j=0;
  lcd.clear();
  lcd.print(question);
  lcd.setCursor(j,1);
  lcd.blink();
  inst_time=millis();
  do
  {
    lcd.setCursor(j,1);
    key=keyp.getKey();
jump_key:
    if(key)inst_time=millis();
    if((key=='*')||(key=='#'))break;
    else if (key=='C'&&j>0)
    {
      param[j]='\0';
      j--;
      lcd.setCursor(j,1);
      lcd.print(" ");
    }
    else if(key=='B'||key=='D'||key=='A');
    else if (key)
    {
      param[j]=key;
      j++;
      lcd.print(key);
      if(isPassword)
      {
        long pass_wait=millis();
        do key=keyp.getKey();
        while(((millis()-pass_wait)<1000)&&(!key));
        lcd.setCursor(j-1,1);
        lcd.write('*');
        if(key)goto jump_key;
      }
    }
  }
  while((millis()-inst_time)<10000&&j<17);
  param[j]='\0';
  lcd.clear();
  if(key=='*')
  {
    Serial.println(param);
    if(!strcmp(param,answer))return 1;
    else return 2;
  }
  else return 0;
}

Allora ho provato a rifare tutto a piccoli passi.
Attualmente ho rifatto quasi l'intero programma anche se ci sono delle piccole cose che non vanno...

Il programma attualmente è senza LCD per facilitare le cose e quindi uso il monitor seriale al suo posto.

#include <Keypad.h> //includo libreria per tastierino numerico 4*4

/*Variabili e Dati*/
#define PIR 2 
#define BUZZER 3 

const byte dim = 4; //costante per indicare dimensione riga e colonna
char tastiera[dim][dim] =
{
    {'1','2','3','A'},
    {'4','5','6','B'},
    {'7','8','9','C'},
    {'*','0','#','D'}
}; //matrice che rappresenta la tastiera collegata ad arduino
byte pinColonna[dim] = {13,12,11,10}; //vettore che contiene i pin delle colonne
byte pinRiga[dim] = {9,8,7,6}; //vettore che contiene i pin delle righe
char tasto; //variabile che contiene il valore del tasto premuto
bool Pass_Completa = false ; 
#define Lunghezza_Password 5 //costante che identifica la lunghezza della password = 4 cifre + '\0' --> ( '\0' indica che la stringa è FINITA)
char password[Lunghezza_Password];//vettore di caratteri per password inserita dall'utente
char passAllarme[] = "1234"; //vettore di caratteri che indica la password dell'antifurto
byte conta = 0;  //variabile contatore
unsigned int tempo = 100; //tempo di ritardo per il debounce della tastiera 4*4
#define DEBUG 1 //costante per il debug --> 1=attiva,0=disattiva
byte stato = 0; //variabile per lo stato dei case dello switch (--> programmazione a stati di Moore)
bool AllarmeAttivo = true; //variabile booleana per indicare se l'allarme è attivo o no
byte valPIR=0;
/*Fine variabilit*/

void interruzione (void); //prototipo della funzione dell'interrupt sul pin 2

Keypad keypad = Keypad(makeKeymap(tastiera),pinRiga,pinColonna,dim,dim); //oggetto keypad

void setup()
{
    pinMode(PIR,INPUT); //imposto il pin 2 come input
    pinMode(BUZZER,OUTPUT); //imposto il pin 3 come output
    Serial.begin(9600); //imposto la velocità di comunicazione seriale a 9600 bit al secondo
 //   attachInterrupt(0,interruzione,RISING); //imposto il pin di interruput,la funzione che deve richiamare e in quale caso si deve attivare (RISING --> sul fronte di salita)
   
}//end setup

void loop()
{
    switch(stato)
    {
      /*Stato di partenza in cui si chiede la password per abilitare l'antifurto*/
       case 0:

         
          //noInterrupts(); //disabilito interrupt
             
           Serial.println("Digitare PIN: ");
           while(Pass_Completa == false)
           {
              tasto = keypad.getKey(); //lettura del tasto premuto
              keypad.setDebounceTime(tempo); //tempo di debounce per premuta tasti 
               if(tasto)
               {
                  password[conta] = tasto;  //salvo il tasto premuto nel vettore di caratteri
                  Serial.print(password[conta]); //stampa del tasto premuto

                  #if DEBUG
                    Serial.print(" "); 
                    Serial.print(conta);
                  #endif //fine if condizionale del preprocessore

                  Serial.println("");
                  conta++; 
               }//end if
          
              if(conta == Lunghezza_Password-1)
              {
                   password[5] = '\0'; //chiudo la stringa 

                   //visualizzo la password per debug
                   #if DEBUG 
                      Serial.print("Password digitata: "); 
                      Serial.println(password);
                   #endif
                
                  Pass_Completa = true; //imposto la password a vero per uscire dal ciclo while
                  conta = 0; //imposto la variabile contatore nuovamente a 0 per un possibile nuovo input di password
              } //end if 
                 
        }//end while  

         /*Controllo se la password è corretta tramite "string-compare"*/
         if(strcmp(password,passAllarme) == 0 )
         {
           Serial.println("PASSWORD ESATTA!"); //comunico che la password digitata è corretta
           Serial.println("Attivazione antifurto in corso..."); //comunico che l'antifurto sta per essere attivato
           stato = 1; //cambio il valore di stato per cambiare case 
         }//end if se la password è corretta 
         else
          Serial.println("PASSWORD ERRATA!");  //comunico che la password digitata è errata
    
          /*Riazzero il vettore caratteri per la password digitata dall'utente*/
          for(int i=0;i<4;i++)
            password[i] = NULL; 
          
          Pass_Completa = false; //imposto nuovamente false 
          
         delay(3000); //ritardo di un secondo

        /* if(stato==1)
          interrupts(); //abilito interrupt un momento prima di entrare nel case 1
         */      
       break; //end case 0


       /*Stato in cui è attivo rilevatore di momvimento (PIR)*/
       case 1:
        
          tasto = 0; //il contenuto di tasto è nullo
          
          Serial.println("Antifurto ON");
          Serial.println("Premere il tasto A per disattivare antifurto");

          while(AllarmeAttivo == true)
          {
              tasto = keypad.getKey(); //lettura tasto premuto 
              keypad.setDebounceTime(tempo); //debounce per tasto premuto

               valPIR = digitalRead(PIR);
              
              #if DEBUG
                Serial.print("Tasto premuto per uscire: ");
                Serial.println(tasto);
                Serial.println(valPIR);
                delay(10);
              #endif //fine if condizionale preprocessore

              if(valPIR == 1)
              {
                stato = 2;
                AllarmeAttivo = false; //imposto il valore a falso 
              }
              
              if(tasto == 'A')
              {
                 Serial.println("Allarme disabilitato...");
                 stato = 0; //imposto lo stato a 0 per tornare così allo stato di partenza
                // noInterrupts(); //disabilito interrupt
                 AllarmeAttivo = false; //imposto il valore a falso 
              } //end if
              
          } //end while

          AllarmeAttivo = true; //reimposto valore iniziale di AllarmeAttivo
          
       break; //end case 1

       case 2:
        
          for(int c = 0; c < 3; c++)
          {
              digitalWrite(BUZZER,HIGH);
              delay(500);
              digitalWrite(BUZZER,LOW);
              delay(500);
          }

          stato = 1;
       break;

        
    }//end switch

} //end loop


/*Funzione interrupt*/
/*void interruzione(void)
{
  stato = 2; 
}*/

Il programma ora fa quello che deve ma non se utilizzo l'interrupt.
Mi spiego meglio: La funzione noInterrups nel loop mi blocca l'input della password e anche se la metto nel setup. Ora lo stato del PIR quindi lo gestisco tramite un "if" ma vorrei che ciò avvenisse tramite interrupt...Le parti dell'interrupt sono commentate.