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?
#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");
}
}
...
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:
if(2==1)
Hai dimenticato di leggere con la digitalRead() il valore rilevato su quel pin :
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
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è
#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
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:
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.
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.
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
}
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!!
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.