Go Down

Topic: Azzerare la funzione millis() (Read 12378 times) previous topic - next topic

leandro78

Dec 04, 2012, 10:41 am Last Edit: Dec 04, 2012, 11:06 am by leandro78 Reason: 1
Salve, sapreste per caso come si fa a far ripartire da zero la funzione millis()??

Mi occorre far variare il valore di una variabile ad intervalli regolari di tempo, facendo partire il conteggio quando lo decido io e riazzerandolo poi in qualche modo. Come potrei fare??

Vi ringrazio come sempre per la collaborazione.

leo72

Devi inserire nella dichiarazione delle variabili globali la seguente riga:
Code: [Select]

extern unsigned long timer0_millis;


A questo punto quando devi azzerare il contatore, chiami questa funzione:
Code: [Select]

void resetMillis() {
  cli();
  timer0_millis = 0;
  sei();
}


Molti suggeriscono di fare un semplice timer0_millis=0 ma quando si ha a che fare con variabili manipolate all'intero di interrupt è bene sempre prima fermare gli interrupt stessi e riattivarli dopo che si è fatto ciò che si doveva fare.

qsecofr


Devi inserire nella dichiarazione delle variabili globali la seguente riga:
Code: [Select]

extern unsigned long timer0_millis;


A questo punto quando devi azzerare il contatore, chiami questa funzione:
Code: [Select]

void resetMillis() {
  cli();
  timer0_millis = 0;
  sei();
}


Molti suggeriscono di fare un semplice timer0_millis=0 ma quando si ha a che fare con variabili manipolate all'intero di interrupt è bene sempre prima fermare gli interrupt stessi e riattivarli dopo che si è fatto ciò che si doveva fare.


per i micros basta sostituire millis a micros???

leo72

Con i microsecondi non è così lineare.
Il core di Arduino usa un meccanismo un po' complicato per conteggiare lo scorrere del tempo, che si basa sugli overflow di un timer. Siccome tale timer è usato anche per generare dei segnali in PWM, la frequenza di questo segnale, 976 Hz, è la stessa usata anche per aggiornare il contatore. Per far sì che ogni secondo si abbiano 1000 millisecondi, viene usato un contatore di overflow per far sì che ogni 1024 overflow vengano conteggiati appunto 1000 millisecondi.
I microsecondi sono invece restituiti usando una formuletta che si basa sulla conversione del numero di overflow fratto il tempo di esecuzione del codice. Non c'è un vero contatore di microsecondi, però c'è un registro che tiene appunto il numero di overflow.
Code: [Select]
timer0_overflow_count
Prova sostituendo questo nella funzione che ho scritto, tenendo però conto del fatto che così cambi ANCHE il valore di millisecondi.

marcello.romani

Quote
Mi occorre far variare il valore di una variabile ad intervalli regolari di tempo, facendo partire il conteggio quando lo decido io e riazzerandolo poi in qualche modo.


Usa la tecnica del blink without delay, aggiungi una variabile di stato come bool isCounting ed esegui il conteggio (immagino tu intenda incremento) solo quanto è true, modifica questa variabile in base all'evento esterno che desideri (la pressione di un pulsante, ad esempio) per mettere in pausa o riavviare il conteggio e azzera il counter quando lo ritieni necessario.

Lascia stare gli "internals" ;)

Se descrivi meglio cosa stai cercando di ottenere, l'hardware e il codice che hai finora risulta più facile dare una mano.

leandro78

#5
Dec 04, 2012, 12:00 pm Last Edit: Dec 04, 2012, 12:11 pm by leandro78 Reason: 1
Salve ragazzi, grazie mille per l'aiuto!!

Quello che devo fare è fare aumentare il tempo di ritardo tra un passo e l'altro di un motorino passo passo a intervalli regolari di tempo in modo da farlo decelerare.
In pratica ogni tot millisecondi, voglio incrementare di una certa quantità regolabile tramite un potenziometro il tempo di ritardo.

Vi riporto la funzione sali che ho creato:

#
void sali() {  
 stop = 0;
 //int j = i;
 resetMillis();
 upDelayTime += decelFactor*(millis()/100);
 
 while(i>0){
   
   digitalWrite(motorPin1, HIGH);  
   digitalWrite(motorPin2, LOW);
   digitalWrite(motorPin3, HIGH);  
   digitalWrite(motorPin4, LOW);  
   delay( upDelayTime /*+ decelFactor * (j-i)*/ );
   i--;
   digitalWrite(motorPin1, HIGH);  
   digitalWrite(motorPin2, LOW);
   digitalWrite(motorPin3, LOW);  
   digitalWrite(motorPin4, HIGH);  
   delay( upDelayTime /*+ decelFactor * (j-i)*/ );  
   i--;
   digitalWrite(motorPin1, LOW);  
   digitalWrite(motorPin2, HIGH);
   digitalWrite(motorPin3, LOW);  
   digitalWrite(motorPin4, HIGH);  
   delay( upDelayTime /*+ decelFactor * (j-i)*/ );  
   i--;
   digitalWrite(motorPin1, LOW);  
   digitalWrite(motorPin2, HIGH);
   digitalWrite(motorPin3, HIGH);  
   digitalWrite(motorPin4, LOW);  
   delay( upDelayTime /*+ decelFactor * (j-i)*/ );  
   i--;
 }
#

La mia idea per sempio era quella di far variare ogni 100 ms il tempo di ritardo upDelayTime di un valore pari a decelFactor. Ma la cosa così non funziona perchè appena entra nel ciclo while il valore di upDelayTime non viene più agiornato!!
Come potrei fare??


marcello.romani


marcello.romani

Ripeto: utilizza la tecnica del blink without delay. Poi calcoli la durata del "ritardo" in base al valore del potenziometro.

Mi chiedo però se per controllare un motorino PP non sia più idoneo affidarsi ad un interrupt per la cadenza degli eventi... A quel punto invece di contare i ms potresti usare un contatore che si incrementa ad ogni eseguzione della ISR: quando supera un certo valore (impostato in base al potenziometro di regolazione), lo azzeri ed "emetti" la successiva configurazione dei pin di controllo dle motore.

PaoloP

Inoltre dovresti usare la manipolazione delle porte per comandare il motore e non il digitalwrite che ci mette un'eternità ed inficia il controllo. Soprattutto se vuoi controllare l'accelerazione e la decelerazione.

marcello.romani

Già... in base al codce che hai postato, mi pare che tu controlli direttamente gli avvolgimenti del motore, quindi il sincronismo tra le forme d'onda è fondamentale. Non sono un esperto in materia, ma ho partecipato tempo alla costruzione di una scheda di controllo per il motorino pp di una stampante (usavamo un PIC)... decisamente non una passeggiata ;)

leandro78

#10
Dec 04, 2012, 12:14 pm Last Edit: Dec 04, 2012, 12:17 pm by leandro78 Reason: 1
Come si aggiungono le tags?

Non conosco quest tecnica del blink without delay...in cosa consisterebbe? e neppure la tecnica di manipolazione delle porte...scusatemi ma non ho grande esperienza con la programmazione...e purtroppo ho tempi molto stretti perchè è un lavoro che mi serve per la mia tesi di laurea... :~

marcello.romani

E' il pulsante # nella toolbar dell'editor.

Se controllare il motore PP non è l'elemento centrale della tesi, allora ti conviene comprare una scheda di controllo già pronta. Personalmente ho acquistato il motor shield di adafruit, molto versatile e dotato già di una libreria di facile utilizzo (no, non mi pagano per fare pubblicità :) )
Ma di schede in giro ce ne sono a bizzeffe. Il fatto che siano o meno shield per Arduino è solo una questione di comodità per certi usi. Ho visto ad esempio schedine che si controllano con un impulso di clock e uno di direzione (e forse uno di stop motore)...

leandro78

Ho provato ad aggiungerle nel mio post ma non cambia nulla...dove devo posizionarle?

In effetti il pilotaggio del motore è ormai un elemento della tesi, per cui devo riuscire a farlo con quello che ho a disposizione...comunque non mi ineteressa fare codice ultraraffinato, perchè in realtà l'apparecchi che sto creando è un mezzo e non un fine...

Volevo chiedervi secondo voi all'interno del seguente ciclo While, il valore della variabile upDelayTime, viene incrementato solo all'inizio di ogni nuovo blocco delle 4 istruzioni che contiene o  viene incrementata blocco dopo blocco?? In altre parole, viene incrementata solo ogni 4 passi o dopo ogni passo del motorino?? E di quanto? quello che credo io è che venga incrementata di un valore pari a decelfactor, è corretto secondo voi??

Scusate per le infinite domande...

#
Quote

void sali() {   
  stop = 0;
  //int j = i;
  resetMillis();
  
  
  while(i>0){
    upDelayTime += decelFactor*(millis()/100);
    digitalWrite(motorPin1, HIGH); 
    digitalWrite(motorPin2, LOW);
    digitalWrite(motorPin3, HIGH); 
    digitalWrite(motorPin4, LOW); 
    delay( upDelayTime /*+ decelFactor * (j-i)*/ );
    i--;
    digitalWrite(motorPin1, HIGH); 
    digitalWrite(motorPin2, LOW);
    digitalWrite(motorPin3, LOW); 
    digitalWrite(motorPin4, HIGH); 
    delay( upDelayTime /*+ decelFactor * (j-i)*/ ); 
    i--;
    digitalWrite(motorPin1, LOW); 
    digitalWrite(motorPin2, HIGH);
    digitalWrite(motorPin3, LOW); 
    digitalWrite(motorPin4, HIGH); 
    delay( upDelayTime /*+ decelFactor * (j-i)*/ ); 
    i--;
    digitalWrite(motorPin1, LOW); 
    digitalWrite(motorPin2, HIGH);
    digitalWrite(motorPin3, HIGH); 
    digitalWrite(motorPin4, LOW); 
    delay( upDelayTime /*+ decelFactor * (j-i)*/ ); 
    i--; 
  }


#

lestofante

Quote
Non conosco quest tecnica del blink without delay


è un'esempio contenuto nell'IDE arduino, e permettimi di dare ragione a "Lascia stare gli "internals""

Quote
quindi il sincronismo tra le forme d'onda è fondamentale

quanto fondamentale? quanto può essere l'errore massimo? arduino ha una precisione di minimo 4 us
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

leandro78

ma cosa sarebbero questi internals?!? Io ho seguito il suggerimento datomi da leo per resettare il timer e la cosa sembra fnzionare bene...

Go Up