Ардуино - Миллис ()

10

Скопировано из ссылки Arduino - Millis ()

Совет : обратите внимание, что параметр для millis - это длина без знака, могут возникать ошибки, если программист пытается выполнить математику с другими типами данных, такими как int.

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

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

user3060854
источник

Ответы:

8

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

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

int (в arduino) хранится в 16 битах, половина значений дана для отрицательных чисел, половина - для положительных значений, а одна - для 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);
  //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

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

BrettAM
источник
Просто простой вопрос: Объявление "unsigned long fake_millis;" равно "uint_32 fake_millis;" ?
user3060854
Да, на Arduino они равны. Разница в том, что она unsigned longможет меняться на разных платформах (например, x86), uint32_tвезде всегда будет 32 беззнаковых бита.
BrettAM
1
Следует отметить, что ваш второй метод example ( 32767 + 1) приводит к неопределенному поведению, что почти всегда плохо . Другие ваши примеры - документированное поведение, на которое вы можете положиться.
Эдгар Бонет,
6

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

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

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

Больше информации о явном приведении в C здесь: https://stackoverflow.com/a/13652624/1544337

Сообщество
источник
Спасибо за редактирование. Я удалил ссылку на uint32_t, так как это что-то другое. uint32_t гарантирует, что у вас есть 32-разрядное целое число без знака, а без знака длинное - нет (хотя в Arduino это так). Я также уже упоминал, что это 32-битный тип.
Тогда разве вы не сказали бы, что правильнее было бы сказать, что он возвращает a, uint32_tкоторый оказывается unsigned longна arduino?
BrettAM
@BrettAM согласно документам, эта функция возвращает unsigned long.
Удалены старые комментарии, так как вся дискуссия не имеет смысла с текущей версией ответа. Просто держать это для записи: если преобразование к подписанному целому числу ( int time = millis() - 1000), результат аналогичен: старшие 16 бит отбрасываются. На этот раз стандарт C говорит, что результат определяется реализацией, а поведение указано в документации gcc по определяемому реализацией поведению целых чисел (четвертая точка).
Эдгар Бонет
2

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

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

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

nemik
источник