Sempre que você escreve uma equação em C / C ++, os tipos de dados que estão sendo operados têm um efeito muito real na saída da equação.
Cada tipo de como int
, float
e unsigned long
têm comportamentos diferentes, e ter uma certa quantidade de espaço na memória para armazenar.
int
(no arduino) é armazenado em 16 bits, com metade de seus valores atribuídos a números negativos, metade-1 atribuída a valores positivos e um valor atribuído a 0. Isso fornece um intervalo de -2 ^ 15 (-32.768) para + 2 ^ 15-1 (32.767).
unsigned long
(no arduino) tem 32 bits, mas nenhum é designado como negativo. seu intervalo é de 0 a 2 ^ 32-1 (4294967295).
Que tipo de matemática? Que tipo de outro tipo de processamento é excluído ao trabalhar com millis?
O cerne da questão é que, quando o tempo em que o millis retorna já ultrapassou 32767 e você tentou armazená-lo em um int, o arduino não conseguiu, porque int
não é possível armazenar um número tão grande. O tipo de matemática que está fora dos limites é a matemática acontecendo com tipos de dados menores, e não com operações específicas. Talvez estes exemplos ajudem:
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
A maneira como isso é implementado é realmente bastante genial; Se você estiver interessado em saber de onde esses números vêm e por que eles se espalham da maneira como eles aparecem, procure as mesmas explicações das representações numéricas do complemento de dois.
unsigned long
pode mudar com plataformas diferentes (por exemplo, x86),uint32_t
sempre haverá 32 bits não assinados em todos os lugares.32767 + 1
) gera um comportamento indefinido, o que é quase sempre uma coisa ruim . Seus outros exemplos são comportamentos documentados nos quais você pode confiar.millis()
retorna aunsigned long
, que é um número inteiro não assinado de 32 bits no Arduino. Quando você tenta fazer algo assimunsigned int time = millis() - 1000
, tenta armazená-lo em um número inteiro não assinado de 16 bitsunsigned int
. Um número inteiro de 16 bits nunca pode conter um valor de 32 bits.De acordo com a especificação C , parágrafo 6.3.1.3, os 16 bits superiores são descartados.
Se possível, mantenha a
millis()
saída emunsigned long
e use apenas tipos de dados com menos bits quando tiver certeza absoluta de que não perderá bits.Há mais informações sobre conversões explícitas em C aqui: https://stackoverflow.com/a/13652624/1544337
fonte
uint32_t
que é umunsigned long
arduino?unsigned long
.int time = millis() - 1000
), o resultado será semelhante: os 16 bits superiores serão descartados. Desta vez, o padrão C diz que o resultado é definido pela implementação e o comportamento é especificado na documentação do gcc sobre o comportamento definido pela implementação dos números inteiros (quarto ponto).Quando você quiser fazer coisas com millis (), lembre-se de inicializar sua variável com o tipo "uint32_t"
Então, faça algo como "uint32_t last_millis" onde você armazenará a saída da função "millis ()".
Caso contrário, como os outros disseram, ele transbordaria quando ultrapassasse os 31.000, o que acontecerá rapidamente.
fonte