Go back

Read a Virtual DS1307 RTC with Raspberry Pi Pico I2C

Introduction

Ever wanted to add a real-time clock (RTC) to your project but didn’t have the hardware handy? With Velxio, you can simulate a complete I2C RTC readout using a Raspberry Pi Pico and a virtual DS1307—all in your browser. In this tutorial, we’ll walk through the circuit, the code, and the key concepts so you can confidently use I2C communication in your own projects.

Circuit Walkthrough

Let’s start by looking at the circuit. Open the example in Velxio and you’ll see the following components:

Circuit diagram of pico-i2c-rtc-read on the Velxio simulator canvas

The circuit is simple: a Raspberry Pi Pico (nano-rp2040) is connected to two LEDs and a virtual DS1307 RTC (not shown as a separate component—the RTC is built into the simulation). The LEDs are used as visual indicators for I2C activity.

Both LEDs share the same ground (GND.1). The I2C bus consists of the SDA (data) and SCL (clock) lines. The DS1307 RTC is internally connected to these lines at address 0x68. The LEDs are not strictly necessary for I2C communication, but they give a visual cue that the lines are toggling.

To build this circuit yourself, you can use the Velxio component picker:

Velxio component picker modal browsing parts by category

Search for “Raspberry Pi Pico” and “LED”, then wire them as described. The canvas toolbar helps you zoom and arrange components:

Velxio canvas toolbar above the simulation viewport

Code Walkthrough

Now let’s dive into the code. The sketch uses the Wire library (built-in) to communicate with the DS1307 over I2C. Here’s the full code:

// Raspberry Pi Pico — I2C DS1307 RTC Read
// Reads time from virtual RTC at address 0x68

#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 Read ===");
  Serial.println("Reading DS1307 at 0x68 (system time)");
  Serial.println();
}

void loop() {
  // Set register pointer to 0
  Wire.beginTransmission(0x68);
  Wire.write(0x00);
  Wire.endTransmission();

  // Read 7 bytes: sec, min, hr, dow, date, month, year
  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[] = {"", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

    Serial.print("Time: ");
    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("  Date: ");
    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 not responding!");
  }

  delay(1000);
}

How It Works

  1. Setup: We start serial communication at 115200 baud and initialize the I2C bus with Wire.begin(). The DS1307 is at address 0x68.

  2. Loop: Every second, we:

    • Send a beginTransmission to address 0x68, write 0x00 (the register pointer to the seconds register), and endTransmission.
    • Request 7 bytes from the RTC using Wire.requestFrom(0x68, 7).
    • Read each byte and convert from BCD (Binary-Coded Decimal) to decimal using the helper function bcdToDec.
    • Format and print the time and date to the Serial Monitor.
  3. BCD Conversion: The DS1307 stores time values in BCD format. For example, the byte 0x45 represents 45 in BCD (4*10 + 5 = 45). The bcdToDec function extracts the tens digit (high nibble) and ones digit (low nibble) and combines them.

  4. Masking: We apply masks to certain registers:

    • Seconds: & 0x7F clears the CH (clock halt) bit.
    • Hours: & 0x3F clears the 12/24-hour mode bit (assuming 24-hour mode).

Key Concepts

Common Pitfalls & Debugging Tips

Suggested Extensions

Try It Yourself!

Ready to experiment? Open the live example in Velxio and run the simulation. You’ll see the time printed in the Serial Monitor every second. Modify the code to change the update interval or add new features.

Launch the Pico I2C RTC Read Example

Happy simulating!


Share this post on:
David Montero

Written by

David Montero

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

GitHub velxio.dev

Related posts


Previous Post
Pico I2C EEPROM Read/Write: Simulate Non-Volatile Memory in Your Browser
Next Post
Pico I2C Scanner: Find Devices on the Bus