返回

使用树莓派Pico I2C读取虚拟DS1307实时时钟

引言

是否曾想为项目添加实时时钟(RTC),但手头没有硬件?借助Velxio,您可以在浏览器中模拟完整的I2C RTC读取过程——使用树莓派Pico和虚拟DS1307。在本教程中,我们将逐步讲解电路、代码和关键概念,帮助您在自己的项目中自信地使用I2C通信。

电路讲解

我们先来看一下电路。在Velxio中打开示例,您将看到以下组件:

pico-i2c-rtc-read在Velxio仿真器画布上的电路图

电路很简单:一个树莓派Pico(nano-rp2040)连接了两个LED和一个虚拟DS1307 RTC(未显示为独立组件——RTC已内置于仿真中)。LED用作I2C活动的视觉指示器。

两个LED共享同一地线(GND.1)。I2C总线由SDA(数据)和SCL(时钟)线组成。DS1307 RTC在内部以地址0x68连接到这些线。对于I2C通信而言,LED并非严格必要,但它们能提供线路切换的视觉提示。

要自行搭建此电路,您可以使用Velxio的组件选择器:

Velxio组件选择器模态框,按类别浏览零件

搜索”Raspberry Pi Pico”和”LED”,然后按描述进行接线。画布工具栏可帮助您缩放和排列组件:

Velxio画布工具栏,位于仿真视口上方

代码讲解

现在我们来深入代码。该程序使用Wire库(内置)通过I2C与DS1307通信。以下是完整代码:

// 树莓派Pico — I2C DS1307 RTC读取
// 从地址0x68的虚拟RTC读取时间

#include <Wire.h>

byte bcdToDec(byte val) {
  return ((val >> 4) * 10) + (val & 0x0F);
}

void setup() {
  Serial.begin(115200);
  delay(500);
  Wire.begin();
  Serial.println("=== Pico I2C RTC读取 ===");
  Serial.println("正在读取地址0x68处的DS1307(系统时间)");
  Serial.println();
}

void loop() {
  // 将寄存器指针设置为0
  Wire.beginTransmission(0x68);
  Wire.write(0x00);
  Wire.endTransmission();

  // 读取7个字节:秒、分、时、星期、日、月、年
  Wire.requestFrom(0x68, 7);
  if (Wire.available() >= 7) {
    byte sec   = bcdToDec(Wire.read() & 0x7F);
    byte min   = bcdToDec(Wire.read());
    byte hr    = bcdToDec(Wire.read() & 0x3F);
    byte dow   = bcdToDec(Wire.read());
    byte date  = bcdToDec(Wire.read());
    byte month = bcdToDec(Wire.read());
    byte year  = bcdToDec(Wire.read());

    const char* days[] = {"", "周日", "周一", "周二", "周三", "周四", "周五", "周六"};

    Serial.print("时间: ");
    if (hr < 10) Serial.print('0'); Serial.print(hr); Serial.print(':');
    if (min < 10) Serial.print('0'); Serial.print(min); Serial.print(':');
    if (sec < 10) Serial.print('0'); Serial.print(sec);
    Serial.print("  日期: ");
    Serial.print(days[dow]); Serial.print(' ');
    if (date < 10) Serial.print('0'); Serial.print(date); Serial.print('/');
    if (month < 10) Serial.print('0'); Serial.print(month); Serial.print('/');
    Serial.print("20"); if (year < 10) Serial.print('0'); Serial.println(year);
  } else {
    Serial.println("RTC无响应!");
  }

  delay(1000);
}

工作原理

  1. 初始化:我们以115200波特率启动串口通信,并通过Wire.begin()初始化I2C总线。DS1307的地址为0x68

  2. 循环:每秒执行一次:

    • 向地址0x68发送beginTransmission,写入0x00(指向秒寄存器的指针),然后endTransmission
    • 使用Wire.requestFrom(0x68, 7)从RTC请求7个字节
    • 读取每个字节,并使用辅助函数bcdToDec从BCD(二进制编码的十进制)转换为十进制。
    • 格式化时间与日期并打印到串口监视器。
  3. BCD转换:DS1307以BCD格式存储时间值。例如,字节0x45在BCD中表示45(4*10 + 5 = 45)。bcdToDec函数提取十位(高半字节)和个位(低半字节)并组合。

  4. 掩码操作:我们对某些寄存器应用掩码:

    • 秒:& 0x7F清除CH(时钟暂停)位。
    • 时:& 0x3F清除12/24小时模式位(假设为24小时模式)。

关键概念

常见陷阱与调试技巧

建议扩展

亲自尝试!

准备好实验了吗?在Velxio中打开实时示例并运行仿真。您将看到时间每秒在串口监视器中打印一次。修改代码以更改更新间隔或添加新功能。

启动Pico I2C RTC读取示例

祝仿真愉快!


分享到:
David Montero

作者

David Montero

Creator of Velxio, the open-source circuit and Arduino simulator.

GitHub velxio.dev

相关文章


上一篇
Pico I2C EEPROM 读写:在浏览器中模拟非易失性存储器
下一篇
Pico I2C 扫描仪:查找总线上的设备