Problema con millis()

Salve a tutti!
Sto realizzando una sorta di allarme con un sensore RFID: con la card corretta, avvicinandola per la prima volta al sensore, si abilita l'allarme (segnalato da un led acceso fisso), mentre se la si avvicina per la seconda volta, si disattiva l'allarme (segnalato dallo spegnimento dello stesso led usato per l'inserimento allarme). Se avvicino la card sbagliata, un altro led inizia a lampeggiare. Fino a qui va tutto bene, lo sketch funziona alla grande. Ho utilizzato un sensore PIR per rilevare il passaggio di persone che porta a livello logico alto la sua uscita: se il PIR si attiva, solo con allarme inserito si attiva una uscita (che potrei usare per comandare il relè di una sirena esterna). Se il PIR rileva qualcosa, viene acceso un led. Quando innesco l'allarme voglio avere il tempo necessario di allontanarmi dalla zona controllata dal PIR e, per farlo, ho pensato di ritardare di X secondi la lettura dell'input del PIR. Ho utilizzato solo ed esclusivamente la funzione millis, senza i fastidiosi delay. Il problema è che la lettura del sensore non viene mai fatta dopo il tempo che ho scelto, ma sballa di qualche secondo (a volte in più altre in meno). Sarà perché ho inserito il tutto all'interno di uno switch case? Ecco il codice:

#include <SPI.h>
#include <RFID.h>

// Vengono definiti PIN del RFID reader
#define SDA_DIO 53  // 53 per Mega
#define RESET_DIO 9

#define delayRead 1000 // Time of delay 
#define delayLed 2000 
#define ledVerde 3
#define ledRosso  4
#define PIR1 24
#define Buzzer 22

int contatore = 0;
int contatore_allarme = 0;
int lettura_PIR1;


// Viene creata una istanza della RFID libreria 
RFID RC522(SDA_DIO, RESET_DIO); 

//Variabili che contengono i valori per i vari conteggi   
int ledState = LOW;            
unsigned long currentMillis;
unsigned long currentMillis1;
unsigned long currentMillis2;
unsigned long previousMillis = 0;    
unsigned long previousMillis1 = 0;  
unsigned long previousMillis2 = 0;
const long interval = 500;  
const long interval1 = 400;  
const long interval2 = 10000;   

String codiceAutorizzato = "915DFD5263";
 
void setup()
{ 
  Serial.begin(9600);
  /* Abilita SPI*/
  SPI.begin(); 
  /* Viene inizilizzato RFID reader */
  RC522.init();
  Serial.println("Setup");
  pinMode(ledVerde,OUTPUT);
  pinMode(ledRosso,OUTPUT);
  pinMode(PIR1, INPUT);
  pinMode(Buzzer, OUTPUT);
}
 
void loop()
{
  currentMillis = millis();
  currentMillis1 = millis();
  currentMillis2 = millis();

  
  
start:

     

  byte i;
  
//Attende 400ms (vedi const long interval1) e analizza la card
 if(currentMillis - previousMillis1 >= interval1) {
  previousMillis1 = millis(); 

    
// Se viene letta una tessera
   if (RC522.isCard())
   {
    // Viene letto il suo codice 
    RC522.readCardSerial();
    String codiceLetto ="";
    Serial.println("Codice delle tessera letto:");
 
    // Viene caricato il codice della tessera, all'interno di una Stringa
    for(i = 0; i <= 4; i++)
    {
      codiceLetto+= String (RC522.serNum[i],HEX);
      codiceLetto.toUpperCase();
    }
    Serial.println(codiceLetto);
    if(verificaCodice(codiceLetto)){
      Serial.println("Tessera autorizzata");
      digitalWrite(ledVerde, HIGH);   
      digitalWrite(ledRosso, LOW);  
      contatore = 0;
      contatore_allarme = contatore_allarme + 1;
    }
   
     else{
      Serial.println("Tessera non autorizzata");
      contatore = 1;
     }   
   }
 }

  switch(contatore)
  {
    case 1:
    if(currentMillis1 - previousMillis >= interval) {
    previousMillis = millis();   
    ledState ^= 1;
    digitalWrite(ledRosso, ledState);
    }
    break;
  } 

   switch(contatore_allarme)  
    {
[color=red][b][u]case 1:
      if (currentMillis2 - previousMillis2 >= interval2){
      previousMillis2 = millis(); 
      lettura_PIR1 = digitalRead(PIR1);
      if(lettura_PIR1 == HIGH){
      digitalWrite(Buzzer, HIGH);}}
      break;[/u][/b][/color]
      
      case 2:
      digitalWrite(Buzzer, LOW);
      digitalWrite(ledVerde, LOW);
      contatore_allarme = 0;
      goto start;
      break;
     }
}


// Questa funzione verifica se il codice Letto è autorizzato
boolean verificaCodice(String codiceLetto){
  if(codiceLetto.equals(codiceAutorizzato)){
    return true;
  }else{
    return false;
  }  
}

Spero di aver spiegato bene il problema che ho riscontrato. Vi ringrazio in anticipo!

Ciao, il codice sembra corretto, può essere il ritardo del sensore pir che non ha tempo di prepararsi prima di poter rilevare la variazione?
Ottimo l'uso delle milli al posto dei delay ma poi.... usi il GOTO???? :o elimina quel goto che non si può vedere :slight_smile: e oltrettutto per come gira il tuo codice non serve a nulla

ciao

direi che il tempo di ritardo di inserimento dell'allarme devi cominciare a contarlo da quando l'allarme è inserito quindi

currentMillis2 = millis();

dovresti farlo solo dopo che hai inserito l'allarme (sempre che io abbia "beccato" il millis giusto)

ciao
pippo72

pippo72:
ciao

direi che il tempo di ritardo di inserimento dell'allarme devi cominciare a contarlo da quando l'allarme è inserito quindi

currentMillis2 = millis();

dovresti farlo solo dopo che hai inserito l'allarme (sempre che io abbia "beccato" il millis giusto)

ciao
pippo72

La verifica la fa solo quando lo stato dell'allarme è stato impostato, casomai essendo le currentMillis 0 1 e 2 uguali (tutte valorizzati a millis(9 all'inizio del loop) potrebbe usarne solo una di variabile

ciao

Sono d'accordo che la verifica la fa solo ad allarme impostato; il problema è che la fa con un currentmillis sbagliato.
Visto che allinea il valore di currentmillis2 a millis solo all'inizio del loop (almeno questo è quello che sono riuscito a leggere dallo sketch) ha gia cominciato a contare quei 10 secondi anche se non metti nessuna tessera.

ciao
pippo72

pippo72:
ciao

Sono d'accordo che la verifica la fa solo ad allarme impostato; il problema è che la fa con un currentmillis sbagliato.
Visto che allinea il valore di currentmillis2 a millis solo all'inizio del loop (almeno questo è quello che sono riuscito a leggere dallo sketch) ha gia cominciato a contare quei 10 secondi anche se non metti nessuna tessera.

ciao
pippo72

Si in questo hai ragione, in effetti dovrebbe valorizzare la previousmillis2 con millis() quando l'allarme si attiva, in tal modo i secondi intercorrano dall'attivazione effettiva

Ricontrolla anche la parte dello switch(contatore) perchè nelle righe precedenti assegni a "contatore" il valore 0 o il valore 1, poi nello switch hai due case 1 e un case 2

  • Non capisco a cosa serva il goto che avevi impostato praticamente a fine del tuo loop quindi l'ho tolto;

  • Ad inizio loop assegni il valore dei millis() a 3 variabili ma è inutile, puoi assegnarlo ad 1 soltanto e usare sempre quella nelle comparazioni (ho commentato le parti da togliere)

  • A che servono queste dichiarazioni:
    #define delayRead 1000 // Time of delay
    #define delayLed 2000
    E' un qualcosa richiesto dalla libreria? Non conoscendola non vorrei che sia qualche delay che viene usato dalla stessa e che sia la causa del tuo problema !?!?

  • Dove controllavi lo stato della variabile contatore usavi uno switch per fare qualcosa solo nel caso in cui il valore fosse 1, ho sostituito con un if che controlla anche il tempo trascorso (quello che tu già facevi dentro lo switch stesso)

#include <SPI.h>
#include <RFID.h>

// Vengono definiti PIN del RFID reader
#define SDA_DIO 53  // 53 per Mega
#define RESET_DIO 9

#define delayRead 1000 // Time of delay 
#define delayLed 2000
#define ledVerde 3
#define ledRosso  4
#define PIR1 24
#define Buzzer 22

int contatore = 0;
int contatore_allarme = 0;
int lettura_PIR1;


// Viene creata una istanza della RFID libreria
RFID RC522(SDA_DIO, RESET_DIO);

//Variabili che contengono i valori per i vari conteggi
int ledState = LOW;
unsigned long currentMillis;
//unsigned long currentMillis1; //inutile
//unsigned long currentMillis2; //inutile
unsigned long previousMillis = 0;
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
const int interval = 500;
const int interval1 = 400;
const int interval2 = 10000;

String codiceAutorizzato = "915DFD5263";

void setup()
{
  Serial.begin(9600);
  /* Abilita SPI*/
  SPI.begin();
  /* Viene inizilizzato RFID reader */
  RC522.init();
  Serial.println("Setup");
  pinMode(ledVerde, OUTPUT);
  pinMode(ledRosso, OUTPUT);
  pinMode(PIR1, INPUT);
  pinMode(Buzzer, OUTPUT);
}

void loop()
{
  currentMillis = millis();
  // currentMillis1 = millis();//inutile
  // currentMillis2 = millis();//inutile
  byte i;

  //Attende 400ms (vedi const long interval1) e analizza la card
  if (currentMillis - previousMillis1 >= interval1) {
    previousMillis1 = millis();


    // Se viene letta una tessera
    if (RC522.isCard())
    {
      // Viene letto il suo codice
      RC522.readCardSerial();
      String codiceLetto = "";
      Serial.println("Codice delle tessera letto:");

      // Viene caricato il codice della tessera, all'interno di una Stringa
      for (i = 0; i <= 4; i++)
      {
        codiceLetto += String (RC522.serNum[i], HEX);
        codiceLetto.toUpperCase();
      }
      Serial.println(codiceLetto);
      if (verificaCodice(codiceLetto)) {
        Serial.println("Tessera autorizzata");
        digitalWrite(ledVerde, HIGH);
        digitalWrite(ledRosso, LOW);
        contatore = 0;
        contatore_allarme = contatore_allarme + 1;
      }

      else {
        Serial.println("Tessera non autorizzata");
        contatore = 1;
      }
    }
  }

  if ((contatore == 1) && (currentMillis - previousMillis >= interval)) {
    previousMillis = millis();
    ledState ^= 1;
    digitalWrite(ledRosso, ledState);
  }


  switch (contatore_allarme)
  {
    case 1:
      if (currentMillis - previousMillis2 >= interval2) {
        previousMillis2 = millis();
        lettura_PIR1 = digitalRead(PIR1);
        if (lettura_PIR1 == HIGH) {
          digitalWrite(Buzzer, HIGH);
        }
      }
      break;

    case 2:
      digitalWrite(Buzzer, LOW);
      digitalWrite(ledVerde, LOW);
      contatore_allarme = 0;
      break;
  }
}


// Questa funzione verifica se il codice Letto è autorizzato
boolean verificaCodice(String codiceLetto) {
  if (codiceLetto.equals(codiceAutorizzato)) {
    return true;
  } else {
    return false;
  }
}

marinaio67:
Ricontrolla anche la parte dello switch(contatore) perchè nelle righe precedenti assegni a "contatore" il valore 0 o il valore 1, poi nello switch hai due case 1 e un case 2

Ciao marinaio67 e grazie dell'a risposta! in realtà il contatore_allarme si incrementa di 1 ogni volta che il sensore RFID legge la card giusta; questa funzione l'ho usata perchè voglio che al primo riconoscimento della card si inserisca l'allarme, e al secondo riconoscimento la disattivi:

if (verificaCodice(codiceLetto)) {
        Serial.println("Tessera autorizzata");
        digitalWrite(ledVerde, HIGH);
        digitalWrite(ledRosso, LOW);
        contatore = 0;
        contatore_allarme = contatore_allarme + 1;
      }

pippo72:
ciao

direi che il tempo di ritardo di inserimento dell'allarme devi cominciare a contarlo da quando l'allarme è inserito quindi

currentMillis2 = millis();

dovresti farlo solo dopo che hai inserito l'allarme (sempre che io abbia "beccato" il millis giusto)

ciao
pippo72

Ciao Pippo72, avevo pensato anche a quello, ma essendo i miei primi utilizzi della funzione millis non credevo influisse! Ora provo a modificare il codice e ti farò sapere. Grazie a tutti del tempo dedicato! Appena ho delle novità vi farò sapere! :smiley:

Leo_Barraco:
Ciao marinaio67 e grazie dell'a risposta! in realtà il contatore_allarme si incrementa di 1 ogni volta che il sensore RFID legge la card giusta; questa funzione l'ho usata perchè voglio che al primo riconoscimento della card si inserisca l'allarme, e al secondo riconoscimento la disattivi:

Per quello ti conviene cambiare il codice utilizzando una semplice variabile booleana, sia come leggibilità del codice che per occupazione di memoria

Ragazzi vi riporto la parte che ho modificato:

switch(contatore_allarme)  

     {
      case 1:
      currentMillis2 = millis();
      if (currentMillis2 - previousMillis2 > interval2){
      previousMillis2 = millis(); 
      lettura_PIR1 = digitalRead(PIR1);
      if(lettura_PIR1){ 
      digitalWrite(Buzzer, HIGH);
      
       }
      }
     
      break;
      
      case 2:
      digitalWrite(Buzzer, LOW);
      digitalWrite(ledVerde, LOW);
      contatore_allarme = 0;
      break;
     }

Ho provato a spostare il currentMillis2 all'inizio del case 1, ma non cambia assolutamente nulla; se il sensore RFID legge una card sbagliata, un led inizia a lampeggiare a intervalli di mezzo secondo, e lo fa anche bene nonostante io stia utilizzando millis per farlo lampeggiare. Quindi sono sicuro che il contatore interno del processore parta nel momento giusto. Non è che all'interno degli switch case il millis parte per la tangente?

Qualcuno riesce a darmi una mano?

Leo_Barraco:
Salve a tutti!

Ti invitiamo a presentarti (dicci quali conoscenze hai di elettronica e di programmazione) qui: Presentazioni
e a leggere il regolamento: Regolamento

ciao

Leo_Barraco:
Qualcuno riesce a darmi una mano?

Ma a che punto sei con il codice?
Hai provato a usare una (o più) variabili booleane come suggerito da fabpolli?

Posta il codice completo

ciao
pippo72