arduino - millis ()


10

Copiato dal riferimento Arduino - millis ()

Suggerimento : si noti che il parametro per millis è un lungo senza segno, è possibile che vengano generati errori se un programmatore tenta di eseguire calcoli con altri tipi di dati come ints.

Che tipo di matematica? Che tipo di altro tipo di elaborazione è escluso quando si lavora con millis?

Qualcuno potrebbe chiarire questa affermazione e / o fare qualche esempio?

Risposte:


8

Ogni volta che si scrive un'equazione in C / C ++, i tipi di dati su cui si opera hanno un effetto molto reale sull'output dell'equazione.

Ogni tipo piace int, floate unsigned longha comportamenti diversi e occupa un certo spazio in memoria per l'archiviazione.

int (su arduino) è memorizzato in 16 bit, con metà dei suoi valori dati a numeri negativi, metà 1 data a valori positivi e un valore dato a 0. Questo gli dà un intervallo di -2 ^ 15 (-32.768) a + 2 ^ 15-1 (32.767).

unsigned long(su arduino) è 32 bit, ma nessuno è designato come negativo. il suo intervallo è quindi da 0 a 2 ^ 32-1 (4294967295).

Che tipo di matematica? Che tipo di altro tipo di elaborazione è escluso quando si lavora con millis?

Il punto cruciale del problema è che il tempo in cui i millesimi di ritorno sono mai passati oltre 32767 e hai provato a memorizzarlo in un int, l'arduino non è riuscito a farlo, perché intnon può contenere un numero così grande. Il tipo di matematica che è off limits è la matematica che sta accadendo a tipi di dati più piccoli, non a operazioni specifiche. Forse questi esempi aiuteranno:

  int i = 32767;
  Serial.println(i);
  //No problems here; it fits just fine

32767

  i = 32767 + 1;
  Serial.println(i);
  //Oh no, the value didn't fit

-32768

  unsigned long fake_millis = 42000;
  i = fake_millis;
  Serial.println(i);
  //This is an example of millis going past an int

-23.536

  i = -10;
  unsigned int j = i;
  Serial.println(j);
  //no way to put a negative number in an unsigned value

65526

  uint32_t k = fake_millis;
  Serial.println(k);
  //unsigned long is a uint32_t on arduino; this works great!

42000

Il modo in cui questo è implementato è davvero abbastanza geniale; Se sei interessato a da dove provengono questi numeri e perché si riversano nel loro modo, dovresti esaminare le stesse spiegazioni delle rappresentazioni dei numeri del complemento a due.


Solo una semplice domanda: dichiarare "unsigned long fake_millis;" è uguale a "uint_32 fake_millis;" ?
user3060854

Sì, quelli sono uguali su Arduino. La differenza è che unsigned longpuò cambiare con piattaforme diverse (ad es. X86), uint32_tsaranno sempre 32 bit senza segno ovunque.
BrettAM

1
Va notato che il tuo secondo esempio ( 32767 + 1) produce un comportamento indefinito, che è quasi sempre una cosa negativa . Altri esempi sono comportamenti documentati su cui puoi fare affidamento.
Edgar Bonet,

6

millis()restituisce a unsigned long, che è un numero intero senza segno a 32 bit su Arduino. Quando poi provi a fare qualcosa del genere unsigned int time = millis() - 1000, provi a memorizzarlo in un numero intero senza segno a 16 bitunsigned int . Un numero intero a 16 bit non può mai contenere un valore a 32 bit.

Secondo la specifica C , paragrafo 6.3.1.3, i 16 bit superiori vengono scartati.

Se possibile, mantieni l' millis()output in a unsigned longe usa i tipi di dati con meno bit solo quando sei assolutamente sicuro di non perdere bit.

Ulteriori informazioni sui cast espliciti in C qui: https://stackoverflow.com/a/13652624/1544337


Grazie per la modifica. Ho rimosso il riferimento a uint32_t poiché è qualcosa di diverso. uint32_t garantisce di disporre di un numero intero senza segno a 32 bit, mentre non è lungo senza segno (anche se su Arduino lo è). Ho anche già detto che è un tipo a 32 bit.

Quindi non diresti che è più corretto dire che restituisce un uint32_tche sembra essere un unsigned longsu Arduino?
BrettAM

@BrettAM secondo i documenti questa funzione restituisce un unsigned long.

Rimossi vecchi commenti, poiché l'intera discussione ha poco senso con la versione attuale della risposta. Proprio tenendo questo per la cronaca: se la conversione è di una firma intero ( int time = millis() - 1000), il risultato è simile: i 16 bit superiori sono scartati. Questa volta lo standard C afferma che il risultato è definito dall'implementazione e il comportamento è specificato nella documentazione di gcc sul comportamento degli interi definito dall'implementazione (quarto punto elenco).
Edgar Bonet,

2

Quando vuoi fare cose con millis () ricorda di inizializzare la tua variabile con il tipo "uint32_t"

Quindi fai qualcosa come "uint32_t last_millis" in cui memorizzerai l'output della funzione "millis ()".

Altrimenti, come hanno detto gli altri, traboccherebbe oltre 31.000, cosa che accadrà abbastanza rapidamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.