Arduino使用millis()的计时不正确或不正确?


9

我一直在使用Arduino记录一些数据。在我的Arduino草图中,我还使用了该millis()函数,以便可以跟踪我正在测量的每个值的获取时间。但是,我注意到时间不正确。例如,在现实生活中,30秒只能显示为10秒(虚构示例)。

我是否正确地说Arduino延迟功能会影响使用时间millis()?换句话说,假设我有一个50ms的延迟,这是否意味着该millis()函数在该持续时间内也停止,然后在连接持续时间内继续等等?当我尝试绘制一些数据并发现经过一定时间后,数据中的峰值频率过于频繁时,我注意到了这一点。因此,我想知道这是否是造成时间不匹配的原因,如果是,那么如何解决此问题,以便保留每个采样发生的时间?

这里给出一些背景是我的草图:

#include <eHealth.h>    

unsigned long time;
// The setup routine runs once when you press reset:
void setup() {
  Serial.begin(9600);  
}

// The loop routine runs over and over again forever:
void loop() {

  float ECG = eHealth.getECG();
  time = millis();
  Serial.print(time);
  Serial.print(" ");
  Serial.print(ECG, 5); 
  Serial.println("");    

  delay(50);
}

您是否正在使用Uno官方板之一?
彼得·布鲁姆菲尔德

1
实际定时而不是虚假值(带有时间戳记的串行监控器是理想的选择)可能会帮助您确定发生了什么。
伊格纳西奥·巴斯克斯·阿布拉姆斯

3
的计算millis()是中断驱动的,因此delay()不应影响它。
microtherion 2014年

我有同样的问题,但只有当我将其(millis())集成到复杂代码中时才有。我猜想代码的复杂性会随着代码的复杂性越来越延迟而影响其准确性。有什么办法可以避免这种情况?也许使用单独的RTC模块?
Josip7171

Answers:


10

millis()是中断驱动的,因此delay()不会影响它,至少不会在基于ATmega的板上。

这也不是说millis()完全准确。计时器的每个刻度不完全是1毫秒,而是1.024毫秒。该错误会逐渐累积,直到进行校正为止。这可以在TIMER0_OVF(定时器0溢出)中断处理程序的实现中看到。

另一个不准确的原因是振荡器/晶体本身,它不完全是16MHz。不过,它非常接近,只要温度变化不大,就相对稳定。

以上表示使用时,您可能需要1毫秒左右的时间millis()。这听起来不像您的问题。

另一个潜在的问题getECG()是正在做什么-可能会很慢。

float eHealthClass::getECG(void)
    {
        float analog0;
        // Read from analogic in. 
        analog0=analogRead(0);
        // binary to voltage conversion
        return analog0 = (float)analog0 * 5 / 1023.0;   
    }

analogRead() 速度很慢,但不慢到会影响这样的循环。

我看到人们遇到的另一个问题是当他们更改时钟速度但未正确更改boards.txt时。这意味着在millis()实现中使用的常量是错误的,并且时间是错误的。

如果您实际上想每50毫秒读取一次值,则实现此目标的更好方法是执行以下操作

static long lastUpdate;

if (millis() - lastUpdate > 50)
{
    lastUpdate = millis();
    //Do stuff
}

我们确实需要查看您得到的时间戳。如果您实际看到30s显示为10s,那么还有其他工作。


2
请注意,对于Uno,时钟不是由晶体驱动的,而是仅使用比晶体精度低的陶瓷谐振器。
jfpoilpret 2014年

@jfpoilpret很高兴知道。 看原理图,这就是CSTCE16M0V53-R0 Murata CERALOCK器件
克里斯·奥

谐振器的初始容差(通常为0.5-2%)和温度稳定性很差,但是如果在使用谐振器时校准定时环,只要温度不动,它们就可以了。
Cyber​​gibbons 2014年

2
Millis()仍在每1.024ms滴答的计时器上工作,但它们添加了错误补偿,以每当错误计量器变量变得过高时递增的方式进行补偿。我认为这实际上是Roman Black的算法。因此,计时应该精确地接近1ms。github.com/arduino/Arduino/blob/master/hardware/arduino/cores/…–
EternityForest

对于那些仍然有兴趣的人,请参阅我在JRobert的答案上发表的评论,由于没有答案,我不想回答自己的答案,我只是改写了这个问题。
user3284376 2014年

2

如果中断在相当eHealth.getECG()长的时间内没有关闭,则millis()的计数可能会落后。否则,millis()返回的时间应该比您描述的3x错误要准确得多。

您说采样信号的频率似乎比预期的要高,如果采样率低于预期,则可能会发生。您是否假设采样率为20Hz?您的循环可能会花费比50ms更长的时间,您会在打印的时间中看到该时间,但这些时间仍应跟踪时钟时间。如果您没有考虑到这一点,而是假设为50ms /采样,那么您将会看到数据的明显加速。

如果这不是问题,那么下一步是在状态下切换输出loop(),并使用频率计(某些价格便宜的DVM可以执行此操作)或'示波器'测量所得方波的频率。空着做同样的事情loop()。第一个实验将是您的实际采样率或间隔;第二个将告诉您是否millis()(即timer0频率)是否符合您的期望。


1
我一直在研究它,并逐渐意识到问题不在Arduino上,在大多数情况下,millis()函数工作得很好,某些值之间的间隔不完全是8ms(延迟)您已经说出了预期。我描述的3x错误是我用于接收数据的Python方面的错误。不知道可能是什么结果,我使用的是python的pyserial,它运行缓慢。
user3284376 2014年

我对您的实现知之甚少,无法给您提供1/2 @的猜测,但是Python方面的速度足够慢以至于无法采样吗?
JRobert

0

同样在这里。我可以补充一点,如果中断被关闭,则测量的时间为“实时”。无论如何,我不明白为什么会出现这种延迟,因为如果循环花费的时间太长,无论如何,millis()应该返回实时值(每个值之间的距离更大)


1
“这里相同”指的是什么?答案应该独立存在,因为StackExchange可以对事物进行重新排序(与论坛不同)。因此,“在此相同”可能意味着任何含义,具体取决于您的答案显示在下面。
尼克·加蒙

尽管(公认地)您缺乏足够的声誉,但该帖子更适合作为评论。
Greenonline 2015年

抱歉,我虽然在您回答问题时,显然是指主要帖子,否则将是评论
user48711 2015年
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.