ардуино - миллисекунды ()

Скопировано из справочника по Arduino – millis()

Совет. Обратите внимание, что параметр для миллисимволов представляет собой беззнаковое длинное число. Если программист попытается выполнить математические операции с другими, могут возникнуть ошибки. типы данных, такие как целые.

Какая математика? Какой другой вид обработки исключается при работе с миллисом?

Может ли кто-нибудь пояснить это утверждение и/или привести пример?

, 👍10


3 ответа


Лучший ответ:

8

Всякий раз, когда вы пишете уравнение на C/C++, типы данных, с которыми вы работаете, очень сильно влияют на результат уравнения.

Каждый тип, такой как int, float и unsigned long, имеет разное поведение и требует определенного объема памяти для хранения.

int (на arduino) хранится в 16 битах, причем половина его значений присваивается отрицательным числам, половина 1 присваивается положительным значениям и одно значение присваивается 0. Это дает ему диапазон от -2^15 (-32 768) до +2^15-1 (32 767).

unsigned long (на Arduino) составляет 32 бита, но ни один из них не обозначен как отрицательный. тогда его диапазон составляет от 0 до 2^32-1 (4294967295).

Какая математика? Какой другой вид обработки исключен при работе с миллисами?

Суть проблемы в том, что если время, когда возвращаемое число в миллисекундах превышает 32767, и вы пытаетесь сохранить его в int, Arduino не может этого сделать, потому что int не может держите это большое число. Тип математики, который запрещен, - это математика, которая применяется к меньшим типам данных, а не к каким-либо конкретным операциям. Возможно, эти примеры помогут:

  int i = 32767;
  Serial.println(i);
  // Здесь нет проблем; это подходит просто отлично

32767

 я = 32767 + 1;
Серийный.println (я);
//О нет, значение не подходит

-32768

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

-23536

 i = -10;
беззнаковое целое j = i;
Серийный.println(j);
//нет возможности поместить отрицательное число в беззнаковое значение

65526

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

42000

Это действительно гениально реализовано; Если вам интересно, откуда берутся эти числа и почему они перетекают таким образом, вы должны изучить те же объяснения представлений чисел в дополнении до двух.

,

Простой вопрос: объявление _"unsigned long fake_millis;"_ равно _"uint_32 fake_millis;"_ ?, @user3060854

Да, они равны на ардуино. Разница в том, что unsigned long может меняться на разных платформах (например, x86), uint32_t всегда будет 32 бита без знака везде., @BrettAM

Следует отметить, что ваш второй пример (32767 + 1) дает неопределенное поведение, которое [почти всегда плохо](http://stackoverflow.com/questions/9024826). Другие ваши примеры — это задокументированное поведение, на которое вы можете положиться., @Edgar Bonet


2

Если вы хотите что-то делать с помощью millis(), просто не забудьте инициализировать свою переменную с типом "uint32_t"

Поэтому сделайте что-нибудь вроде "uint32_t last_millis", где вы будете хранить выходные данные функции "millis()".

В противном случае, как говорили другие, он переполнится, когда превысит 31 000, что произойдет довольно быстро.

,

7

millis() возвращает unsigned long, который на Arduino представляет собой 32-битное целое число без знака. Когда вы затем попытаетесь сделать что-то вроде unsigned int time = millis() - 1000, вы попытаетесь сохранить это в 16-битном целом беззнаковом unsigned int. 16-битное целое никогда не может содержать 32-битное значение.

Согласно спецификации C, параграф 6.3.1.3, старшие 16 бит отбрасываются.

По возможности сохраняйте выходные данные millis() в формате unsigned long и используйте типы данных с меньшим количеством битов только в том случае, если вы абсолютно уверены, что не потеряете биты.

Дополнительную информацию о явных приведениях типов в C можно найти здесь: https://stackoverflow.com/a/13652624/1544337

,

Тогда не могли бы вы сказать, что правильнее сказать, что он возвращает uint32_t, который оказывается unsigned long на arduino?, @BrettAM

Удалены старые комментарии, так как вся дискуссия имеет мало смысла с текущей версией ответа. Просто сохрани это для записи: если преобразование происходит в целое число со знаком (int time = millis() - 1000), результат аналогичен: старшие 16 бит отбрасываются. На этот раз стандарт C говорит, что результат определяется реализацией, а поведение указано в [документации gcc по поведению целых чисел, определяемому реализацией](https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation). .html) (четвертый пункт списка)., @Edgar Bonet