微控制器定时器中的实时时钟 (RTC)
这篇文章是关于微控制器定时器的系列文章的第三篇,它描述了微控制器内部的 RTC。
这篇文章是关于微控制器定时器的系列文章的第三篇。第一篇介绍了大多数类型定时器的主要特点,涵盖了周期定时器,第二篇涵盖了脉宽调制MCU定时器。
实时时钟 (RTC) 是专用于维持一秒时基的定时器。此外,RTC 通常用于在软件或硬件中跟踪时钟时间和日历日期。 RTC 的许多功能非常专业,需要保持高精度和非常可靠的操作。微控制器外部的 RTC 设备与 I 2 接口 C或SPI总线。
本文介绍了微控制器内的 RTC。
实时时钟概述
实时时钟的基本功能是产生一秒的间隔并保持连续计数。
您可以在下图中看到这一点。
图 1。 此时序图描述了 RTC 的基本功能
还显示了一个程序函数 A,它读取秒计数器并安排事件 B 在未来三秒内发生。此操作称为警报。请注意秒计数器连续运行,不会停止和启动。 RTC 的两个主要要求是准确性和连续运行。
下图显示了 RTC 的常见硬件特性。
图 2。 实时时钟硬件特性
RTC 通常有自己的内部振荡器,带有外部晶体和使用外部频率参考的选项。所有时钟源都以 32,768 Hz 运行。外部时钟源允许使用非常精确和稳定的设备,例如TCXO(温度补偿晶体振荡器)。
使用多路复用器选择时钟源并输入到预分频器,预分频器将时钟分频为 32,768 (215) 倍以产生一秒时钟。
基本的 RTC 有一个秒计数器,通常为 32 位或更多。一些 RTC 有专门的计数器来跟踪一天中的时间和日历日期。
没有时间和日期计数器的基本 RTC 为此使用软件。一个常见的选项是来自输出引脚的 1 Hz 方波。 RTC 将有几个可能的事件来产生处理器中断。
RTC 通常有一个专用的电源引脚,以在微控制器的其余部分断电时允许操作。此电源引脚通常连接到电池或单独的电源。
RTC 精度和频率补偿
RTC 的精度取决于 32,768 Hz 时钟源。在设计良好的晶体振荡器中,误差的主要来源是晶体。外部 TCXO 可用于高精度计时,或者使用特殊频率补偿技术与较便宜的晶体和内部振荡器。晶体的三个主要误差来源。
- 初始电路和晶体容差
- 晶体随温度漂移
- 晶体老化
下图显示了与 RTC 精度相关的几个概念。
图 3。 图表显示了使用德州仪器提供的温度进行的误差测量
此图上的深蓝色轨迹显示了典型的初始容差和随温度的变化。粉色轨迹仅显示温度误差。温度补偿的关键在于晶体的行为是众所周知的,并且可以通过二次方程进行预测。如果在电路板制造后测量初始误差并且知道温度,则可以补偿最大的误差源。
在仔细补偿后,黄色带是准确度的合理目标。请记住,一年内 1 ppm 大约是 30 秒。晶体老化难以弥补。幸运的是,老化通常每年只有几 ppm。
如何更改 RTC 时序
这里有两种方法可以更改作为系统一部分的 RTC 的时序以补偿错误。
第一张图(图 4)描述了预分频器为秒计数器的每个周期计数的振荡器周期数。
前两秒是通常的 32,768 个周期。软件使用温度读数和初始误差来确定振荡器运行得有点快,32,768 个周期实际上是 0.99990 秒的周期。为了补偿这个小错误,软件告诉 RTC 每四秒将预分频器的模数更改为 32,781 以增加一些时间。
图 4。 预分频器计数的振荡器周期表示
这种技术的优点是从一秒到一秒的周期变化很小。然而,该技术需要一个可调预分频器和额外的寄存器来保存特殊预分频计数和特殊计数应用之间的秒数。我觉得这很酷。有点复杂但很酷。
如果 RTC 没有特殊的预分频器来调整时序怎么办?这张图展示了另一种方法。
图 5。 与图 4 相同的情况,但没有预分频器
在这种情况下,框中的数字是秒计数器。显示的计数是 100251,然后是 100252。软件一直在不断计算调整并跟踪 RTC 秒计数。当误差累积到恰好一秒时,软件会增加或减去一秒以调整累积误差。
这种技术的一个缺点是当调整完成时,秒到秒的变化很大。这种技术的优点是与任何 RTC 兼容。
RTC 中的安全性
安全性是一个有趣的要求。有些应用程序使用时间来向客户收取使用服务或消耗资源的费用。有大量关于防止或检测 RTC 黑客行为的实践。技术范围从外壳的入侵检测到微控制器内的特殊功能。
我目前使用的微控制器上的 RTC 具有特殊寄存器,允许软件永久锁定关键寄存器。一旦锁定,它们就无法更改,并且不会受到黑客攻击或代码失控。改变时间需要完全复位微控制器。
时间和日期
一些 RTC 有硬件计数器来维护一天中的时间和日历日期。这需要分钟、小时、天、月、年的计数器,并考虑闰年。时间和日历日期也可以通过软件保存。
一个突出的例子是在 time.h 文件中看到的 C 标准库中的函数。对于微控制器,该系统可以基于 RTC 的秒计数器。必须编写四个小的自定义函数才能完全支持 time.h 库。
此处感兴趣的一个函数由库中的 time() 函数调用,该函数返回自称为“纪元”的起点(通常为 1970 年 1 月 1 日)以来经过的秒数。通常,要读取的自定义函数硬件定时器被命名为 get_time() 或类似的变体。 get_time() 所做的只是读取秒计数器并返回值。图书馆会完成剩下的工作,将这个以秒为单位的时间转换为当前的时间和日期。
32 位秒计数器的问题
32 位秒计数器运行很长时间但不是永远。由于计数范围有限,可能会出现严重问题。例如,基于使用 C 标准库的 32 位计数器和 1970 年 1 月 1 日纪元的系统时间可能会在 2038 年 1 月当计数器在最大计数后翻转时失败。这个问题被称为Y2038问题。
美国宇航局深度撞击太空任务研究彗星时发生了故障。主要任务目标已经实现,航天器继续研究其他物体。然而,通讯在2013年突然中断。这是美国宇航局的官方评论。
<块引用>
“虽然损失的确切原因尚不清楚,但分析发现了计算机时间标记的潜在问题,该问题可能导致对 Deep Impact 的方向失去控制。”
- NASA 2013 年新闻发布
失败的一个可能原因是 32 位计时器以 0.1 秒的增量维持时间并翻转导致任务“终止”。
我的建议是,当涉及时间和日期时,在您的设计中使用比预期更长的生命周期。
接下来是什么
下一篇文章总结了看门狗定时器系列。
工业技术