DS3231 clock basic questions

I plan to build a rudimentary sprinkler controller. My first hurdle is reading the clock. Example sketches show conversion of time information (byte) to binary. What is it for? Thank you.

Example sketches

??

My apology. Here is an example sketch.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
	
#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  // set the initial time here:
  // DS3231 seconds, minutes, hours, day, date, month, year
  // setDS3231time(30,42,21,4,26,11,14);
}
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}
void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}
void displayTime()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  // send it to the serial monitor
  Serial.print(hour, DEC);
  // convert the byte variable to a decimal number when displayed
  Serial.print(":");
  if (minute<10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second<10)
  {
    Serial.print("0");
  }
  Serial.print(second, DEC);
  Serial.print(" ");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.print(" Day of week: ");
  switch(dayOfWeek){
  case 1:
    Serial.println("Sunday");
    break;
  case 2:
    Serial.println("Monday");
    break;
  case 3:
    Serial.println("Tuesday");
    break;
  case 4:
    Serial.println("Wednesday");
    break;
  case 5:
    Serial.println("Thursday");
    break;
  case 6:
    Serial.println("Friday");
    break;
  case 7:
    Serial.println("Saturday");
    break;
  }
}
void loop()
{
  displayTime(); // display the real-time clock data on the Serial Monitor,
  delay(1000); // every second
}

Please explain why the decimal-to-binary and binary-to-decimal are necessary. Thank you.

Please explain why the decimal-to-binary and binary-to-decimal are necessary.

Because the makers of the clock chip decided that binary-coded-decimal was a good idea. If you want to use the data, you need to convert it from the way that the chip delivers it to something that makes sense to you (or the Arduino). If you want the chip to use some data, you must convert the data you want it to use to the format that it expects the data to be in.

Tain't rocket science.

Thank you for the explanation.

Please explain why the decimal-to-binary and binary-to-decimal are necessary.

The time keeping registers of the DS3231 RTC maintain the time of the day in BCD format. For example: 39 seconds -- it remains as 00111001 in the SEC Register of the RTC.

Say, after 10 days we have observed that the watch has slowed down by 1-sec; our watch is showing 29 seconds instead of 30 seconds. We want to adjust it to 30 sec -- how?

Let us read the time (second) from the SEC Register; convert the BCD time into BIN time; increment the BIN time; convert BIN time back to BCD time; put back the BCD time into the SEC Register of the DS3231 RTC.

The following texts have outlines the reasons of the necessity of these inter-conversion strategy and also the procedures of implementation.

1. ==> 29 : 0010 1001 //we have read these bit pattern from SEC Register
2. ==> 29 + 1 = 0010 1001 + 1 = 0010 1010 = 2A (the MCU performs binary addition instead of BCD addition).

3. Do we want to put back 0010 1010 (2A) or 0011 0000 (30) into the SEC Register of the RTC? Of course, it is 0011 0000. But, we have got 0010 1010 after adding 1 with 29 seconds (0010 1001). Therefore, we need to convert/transform the bit pattern of 00101010 into 00110000. The following is one of the ways for the conversion:

(a) Convert the BCD formatted second (0011 1001 = 29) into normal decimal (aka natural binary)
BCDSEC = 29 = 2x10 + 9x1

BINSEC = 2x0Ah + 9x01h
= Ten Positional Factor (TPF) x Ten Positional Weight (0Ah) + UPFxUPW
= 0001 0100 + 0000 1001 = 0001 1101 = 0x1D

(b) Add 0000 0001 (1) with 0x1D (0001 1101); we get -- 0001 1110 (0x1E)
BINSEC = 0x1E (now, we have to extract 30 = 0010 0000 from here which is the desired BCD).

(c) Convert the BINSEC back into BCDSEC using modulus and division operators
Extract unitPositionDigitOfBCDSec = BCDSEC % 10 = 00000000 (0) //remainder
Extract tenPositionDgitOfBCDSec = BCDSEC = BCDSEC / 10 = 00000011 (3) //quotient

(d) Now, let us combine (a) and (b) to get 30 (0011 0000) and put it back into the SEC Register of RTC.
BCDSEC = (tenPositionDigitOfBCDSec << 4) + unitPositionDigitOfBCDSec

Went through my head like a turbo neutrino. :confused: :grin: