一板网电子技术论坛

风筝
发表于: 2022-7-26 15:51:53 | 显示全部楼层

我们都知道,用于项目的大多数MCU都与时间无关。简单地说,他们不知道周围的时间。对于大多数项目来说都可以,但偶尔当您想到保持时间是首要考虑因素时,DS3231高精度RTC模块就是一个救星。它非常适合包含数据记录、时钟构建、时间戳、计时器和警报的项目。


DS3231实时时钟芯片

该模块主要采用Maxim公司的低成本、极其精确的实时时钟芯片 – DS3231。它管理所有计时功能,并具有一个简单的两线I2C接口,可轻松与您选择的任何微控制器连接。

DS3231-RTC-Module-Chip.jpg


该芯片维护秒、分、小时、星期、日期、月份和年份信息。对于少于31天的月份,月末的日期会自动调整,包括闰年的更正(直到2100年有效)。


时钟以24小时制或12小时制运行,带有AM/PM指示器。它还提供两个可编程的时间警报。


该模块的另一个很酷的功能是SQW引脚,它可以输出1Hz、4kHz、8kHz或32kHz的漂亮方波,并且可以通过编程方式进行处理。在许多基于时间的应用程序中,这可以进一步用作由于警报条件而产生的中断。


温度补偿晶体振荡器(TCXO)

大多数RTC模块都带有一个用于计时的外部32kHz晶体。但是这些晶体的问题是外部温度会影响它们的振荡频率。这种频率变化可以忽略不计,但肯定会增加。


为避免晶体出现如此轻微的漂移,DS3231由一个32kHz温度补偿晶体振荡器 (TCXO) 驱动。它对外部温度变化具有很强的免疫力。

TCXO-Crystal-Oscillator-Compensation.jpg


TCXO封装在RTC芯片内部,使整个封装体积庞大。紧挨着集成晶体的是一个温度传感器。该传感器通过添加或删除时钟节拍来补偿频率变化,从而使计时保持在正轨上。


这就是TCXO提供稳定准确的参考时钟并将RTC保持在每年±2分钟以内的原因。


后备电池

DS3231包含电池输入,并在设备的主电源中断时保持准确的计时。


内置电源检测电路持续监控VCC状态以检测电源故障并自动切换到备用电源。因此,您不必担心停电,您的MCU仍然可以跟踪时间。

DS3231-RTC-Module-CR2032-Battery-Holder.jpg


电路板的背面装有一个用于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芯片,具有无限的读写周期。它可以用来保存设置或任何东西。

DS3231-RTC-Module-24C32-EEPROM-I2C-Address-Selection-Jumpers.jpg


24C32 EEPROM使用I2C接口进行通信,并与DS3231共享相同的I2C总线。


EEPROM的I2C地址可以通过背面的三个A0、A1和A2焊接跳线轻松更改。这些中的每一个都用于在地址中进行硬编码。如果跳线与焊料短路,则设置地址。

I2C-Address-selection-jumpers-on-DS3231-module.jpg


根据 24C32 的数据表,这3位位于7位I2C地址的末尾,就在读/写位之前。

24C32-EEPROM-I2C-Address-Register.jpg


由于有3个地址输入,可以采用2种状态,高电平/低电平,因此我们可以创建8个不同的组合(地址)。


通过短路焊接跳线,地址输入被拉低。它允许您根据下表设置 I2C 地址。

DS3231-RTC-module-24C32-EEPROM-I2CAddress-Selection-Jumpers-Tables.jpg


DS3231实时时钟模块引脚

DS3231实时时钟模块共有6个引脚与外界连接。连接如下:

DS3231-RTC-Module-Pinout.jpg


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)。


下图向您展示了如何连接所有组件。

Wiring-DS3231-RTC-module-with-Arduino.jpg


安装RTClib库

与RTC模块通信是一项繁重的工作。幸运的是,编写RTClib库以隐藏所有复杂性,以便我们可以发出简单的命令来读取RTC数据。


要安装库,请导航到 Sketch > Include Library > Manage Libraries...等待库管理器下载库索引并更新已安装库的列表。

Manage-Libraries.jpg


通过输入“rtclib”过滤您的搜索。应该有几个条目。查找Adafruit公司的RTClib。单击该条目,然后选择安装。

Installing-RTClib-Arduino-library.jpg


Arduino代码 – 读取日期和时间

以下草图将让您全面了解如何在DS3231实时时钟模块上设置/读取日期和时间,并可以作为更多实际实验和项目的基础。

  1. #include <Wire.h>
  2. #include "RTClib.h"

  3. RTC_DS3231 rtc;

  4. char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

  5. void setup ()
  6. {
  7.   Serial.begin(9600);
  8.   delay(3000); // wait for console opening

  9.   if (! rtc.begin()) {
  10.     Serial.println("Couldn't find RTC");
  11.     while (1);
  12.   }

  13.   if (rtc.lostPower()) {
  14.     Serial.println("RTC lost power, lets set the time!");
  15.         
  16.         // Comment out below lines once you set the date & time.
  17.     // Following line sets the RTC to the date & time this sketch was compiled
  18.     rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  19.         
  20.     // Following line sets the RTC with an explicit date & time
  21.     // for example to set January 27 2017 at 12:56 you would call:
  22.     // rtc.adjust(DateTime(2017, 1, 27, 12, 56, 0));
  23.   }
  24. }

  25. void loop ()
  26. {
  27.     DateTime now = rtc.now();
  28.    
  29.     Serial.println("Current Date & Time: ");
  30.     Serial.print(now.year(), DEC);
  31.     Serial.print('/');
  32.     Serial.print(now.month(), DEC);
  33.     Serial.print('/');
  34.     Serial.print(now.day(), DEC);
  35.     Serial.print(" (");
  36.     Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
  37.     Serial.print(") ");
  38.     Serial.print(now.hour(), DEC);
  39.     Serial.print(':');
  40.     Serial.print(now.minute(), DEC);
  41.     Serial.print(':');
  42.     Serial.print(now.second(), DEC);
  43.     Serial.println();
  44.    
  45.     Serial.println("Unix Time: ");
  46.     Serial.print("elapsed ");
  47.     Serial.print(now.unixtime());
  48.     Serial.print(" seconds/");
  49.     Serial.print(now.unixtime() / 86400L);
  50.     Serial.println(" days since 1/1/1970");
  51.    
  52.     // calculate a date which is 7 days & 30 seconds into the future
  53.     DateTime future (now + TimeSpan(7,0,0,30));
  54.    
  55.     Serial.println("Future Date & Time (Now + 7days & 30s): ");
  56.     Serial.print(future.year(), DEC);
  57.     Serial.print('/');
  58.     Serial.print(future.month(), DEC);
  59.     Serial.print('/');
  60.     Serial.print(future.day(), DEC);
  61.     Serial.print(' ');
  62.     Serial.print(future.hour(), DEC);
  63.     Serial.print(':');
  64.     Serial.print(future.minute(), DEC);
  65.     Serial.print(':');
  66.     Serial.print(future.second(), DEC);
  67.     Serial.println();
  68.    
  69.     Serial.println();
  70.     delay(1000);
  71. }
复制代码

这是串口监视器中输出的样子。

DS3231-Output-On-Serial-Monitor.jpg


代码说明

草图首先包含用于与模块通信的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) 返回过去的时间。

跳转到指定楼层
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 671 | 回复: 1388



手机版|

GMT+8, 2022-8-14 03:18 , Processed in 0.025774 second(s), 7 queries , Gzip On, MemCache On. Powered by Discuz! X3.4

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表