ардуино - миллисекунды ()
Скопировано из справочника по Arduino – millis()
Совет. Обратите внимание, что параметр для миллисимволов представляет собой беззнаковое длинное число. Если программист попытается выполнить математические операции с другими, могут возникнуть ошибки. типы данных, такие как целые.
Какая математика? Какой другой вид обработки исключается при работе с миллисом?
Может ли кто-нибудь пояснить это утверждение и/или привести пример?
@user3060854, 👍10
3 ответа
Лучший ответ:
Всякий раз, когда вы пишете уравнение на 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
Это действительно гениально реализовано; Если вам интересно, откуда берутся эти числа и почему они перетекают таким образом, вы должны изучить те же объяснения представлений чисел в дополнении до двух.
Если вы хотите что-то делать с помощью millis(), просто не забудьте инициализировать свою переменную с типом "uint32_t"
Поэтому сделайте что-нибудь вроде "uint32_t last_millis", где вы будете хранить выходные данные функции "millis()".
В противном случае, как говорили другие, он переполнится, когда превысит 31 000, что произойдет довольно быстро.
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
- Как справиться с rollover millis()?
- Как получить тип данных переменной?
- Преобразование в Unix Timestamp и обратно
- Использование millis() и micros() внутри процедуры прерывания
- Невозможно создать массив типа const char*
- Ошибка Cast from 'char*' to 'uint8_t {aka unsigned char}' loses precision [-fpermissive]
- Кнопка с таймером переключения и функцией сброса времени + светодиод обратной связи
- Использовать timer0, не влияя на millis() и micros().
Простой вопрос: объявление _"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