Wire-Level (I2C) RTC Exercises


DS1307 Square Wave Investigation. in this exercise you'll gain familiarity with both the Arduino Serial Plotter and the DS1307's Square Wave functionality. We'll also review external interrupts.

Reference 1: Arduino Serial Plotter: Multiple Graphs
Reference 2: Arduino DS1307 Real Time Clock Square Wave Generator

The Serial Plotter feature is fairly crude but can be useful in visualizing your data. You simply use the Serial print and println functions for numeric data and launch the Serial Plotter feature in the Tools menu. Changing the baud rate can adjust the speed of animation of your plot.

Our goal will be to plot various square waves generated through Wire-level manipulation of Register 7 in the DS1307 and combining the output with our knowledge of external interrupts and mid-level coding techniques.

As can be determined below left, one pin on the DS1307 (pin 7) offers an open drain square wave signal that mimics the oscillation of the crystal (32.768 kHz). Through the setting of internal prescalers, the signal can be divided down to achieve three other frequencies,
(8.192 kHz, 4.096 kHz or 1 Hz). The block diagram to the left (below) suggests the use of an external pullup resistor in combination with the open drain pin however, since we're using a microcontroller, an internal pullup resistor can be set on the monitoring pin, simplifying the circuit further.


Stage 1. Enable the RTC Square Wave.

  1. Create the sketch RTCSquareWavePlotter.
  2. Using Wire-level commands only, configure the RTC's Register 7 to enable the Square Wave with a frequency of 1 Hz.

Stage 2. RTC Square Wave Interrupt

  1. The goal of the second stage is to configure our RTC's Square Wave to interrupt our code with a known frequency so that we may have our sensor(s) take its reading and its data logged to EEPROM. The ATmega328P offers two external interrupt pins (INT0 and INT1) mapped to Arduino pins 2 and 3, respectively. Since INT1 (pin 3) is also mapped to a PWM source, we'll stay away from that one for now, in case we require it later. Wire your RTC's SQW pin to Arduino pin 2.
  2. As the SQW pin is an open-drain type we need to attach a pullup resistor. Using mid-level code, configure the appropriate register to set the pullup resistor on pin 2.
  3. We're going to visually monitor the interrupts as well. Within the setup() function, again, using mid-level code, configure the appropriate register for pin 13 for output.
  4. Within the setup() function, attach an interrupt function, pulse(), to Arduino pin 2, to be invoked on a CHANGE event .
  5. Implement the function pulse() as an Interrupt Service Routine (ISR) so that will increment the global variable count, set the global variable triggered to true, and toggle the state of pin 13, every time the pin senses a CHANGE event.
  6. Have your loop() function check the value of triggered. On true, set triggered to false, and use Wire-level calls to obtain the RTC's time and date information and println the values to the Serial Monitor.

Stage 3. Plotting the Square Wave

  1. Comment out all Serial.print and println calls.
  2. Add the statement Serial.println(count%2) to your loop() function, to be executed on every iteration (not just when triggered)
  3. Run your code and launch the Serial Plotter instead of the Serial Monitor.
  4. Reduce the baud rate to 1200 in both your setup() function and the Serial Plotter to slow the display down.


DS1307 Time Functions

Reference 1: Wire Library, Explored
Reference 2: DS1307 Datasheet
Reference 3: DS1307 Registers

  1. Insert your DS1307 board as shown to the right.
  2. Create a new project sketch, WireLevelRTC.ino.
  3. Include the Wire library as the only import.
  4. Declare the DS1307 I2C address B1101000 with a #define compiler directive.
  5. In setup(), provide ground and 5V to their respective pins.
  6. Make a call to the appropriate Wire library function to initialize it.
  7. Establish Wire-level access to your RTC.
  8. The DS1307 counts the finely-tuned oscillations of its crystal to mark the passage of time. A mapping of these counts are recorded in its memory registers, in BCD format. For what follows in this exercise, a function that converts a byte-size BCD value to its decimal equivalent is indispensable. Implement the function,
    uint8_t bcd2dec(uint8_t bcd)
    And, as is usually the case, you'll need the complementary function, so implement,
    uint8_t dec2bcd(uint8_t dec)
  9. C's printf() function (and String variant, sprintf() ) facilitate readable output. Review their use.
  10. Implement a loop that will acquire the seconds from the RTC and report them continuously as show in the Serial Monitor screen capture (below left), using the sprintf() function.
  11. Adafruit's DS1307RTC library example sketch, ReadTest, yields the results below right. Duplicate this result, precisely, using only Wire level calls exclusively (no DS1307RTC library usage). Exploit maximum use of C's sprintf() function in the process.