arduino - millis ()

10

Copié à partir de la référence Arduino - millis ()

Astuce : Notez que le paramètre pour millis est un long non signé, des erreurs peuvent être générées si un programmeur essaie de faire des calculs avec d'autres types de données tels que les entiers.

Quel genre de mathématiques? Quel autre type de traitement est exclu lorsque vous travaillez avec des millis?

Quelqu'un pourrait-il clarifier cette déclaration et / ou donner un exemple?

user3060854
la source

Réponses:

8

Chaque fois que vous écrivez une équation en C / C ++, les types de données utilisés ont un effet très réel sur la sortie de l'équation.

Chaque type, comme int, floatet unsigned longont des comportements différents, et prennent une certaine quantité d'espace en mémoire pour stocker.

int (sur arduino) est stocké sur 16 bits, la moitié de ses valeurs étant données à des nombres négatifs, la moitié 1 à des valeurs positives et une valeur à 0. Cela lui donne une plage de -2 ^ 15 (-32 768) à + 2 ^ 15-1 (32 767).

unsigned long(sur arduino) est de 32 bits, mais aucun n'est désigné comme négatif. sa plage est alors de 0 à 2 ^ 32-1 (4294967295).

Quel genre de mathématiques? Quel autre type de traitement est exclu lorsque vous travaillez avec des millis?

Le nœud du problème est que le temps que les millis reviennent a dépassé 32767 et que vous avez essayé de le stocker dans un int, l'arduino n'a pas pu le faire, car un intne peut pas contenir un si grand nombre. Le type de calcul hors limites est le calcul mathématique qui s'applique aux types de données plus petits, et non à des opérations spécifiques. Peut-être que ces exemples aideront:

  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

La façon dont cela est mis en œuvre est vraiment très géniale; Si vous souhaitez savoir d'où viennent ces nombres et pourquoi ils se répercutent dans la façon dont ils le font, vous devriez examiner les mêmes explications des représentations des nombres du complément à deux.

BrettAM
la source
Juste une question simple: déclarer "long fake_millis non signé;" est égal à "uint_32 fake_millis;" ?
user3060854
Oui, ceux-ci sont égaux sur l'arduino. La différence est unsigned longpeut changer avec différentes plates-formes (par exemple x86), uint32_tsera toujours 32 bits non signés partout.
BrettAM
1
Il convient de noter que votre deuxième exemple ( 32767 + 1) donne un comportement non défini, ce qui est presque toujours une mauvaise chose . Vos autres exemples sont des comportements documentés sur lesquels vous pouvez compter.
Edgar Bonet du
6

millis()renvoie un unsigned long, qui est un entier non signé 32 bits sur l'Arduino. Lorsque vous essayez ensuite de faire quelque chose comme unsigned int time = millis() - 1000, vous essayez de stocker cela dans un entier non signé 16 bits unsigned int. Un entier 16 bits ne peut jamais contenir une valeur 32 bits.

Selon la spécification C , paragraphe 6.3.1.3, les 16 bits supérieurs sont rejetés.

Si possible, conservez la millis()sortie dans un unsigned longet utilisez uniquement les types de données avec moins de bits lorsque vous êtes absolument sûr de ne pas perdre de bits.

Il y a plus d'informations sur les conversions explicites en C ici: https://stackoverflow.com/a/13652624/1544337

Communauté
la source
Merci pour l'édition. J'ai supprimé la référence à uint32_t car c'est quelque chose de différent. uint32_t garantit que vous avez un entier non signé 32 bits, non signé long non (bien que sur Arduino c'est le cas). J'ai également déjà mentionné qu'il s'agit d'un type 32 bits.
Alors ne diriez-vous pas qu'il est plus correct de dire qu'il renvoie un uint32_tqui se trouve être un unsigned longarduino?
BrettAM
@BrettAM selon les documents, cette fonction renvoie un unsigned long.
Suppression des anciens commentaires, car toute la discussion n'a guère de sens avec la version actuelle de la réponse. Gardons ceci pour mémoire: si la conversion est en un entier signé ( int time = millis() - 1000), le résultat est similaire: les 16 bits supérieurs sont rejetés. Cette fois, la norme C indique que le résultat est défini par l'implémentation et que le comportement est spécifié dans la documentation gcc sur le comportement des entiers défini par l'implémentation (quatrième puce).
Edgar Bonet
2

Lorsque vous voulez faire des choses avec millis (), n'oubliez pas d'initialiser votre variable avec le type "uint32_t"

Faites donc quelque chose comme "uint32_t last_millis" où vous stockerez la sortie de la fonction "millis ()".

Sinon, comme les autres l'ont dit, cela déborderait au-delà de 31 000, ce qui se produira assez rapidement.

nemik
la source