Arduino - Millis ()

8

Von der Arduino-Referenz kopiert - millis ()

Tipp : Beachten Sie, dass der Parameter für Millis eine lange Länge ohne Vorzeichen ist. Wenn ein Programmierer versucht, mit anderen Datentypen wie Ints zu rechnen, können Fehler generiert werden.

Was für eine Art von Mathe? Welche andere Art der Verarbeitung ist bei der Arbeit mit Millis ausgeschlossen?

Könnte jemand diese Aussage klarstellen und / oder ein Beispiel geben?

user3060854
quelle

Antworten:

8

Wenn Sie eine Gleichung in C / C ++ schreiben, wirken sich die zu bearbeitenden Datentypen sehr real auf die Ausgabe der Gleichung aus.

Jeder Typ mag int, floatund unsigned longhat unterschiedliche Verhaltensweisen und benötigt eine bestimmte Menge an Speicherplatz zum Speichern.

int (auf Arduino) wird in 16 Bit gespeichert, wobei die Hälfte seiner Werte für negative Zahlen, die Hälfte für positive Werte und ein Wert für 0 angegeben wird. Dies ergibt einen Bereich von -2 ^ 15 (-32.768) bis + 2 ^ 15-1 (32.767).

unsigned long(auf Arduino) ist 32 Bit, aber keines wird als negativ bezeichnet. sein Bereich ist dann 0 bis 2 ^ 32-1 (4294967295).

Was für eine Art von Mathe? Welche andere Art der Verarbeitung ist bei der Arbeit mit Millis ausgeschlossen?

Der Kern des Problems ist, dass die Zeit, in der Millis zurückkehrt, immer über 32767 hinausgeht und Sie versucht haben, es in einem Int zu speichern. Das Arduino konnte es nicht, weil es eine intso große Zahl nicht halten kann. Die Art der Mathematik, für die dies verboten ist, ist die Mathematik, die mit kleineren Datentypen geschieht, nicht mit bestimmten Operationen. Vielleicht helfen diese Beispiele:

  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

-23536

  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

Die Art und Weise, wie dies implementiert wird, ist wirklich ziemlich genial; Wenn Sie daran interessiert sind, woher diese Zahlen kommen und warum sie so übergreifen, wie sie es tun, sollten Sie sich die gleichen Erklärungen der Zweierkomplement-Zahlendarstellungen ansehen.

BrettAM
quelle
Nur eine einfache Frage: Deklarieren von "unsigned long fake_millis"; entspricht "uint_32 fake_millis;" ?
user3060854
Ja, diese sind auf dem Arduino gleich. Der Unterschied ist, unsigned longdass sich mit verschiedenen Plattformen (z. B. x86) ändern kann, uint32_timmer 32 vorzeichenlose Bits überall sein werden.
BrettAM
1
Es sollte beachtet werden, dass Ihr zweites Beispiel ( 32767 + 1) undefiniertes Verhalten liefert, was fast immer eine schlechte Sache ist . Ihre anderen Beispiele sind dokumentiertes Verhalten, auf das Sie sich verlassen können.
Edgar Bonet
6

millis()Gibt a zurück unsigned long, eine 32-Bit-Ganzzahl ohne Vorzeichen auf dem Arduino. Wenn Sie dann versuchen, so etwas zu tun unsigned int time = millis() - 1000, versuchen Sie, dies in einer 16-Bit-Ganzzahl ohne Vorzeichen zu speichern unsigned int. Eine 16-Bit-Ganzzahl kann niemals einen 32-Bit-Wert enthalten.

Gemäß der C-Spezifikation , Absatz 6.3.1.3, werden die oberen 16 Bits verworfen.

Behalten Sie die millis()Ausgabe nach Möglichkeit in a unsigned longund verwenden Sie Datentypen mit weniger Bits nur, wenn Sie absolut sicher sind, dass Sie keine Bits verlieren.

Weitere Informationen zu expliziten Casts in C finden Sie hier: https://stackoverflow.com/a/13652624/1544337

Gemeinschaft
quelle
Danke für die Bearbeitung. Ich habe den Verweis auf uint32_t entfernt, da es etwas anderes ist. uint32_t garantiert, dass Sie eine 32-Bit-Ganzzahl ohne Vorzeichen haben, Long ohne Vorzeichen nicht (obwohl dies auf Arduino der Fall ist). Ich habe auch bereits erwähnt, dass es sich um einen 32-Bit-Typ handelt.
Würden Sie dann nicht sagen, dass es korrekter ist zu sagen, dass es uint32_tein unsigned longOn-Arduino zurückgibt?
BrettAM
@BrettAM gemäß den Dokumenten gibt diese Funktion eine zurück unsigned long.
Alte Kommentare wurden entfernt, da die gesamte Diskussion mit der aktuellen Version der Antwort wenig Sinn macht. Behalten Sie dies nur für den Datensatz: Wenn die Konvertierung in eine vorzeichenbehaftete Ganzzahl ( int time = millis() - 1000) erfolgt, ist das Ergebnis ähnlich: Die oberen 16 Bits werden verworfen. Diesmal sagt der C-Standard, dass das Ergebnis implementierungsdefiniert ist und das Verhalten in der gcc-Dokumentation zum implementierungsdefinierten Verhalten von Ganzzahlen angegeben ist (vierter Aufzählungspunkt).
Edgar Bonet
2

Wenn Sie mit millis () arbeiten möchten, denken Sie daran, Ihre Variable mit dem Typ "uint32_t" zu initialisieren.

Machen Sie also so etwas wie "uint32_t last_millis", wo Sie die Ausgabe der Funktion "millis ()" speichern.

Andernfalls würde es, wie die anderen sagten, überlaufen, wenn es über 31.000 hinausgeht, was ziemlich schnell passieren wird.

nemik
quelle