Go Down

Topic: Problema con millis() (Read 7185 times) previous topic - next topic

mooger

Salve,credo di avere un problema con la funzione millis().
La macchine viene attivata tramite l'inserimento di una SIMCARD,la quale se e' valida,si chiede all'utente  di effettuare una scelta entro un tempo prestabilito (nel mio caso 10 secondi).Dopodiche' se la macchina va in timeout,chiede all'utente di rimuovere la scheda.

Il mio problema e' questo:
La macchina chiede di inserire la SIM CARD,ma subito chiede di estrarla,come se andasse subito in TIMEOUT
Ecco il risultato della seriale:

Inserire la simcard prego........OK

SIMCARD VALIDA

Effettua la scelta del materiale da conferire entro 10 secondi..
Estrarre la SIMCARD,Grazie...


Ho esaminato varie volte il codice,e letto guide sulla libreria millis(),ma non ho trovato nulla di anomalo,cosa sbaglio?Ecco la porzione di codice interessata:

Code: [Select]
   if((ascii_data[0] == '5')&&(ascii_data[1] == '0'))
      {
       
       // Se la simcard è riconosciuta,accendi il led
        digitalWrite(2, HIGH);  // LED CHE INDICA IL RICONOSCIMENTO DI UNA SIM CARD VALIDA
        Serial.println("SIMCARD VALIDA");
        Serial.println();
        PreviousDurata=millis();
       
         VAL_CTRL1=digitalRead(CTRL1);
         VAL_CTRL2=digitalRead(CTRL2);
         
       
         // Verifica se ci sono malfunzionamenti nel compattatore:
     
       
         if ((VAL_CTRL1==HIGH) || (VAL_CTRL2==HIGH)) { // simulazione errori tramite i pulsanti
           Serial.println("Attenzione!Errore compattatore!");
          }
         
          else {
           
                Serial.println ("Effettua la scelta del materiale da conferire entro 10 secondi..");
               
                // Parte il conto alla rovescia per la scelta del materiale da conferire:
               
                //PreviousDurata=millis();
               
                if ((CurrentDurata - PreviousDurata) > Timeout)
                 {   
                 
                   // Manda l'impulso solo se non l'ha già mandato prima
                   if (impulso_mandato == false)
                    {
                     Serial.println("BLOCCATO");
                     impulso_mandato = true;
                    }
                 }
     
                else   
                {
                 CurrentDurata=millis();
             
                 if (pulsantePremuto(PET) == true && giaPremuto == false)
                   {
                   giaPremuto = true;
                   Serial.println("Scelta effettuata : PET");
                   apriportelloPET();
                   Contatore=0;
                   contaPET();
                   }
                }
            }
      }
       
       // CHIUSURA PARENTESI if ascii
       else
        {
         //Se la simcard non e' riconosciuta,spegni il led
         digitalWrite(2, LOW);
        Serial.println("Simcard non valida!");
        Serial.println();
      }
      Serial.print("Estrarre la SIMCARD,Grazie...");
      Serial.println();
     
      smartcard.PowerOffSC();

      //wait smartcard extraction
      while(smartcard.IsCardPresent(1)){
        delay(500); 
      }
     
      chiudiportelloPET(); // Chiude portello PET quando si estrae la scheda.
     
      Serial.println("Operazione conclusa");
      Serial.println();
     
     
  } // Fine LOOP

Brado

Ad occhio, mi pare che il controllo se Timeout è scaduto lo fai una volta sola.

Cioè: controlli che CurrentDurata - PreviousDurata sia minore di Timeout, essendo la prima volta vai all'else di quel if; aggiorni CurrentDurata con il nuovo millis(), e poi il programma prosegue e l'istruzione successiva è appunto stampare la dicitura di estrarre la card.

Secondo me dovresti inserire un rimando a prima di if ((CurrentDurata - PreviousDurata) > Timeout).
Ad esempio un while che decade allo scadere del timeout e/o alla scelta da parte dell'utente.

mooger


Ad occhio, mi pare che il controllo se Timeout è scaduto lo fai una volta sola.

Cioè: controlli che CurrentDurata - PreviousDurata sia minore di Timeout, essendo la prima volta vai all'else di quel if; aggiorni CurrentDurata con il nuovo millis(), e poi il programma prosegue e l'istruzione successiva è appunto stampare la dicitura di estrarre la card.

Secondo me dovresti inserire un rimando a prima di if ((CurrentDurata - PreviousDurata) > Timeout).
Ad esempio un while che decade allo scadere del timeout e/o alla scelta da parte dell'utente.


Cioe dovrei inserire while (Timeout <10000) ?

Brado

#3
Aug 04, 2014, 02:26 pm Last Edit: Aug 04, 2014, 02:28 pm by Brado Reason: 1
No, così non usciresti più perchè Timeout = 10000 e con quel controllo ti blocchi.

Io inserirei una variabile di stato, dove ad esempio 0 sta per timeout non scaduto ed azione richiesta non effettuata, in modo tale che if ((CurrentDurata - PreviousDurata) > Timeout) lo controlli più volte.

Code: [Select]
stato = 0;
while (stato < 1)
{
      if ((CurrentDurata - PreviousDurata) > Timeout)
                {  
                 stato = 1;
                  // Manda l'impulso solo se non l'ha già mandato prima
                  if (impulso_mandato == false)
                   {
                    Serial.println("BLOCCATO");
                    impulso_mandato = true;
                   }
                }
     
               else  
               {
                CurrentDurata=millis();

                if (pulsantePremuto(PET) == true && giaPremuto == false)
                  {
                  stato=1;
                  giaPremuto = true;
                  Serial.println("Scelta effettuata : PET");
                  apriportelloPET();
                  Contatore=0;
                  contaPET();
                  }
               }
             } // End While
           }
     }
       
      // CHIUSURA PARENTESI if ascii
      else
       {
        //Se la simcard non e' riconosciuta,spegni il led
        digitalWrite(2, LOW);
       Serial.println("Simcard non valida!");
       Serial.println();
     }
     Serial.print("Estrarre la SIMCARD,Grazie...");
     Serial.println();
     
     smartcard.PowerOffSC();

     //wait smartcard extraction
     while(smartcard.IsCardPresent(1)){
       delay(500);  
     }
     
     chiudiportelloPET(); // Chiude portello PET quando si estrae la scheda.
     
     Serial.println("Operazione conclusa");
     Serial.println();
     
     
 } // Fine LOOP


Così dovrebbe andare

mooger

Niente da fare,ho modificato lo sketch come segue,secondo le tue indicazioni,
il risultato della seriale e' come prima! =(
Code: [Select]
if((ascii_data[0] == '5')&&(ascii_data[1] == '0'))
      {
       
       // Se la simcard è riconosciuta,accendi il led
        digitalWrite(2, HIGH);  // LED CHE INDICA IL RICONOSCIMENTO DI UNA SIM CARD VALIDA
        Serial.println("SIMCARD VALIDA");
        Serial.println();
        PreviousDurata=millis();
       
         VAL_CTRL1=digitalRead(CTRL1);
         VAL_CTRL2=digitalRead(CTRL2);
         
       
         // Verifica se ci sono malfunzionamenti nel compattatore:
     
       
         if ((VAL_CTRL1==HIGH) || (VAL_CTRL2==HIGH)) { // simulazione errori tramite i pulsanti
           Serial.println("Attenzione!Errore compattatore!");
          }
         
          else {
           
                Serial.println ("Effettua la scelta del materiale da conferire entro 10 secondi..");
               
                // Parte il conto alla rovescia per la scelta del materiale da conferire:
               
                //PreviousDurata=millis();
                int stato =0;
                while (stato <1)
                 {
               
                if ((CurrentDurata - PreviousDurata) > Timeout)
                 {   
                  stato = 1;
                   // Manda l'impulso solo se non l'ha già mandato prima
                   if (impulso_mandato == false)
                    {
                     Serial.println("BLOCCATO");
                     impulso_mandato = true;
                    }
                 }
     
                else   
                {
                 CurrentDurata=millis();
             
                 if (pulsantePremuto(PET) == true && giaPremuto == false)
                   {
                     stato = 1;
                   giaPremuto = true;
                   Serial.println("Scelta effettuata : PET");
                   apriportelloPET();
                   Contatore=0;
                   contaPET();
                   }
                }
               }
            }
      }
       
       // CHIUSURA PARENTESI if ascii
       else
        {
         //Se la simcard non e' riconosciuta,spegni il led
         digitalWrite(2, LOW);
        Serial.println("Simcard non valida!");
        Serial.println();
      }
      Serial.print("Estrarre la SIMCARD,Grazie...");
      Serial.println();
     
      smartcard.PowerOffSC();

      //wait smartcard extraction
      while(smartcard.IsCardPresent(1)){
        delay(500); 
      }
     
      chiudiportelloPET(); // Chiude portello PET quando si estrae la scheda.
     
      Serial.println("Operazione conclusa");
      Serial.println();
     
     
  } // Fine LOOP


cyberhs

Ti sei ricordato di dichiarare le variabili temporali come unsigned long?

mooger


Ti sei ricordato di dichiarare le variabili temporali come unsigned long?

Ecco qui ,la parte relativa alla dichiarazione delle variabili
Code: [Select]
int distance;
   unsigned long Timer = 0;
   unsigned int Contatore = 0;
   const unsigned long Timeout = 10000;  // Costante di timeout= 10 secondi
   boolean giaPremuto = false;
   boolean premuto=false;
   boolean impulso_mandato = false;
   
   unsigned long CurrentDurata;
   unsigned long PreviousDurata;

pippo72

ciao mooger.
Ma cosa hai cambiato rispetto il codice dalla fine di questo tread?
E comunque ti conviene postare tutto il codice, non solo degli spezzoni, magari il problema non e dove credi che sia  ;)

ciao
pippo72

Brado

Ma ancora arriva al timeout istantaneamente appena riconosce la card?

Per essere sicuro che il ciclo while funzioni, prova ad inserire la stampa della differenza fra i valori millis memorizzati.
Code: [Select]
Serial.println(CurrentDurata - PreviousDurata);
Serial.println();

Io la metterei tra il while(stato<1) e if ((CurrentDurata - PreviousDurata) > Timeout) .

In base a quante stampe hai sai quanti cicli ha fatto, e contemporaneamente hai un countdown per il timeout, per la sola fase di debug.

mooger


ciao mooger.
Ma cosa hai cambiato rispetto il codice dalla fine di questo tread?
E comunque ti conviene postare tutto il codice, non solo degli spezzoni, magari il problema non e dove credi che sia  ;)

ciao
pippo72


Ciao Pippo,quella era solo una parte del codice ,che poi e'stata inserita nel programma principale che e' questo:
TI posto tutto lo sketch completo!
Code: [Select]
// includi libreria Smartcard:
#include <Smartcard.h>

// includi la libreria del sensore SHARP GP2Y0A21YK:
#include <DistanceGP2Y0A21YK.h>

// include libreria SPI:
#include <SPI.h>

// initialize the library with address of slave select pin
Smartcard smartcard(7);


  //Definizione dei PIN dei pulsanti che simulano i controlli CTRL1 e CTRL2

  const int CTRL1 = 3;
  const int CTRL2 = 4;
 
   //Definizione dei PIN dei pulsanti di scelta materiale:

  const int PET = 5;
  const int PS = 6;
  const int ALU = 8;
  const int Rele_PET = 9;
 
 



//convert from hexadecimal to ASCII for display the result
void HexToAsc(char *c){
if (((*c&0x0F)>=0)&&((*c&0x0F)<=9))
*(c+1) = (*c&0x0F)+0x30;
else
*(c+1) = (*c&0x0F)+0x37;

if ((((*c&0xF0)>>4)>=0)&&(((*c&0xF0)>>4)<=9))
*c = ((*c&0xF0)>>4)+0x30;
else
*c = ((*c&0xF0)>>4)+0x37;
}


   int VAL_CTRL1=0;
   int VAL_CTRL2=0;
   int VAL_PET=0;
   int VAL_PS=0;
   int VAL_ALU=0;
 
 
// Setup relativo al sensore IR GP2Y0A21YK 

   DistanceGP2Y0A21YK Dist;
   int distance;
   unsigned long Timer = 0;
   unsigned int Contatore = 0;
   const unsigned long Timeout = 10000;  // Costante di timeout= 10 secondi
   boolean giaPremuto = false;
   boolean premuto=false;
   boolean impulso_mandato = false;
   
   unsigned long CurrentDurata;
   unsigned long PreviousDurata;

///////////////////////////////////////////////////////////////////////////////////////////////

 
  void setup() {
   
    // start the serial library:
       Serial.begin(9600);
       pinMode(2, OUTPUT);  // LED DI STATO ON -> CARD RICONOSCIUTA
 
    // Definizione dei pin relativi ai controlli del compattatore:
       pinMode(CTRL1,INPUT_PULLUP);
       pinMode(CTRL2,INPUT_PULLUP);
 
    // Definizione dei pin relativi al materiale da conferire:
       pinMode(PET,INPUT_PULLUP);
       pinMode(PS,INPUT_PULLUP);
       pinMode(ALU,INPUT_PULLUP);
 
    // Definizione dei pin dei RELE' Relativi all' apertura delle bocche:
       pinMode (Rele_PET,OUTPUT);
 
 
  ///////////////////////////////////////////////////////////////////////
 
    // Pin analogico a cui è collegato il sensore IR,che gestisce la presenza del materiale PET:
       Dist.begin(A0);
 
   // Pin analogico a cui è collegato il sensore IR,il quale misura il riempimento del contenitore PET:
       Dist.begin(A1);
 
                 
                  } // Fine setup
                   
////////////////////////////////////////////////////////////////////////////////////////////////



  void loop() {
 
      unsigned char data[16];
      char ascii_data[2];
   
      Serial.print("Inserire la simcard prego........");
     
      //wait smartcard
      while(!smartcard.IsCardPresent(1)){
        delay(500); 
      }
      Serial.println("OK");
      Serial.println();

      //reset smartcard
      smartcard.PowerOnATRSC(data);
     
   //   Serial.println(">> ReadByte4442 <<");
    //  Serial.println();
     
      ascii_data[0] = smartcard.ReadByte4442(0x20);
      HexToAsc(ascii_data);     
   
      if((ascii_data[0] == '5')&&(ascii_data[1] == '0'))
      {
       
       // Se la simcard è riconosciuta,accendi il led
        digitalWrite(2, HIGH);  // LED CHE INDICA IL RICONOSCIMENTO DI UNA SIM CARD VALIDA
        Serial.println("SIMCARD VALIDA");
        Serial.println();
        PreviousDurata=millis();
       
         VAL_CTRL1=digitalRead(CTRL1);
         VAL_CTRL2=digitalRead(CTRL2);
         
       
         // Verifica se ci sono malfunzionamenti nel compattatore:
     
       
         if ((VAL_CTRL1==HIGH) || (VAL_CTRL2==HIGH)) { // simulazione errori tramite i pulsanti
           Serial.println("Attenzione!Errore compattatore!");
          }
         
          else {
           
                Serial.println ("Effettua la scelta del materiale da conferire entro 10 secondi..");
               
                // Parte il conto alla rovescia per la scelta del materiale da conferire:
               
                //PreviousDurata=millis();
                int stato =0;
                while (stato <1)
                 {
                   Serial.println(CurrentDurata - PreviousDurata);
                   Serial.println();
               
                if ((CurrentDurata - PreviousDurata) > Timeout)
                 {   
                  stato = 1;
                   // Manda l'impulso solo se non l'ha già mandato prima
                   if (impulso_mandato == false)
                    {
                     Serial.println("BLOCCATO");
                     impulso_mandato = true;
                    }
                 }
     
                else   
                {
                 CurrentDurata=millis();
             
                 if (pulsantePremuto(PET) == true && giaPremuto == false)
                   {
                     stato = 1;
                   giaPremuto = true;
                   Serial.println("Scelta effettuata : PET");
                   apriportelloPET();
                   Contatore=0;
                   contaPET();
                   }
                }
               }
            }
      }
       
       // CHIUSURA PARENTESI if ascii
       else
        {
         //Se la simcard non e' riconosciuta,spegni il led
         digitalWrite(2, LOW);
        Serial.println("Simcard non valida!");
        Serial.println();
      }
      Serial.print("Estrarre la SIMCARD,Grazie...");
      Serial.println();
     
      smartcard.PowerOffSC();

      //wait smartcard extraction
      while(smartcard.IsCardPresent(1)){
        delay(500); 
      }
     
      chiudiportelloPET(); // Chiude portello PET quando si estrae la scheda.
     
      Serial.println("Operazione conclusa");
      Serial.println();
     
     
  } // Fine LOOP
 

///////////////////////////////////////////////////////////////////////


  void apriportelloPET ()  // Procedura per l'apertura del portello PET
  {
    digitalWrite (Rele_PET,HIGH); // pin 9
    Serial.print("PREGO CONFERIRE PET");
    Serial.println();
  }
     
 
  void chiudiportelloPET ()
  {
    digitalWrite (Rele_PET,LOW); // pin 9
   
  }
     
  void contaPET()
  {
    Timer = millis();  // PARTE IL TIMER
     while((millis() - Timer) < Timeout) {   // Mentre t < timeout
        distance = Dist.getDistanceCentimeter(); // Acquisisci dati dal sensore
         if (distance>=7) { // Se la distanza e' maggiore di 7,non contare
            premuto = false;
                          }
            if ((distance<7) && premuto == false) {  // Se la distanza e'minore di 7 comincia a contare
              Contatore ++;  // incrementa contatore
              Timer = millis();  // timer partito/resettato
              premuto = true;
              Serial.print("Contatore: ");
              Serial.println(Contatore);
                    }         
              }
  }
         
         
bool pulsantePremuto(int pinPulsante)
{
  // pulsante premuto
  if (digitalRead(pinPulsante) == LOW)
  {
    delay(20);  // ritardo antiribalzo
   
    // conferma pulsante premuto
    if (digitalRead(PET) == LOW )
    {       
      //Pulsante premuto, ritorna true e ferma la funzione
      return true;
    }
  }
 
  //Nessun pulsante è stato premuto, la funzione ritorna false
  return false;

 

mooger


Ma ancora arriva al timeout istantaneamente appena riconosce la card?

Per essere sicuro che il ciclo while funzioni, prova ad inserire la stampa della differenza fra i valori millis memorizzati.
Code: [Select]
Serial.println(CurrentDurata - PreviousDurata);
Serial.println();

Io la metterei tra il while(stato<1) e if ((CurrentDurata - PreviousDurata) > Timeout) .

In base a quante stampe hai sai quanti cicli ha fatto, e contemporaneamente hai un countdown per il timeout, per la sola fase di debug.


Fatto,ecco dove l'ho inserito:
Code: [Select]
//PreviousDurata=millis();
                int stato =0;
                while (stato <1)
                 {
                   Serial.println(CurrentDurata - PreviousDurata);
                   Serial.println();
               
                if ((CurrentDurata - PreviousDurata) > Timeout)
                 {   
                  stato = 1;


In uscita ottengo:
Inserire la simcard prego........OK

SIMCARD VALIDA

Effettua la scelta del materiale da conferire entro 10 secondi..
4294967125

BLOCCATO
Estrarre la SIMCARD,Grazie...
Operazione conclusa

Inserire la simcard prego........OK

SIMCARD VALIDA

Effettua la scelta del materiale da conferire entro 10 secondi..
4294960996

Estrarre la SIMCARD,Grazie...

C'e' qualcosa che non quadra! :(

pippo72

ciao
ti sei chiesto cosa siano questi numeri?
Quote
...
4294967125
...
4294960996
...

Alla riga 158: quando fai quel controllo:
Code: [Select]
if ((CurrentDurata - PreviousDurata) > Timeout)
abbiamo CurrentDurata che è stato solo dichiarato ma non hai dato nessun valore (quindi credo 0)mentre PreviousDurata lo hai allineato a millis qualche riga prima. Quini 0 - (un numero a caso) da un valore negativo ma siccome entrambi sono unsigned long (non può essere negativo) ti ritrovi quei numeri (4294960996 ecc) che decisamente sono maggiori di Timeout.
quel ciclo while lo fa solo una volta.
Ma perchè anziche usare CurrentDurata non scrivi direttamente millis()?

ciao
pippo72


mooger

Si ovvio che avendo visto quel numero,ho pensato subito a qualcosa che non andava..
mi sono rifatto a questo esempio,percio' non ho scritto direttamente millis()
http://arduino.cc/en/Tutorial/BlinkWithoutDelay

Ho provveduto a dichiarare la variabile

unsigned long PreviousDurata =0;
Anche cosi',il problema rimane..

mooger

Ci sono dei progressi: Ho modificato la parte del codice interessata in questo modo:
ho cancellato le vecchie variabili: currentDurata e previousDurata

e inserito:

long startTime;
long duration;



Code: [Select]
int stato =0;
                while (stato <1)
                 {
                 
                long duration =millis() - startTime;
                if ( duration > Timeout)
                 {   
                  stato = 1;
                   // Manda l'impulso solo se non l'ha già mandato prima
                   if (impulso_mandato == false)
                    {
                     Serial.println("BLOCCATO");
                     impulso_mandato = true;
                    }
                 }


Non va piu in timeout,ma direttamente alla selezione,che per il momento non funziona (ma presumo problemi di collegamenti di switch,che devo verificare). Volevo sapere,cosi' come ho modificato il codice va bene?

Brado

Ma il timeout funziona? Cioè, se non fai nulla, dopo 10 secondi ti dice di levare la tessera ?
Prima della porzione postata all'ultimo messaggio fai un startTime = millis();  ??

Poi, se posso darti un consiglio, la dichiarazione delle variabili falla solo nella parte iniziale dello sketch.
Nello spezzone che hai appena messo, la variabile duration la dichiari n volte ad ogni riconoscimento della simcard. Stessa cosa dicasi per la variabile stato.
In quei punti dovresti solo inizializzarle, e non dichiararle.
Questo comportamento non fa bene alla memoria di arduino, che è un microcontrollore, non un PC. ;)

Go Up