我们都知道,用于项目的大多数MCU都与时间无关。简单地说,他们不知道周围的时间。对于大多数项目来说都可以,但偶尔当您想到保持时间是首要考虑因素时,DS3231高精度RTC模块就是一个救星。它非常适合包含数据记录、时钟构建、时间戳、计时器和警报的项目。
DS3231实时时钟芯片 该模块主要采用Maxim公司的低成本、极其精确的实时时钟芯片 – DS3231。它管理所有计时功能,并具有一个简单的两线I2C接口,可轻松与您选择的任何微控制器连接。
该芯片维护秒、分、小时、星期、日期、月份和年份信息。对于少于31天的月份,月末的日期会自动调整,包括闰年的更正(直到2100年有效)。
时钟以24小时制或12小时制运行,带有AM/PM指示器。它还提供两个可编程的时间警报。
该模块的另一个很酷的功能是SQW引脚,它可以输出1Hz、4kHz、8kHz或32kHz的漂亮方波,并且可以通过编程方式进行处理。在许多基于时间的应用程序中,这可以进一步用作由于警报条件而产生的中断。
温度补偿晶体振荡器(TCXO) 大多数RTC模块都带有一个用于计时的外部32kHz晶体。但是这些晶体的问题是外部温度会影响它们的振荡频率。这种频率变化可以忽略不计,但肯定会增加。
为避免晶体出现如此轻微的漂移,DS3231由一个32kHz温度补偿晶体振荡器 (TCXO) 驱动。它对外部温度变化具有很强的免疫力。
、
TCXO封装在RTC芯片内部,使整个封装体积庞大。紧挨着集成晶体的是一个温度传感器。该传感器通过添加或删除时钟节拍来补偿频率变化,从而使计时保持在正轨上。
这就是TCXO提供稳定准确的参考时钟并将RTC保持在每年±2分钟以内的原因。
后备电池 DS3231包含电池输入,并在设备的主电源中断时保持准确的计时。
内置电源检测电路持续监控VCC状态以检测电源故障并自动切换到备用电源。因此,您不必担心停电,您的MCU仍然可以跟踪时间。
电路板的背面装有一个用于20毫米3V纽扣锂电池的电池座。任何CR2032电池都可以很好地安装。
假设使用容量为220mAh的充满电的CR2032电池并且芯片消耗其最小3µA电流,则该电池可以在没有外部5V电源的情况下使RTC运行至少8年。 220mAh/3µA = 73333.34 小时 = 3055.56 天 = 8.37 年
板载24C32 EEPROM DS3231 RTC模块还配备了一颗Atmel公司的32 字节24C32 EEPROM芯片,具有无限的读写周期。它可以用来保存设置或任何东西。
24C32 EEPROM使用I2C接口进行通信,并与DS3231共享相同的I2C总线。
EEPROM的I2C地址可以通过背面的三个A0、A1和A2焊接跳线轻松更改。这些中的每一个都用于在地址中进行硬编码。如果跳线与焊料短路,则设置地址。
根据 24C32 的数据表,这3位位于7位I2C地址的末尾,就在读/写位之前。
由于有3个地址输入,可以采用2种状态,高电平/低电平,因此我们可以创建8个不同的组合(地址)。
通过短路焊接跳线,地址输入被拉低。它允许您根据下表设置 I2C 地址。
DS3231实时时钟模块引脚 DS3231实时时钟模块共有6个引脚与外界连接。连接如下:
32K 引脚输出稳定(温度补偿)和准确的参考时钟。 SQW 引脚以1Hz、4kHz、8kHz或32kHz输出漂亮的方波,并且可以通过编程方式进行处理。在许多基于时间的应用程序中,这可以进一步用作由于警报条件而产生的中断。 SCL 是I2C接口的串行时钟引脚。 SDA 是I2C接口的串行数据引脚。 VCC 引脚为模块供电。它可以在3.3V至5.5V之间的任何电压。 GND 是接地引脚。
将DS3231实时时钟模块连接到Arduino UNO开发板 让我们将模块连接到Arduino。连接相当简单。首先将VCC引脚连接到Arduino上的5V输出,然后将GND接地。
现在我们剩下用于I2C通信的引脚。请注意,每个Arduino开发板都有不同的I2C引脚,应相应地连接。在Arduino R3开发板上,SDA(数据线)和 SCL(时钟线)位于靠近AREF引脚的引脚排针上。它们也被称为 A5 (SCL) 和 A4 (SDA)。
下图向您展示了如何连接所有组件。
安装RTClib库 与RTC模块通信是一项繁重的工作。幸运的是,编写RTClib库以隐藏所有复杂性,以便我们可以发出简单的命令来读取RTC数据。
要安装库,请导航到 Sketch > Include Library > Manage Libraries...等待库管理器下载库索引并更新已安装库的列表。
通过输入“rtclib”过滤您的搜索。应该有几个条目。查找Adafruit公司的RTClib。单击该条目,然后选择安装。
Arduino代码 – 读取日期和时间 以下草图将让您全面了解如何在DS3231实时时钟模块上设置/读取日期和时间,并可以作为更多实际实验和项目的基础。 - #include <Wire.h>
- #include "RTClib.h"
- RTC_DS3231 rtc;
- char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
- void setup ()
- {
- Serial.begin(9600);
- delay(3000); // wait for console opening
- if (! rtc.begin()) {
- Serial.println("Couldn't find RTC");
- while (1);
- }
- if (rtc.lostPower()) {
- Serial.println("RTC lost power, lets set the time!");
-
- // Comment out below lines once you set the date & time.
- // Following line sets the RTC to the date & time this sketch was compiled
- rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
-
- // Following line sets the RTC with an explicit date & time
- // for example to set January 27 2017 at 12:56 you would call:
- // rtc.adjust(DateTime(2017, 1, 27, 12, 56, 0));
- }
- }
- void loop ()
- {
- DateTime now = rtc.now();
-
- Serial.println("Current Date & Time: ");
- Serial.print(now.year(), DEC);
- Serial.print('/');
- Serial.print(now.month(), DEC);
- Serial.print('/');
- Serial.print(now.day(), DEC);
- Serial.print(" (");
- Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
- Serial.print(") ");
- Serial.print(now.hour(), DEC);
- Serial.print(':');
- Serial.print(now.minute(), DEC);
- Serial.print(':');
- Serial.print(now.second(), DEC);
- Serial.println();
-
- Serial.println("Unix Time: ");
- Serial.print("elapsed ");
- Serial.print(now.unixtime());
- Serial.print(" seconds/");
- Serial.print(now.unixtime() / 86400L);
- Serial.println(" days since 1/1/1970");
-
- // calculate a date which is 7 days & 30 seconds into the future
- DateTime future (now + TimeSpan(7,0,0,30));
-
- Serial.println("Future Date & Time (Now + 7days & 30s): ");
- Serial.print(future.year(), DEC);
- Serial.print('/');
- Serial.print(future.month(), DEC);
- Serial.print('/');
- Serial.print(future.day(), DEC);
- Serial.print(' ');
- Serial.print(future.hour(), DEC);
- Serial.print(':');
- Serial.print(future.minute(), DEC);
- Serial.print(':');
- Serial.print(future.second(), DEC);
- Serial.println();
-
- Serial.println();
- delay(1000);
- }
复制代码
这是串口监视器中输出的样子。
代码说明 草图首先包含用于与模块通信的wire.h和RTClib.h库。然后我们创建一个RTClib库对象并定义daysOfTheWeek二维字符数组来存储天数信息。
在setup和loop函数中,我们使用以下函数与 RTC模块进行交互。
begin() 函数确保RTC模块已连接。 lostPower() 函数读取DS3231的内部I2C寄存器以检查芯片是否丢失了时间。如果函数返回true,我们就可以设置日期和时间。 adjust() 函数设置日期和时间。这是一个重载函数。 ● 第一个重载函数 DateTime(F(__DATE__), F(__TIME__)) 设置草图编译的日期和时间。 ● 第二个重载方法 DateTime(YYYY, M, D, H, M, s) 使用明确的日期和时间设置RTC。例如,要将 2017 年 1 月 27 日的 12:56 设置为: rtc.adjust(DateTime(2017, 1, 27, 12, 56, 0)); now() 函数返回当前日期和时间。它的返回值通常存储在数据类型DateTime的变量中。 year() 函数返回当前年份。 month() 函数返回当前月份。 day() 函数返回当前日期。 dayOfTheWeek() 函数返回当前星期几。此函数通常用作二维字符数组的索引,该数组存储天数信息,如上述程序 daysOfTheWeek 中定义的 hour() 函数返回当前小时。 minute() 函数返回当前分钟。 second() 函数返回当前秒数。 unixtime() 函数以秒为单位返回unix时间。 Unix时间是用于描述时间点的系统。它是自00:00:00(称为协调世界时 - 1970年1月1日星期四)以来经过的秒数。 TimeSpan() 函数用于从当前时间添加/减去时间。您可以添加/减去天、小时、分钟和秒。它也是一个重载函数。 now() + TimeSpan(seconds) 返回当前时间加上秒数的未来时间。 now() - TimeSpan(days,hours, minutes, seconds) 返回过去的时间。 |