DS3231时钟模块,库详解

DS3231概述

常用的DS1302需要使用外置晶振,且没有温度补偿,误差较大。

DS3231内置晶振且有内部温度补偿,误差可做到1分钟每年。

在这里插入图片描述

项目地址:https://github.com/NorthernWidget/DS3231

  • 工作电压:3.3V–5.5V

  • 时钟芯片:高精度时钟芯片DS3231

  • 时钟精度:0-40度范围内,精度2pm,年误差约1分钟

  • 2个日历闹钟可编程输出,年月日有效时间到2100年,芯片内部自带温度传感器,精度正负3摄氏度

  • 存储芯片:AT24c32(存储容量32k)

  • 可编程方波输出

AT24C32级联

许多 DS3231 模块会集成一个 24C32 EEPROM 芯片(AT24C32 是一种常用的串行电可擦除可编程只读存储器(EEPROM)芯片),主要用于:

  1. 存储校准数据:DS3231 的时钟精度可通过校准参数优化,这些参数可存储在 24C32 中。
  2. 保存用户数据:例如闹钟设置、定时器配置等,断电后不丢失。
  3. 扩展存储容量:DS3231 内部仅有 32 字节 RAM,而 24C32 提供32KB 存储空间。

24C32 芯片的地址设置主要通过其 A0、A1、A2 引脚来实现。这三个引脚可以接高电平(VCC)或低电平(GND),通过不同的电平组合来设置芯片在 I²C 总线上的地址。

  • A0、A1、A2 引脚的电平状态决定了芯片地址的低三位。例如,当 A0 = 0、A1 = 0、A2 = 0 时,芯片地址的低三位为 000;当 A0 = 1、A1 = 0、A2 = 1 时,芯片地址的低三位为 101。

  • 24C32 芯片的 I²C 地址通常为 7 位,高四位固定为 1010,低三位由 A0、A1、A2 引脚决定。比如,当 A0 = A1 = A2 = 0 时,芯片的 I²C 地址为 1010000(十六进制为 0x50);当 A0 = 1、A1 = 1、A2 = 1 时,芯片的 I²C 地址为 1010111(十六进制为 0x57)。

虽然 DS3231 不能级联,但通过 24C32 的级联可以实现:

1. 大幅扩展数据存储容量

每个 24C32 提供32KB 存储,级联多个后总容量倍增。例如:

  • 2 个 24C32 → 64KB
  • 4 个 24C32 → 128KB

适用于需要长期记录时间戳和传感器数据的场景(如环境监测、工业日志)。

2. 分离不同类型的数据

将时钟校准数据、用户配置、日志数据分别存储在不同的 24C32 中,避免数据覆盖风险。例如:

  • 24C32-1(地址 0x50):存储时钟校准参数
  • 24C32-2(地址 0x51):存储用户设置
  • 24C32-3(地址 0x52):存储历史事件日志

3. 提高系统可靠性

当某个 24C32 出现故障时,其他芯片的数据不受影响。例如:

  • 关键配置数据存储在多个 24C32 中,实现冗余备份。
  • 按时间分片存储数据,便于故障排查(如只恢复最近 7 天的数据)。

4.示例

通过设置 A0/A1/A2 引脚的电平,可在同一 I2C 总线上连接最多 8 个 24C32:

#include <Wire.h>

// 定义多个24C32的地址
const uint8_t EEPROM_ADDR1 = 0x50;  // A0=A1=A2=0
const uint8_t EEPROM_ADDR2 = 0x51;  // A0=1, A1=A2=0
const uint8_t EEPROM_ADDR3 = 0x52;  // A0=0, A1=1, A2=0

void setup() {
  Wire.begin();
}

// 向指定地址的24C32写入数据
void writeEEPROM(uint8_t addr, uint16_t memoryAddress, uint8_t data) {
  Wire.beginTransmission(addr);
  Wire.write((memoryAddress >> 8) & 0xFF);  // 高字节地址
  Wire.write(memoryAddress & 0xFF);         // 低字节地址
  Wire.write(data);
  Wire.endTransmission();
  delay(5);  // EEPROM写入需要时间
}

// 从指定地址的24C32读取数据
uint8_t readEEPROM(uint8_t addr, uint16_t memoryAddress) {
  Wire.beginTransmission(addr);
  Wire.write((memoryAddress >> 8) & 0xFF);  // 高字节地址
  Wire.write(memoryAddress & 0xFF);         // 低字节地址
  Wire.endTransmission();
  
  Wire.requestFrom(addr, 1);
  return Wire.read();
}

void loop() {
  // 向不同的24C32写入数据
  writeEEPROM(EEPROM_ADDR1, 0, millis() & 0xFF);  // 存储时间戳
  writeEEPROM(EEPROM_ADDR2, 0, analogRead(A0));   // 存储传感器数据
  
  // 从不同的24C32读取数据
  uint8_t data1 = readEEPROM(EEPROM_ADDR1, 0);
  uint8_t data2 = readEEPROM(EEPROM_ADDR2, 0);
  
  delay(1000);
}

多个RTC的级联

时钟芯片DS3231 I²C地址固定为0x68,本身无法级联。若需要多个RTC的级联,可通过以下方法实现:

1. 使用I2C多路复用器(如 TCA9548A)

TCA9548A库

项目地址: https://github.com/WifWaf/TCA9548A

TCA9548A 是德州仪器(TI)推出的一款 8 通道 I²C 总线多路复用器 / 解复用器,主要用于扩展 I²C 总线的负载能力,解决单一主控制器与多个从设备通信时的地址冲突问题。

  1. 通道数量与切换
    • 支持 8 个独立的 I²C 通道(通道 0~7),每个通道可连接一个或多个 I²C 从设备。
    • 通过简单的寄存器配置,主控制器可选择任意一个通道与目标设备通信,实现 “单主多从” 的灵活扩展。
  2. 电气特性
    • 宽电压范围:支持 1.65V~5.5V 的电源电压,兼容不同逻辑电平的主控制器(如 3.3V 或 5V 系统)。
    • 双向电平转换:自动适配主控制器与从设备的电压电平,无需额外电平转换电路,简化设计。
    • 高总线速度:支持标准模式(100kHz)、快速模式(400kHz)和快速模式 Plus(1MHz),满足高速 I²C 通信需求。

在这里插入图片描述

在这里插入图片描述

类成员函数
1. 构造函数 TCA9548A(uint8_t address = 0x70)
  • 功能:创建 TCA9548A 类的一个实例,同时设定 TCA9548A 芯片的 I2C 地址。
  • 参数:
    • address:TCA9548A 芯片的 I2C 地址,默认值为 0x70
  • 示例
#include "TCA9548A.h"

TCA9548A tca(0x70); // 创建一个 TCA9548A 实例,地址为 0x70
2. begin(TwoWire &inWire = Wire)
  • 功能:对 I2C 总线进行初始化,并且把其关联到 TCA9548A 实例。
  • 参数:
    • inWireTwoWire 类型的引用,代表 I2C 总线,默认值是 Wire
  • 示例
#include "TCA9548A.h"

TCA9548A tca(0x70);

void setup() {
   
   
  tca.begin(Wire); // 初始化 I2C 总线
}

void loop() {
   
   
  // 主循环代码
}
3. openChannel(uint8_t channel)
  • 功能:开启指定的通道。
  • 参数:
    • channel:要开启的通道编号,范围是 0 到 7。
  • 示例
#include "TCA9548A.h"

TCA9548A tca(0x70);

void setup() {
   
   
  tca.begin(Wire);
  tca.openChannel(0); // 开启通道 0
}

void loop() {
   
   
  // 主循环代码
}
4. closeChannel(uint8_t channel)
  • 功能:关闭指定的通道。
  • 参数:
    • channel:要关闭的通道编号,范围是 0 到 7。
  • 示例
#include "TCA9548A.h"

TCA9548A tca(0x70);

void setup() {
   
   
  tca.begin(Wire);
  tca.openChannel(0); // 开启通道 0
  delay(1000); // 等待 1 秒
  tca.closeChannel(0); // 关闭通道 0
}

void loop() {
   
   
  // 主循环代码
}
5. writeRegister(uint8_t value)
  • 功能:向 TCA9548A 芯片的控制寄存器写入指定的值。
  • 参数:
    • value:要写入寄存器的值。
  • 示例
#include "TCA9548A.h"

TCA9548A tca(0x70);

void setup() {
   
   
  tca.begin(Wire);
  tca.writeRegister(TCA_CHANNEL_0 | TCA_CHANNEL_1); // 开启通道 0 和通道 1
}

void loop() {
   
   
  // 主循环代码
}
6. readRegister()
  • 功能:从 TCA9548A 芯片的控制寄存器读取当前的值。
  • 返回值:控制寄存器的当前值。
  • 示例
#include "TCA9548A.h"
#include <Serial.h>

TCA9548A tca(0x70);

void setup() {
   
   
  Serial.begin(9600);
  tca.begin(Wire);
}

void loop() {
   
   
  byte regValue = tca.readRegister(); // 读取寄存器的值
  Serial.print("Register value: ");
  Serial.println(regValue, HEX);
  delay(1000);
}
7. closeAll()
  • 功能:关闭所有通道。
  • 示例
#include "TCA9548A.h"

TCA9548A tca(0x70);

void setup() {
   
   
  tca.begin(Wire);
  tca.openChannel(0); // 开启通道 0
  tca.openChannel(1); // 开启通道 1
  delay(1000); // 等待 1 秒
  tca.closeAll(); // 关闭所有通道
}

void loop() {
   
   
  // 主循环代码
}
8. openAll()
  • 功能:开启所有通道。
  • 示例
#include "TCA9548A.h"

TCA9548A tca(0x70);

void setup() {
   
   
  tca.begin(Wire);
  tca.openAll(); // 开启所有通道
}

void loop() {
   
   
  // 主循环代码
}
私有成员函数
1. write(uint8_t inData)
  • 功能:通过 I2C 总线向 TCA9548A 芯片写入数据。
  • 参数:
    • inData:要写入的数据。
2. read()
  • 功能:通过 I2C 总线从 TCA9548A 芯片读取数据。
  • 返回值:读取到的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贾小号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值