contatore

Buonasera, mi serve un aiuto, vorrei creare un contatore. Ho a disposizione un magnetic switch (sistema grove) http://www.seeedstudio.com/wiki/Grove_-_Magnetic_Switch, in particolare questa. A questo punto pensavo attraverso la funzione millis di creare il contatore, cioè quando il magnete passa davanti al sensore assegno il valore millis al Time[0], quando il magnete ripassa davanti al sensore assegno AL Time[1] il valore milis a quell'istante a questo punto faccio la differenza tra time[1] e time[2] e trovo il tempo tra i due passaggi; questo mi serve per calcolare la velocità conoscendo la distanza.
Una parte di codice ho provato a farla, ma non ci capisco molto con i timer. Qualcuno ha dei suggerimenti? :fearful:

#define MAGNETIC_SWITCH 2

unsigned long Time[3]={0, 0,0};
int S;

void setup()
{
 	
        Serial.begin(9600);
        pinMode(MAGNETIC_SWITCH, INPUT); 
}
 
void loop() 
{
	if(MAGNETIC_SWITCH==1)//if the magnetic switch is near the magnet?
	{
		Time[0]=millis();
	        
        }
	else
	{
		Time[1]=millis();
                
                
                Serial.println();
	        Serial.print("velocità: ");
                unsigned long Time_A=Time[1]-Time[0];
                unsigned long Time_B=Time_A/1000;
                S=10;
                unsigned long Velocita_angolare=S/Time_B;
                Serial.println(Velocita_angolare);
                Serial.print("m/s");  
    }
}

Eccetto che non mi sembra che la velocitá angolare si calcola in m/s cosa é il Tuo problema?
Ciao Uwe

gabry_92:

#define MAGNETIC_SWITCH 2

...
void setup()
{       Serial.begin(9600);
       pinMode(MAGNETIC_SWITCH, INPUT);
}
void loop()
{  if(MAGNETIC_SWITCH==1)//if the magnetic switch is near the magnet?
...

Ma soprattutto cosa pensi che faccia quella istruzione if ?
Dichiari la parola MAGNETIC_SWITCH come alias di 2 perciò il compilatore sostituisce ovunque quella parola con due.
Perciò l'istruzione if diventa: :smiley:

if(2==1)

Hai dimenticato di leggere con la digitalRead() il valore rilevato su quel pin :

if( digitalRead(MAGNETIC_SWITCH)==1)

uwefed hai ragione, sono andato troppo avanti con l'idea :sweat_smile: , in seguito trasformerò la velocità angolare in velocità lineare :slight_smile:

Grazie nid69ita, ieri ero fuso e non mi sono accorto, quindi secondo te il problema è solo quello?

Per il resto non sò, ma quello era grave come errore, in pratica non leggevi nulla dal sensore.
Verifica ora. :wink:

Grazie, appena possibile verifico, poi ti faccio sapere

C'è un errore di base nel tuo software.
Anche ammesso di corregere il calcolo della velocità e l'istruzione

  if(MAGNETIC_SWITCH==1)   ----->  if (digitalRead(MAGNETIC_SWITCH) == HIGH)

la cosa non puo funzionare.

Sino a che l'input rimane basso la seriale manderebbe in uscita dati senza senso e sopratutto a raffica!

L'approccio corretto in questi casi bisogna calcolare la differenza di tempo sul fornte di salita (o discesa ) tra due impulsi.

void setup(){
  int memStato = 0;
  unsigned long Time0 = millisec();
  unsigned long Time1 = Time0;
  unsigned long Intervallo  = 0;
}

void Loop(){

if (digitalRead(MAGNETIC_SWITCH)==LOW)  MemStato=0;
else  {
  if (MemStato ==0) {
     MemStato = 1;
     Time1 = millisec();
     Intervallo = Time1 - Time0;
     // --------------------- calcolo e uscita seriale dato
     Time0 = Time1;
  }
}

}

Con la mia proposta otteresti un invio sulla seriale ad ogni impulso ricevuto, che a seconda dell'applicazione
potrebbe essere esagerato e/o illegibile

Renzo

edit by mod: per favore includi il codice usando gli appositi tag

Per favore @over, il codice deve essere racchiuso negli appositi tag. :smiley:
Vedi sezione 7 del regolamento, spiega come fare: [REGOLAMENTO] Come usare questa sezione del forum - Italiano - Arduino Forum

P.S. nel codice spero che le variabili le sposti prima dalla setup() e le rendi globali altrimenti un pò di errori di compilazione.

Scusa!
La prossima volta vedro' di rispettare le regole

Partendo dal presupposto che con i timer non ho mai capito nulla :), ho provato il tuo codice mettendoci le istruzioni per visualizzarle sul monitor seriale però mi visualizza un solo valore nn capisco perchè :fearful:

#define MAGNETIC_SWITCH 2
int memStato = 0;
  int Stato = digitalRead(MAGNETIC_SWITCH);
  unsigned long Time0 = millis();
  unsigned long Time1 = Time0;
  unsigned long Intervallo  = 0;

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

void loop()
{
Stato = digitalRead(MAGNETIC_SWITCH);
if (Stato) {
  if (memStato ==0) {
     memStato = 1;
     Time1 = millis();
     Intervallo = Time1 - Time0;
     Serial.println();
     Serial.println(Intervallo);  
      //--------------------- calcolo e uscita seriale dato
     Time0 = Time1;
}
}
}[/code

Perché nell'IF metti a 1 la var memstato ma dopo non la modifichi più, quindi non stampi più nulla.

Mi hai fregato sul tempo!

Io mi ero già accorto del problema e avevo modificato la risposta al volo senza segnalare la modifica, ma tu nel frattempo avevi già scaricato il codice.
Dai un occhiata al codice. Ho invertito la funzionalità dell' if e ovviamente aggiungendo MemStato =0

Il codice te l'ho buttato la al volo giusto per farti capire cosa devi fare.
Preciso inoltre:

  1. Fatte salve applicazioni particolari, la velocità va calcolata sull'unita' di tempo non sul periodo come nel tuo caso.
    Crei un timer con cadenza x esempio 1 sec. e poi conti gli impulsi (km) in arrivo nell'intervallo di tempo, quindi km/h.

  2. Come citato Il codice che ti ho dato e' puramente propedeutico, perche' if, else, MemStato, ecc. preferisco un approccio matematico logico più efficente. Appena ho due minuti lo testo e te lo faccio avere.

Tu intanto divertiti

Renzo

Questo e' il codice promesso.

  int PinInput = ??????;    // pin che verrà utilizzato

  int Stato0;
  int Stato1;
  int StatoXor;
  int StatoUp;
  int StatoDown;

void setup (){

  Serial.begin(9600);
  Stato1 = digitalRead(PinInput);  

}

void loop (){
   
  Stato0 = Stato1;                   // salva stato precedente
  Stato1 = digitalRead(PinInput);       // legge stato attuale
  
  StatoXor = Stato0 ^ Stato1;        // calcola xor tra stato precedente e attuale
  StatoUp = StatoXor & Stato1;       // variazione su fronte salita
  StatoDown = StatoXor & Stato0;     // variazione su fronte discesa
  
  if  (StatoUp) Serial.println   ("variaz. su fronte Salita  (0 -> 1)");
  if  (StatoDown) Serial.println ("variaz. su fronte Discesa (1 -> 0)f");
  
}

Ovviamente in corrispondenza del " if (StatoUp)" o " if (StatoDown)" potrai mettere il codice per il calcolo velocità.

A prima vista il software puo sembrare complicato, ma lavorando sui "fronti" piuttosto che sullo stato dell'ingresso si possono fare cose interessanti.
In genere io quando posso, cerco di utilizzare ingressi associati alla stessa porta,.
Mantenendo invariati i calcoli logici elencati, in un sol colpo effettuo il calcolo dei "fronti" su un massimo di 8 ingressi, con indubbi vantaggi in termini di efficenza e flessibilità di utilizzo.

In ogni caso il codice si presta ad essere ottimizzato e/o in alcuni punti eliminato.

@over grazie mille per il codice, non capisco ancora una cosa (su timer, fronte di salita... non ci capisco molto :))

StatoXor = Stato0 ^ Stato1;        // calcola xor tra stato precedente e attuale
  StatoUp = StatoXor & Stato1;       // variazione su fronte salita
  StatoDown = StatoXor & Stato0;     // variazione su fronte discesa
  
  if  (StatoUp) Serial.println   ("variaz. su fronte Salita  (0 -> 1)");
  if  (StatoDown) Serial.println ("variaz. su fronte Discesa (1 -> 0)f");

in questa parte di codice non capisco queste istruzioni cosa fanno perchè non riesco a capire come fare per calcolare il tempo ( mi serve calcolare il tempo per calcolare la velocità)

Le operazioni logiche vanno a sostituire quella serie di "IF", ma non c'e' il timer.
Ora hai tutto pronto e fatto, completa con i calcoli, dai una controllata e vedi sopratutto di analizzare il codice
cosi' impari.
Fammi sapere come è andata!

  unsigned long MillisTmp;
  unsigned long MillisTmr;
  unsigned long Timer= 1000;   // 1000 mS = 1 Secondo
  unsigned int Count;          // conteggio impulsi

  int Stato0;
  int Stato1;
  int StatoXor;
  int StatoUp;
  int StatoDown;
  
  int PinIn = 2; // ************* da modificare ******

void setup (){

  pinMode (PinIn,INPUT_PULLUP);
  Stato1 = digitalRead(PinIn);  
  MillisTmp = millis();              // legge millisecondi

}

void loop (){
 
  Stato0 = Stato1;                   // salva stato precedente
  Stato1 = digitalRead(PinIn);       // legge stato attuale
  MillisTmp = millis();              // legge millisecondi

// questa è la sezione che genera il temporizzatore

  if ((MillisTmp - MillisTmr)>= Timer){
    // a questo punto e trascorso 1 secondo hai gli impusi in Count
    // inserisci i calcoli per la velocità  (impulsi / tempo). 
    // Non escludo che tu debba mettere mano a Timer o inserire un moltiplicatore
    // su Count per ottenere un dato reale
    
    Count = 0;                                      // Azzerri il contatore per nuovo conteggio
    MillisTmr = MillisTmr + Timer;   // e aggiorni nuova cadenza x nuovo calcolo
  }
  
    
  StatoXor = Stato0 ^ Stato1;        // calcola xor tra stato precedente e attuale
  StatoUp = StatoXor & Stato1;       // variazione su fronte salita
  // visto che usi solo "StatoUp" ho tolto il calcolo di "StatoDown"

  if (StatoUp) Count += 1;           // conta impulsi in arrivo all'input su fronte salita

}

Grazie mille per il codice,
:~ non so se sono io che sono rinc.... (molto probabile :)) ma non riesco a farlo andare

Come per altro specificato,

  • ho definito "PinIn" (il pin che usi come ingresso)
  • in sostituzione della rem "// calcoli la velocità." ho inserito
Serial.print(Count);
Serial.println(" Hz");

e tutto ha funziona.
Lasciando tutto come sta, si ottiene un frequenzimetro.
Conta gli impulsi nell'arco di 1 secondo.

Ora è da capire cosa hai colegato al pin per inserire eventuali moltiplicatori o modificare eventualmente la base dei tempi

Ok, come ingresso ho un magnetic switch del sistema grove, la mia idea era quella di implementare una stazione meteo già esistente (ne avevo creato una con sensore di temperatura pressione e umidità), volevo attraverso questo sensore misurare la velocità del vento!!

Segui il ragionamento e poi adattalo alle tue esigenze

Dati stimati:
diametro teorico pale anemometro = 0,30 m.
inpulsi x giro = 1

circonferenza anemometro = 0,30 x 3.14 = 0,94 cm
Cosi' il calcolo si trasforma:

flot Speed = Count * 0.94;
Serial.print(Speed);
Serial.println(" m/s");

ConsIderazioni finali:
Il calcolo suggerito è puramente teorico e causa atriti meccanici e aerodinamici, il valore risultante sarà inferiore al reale.
Magari alla criconferenza teorica aggiungi 10-15%. C'e' chi tara tale coefficente correndo in auto con l'anemometro fuori del finestrino.!

Se come da me stimato hai un solo impulso per giro, la precisione dello strumento sara' molto approssimativa specialmente alle basse velocita'.
Ti consiglio di modificare Timer e Speed per un fattore K=4:
Timer = 1000 x K
flot Speed = Count * 0.94 / K;
Allunghi il tempo di campionamento ma ottieni una maggior precisione.