如何获得准确的时间?


16

我已经使用Arduino制作了一个时钟,但是时间似乎在漂移。我知道过渡问题;一周内时钟似乎会偏移15分钟左右。

我正在为此 Digi-key的谐振器使用定制PCB 。该代码在每个循环的开头读取millis()函数,并从该值开始工作。

我的问题是:我该如何使用Arduino测量时间,准确到足以制作出可通过的台式时钟?


3
中断功能提供了毫秒功能,这需要几个时钟周期才能运行。这为每个刻度增加了微不足道的时间。
TheDoctor 2014年

3
@TheDoctor:这是不正确的。中断不会减慢驱动器的硬件计时器millis()
Edgar Bonet 2015年

Answers:


15

注意:尽管我的回答被接受并且具有较高的投票分数,但是请确保您阅读了Edgar Bonet关于如何使Arduino保持时间而不使用RTC 的出色回答

我在使用DS1307实时时钟方面非常成功。这是其数据表的链接。

以下是其一些功能:

  • 它使用IC接口与Arduino进行通信,从而可以轻松地使用正确的库(可从网上获得)进行编程。

  • 它通过SCL和SDA引脚(分别为模拟A4和A5)连接到Arduino,因此仅使用2个引脚。

  • 它只需要很少的外部组件即可运行。

  • IT可以连接到纽扣电池,因此即使关闭Arduino也可以节省时间。在其低功率模式下,纽扣电池可持续使用数年。

  • 它的漂移很小(在我的情况下,每周仅漂移几秒钟)。

  • 它不是很贵。

如果您不打算使用RTC,则可以替换通常用于为arduino提供时钟的晶体,例如Farnel晶体振荡器模块另一种晶体振荡器模块。它们采用4引脚封装,如下图所示。它们将为您的arduino生成更精确的时钟。

晶体振荡器图像 晶体振荡器图像 晶体振荡器图像

提到的两个模块的公差均为50 ppm,并在5V下工作。

同样,请注意,不要将这些晶体振荡器模块与常规的2引脚晶体混淆,如下所示。例如,这些是MCU外部时钟电路的一部分。

晶体振荡器


DS1302是否足够好?还是应该移至DS1307?
凯利·S·法

14

您不需要RTC来构建时钟:ATmega芯片具有执行RTC本身职责所需的所有硬件。方法如下:

  1. 获得32768 Hz的手表晶体:购买或拆卸旧时钟。这些专为计时而设计的晶体具有极小的温度漂移。如果您想使用RTC芯片,则还需要其中之一。

  2. 配置ATmega的保险丝,使其在8 MHz RC振荡器上运行。这将使您的millis()功能极其不准确,并且还会释放XTAL1和XTAL2引脚。

  3. 将手表晶体连接到TOSC1和TOSC2引脚。这些引脚与XTAL1和XTAL2相同(328P上为9和10)。不同的名称用于表示不同的功能。

  4. 将定时/计数器2配置为异步操作,正常计数模式,预分频器设置为128,并启用定时器溢出中断。

现在,您将以非常稳定的速率(每秒一次)获得TIMER2_OVF中断。您只需在ISR中将时钟显示提前一秒。在两次中断之间,您可以使MCU处于深度睡眠状态(节能睡眠模式:只有定时器2才能运行),并且可以在几个AA单元上运行数年。显然,除非显示器耗电。

我正是这样做的,目的是建造我的24小时单手挂钟。现在,该链接指向原始文档的法文英文翻译。

石英校准

如果您不校准石英,则可能会出现很大的漂移,通常每周几秒钟。漂移速率取决于将晶体连接至MCU的走线的杂散电容。原则上,可以通过添加一些额外的,经过微调的电容将其删除。值得注意的是,使用RTC时也会遇到相同的漂移问题

如果您对这种准确性感到满意,那就忍受它并感到高兴。但是,如果您想测量漂移,则会发现它非常稳定。然后,您可以轻松地用软件对其进行补偿,并达到每年几秒钟的精度。

校正漂移的算法非常简单。从测得的漂移中,您可以得出中断之间的精确延迟,该延迟应非常接近10 9  纳秒,然后:

#define ONE_SECOND    1000000000  // in nanoseconds
#define ONE_INTERRUPT  999993482  // for example

ISR(TIMER2_OVF_vect)
{
    static uint32_t unaccounted_time;

    unaccounted_time += ONE_INTERRUPT;
    while (unaccounted_time >= ONE_SECOND) {
        advance_display_by_one_second();
        unaccounted_time -= ONE_SECOND;
    }
}

在上面的示例中,石英速度有点过快,并且软件会每隔几天“丢失”一个刻度来进行补偿。如果石英速度太慢,则同一代码将每隔几天两次双击。

也可以对RTC进行这种校准,但是它将更加复杂,因为RTC以细分形式报告时间,这自然不适合进行算术运算。


哇,这是一个非常漂亮的设计!我真的很喜欢您提供足够的照片来使设计清晰,即使对于我们这个愚蠢的美国人也是如此:)我真的很喜欢看到这样的明确项目文档!
John Walthour 2015年

2
@JohnWalthour:谢谢!现在,您鼓励我写译文。:-)
Edgar Bonet 2015年

2
@JohnWalthour:完成!现在,该链接指向英语翻译。
Edgar Bonet 2015年

明确地说,当您说“ ATmega芯片具有所需的所有硬件”时,当您必须获得新的晶体时,这并不是完全正确的。我认为您的解决方案很精巧,不能取代晶体,但是当您说我不需要硬件然后转过来说我需要更换一块硬件时,我有些困惑。
凯利·S·法兰西

@ KellyS.French:我的意思是“ ATmega芯片具有执行RTC本身职责所需的所有硬件”(强调了一点)。但是重要的是要注意,大多数RTC,包括无所不在的DS1307,都需要一个外部晶振来工作。ATmega没什么不同:它具有取代RTC本身所需的全部功能,但又无须取代无论如何都必须连接到RTC的晶振。请注意,RTC 模块不仅仅是一个RTC,因为它包括了水晶。
Edgar Bonet

6

您指定的谐振器具有0.3%的稳定性,其中晶体或晶体振荡器(如Ricardo所述)为50ppm。稳定很多倍。更不用说谐振器的温度漂移是可怕的。阳光加热会改变它。因此,谐振器不应用于长时间保持时间。

因此,使用晶体或晶体振荡器将得到您想要的。要么在ATmega上使用它并分别设置保险丝,要么我们将其连接到RTC。


50ppm是0.005%的稳定性吗?
Matthew G.

我对此规范进行了概括,以使回答简短。注意稳定性(Res)。具有更大的容忍度,可能会相差甚远。正如John W所经历的那样。“正确工作的正确部分”
mpflaga 2014年

哦,我只是对术语@mpflaga感到好奇,这对我来说是新的。
马修·G。

4

如果您不想使用诸如实时时钟之类的额外硬件(例如DSDS1307),则可以通过禁用所有未使用的中断来显着提高定时精度。默认情况下,Arduino草图带有启用的各种中断例程,通常它们实际上并未用于草图。找出是否可以做的最快方法,尝试通过发出尝试禁用它们noInterrupts();


3
-1(尽管这应为-4),因为:1.除非您实际需要它们,否则默认情况下所有中断都被禁用,唯一的例外是TIMER0_OVF,这是保持时间的必要条件。2. Arduino的定时精度主要受谐振器质量的限制。3.中断不会影响精度,millis()除非您一次要花费超过一毫秒的时间来维护它们,在这种情况下,您还会遇到其他问题... 4.禁用中断noInterrupts()会完全millis()浪费时间!
Edgar Bonet 2015年

2

我了解Arduino的许多精神是节俭,偶尔会遇到问题。我在工作场所使用Arduino(现在使用chipKIT,因为它具有10倍的RAM和10倍的时钟速度),而我需要“外围功能”以使其尽可能快地工作。

我在我的一个项目中使用了sparkfun实时时钟,对此感到非常满意。他们也有一个“ Dead on”变体

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.