problema con semplice timer conta pezzi.

Salve vi spiego brevemente quello che devo fare:
In pratica mi serve un conta pezzi gestito da un timer:

Il numero dei pezzi da contare e’ “simulato” tramite uno switch (verra’ poi sostituito un sensore IR)

Funzionamento:
Premendo il tasto, il contatore dei pezzi si incrementerà di un unita’.
Il timer conta l’intervallo di tempo da quando e’ stato premuto l’ultima volta il tasto

Se non viene premuto il tasto per tot secondi (quindi non ha contatonessun pezzo) il programma dovrebbe avvertire con un messaggio di errore,oppure accendere un led ecc…
Il programma mi da errore l’errore ad oltranza!Forse il problema e’ che inizializzo la variabile a 0.Ma come posso ovviare?Se elimino la condizione del ciclo while,il programma funziona (conta e mi rileva il tempo trascorso tra uno switch e l’altro)ma ovviamente senza il messaggio di errore. Ecco lo sketch:

const int switchPin=3;
long startTime;
long duration;

int conta=0;

void setup() {
  // put your setup code here, to run once:
pinMode (switchPin,INPUT);
digitalWrite(switchPin,HIGH);
Serial.begin(9600);

}

void loop() {

  
 while ((conta!=0) && (duration/1000)<10){
    
if (digitalRead(switchPin)==LOW){
  startTime=millis();
  while (digitalRead(switchPin)==LOW);
  long duration = millis()-startTime;
  Serial.println(duration/1000); // converte in secondi
  
  }
 if (digitalRead(switchPin)==HIGH) {
  conta=conta+1;
  Serial.print("conta");Serial.print(":");Serial.print(conta);
  Serial.println();
  delay(800);
  
   }
   
}

Serial.println("BLOCCA TUTTO"); 
}

Ciao, è normale appena viene valutata la condizione di conta diverso da zero fallisce e esce con errore. Per fare quello che dici tu ti conviene spostare il controllo del tempo massimo trascorso in un if dentro al while, nel while lasci solo una vriabile come test che inizializareai opportunamente (Es. true) all'interno del while se è trascorso troppo tempo metti la variabile a false e il ciclo termina. Ciao

ciao. un altro approccio potrebbe essere quello di non usare nessun while e di portare tutto dentro al void loop con un paio di flag. mi spiego meglio (o almeno ci provo ;)) : -quando premi il tasto oltre che incrementare il contatore riallinei il valore startTime a millis. -se la differenza di startTime e millis è maggiore di (quello che è) vai in allarme. in questo modo se sei in allarme e premi il tasto si "resetta" e non blocchi niente se nel frattempo il micro deve fare altro. Devi anche aggiungere un flag per capire se il tasto è gia premuto altrimenti il contatore si incrementerà continuamente.

ciao pippo72

p.s. non sono sicuro di essere stato troppo chiaro :blush:

pippo72:
ciao.
un altro approccio potrebbe essere quello di non usare nessun while e di portare tutto dentro al void loop con un paio di flag.
mi spiego meglio (o almeno ci provo ;)) :
-quando premi il tasto oltre che incrementare il contatore riallinei il valore startTime a millis.
-se la differenza di startTime e millis è maggiore di (quello che è) vai in allarme.
in questo modo se sei in allarme e premi il tasto si “resetta” e non blocchi niente se nel frattempo il micro deve fare altro.
Devi anche aggiungere un flag per capire se il tasto è gia premuto altrimenti il contatore si incrementerà continuamente.

ciao
pippo72

p.s.
non sono sicuro di essere stato troppo chiaro :blush:

Ragazzi,anzitutto grazie per le risposte!Visto che questa dovrebbe essere solo una piccola parte di un programma molto piu grande,vorrei evitare di complicarmi la vita con vai if e flag!In effetti forse ne basterebbe solo uno…il problema e’ capire come implementarlo,partendo dal mio sketch! :frowning:

Dovrebbe funzionare...

#define SwitchPin 3

unsigned long Timer = 0;
const unsigned long Timeout = 10000;  // 10 secondi

unsigned int Contatore = 0;

void setup() {
  pinMode (SwitchPin, INPUT_PULLUP);  // pulsate chiude verso massa (per evitare il resistore di pullup si usa quello interno)
  Serial.begin(9600);
}

void loop() {

  if (Timer > 0 && ((millis() - Timer) > Timeout)) {  // raggiunto timeout
    Serial.println("BLOCCATO"); 
  }
  else {
    if (digitalRead(SwitchPin) == LOW) {  // pulsante premuto
      delay(20);  // ritardo antiribalzo 
      if (digitalRead(SwitchPin) == LOW) {  // conferma pulsante premuto
        Contatore ++;  // incrementa contatore
        Timer = millis();  // timer partito/resettato
      }
    }
    Serial.print("Contatore: ");
    Serial.println(Contatore);
  }
}

cyberhs: Dovrebbe funzionare...

#define SwitchPin 3

unsigned long Timer = 0; const unsigned long Timeout = 10000;  // 10 secondi

unsigned int Contatore = 0;

void setup() {   pinMode (SwitchPin, INPUT_PULLUP);  // pulsate chiude verso massa (per evitare il resistore di pullup si usa quello interno)   Serial.begin(9600); }

void loop() {

  if (Timer > 0 && ((millis() - Timer) > Timeout)) {  // raggiunto timeout     Serial.println("BLOCCATO");   }   else {     if (digitalRead(SwitchPin) == LOW) {  // pulsante premuto       delay(20);  // ritardo antiribalzo       if (digitalRead(SwitchPin) == LOW) {  // conferma pulsante premuto         Contatore ++;  // incrementa contatore         Timer = millis();  // timer partito/resettato       }     }     Serial.print("Contatore: ");     Serial.println(Contatore);   } }

Non funziona purtroppo,appena invio lo sketch il contatore viene incrementato senza che io prema nulla...se tengo premuto il tasto continua a visualizzarmi continuamente la cifra del conteggio in cui l'ho bloccato:Dopo 10 secondi non succede nulla A 378 premo il tasto!: Contatore: 357 Contatore: 358 Contatore: 359 Contatore: 360 Contatore: 361 Contatore: 362 Contatore: 363 Contatore: 364 Contatore: 365 Contatore: 366 Contatore: 367 Contatore: 368 Contatore: 369 Contatore: 370 Contatore: 371 Contatore: 372 Contatore: 373 Contatore: 374 Contatore: 375 Contatore: 376 Contatore: 377 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378 Contatore: 378

ri-ciao. Mi sono permesso di modificare il programma di cyberhs (sperando non si arrabbi... :grin:)

#define SwitchPin 3

unsigned long Timer = 0;
const unsigned long Timeout = 10000;  // 10 secondi
boolean premuto = false;
unsigned int Contatore = 0;

void setup() {
  pinMode (SwitchPin, INPUT_PULLUP);  // pulsate chiude verso massa (per evitare il resistore di pullup si usa quello interno)
  Serial.begin(9600);
}

void loop() {

  if ((millis() - Timer) > Timeout) {  // raggiunto timeout
    Serial.println("BLOCCATO"); 
  }
  else {
    if (digitalRead(SwitchPin) == HIGH) { //pulsante non premuto
      premuto = false;
    }
    if (digitalRead(SwitchPin) == LOW && premuto == false) {  // pulsante premuto
      delay(20);  // ritardo antiribalzo 
      if (digitalRead(SwitchPin) == LOW ) {  // conferma pulsante premuto
        Contatore ++;  // incrementa contatore
        Timer = millis();  // timer partito/resettato
        premuto = true;
        Serial.print("Contatore: ");
        Serial.println(Contatore);
      }
    }

  }
}

il pulsante è collegato tra GND e il PIN3 di arduino. Ho aggiunto un flag per evitare che il contatore si incrementi se tieni il pulsante premuto. Quando va in allarme non ne esci più, se anche qui mettessi un flag non sarebbe male.

ciao pippo72

P.S.

mooger: vorrei evitare di complicarmi la vita con vai if e flag!

un flag si semplifica la vita ;) ;) ;)

Provato e funziona GRAZIE MILLE!!Sembrava semplice e invece ci stavo sbattendo la testa giorno e notte!!!Si in effetti i flag sono comodi,ma devo imparare ad usarli!! :)

Mi sono permesso di modificare il programma di cyberhs (sperando non si arrabbi... smiley-mr-green)

Arrabbiarmi e perché mai? L'importante è che il nostro amico sia arrivato alla soluzione.

Rieccomi,dunque ho provato a montare il sensore al posto dello switch!Si tratta di un sensore ad infrarossi:
SHARP 2Y0A21,qui le caratteristiche:

http://www.sharpsma.com/webfm_send/1489
E’ un sensore analogico ad infrarossi ,connesso al pin A0 di Arduino.
Ho utilizzato la libreria apposita,in modo da ottenere la lettura in cm.
Ho stabilito una distanza di 7cm,in cui se il valore e’ <7 ,il contatore si incrementa altrimenti no.
Nella logica dello sketch precedente, ho fatto le seguenti sostituzioni:
Switchpin==HiGH → Distance>=7;

Switchpin==LOW-> Distance<7;

Lo sketch conta solo un unita’.
Contatore=1;Si blocca e dopo 10 secondi mi da il messaggio di errore,come impostato.

Devo per caso cambiare anche il flag della variabile “premuto”?

#include <DistanceGP2Y0A21YK.h>

DistanceGP2Y0A21YK Dist;
int distance;


unsigned long Timer = 0;
const unsigned long Timeout = 10000;  // 10 secondi
boolean premuto = false;
unsigned int Contatore = 0;

void setup() {
  
  Serial.begin(9600);
  Dist.begin(A0);
}

void loop() {

  if ((millis() - Timer) > Timeout) {  // raggiunto timeout
    Serial.println("BLOCCATO"); 
  }
  else {
 
    if (distance>=7) { //pulsante non premuto
    
      premuto = false;
    }
  
      
      if ((distance<7) && premuto == false) {  // pulsante premuto
      
       if (distance<7) {  // conferma pulsante premuto
      
        Contatore ++;  // incrementa contatore
        Timer = millis();  // timer partito/resettato
        premuto = true;
        Serial.print("Contatore: ");
        Serial.println(Contatore);
      }
    }

  }
}

ciao le sostituzioni che hai fatto sono giuste, il problema è un altro: non leggi-aggiorni mai il valore di distance. all'interno del loop, prima del primo if aggiungi

distance = Dist.getDistanceCentimeter();

così ad ogni ciclo di loop andrà a leggere il valore della distanza e si comporterà di conseguenza.

p.s. non ho il tuo sensore e non ho provato ma il tutto è ricavato dal seguente esempio

ciao pippo72

Si,in effetti l’avevo mancato!!Per forza non funzionava! Ho inglobato tutto in una void,e inserita nel programma principale.
Mi succede una cosa strana,i valori non vengono contati e subito va in timeout.Ma per caso la funzione millis () deve essere inizializzata subito dopo dove comincia il loop principale?
Il programma funziona cosi’,viene inserita una sim card,si apre un portello (rele’),si inseriscono gli oggetti e comincia a contare.

L’errore che mi da e’ questo:

Inserire la simcard prego…done

SIMCARD VALIDA

PREGO CONFERIRE PET
Contatore: 1
Estrarre la SIMCARD,Grazie…

Mi conta solo 1 pezzo e poi mi dice di estrarre la card

Se estraggo la card e le rimetto,non mi conta neanche un pezzo:

Inserire la simcard prego…done

SIMCARD VALIDA

PREGO CONFERIRE PET
Estrarre la SIMCARD,Grazie…

Ecco lo sketch completo:

// include the SPI library:
#include <SPI.h>

//include the Smartcard library
#include <Smartcard.h>

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


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

//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;
}


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

  const int CTRL1 = 3;
  const int CTRL2 = 4;
  int VAL_CTRL1=0;
  int VAL_CTRL2=0;
  
 //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;
  
  int VAL_PET=0;
  int VAL_PS=0;
  int VAL_ALU=0;
  
  
// SET UP RELATIVO AL SENSORE  IR GP2Y0A21YK  

DistanceGP2Y0A21YK Dist;
int distance;
unsigned long Timer = 0;
const unsigned long Timeout = 10000;  // 10 secondi
boolean premuto = false;
unsigned int Contatore = 0;

///////////////////////////////////////////////  
  
  
  
  void setup() {
    
  // start the serial library:
  Serial.begin(9600);
  pinMode(2, OUTPUT);  // LED DI STATO - CARD RICONOSCIUTA
  
  pinMode(CTRL1,INPUT);
  pinMode(CTRL2,INPUT);
  
  pinMode(PET,INPUT);
  pinMode(PS,INPUT);
  pinMode(ALU,INPUT);
  
  // Definizione dei pin dei RELE' Relativi all' apertura delle bocche:
  pinMode (Rele_PET,OUTPUT);
  
  
  // PIN ANALOGICO A CUI E' COLLEGATO IL SENSORE IR
  
  Dist.begin(A0);
  
}

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("done");
      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);
       
        Serial.println("SIMCARD VALIDA");
        Serial.println();
        
         VAL_CTRL1=digitalRead(CTRL1);
         VAL_CTRL2=digitalRead(CTRL2);
         
         
         if ((VAL_CTRL1==HIGH) || (VAL_CTRL2==HIGH)) { // simulazione errori tramite i pulsanti
           Serial.println("ERRORE COMPATTATORE");
          } 
          
          else {
            
            // EFFETTUA LA SCELTA DEL MATERIALE DA CONFERIRE ENTRO T=10secondi!

            
             apriportelloPET();
             contaPET();
             
            
            
              }
        
      } // CHIUSURA PARENTESI if controllo pin sim card
      
      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...");
      
      smartcard.PowerOffSC();

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

  }
  
  
  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() {
    
    distance = Dist.getDistanceCentimeter();
  if ((millis() - Timer) > Timeout) {  // raggiunto timeout
    Serial.println("BLOCCATO"); 
  }
  else {
  
    if (distance>=7) { //pulsante non premuto
    
      premuto = false;
                    }
        if ((distance<7) && premuto == false) {  // pulsante premuto
      
          if (distance<7) {  // conferma pulsante premuto
      
          Contatore ++;  // incrementa contatore
          Timer = millis();  // timer partito/resettato
          premuto = true;
          Serial.print("Contatore: ");
          Serial.println(Contatore);
                          }                    
                   }          

              }
  
        }

ciao. Alla faccia del "semplice timer contapezzi"... Ad una rapida occhiata.... questi computer sono tremendi; fanno ESATTAMENTE quello che gli dici :stuck_out_tongue_closed_eyes: :stuck_out_tongue_closed_eyes: :stuck_out_tongue_closed_eyes:. Nel void loop: -attendi che una card sia inserita -se inserita e valida:accendi il led -se non ci sono errori compattatore: - apri pet - conta pet -se non valida:spegni led -adesso IN QUALSIASI CASO aspetta che venga tolta la card. -chiudi sportello pet. Fa esattamente quello che gli hai chiesto!! A parte questo c'è un altro problema: da quando comincia a contare i 10 secondi (ovvero da quando gli dai timer = millis())? Adesso comincia a contare da quando arduino viene acceso, non so se è quello che vuoi.

Per adesso studia un pò. ciao pippo72

Si,tutta la macchine funziona SOLO se la card e' inserita. Il mio approccio e' quello di creare piccoli blocchi funzionali e poi inserirli nel loop principale,altrimenti e' difficile intervenire in modo "mirato",su malfunzionamenti o modifiche.Sbaglio approccio?(fondamentalmente programmo da poco,e quello che sto facendo e' solo frutto di quello che ho letto in vari manuali che ho comprato e cercando di capire vari sketch postati in rete) Dunque,deve cominciare a contare da poco prima che si apre il portello. Si ,non smetto mai di studiare :-)

ciao.

mooger:
Sbaglio approccio?

Assolutamente NO.
In questo caso la funzione dovrebbe essere bloccante ovvero rimani li a contare fino a che non va in timeout (a onor del vero è quello che avevi chiesto sin dall’inizio):
potrebbe essere così:

void contaPET() {
    Timer = millis();
     while((millis() - Timer) < Timeout) {
    distance = Dist.getDistanceCentimeter();
      if (distance>=7) { //pulsante non premuto
         premuto = false;
                    }
        if ((distance<7) && premuto == false) {  // pulsante premuto
          Contatore ++;  // incrementa contatore
          Timer = millis();  // timer partito/resettato
          premuto = true;
          Serial.print("Contatore: ");
          Serial.println(Contatore);
                    }          
              }
          }

all’inizio di quella funzione attivi il timer e parti con un while che conta fino al timeout
Il secondo if (distance<7) {  // conferma pulsante premuto in questo caso non serve, lo puoi togliere.

ciao
pippo72
p.s. Non sono a casa, non so se il codice funziona o se ci sono errori di “ortografia”.

Ciao,grazie per la risposta!Lo sketch diciamo che funziona,ma quando reinserisco di la card,non mi resetta in conteggio,bensi' continua dal conteggio precedente.

ciao. Il contatore non viene mai azzerato. Aggiungi

Contatore = 0;

prima di

contaPET();

all'interno del void loop() ciao pippo72

Grazie mille,ora funziona bene! :)