描述
DIY RTC模块
DS3231 RTC芯片
该模块的核心是 Maxim 的低成本、极其精确的 RTC 芯片 – 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 RTC 模块连接到 Arduino UNO
让我们将 RTC 连接到 Arduino。
连接相当简单。首先将 VCC 引脚连接到 Arduino 上的 5V 输出,然后将 GND 接地。
现在我们剩下用于 I2C
通信的引脚。请注意,每个 Arduino 板都有不同的 I2C 引脚,应相应地连接。在具有 R3 布局的 Arduino 板上,SDA(数据线)和 SCL(时钟线)位于靠近 AREF 引脚的引脚接头上。它们也被称为 A5 (SCL) 和 A4 (SDA)。
如果您有 Mega,则针脚不同!您需要使用数字 21 (SCL) 和 20 (SDA)。请参阅下表以快速了解。
代码说明:
草图首先包含用于与模块通信的wire.h 和RTClib.h 库。然后我们创建一个 RTClib 库对象并定义 daysOfTheWeek 二维字符数组来存储天数信息。
在代码的设置和循环部分,我们使用以下函数与 RTC 模块进行交互。
begin() 函数确保 RTC 模块已连接。
lostPower() 函数读取 DS3231 的内部 I2C 寄存器以检查芯片是否丢失了时间跟踪。如果函数返回 true,我们就可以设置日期和时间。
adjust() 函数设置日期和时间。这是一个过载功能。
一种重载方法 Date
time(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() 函数返回当前星期几。此函数通常用作 2D 字符数组的索引,该数组存储天数信息,如上述程序 daysOfTheWeek 中定义的
hour() 函数返回当前小时。
minute() 函数返回当前分钟。
second() 函数返回当前秒数。
unixtime() 函数以秒为单位返回 unix 时间。Unix 时间是用于描述时间点的系统。它是自 00:00:00(称为协调世界时 - 1970 年 1 月 1 日星期四)以来经过的秒数。
TimeSpan() 函数用于从当前时间添加/减去时间。您可以添加/减去天、小时、分钟和秒。它也是一个重载函数。
now() + TimeSpan(seconds) 返回当前时间加上秒数的未来时间。
now() - TimeSpan(days,hours, minutes, seconds) 返回过去的时间。
Arduino 代码 – 在 24C32 EEPROM 中读/写
使用 DS3231 RTC 模块,您可以获得 32 字节的电可擦除 ROM。即使设备的主
电源中断,其内容也不会被删除。
以下程序从 24C32 EEPROM 写入然后读取消息。您可以使用此程序来保存设置或密码或其他任何东西。
#include
无效设置()
{
char somedata[] = "lastminuteengineers.com"; //要写入的数据
Wire.begin(); //初始化连接
序列号.开始(9600);
Serial.println("正在写入内存...");
// 写入 EEPROM
i2c_eeprom_write_page(0x57, 0, (byte *)somedata, sizeof(somedata));
延迟(100);//添加一个小延迟
Serial.println("内存写入");
}
无效循环()
{
Serial.print("读取内存:");
int地址=0;//第一个地址
// 访问内存中的第一个地址
字节 b = i2c_eeprom_read_byte(0x57, 0);
而 (b!=0)
{
Serial.print((char)b); //打印内容到串口
地址++; //增加地址
b = i2c_eeprom_read_byte(0x57, addr); //从内存中访问一个地址
}
序列号.println(" ");
延迟(2000);
}
void i2c_eeprom_write_byte(int deviceaddress, unsigned int eeaddress, byte data) {
int rdata = 数据;
Wire.beginTransmission(设备地址);
Wire.write((int)(eeaddress >> 8)); // 最高位
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.write(rdata);
Wire.endTransmission();
}
// 警告:address 是页地址,6 位结束会回绕
// 另外,数据最大可以是 30 字节左右,因为 Wire 库有一个 32 字节的缓冲区
void i2c_eeprom_write_page(int deviceaddress, unsigned int eeaddresspage, byte* data, byte length) {
Wire.beginTransmission(设备地址);
Wire.write((int)(eeaddresspage >> 8)); // 最高位
Wire.write((int)(eeaddresspage & 0xFF)); // LSB
字节 c;
对于 ( c = 0; c < 长度; c++)
Wire.write(data[c]);
Wire.endTransmission();
}
byte i2c_eeprom_read_byte(int deviceaddress, unsigned int eeaddress) {
字节 rdata = 0xFF;
Wire.beginTransmission(设备地址);
Wire.write((int)(eeaddress >> 8)); // 最高位
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress,1);
if (Wire.available()) rdata = Wire.read();
返回rdata;
}
// 也许我们一次不能读取超过 30 或 32 个字节!
void i2c_eeprom_read_buffer(int deviceaddress, unsigned int eeaddress, byte *buffer, int length) {
Wire.beginTransmission(设备地址);
Wire.write((int)(eeaddress >> 8)); // 最高位
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(设备地址,长度);
诠释 c = 0;
对于 ( c = 0; c < 长度; c++ )
if (Wire.available()) 缓冲区[c] = Wire.read();
}
特征:
两个时间警报。
数字温度传感器输出。
注册老化修剪。
DS 3231 RTC 与 2032 电池座。
高度准确的 RTC 完全管理所有计时功能。
实时时钟计数秒、分、小时、月日期、月、星期几和年,闰年补偿有效至 2100。
使用 PCB 上的 SMD 跳线(A0、A1、A2)为 AT24C32 配置 I2C 设备地址。
可编程方波输出信号。
用于连续计时的备用电池输入。
低功耗操作可延长电池备用运行时间。