arduino - milhões ()

10

Copiado da referência do Arduino - millis ()

Dica : Observe que o parâmetro para millis é um comprimento não assinado. Podem ser gerados erros se um programador tentar fazer contas com outros tipos de dados, como ints.

Que tipo de matemática? Que tipo de outro tipo de processamento é excluído ao trabalhar com millis?

Alguém poderia esclarecer esta afirmação e / ou dar algum exemplo?

user3060854
fonte

Respostas:

8

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, floate unsigned longtê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 intnã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.

BrettAM
fonte
Apenas uma pergunta simples: declarando "fake_millis long sem assinatura"; é igual a "uint_32 fake_millis;" ?
user3060854
Sim, esses são iguais no arduino. A diferença é que unsigned longpode mudar com plataformas diferentes (por exemplo, x86), uint32_tsempre haverá 32 bits não assinados em todos os lugares.
BrettAM 6/15
11
Note-se que o seu segundo exemplo ( 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.
Edgar Bonet
6

millis()retorna a unsigned long, que é um número inteiro não assinado de 32 bits no Arduino. Quando você tenta fazer algo assim unsigned int time = millis() - 1000, tenta armazená-lo em um número inteiro não assinado de 16 bits unsigned 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 em unsigned longe 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

Comunidade
fonte
Obrigado pela edição. Eu removi a referência ao uint32_t, pois é algo diferente. O uint32_t garante que você tenha um número inteiro não assinado de 32 bits, não assinado por muito tempo não (embora seja no Arduino). Eu também já mencionei que é um tipo de 32 bits.
Então você não diria que é mais correto dizer que ele retorna e uint32_tque é um unsigned longarduino?
BrettAM 5/03
@BrettAM de acordo com os documentos que essa função retorna an unsigned long.
Removidos comentários antigos, pois toda a discussão faz pouco sentido com a versão atual da resposta. Apenas mantendo isso para o registro: se a conversão for para um número inteiro assinado ( 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).
Edgar Bonet
2

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.

nemik
fonte