Azzerare la funzione millis()

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.

Devi inserire nella dichiarazione delle variabili globali la seguente riga:

extern unsigned long timer0_millis;

A questo punto quando devi azzerare il contatore, chiami questa funzione:

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.

leo72:
Devi inserire nella dichiarazione delle variabili globali la seguente riga:

extern unsigned long timer0_millis;

A questo punto quando devi azzerare il contatore, chiami questa funzione:

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???

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.

timer0_overflow_count

Prova sostituendo questo nella funzione che ho scritto, tenendo però conto del fatto che così cambi ANCHE il valore di millisecondi.

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" :wink:

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

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??

Usa i code tags #

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.

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.

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 :wink:

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... :~

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à :slight_smile: )
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)...

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...

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

Non conosco quest tecnica del blink without delay

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

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

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

Intendiamoci: se riesci a far funzionare ciò che hai già, tutti contenti. Non era mia intenzione dare giudizi :smiley:

Dico solo che per mia esperienza il pilotaggio dei PP, anche se semplice in linea di principio, nella pratica è talmente pieno di criticità e trabocchetti da giustificare ampiamente (a meno che non sia lo scopo principale del progetto, ovvio) l'acquisto di una soluzione "chiavi in mano". Quanto "chiavi in mano" dipende da caso a caso e dalle preferenze / capacità del singolo.

"internals" sta per "gli oscuri meccanismi interni"... :smiley:

leandro78:
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??

updelaytime viene calcolato solo ad ogni inizio di ciclo while quindi hai 4 delay tutti uguali ogni ciclo.
Non so se il mio intervento può essere utile ma devi prestare un attimo attenzione alla "granularità" del millis e alla moltiplicazione con il tuo decelFactor... l'arrotondamento degli interi... presta attenzione...
dopo un'altra annotazione: se per esempio decel factor = 1 questo implica che tra millis =1 e millis = 2 hai un dimezzamento netto della velocità....mentre tra millis = 9 e millis = 10 avresti un calo del 10% della velocità... non so se è quello che vuoi...

un'altra cosa: ti hanno già parlato della lentezza del writedigital... io ti parlo della "asincronia" dei quattro movimenti che fai sugli avvolgimenti... a piccole velocità probabilmente non te ne renderai conto ma sarebbe bene che i 4 valori di uscita fossero settati contemporaneamente perchè se no rischi di dare corrente seppur per qualche microsecondo all'avvolgimento sbagliato... dovresti vedere l'uso delle porte.

Ciao qsecofr, grazie mille per la risposta, era proprio come pensavo io...

Quanto al problema relativo al dimezzamento della velocità, questo in realtà non si pone, perchè il nuovo valore viene sommato al precedente, cioè il motorino non è fermo iniziamlemte ma parte già con una certa velocità che viene progressivamente ridotta.

Scusate questa istruzione dovrebbe incrementare il valore della variabile upDelayTime di un valore pari a decelFactor ogni 100 millisecondi, è corretto?

upDelayTime += decelFactor*(millis()/100);

Grazie ancora infinitamente a tutti gli intervenuti....

Se ricordo bene il mio codice era più o meno così:

const N = 4
byte portValue[N] = { ... }

loop():
PORTB = portValue[passo]
delay(d)
passo++
if passo >= N
passo = 0
endif

PORTB va ovviamente sostituita in base agli specifici collegamenti.
I valori da assegnare a portValue vanno calcolati in base alle configurazioni degli avvolgimenti.
Inoltre se PORTB è usata anche per altri scopi le cose si complicano.

internals non vuol dire niente, è inteso per indicare questi comportamenti a basso livello.

Arduino a causa delle risorse limitate ha molti "accrocchi" per far funzionare le cose (vedi micros() spiegata da leo poco sopra), quindi se cambi qualcosa di basso livello normalmente "rompi" alcune funzioni di arduino o delle sue librerie, quindi se non sai cosa stai toccando è molto probabile che gli effetti collaterali di una modifica a basso livello vadano a rompere un'altra parte del tuo codice.