Due contatori in contempornea

Ciao a tutti,

premesso che le mie esperienze con Arduino sono pari a ZeRo e si perdono nel tempo, mi è venuta questa idea.........

volendo controllare il numero dei passi di un motore passo passo, vorrei capire la fattibilità di un progettino che ho pensato di realizzare con due contatori.............

Mi spiego meglio, al primo contatore arriveranno gli impulsi di pilotaggio del driver del motore e al secondo arriveranno gli impulsi generati da un encoder fissato sull'asse del motore stesso.

Il numero di passi giro sarà diverso ovvero ad un impulso per il motore non corrisponderà un impulso generato dall'encoder.

I due contatori devono poter leggere sempre i segnali che gli arrivano!!!

La frequenza massima dei segnali non dovrebbe essere superiore a qualche kHz (10kHz max)

Se tutto funziona bene il rapporto passi motore / passi encoder rimane costante.
Se vengono persi dei passi, per i motivi più diparati il rapporto varia e deve essere attivata una segnalazione ottico acustica.

Un po di informazioni dovrebbero essere visualizzate da un display di almeno a 4 righe.

Ho girovagato in rete in cerca di consigli e di qualche spezzone di SW che mi permttesse di capire qualcosina, purtroppo, senza grandi risultati.

Credo che Arduino UNO non sia in grado di gestire la cosa.

Mi saranno molto utili tutti i consigli che avrete la gentilezza di fornirmi.

Grazie

Andrea

Ciao,
solitamente tutti gli Arduino hanno almeno 2 interrupt esterni che pui utilmente sfruttare per rilevare gli impulsi che vuoi contare.

Nel tuo caso avrai due funzioni che incrementeranno due contatori (due variabili globali) al verificarsi degli interrupt.

Nella funzione loop potrai fare dei calcoli sui contatori per ricavare le informazioni che cerchi. Dovrai probailmente considerare il fatto che gli interrupt sono asincroni rispetto al loop, quindi non è garantito che i conteggi vengano fatti in sequenza e i tuoi calcoli eseguiti dopo i conteggi.

Qui: Arduino Playground - Interrupts trovi alcune informazini di base sugli interrupts

Ricorda di dichiarare "volatile" le variabili che userai come contatore nelle ISR e che a seconda del tipo di variabile usata a un certo punto ripartirà da zero (overflow).

Un esempio di codice di riferimento potrebbe essere questo:

volatile unsigned long counter1 = 0;
volatile unsigned long counter2 = 0;

void setup()
{
  attachInterrupt(0, count1, CHANGE);
  attachInterrupt(1, count2, CHANGE);
}

void loop()
{
   // fai calcoli sui counters
}

void count1()
{
  counter1++;
  // Gestire overflow counter
}

void count2()
{
  counter2++;
  // Gestire overflow counter
}

Una cosa da verificare è che sfalsamento temporale c'è tra i due segnali. Perchè se non ricordo male nel caso in cui il secondo arrivi mentre la ISR avviata dal primo non è terminata (o viceversa), l'interrupt viene ignorato.

I due interrupt devono essere distanti almeno il tempo necessari per eseguire le funzioni count1 e count2 altrimenti questa soluzione non funzionerebbe.

Ciao
Silvio

Ciao Silvio,

grazie del tuo consiglio.

Purtroppo gli impulsi possono arrivare anche in contemporanea e comunque non ne devo perdere!

Ho letto in giro per la rete che alcuni 'PIC' 0 similari, hanno alcuni piedini che possono essere programmati per come timer con il clock esterno, diventano in pratica dei contatori indipendenti che non hanno bisogno di interrupt per lavorare.

Leggendo il manuale dell'ATmega2560 ho visto che ha 5 piedini che possono essere programmati come timer/temporizzatori però mi sembra che detti piedini non siano portati in morsettiera.

A questo proposito ho chiesto lumi in merito sia qui che nella sezione hardware ma l'unico consiglio è stato il tuo di cui ti ringrazio ancora.

Resto in attesa fiducioso di ulteriori consigli......

Andrea

Ciao a tutti,

le mie ricerche in rete continuano.................................

Ho trovato il link che copio

http://blog.oscarliang.net/arduino-timer-and-interrupt-tutorial/

con il traduttore automatico ho, grosso modo, capito la descrizione dell'argomento e mi sembra che sia fattibile la realizzazione del mio progetto.

Per la realizzazione del mio progetto mi servirebbero 2 contatori abbastanza veloci a 16 bit (i segnali in ingresso potrebbe avere una frequenza massima di 5-6 kHz) con i quali contare degli impulsi provenienti da due ancoder, purtroppo diversi fra loro per numero di impulsi giro, ogni 50-100 ms, effettuare un conteggio (verifica del raporto fra i due valori) ed in caso si verificasse un errore superiore ad un dato impostato attivare un allarme.
Premetto che non vorrei usare interrupt perchè i conteggi potrebbero perdere dei passi.

La mia spiegazione è un po riduttiva però il grosso del lavoro che vorrei eseguire è quello indicato.

Visto che mi sembra di aver capito che con Arduino Mega2560 la cosa si possa realizzare, mi sarebbe molto utile qualche dritta di chi ha già fatto qualcosa i simile al mio progetto al fine di partire con il piede giusto.

Grazie

Andrea

Usa gli interrupt ma non disabilitarli al loro interno, in questo modo non ne perdi nessuno.

Ciao Vbextreme,

grazie per il consiglio, hai per le mani qualche pezzo di SW di esempio oppure mi sai indicare dei link dove trovare qualcosa già impostato, purtroppo sono mooooolto alle prime armi :o :o :o

grazie

Andrea

Campa1957:
Premetto che non vorrei usare interrupt perchè i conteggi potrebbero perdere dei passi.

Uh? Scusa, ma usare gli interrupt serve proprio a evitare di perdere eventi e quindi conteggi...
Io ho agganciato due encoder ai pin 2 e 3 del mio UNO, e nelle routine faccio solo incremento di un contatore, poi nel loop() mi verifico i valori dei contatori e faccio quello che devo fare. Tipo questo:

volatile StepsL = 0;
volatile StepsR = 0; 

void setup() {  
  Serial.begin(9600);
  Serial.println("SETUP");

  // Gestione interrupt della libreria
  attachInterrupt(0, motorStepL, FALLING);
  attachInterrupt(1, motorStepR, FALLING); 
  //...
}

void motorStepL() {
  ++StepsL;
}
void motorStepR() {  
  ++StepsR;
} 

void loop() {
  //..
  if (StepsL>100) {
    //..fai qualcosa
  }

  if (StepsR>100) {
    //..fai qualcosa
  }

Ciao DocDoc,

grazie del tuo suggerimento, ma se i due impulsi arrivano simultaneamente il tu SW come si comporta?

Mi è stato suggerito, di evitare gli interrupt per questo motivo, i miei impulsi porebbero arrivare ad una frequenza di circa 4 - 5 kHz.

Andrea

Campa1957:
grazie del tuo suggerimento, ma se i due impulsi arrivano simultaneamente il tu SW come si comporta?

Definire "simultaneamente".... :smiley: Neanche in fisica si può affermare (Einstein insegna) che due eventi siano realmente simultanei...
Scherzi a parte (anche se non sono affermazioni false), Arduino non è multithread quindi sarà in esecuzione una sola routine di gestione, la seconda scatterà al termine della prima, ed è per questo che il codice delle ISR deve esere più corto possibile

Campa1957:
Mi è stato suggerito, di evitare gli interrupt per questo motivo, i miei impulsi porebbero arrivare ad una frequenza di circa 4 - 5 kHz.

Ma no, Arduino lavora a 16MHz, ti pare che potrebbe impiegare talmente tanto tempo a incrementare una semplice variabile (è questo che faccio nelle routine in genere) da perdersi qualche evento di interrupt con frequenza pari si e no a un millesimo di quella di lavoro? :wink: Ovviamente non solo devono essere più brevi possibile, ma non devono esserci delay(), possibilmente neanche dentro al loop(), e il loop() stesso comunque deve poter lavorare in modo "snello".
Fai tu, ma per me senza interrupt la vedo difficile.