arduino-millis()


10

Arduino参考复制-millis()

提示:请注意,millis的参数是无符号长整数,如果程序员尝试使用其他数据类型(例如int)进行数学运算,则可能会生成错误。

什么样的数学?与Millis一起工作时,排除了哪种其他类型的处理?

有人可以澄清这一说法和/或举一些例子吗?

Answers:


8

每当您用C / C ++编写方程式时,要操作的数据类型都会对方程式的输出产生非常实际的影响。

每种类型(例如intfloat和)unsigned long都有不同的行为,并占用一定的内存空间来存储。

int (在arduino上)存储为16位,其中一半的值提供给负数,一半的值提供给正值,一个值提供给0。这使其范围为-2 ^ 15(-32,768)到+ 2 ^ 15-1(32,767)。

unsigned long(在arduino上)为32位,但没有一个被指定为负数。那么其范围是0到2 ^ 32-1(4294967295)。

什么样的数学?与Millis一起工作时,排除了哪种其他类型的处理?

问题的症结在于,毫秒返回的时间超过了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

这种实现的方式确实很天才。如果您对这些数字的来源以及它们为什么以这种方式溢出感兴趣,您应该研究一下关于补数数字表示形式的相同解释。


只是一个简单的问题:声明“ unsigned long fake_millis;”。等于“ uint_32 fake_millis;”
user3060854 2015年

是的,这些在arduino上是相等的。不同之处在于unsigned long可以随不同平台(例如x86)而变化,uint32_t到处总是32个无符号位。
BrettAM'3

1
请注意,您的第二个示例(32767 + 1)产生未定义的行为,这几乎总是一件坏事。您的其他示例是您可以依靠的已记录行为。
Edgar Bonet 2015年

6

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的引用,因为它有所不同。uint32_t保证您有一个32位无符号整数,无符号long则没有(尽管在Arduino上是)。我也已经提到它是32位类型。

然后,您不是说它返回uint32_t恰好是unsigned longarduino的返回值更正确吗?
BrettAM 2015年

@BrettAM根据文档,此函数返回一个unsigned long

删除了旧评论,因为整个讨论对当前版本的答案没有多大意义。只需保留此记录即可:如果转换为有符号整数(int time = millis() - 1000),则结果类似:丢弃高16位。这次,C标准说结果是实现定义的,并且行为在gcc文档中指定了实现定义的整数行为(第四个要点)。
Edgar Bonet 2015年

2

当您想使用millis()进行操作时,请记住要使用“ uint32_t”类型初始化变量

因此,请执行“ uint32_t last_millis”之类的操作,您将在其中存储“ millis()”函数的输出。

否则,就像其他人所说的那样,当超过31,000时,它将溢出,并且很快就会发生。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.