Display 7 segmenti via BCD

No, intendevo che non capisco quando si comincia a contare millis e come mai elapsed varia fino ad andare sopra a 750 mS e 250 mS (uso i miei valori ma anche 500 mS vanno bene). Insomma non riesco a immaginarmi questa variabile cambiare e soprattutto come. Purtroppo anche la tua immagine non mi è d'aiuto.

Seguendo il codice di prima:

previousMillis = millis() inizia a contare dall'accensione del processore

funzione(){ elapsed = millis() - previousMillis inizia a contare da quando parte la funzione e contemporaneamente sottrae al conteggio previousMillis

tipo previousMillis è a 1000 mS, la funzione parte e elapsed sarà mettiamo caso 1000 mS - 2000 mS, perché la funzoine è partita quando previousMillis era a 1000 mS, ma dopo 1000 mS contati dentro elapsed, previousMillis sarà a 2000 mS (1000 mS iniziali più altri 1000 mS). In questo modo elapsed sarà una costante perché previousMillis e elapsed avanzeranno con lo stesso passo e la differenza sarà sempre la medesima.

Io ho capito questo usando queste funzioni, per questo non mi è chiaro.

Forse ho capito il tuo dubbio, ricapitomboliamo....

  • C'è un contatore interno che aumenta da solo.
  • La funzione millis non inizia niente, legge e restituisce il valore del contatore nel momento in cui è eseguita.
  • Il valore prevoiusMillis non aumenta da solo, resta fisso fino a modifica manuale.
  • La differenza millis() - previousMillis aumenta sempre (è il valore chiamato elapsed).

Nel grafico abbiamo in rosso il valore ritornato da millis istante per istante, in azzurro il valore previousMillis (o control che dir si voglia) che viene aggiornato manualmente ("inseguendo" millis()) quando la differenza (elapsed) in verde raggiunge la soglia prefissata.

Quindi praticamente io scrivo una sola volta i millisecondi trascorsi dall’accensione del micro nella variabile previousMillis, dopodiché con elapsed conto i millisecondi togliendo quello che ho scritto in previousMillis e quando questo numero è maggiore del valore, faccio quello che devo fare.

previousMillis legge una volta il valore di millis() che può essere per esempio 10

elapsed = dall’inizio della condizione della funzione inizia a contare - 10

quando elapsed è >= di 750, fai l’istruzione e aggiungi a previousMillis 750

Domanda: ma siccome cambio stato e utilizzo “case”, per cui il contatore serve solo per cambiare stato dopo un certo tot di tempo, non mi conviene fare una variabile elapsed = millis() all’interno dell’IF così mi conta i millisecondi dall’inizio della condizione.

Non capisco perché sia così difficile...

#define LED 13

const int TEMPO=500; // in mS, fino a 32 secondi (unsigned int fino a 65, se vuoi...)
unsigned long t1=0;

setup()
{
pinMode(LED,OUTPUT);
}

loop()
{
if(millis()-t1>TEMPO) {t1=millis(); digitalWrite(LED,!digitalRead(LED));}
}

Ogni volta che fra t1 e millis() trascorre TEMPO, pone t1=millis() (quindi azzera la differenza) e inverte lo stato dell'uscita.

Si ok, in questo caso t1 è "fermo" per cui con millis() conta i millisecondi da un punto fermo.

Mentre quello che dicevo io prima era che la variabile previousMillis era uguale a millis() al di fuori della funzione e pensavo non stesse "fermo" ma variasse in continuazione.

Datman: if(millis()-t1 > TEMPO) {t1=millis(); digitalWrite(LED,!digitalRead(LED));}

In questo modo comunque trascorso TEMPO+δ, dove δ è un ritardo casuale incontrollabile di pochi (o molti) ms rispetto al momento ideale esatto dello scadere di TEMPO, si riparte dal valore attuale di millis() contando un altro TEMPO+δ.

Se non si vuole continuare ad accumulare l'errore δ ad ogni scadere di TEMPO basta aggiornare t1 dell'esatto valore TEMPO, così la differenza millis()-t1 parte già da un certo valore corrispondente all'ultimo ritardo casuale δ:

if(millis()-t1 >= TEMPO) {t1+=TEMPO; digitalWrite(LED,!digitalRead(LED));}

Qui rappresentato graficamente con due ritardi esagerati segnati in giallo:

Se invece non interessa l'esatta periodicità dei tempi, allora questa finezza si può ignorare.

Sì, hai ragione. Non mi sono mai posto il problema, perché non ho mai avuto la necessità di una precisione molto elevata. Certo, se il loop gira a molto meno di 1kHz, quando si accorge che TEMPO è trascorso, ormai potrebbe essere trascorso TEMPO+x.

Grazie per avermelo fatto notare.

Credo di aver finalmente capito. La variabile previousMillis salva una sola volta il valore di millis(), che viene comparato in elapsed. Elapsed contiene millis() per cui ogni loop della funzione aumenta il suo valore fino a che non è maggiore del mio intervallo scelto. A quel punto previousMillis aggiunge il valore dell'intervallo... ma per quale motivo? Perché invece non ho un'unica variabile di tempo che se è maggiore dell'intervallo scelto allora fa quello che deve fare e poi si azzera?

Perdonate la stupidità delle domande, ma non riesco a capire bene la situazione, anche con le immagini, malgrado i vostri sforzi, scusatemi.

Questo codice è molto simile a quello scritto da Datman solo che utilizza una variabile per ricordare lo stato del led. Questa variabile credo si chiami "flag".

#define ledPin 13
byte ledState = 0;
unsigned long previousMillis = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void blinkLed() {
  if (millis() - previousMillis > interval) {
    previousMillis = interval;
    ledState ^= 1;
    digitalWrite(ledPin, ledState);
  }
}

void loop() {
  blinkLed();
}

>ricki158: Devi a studiarti bene come si usa la millis(), prima QUI, poi QUI ed infine leggi anche QUI e QUI … vedrai che ti sarà tutto più chiaro :wink:

Guglielmo

I primi due link li ho appena letti ed hanno partorito quel codice, ora leggo gli altri due. Grazie mille!

Infatti elapsed non serve: basta mettere il calcolo all'interno dell'if().

Io dicevo una cosa del tipo

if(millis()>=intervallo){ fai qualcosa }

ricki158: Io dicevo una cosa del tipo...

La sintassi è valida e può servire a controllare che il valore di millis() abbia superato un certo valore ... ovvero che, [u]dal momento del reset di Arduino[/u] (momento in cui millis() viene azzerato) al momento in cui fai quella IF in quel modo, è passato almeno un tempo pari a "intervallo" ... ... ma è cosa [u]ben diversa[/u] dal voler sapere un intervallo tra un certo momento ed un altro !!!

Guglielmo

Non puoi azzerare millis() impunemente... :) quindi devi usare un'altra variabile.

Quello che non capisco è come mai se faccio un:

#define intervallo 500
unsigned long precedente = 0;

void blink(){
  if(millis() - precedente >= intervallo) {
    precedente=intervallo
    funzione
  }
}

La variabile "precedente" si blocca mentre "millis - precedente" continua a contare. Cioè è così che funziona?

Cioè io mi immagino "precedente" uguale a 0, la funzione parte e finché millis() non arriva all' "intervallo", non succede niente. Quando arriva all' "intervallo" fa la funzione, tra le quali scrive in "precedente" l' "intervallo".

millis() è come se si azzerasse perché in quel momento è uguale a "intervallo", sarebbe come dire

 if(intervallo - 0 >= intervallo)

ma dopo a questa funzione sarà

intervallo - intervallo (cioè 0) >= intervallo

Quindi da 0 conta fino a "intervallo", a "precedente" si aggiunge ancora un intervallo e così via.

Quindi "precedente" deve essere uguale a 0 e non a millis()

ricki158 ... nel mio post #73 avevo scritto STUDIARE BENE ... e ... dalle domande che fai qua sopra mi sembra che tu non l'abbia fatto ! ::)

[u]Non basta leggere[/u] quei due articoli di Leonardo Miliani, occorre veramente [u]studiarli[/u] e digerirli ... altrimenti continuerai a non capire come funziona e a porre le domande che poni ...

Guglielmo

Da quello che ho capito, la funzione millis() restituisce il numero del millisecondo dall'accensione. Questo vuol dire che se ho una variabile che non fa un ciclo e non viene riscritta, essa rimarrà al valore di partenza, cioè 0. Io con il mio codice faccio la differenza fra il valore millis() iniziale e il susseguirsi di millis() siccome è dentro un ciclo. Ciclando quindi millis() restituisce un valore differente che si incrementa fino ad arrivare all'intervallo che ho scelto. Quando arrivo all'intervallo "azzero la differenza" fra millis() attuale e la variabile che contiene il millis() precedente perché riscrivo questa variabile con il numero esatto di passi di differenza. Il problema è quando millis() andrà in overflow... devo continuare a leggere per capire che strategia posso usare.

Sono sulla buona strada?

precedente=intervallo

No! precedente=millis(); (e col punto e virgola!)

Perché precedente = intervallo è sbagliato, dovevo scrivere invece precedente += intervallo, oppure precedente = millis() ma prima si diceva che è meglio aggiungere il valore di intervallo per essere sicuri di avere sempre quel valore, sennò con millis() conta anche i millisecondi che ci mette per fare la funzione.

if(millis()-t1>TEMPO) {t1+=TEMPO; digitalWrite(LED,!digitalRead(LED));}

(messaggio #70) Facendo if(millis()-t1>TEMPO) non ci sono problemi di overflow, come hai letto dove ti è stato indicato prima.