/*
WOW! Works great and much easier to program using shift registers!
Nine pins to control hours, minutes and seconds. Leaves three pins plus
analog pins for AM/PM or day of week indicator lights.
*/
#include <Wire.h>
#define DS1307_ADDR 0x68
/* - - - - - - - - - -
Two ways to enter time and date.
1. Set a value for each item, then compile and upload at the 'set value' time.
2. Use __TIME__ to obtain the values from the system clock at time of compile.
*/
// dayofWeek 1,Monday 2,Tuesday 3,Wednesday 4,Thursday 5,Friday 6,Saturday 7,Sunday
uint8_t day = 6, date = 28, month = 12;
char time[] = __TIME__;
int UTC = atoi(&time[0]); // does not obtain hours from computer clock
int hours = UTC - 6; // UTC (GMT: 0) -> CST (GMT: -6)
int minutes = atoi(&time[3]);
int seconds = atoi(&time[6]);
int year = 24;
uint8_t hour; // AM or PM hour
uint8_t hoursAMPM;
uint8_t sLSB;
uint8_t sMSB;
uint8_t sVal;
uint8_t mLSB;
uint8_t mMSB;
uint8_t mVal;
uint8_t hLSB;
uint8_t hMSB;
uint8_t hVal;
// in this sketch, AM-PM is not used
bool isPM = false; // 0x02 Hour regester, Bit 5 is set low(0) for AM and set high(1) for PM
bool is12HourMode;
const int sClockPin = 13;
const int sLatchPin = 12;
const int sDataPin = 11;
const int mClockPin = 10;
const int mLatchPin = 9;
const int mDataPin = 8;
const int hClockPin = 7;
const int hLatchPin = 6;
const int hDataPin = 5;
void setup() {
Serial.begin(115200);
Wire.begin();
pinMode(sClockPin, OUTPUT);
pinMode(sLatchPin, OUTPUT);
pinMode(sDataPin, OUTPUT);
pinMode(mClockPin, OUTPUT);
pinMode(mLatchPin, OUTPUT);
pinMode(mDataPin, OUTPUT);
pinMode(hClockPin, OUTPUT);
pinMode(hLatchPin, OUTPUT);
pinMode(hDataPin, OUTPUT);
// - - - Wokwi DS1307 doesn't work with 12 hour mode - - -
hoursAMPM = dectoBcd(hours); // 1st: set the hour, in this example 11 or (0001 + 0001) in BCD
Serial.print("24hr mode: "); Serial.println(hoursAMPM, BIN);
// 2nd: Set the DS3231 12-hour format bit settings
// 0x02 Hour address, Bit 6 is set high(1) for 12 hour format or set low(0) for 24 hour format
// - - - In this sketch, 12 hour mode is not selected - - -
hoursAMPM = hoursAMPM | 0b00000000; // OR's 00010001 | 00000000 = (0001 + 0001)
// 3rd: Is PM set to 'true'?
// - - - In this sketch, AM-PM is not used - - -
if (isPM) { // Bit 5 set high in 12 hour mode = PM
hoursAMPM = hoursAMPM | 0b00000000; // OR's 01010001 | 00000000 = (0101 + 0001)
Serial.print(hoursAMPM, BIN);
}
// Set-Time by writing to DS3231
Wire.beginTransmission(DS1307_ADDR); // start communication using DS3231 hex address
Wire.write(0x00); // write to register address 0x00 the seconds register
Wire.write(dectoBcd(seconds)); // write seconds in BCD format, 0100(MSB) and 0111(LSB)
Wire.write(dectoBcd(minutes));
Wire.write(hoursAMPM); // Has already been converted to dectoBcd
Wire.write(dectoBcd(day));
Wire.write(dectoBcd(date));
Wire.write(dectoBcd(month));
Wire.write(dectoBcd(year));
Wire.endTransmission();
}
void loop() {
Wire.beginTransmission(DS1307_ADDR);
Wire.write(0); // Start reading from address 0 (seconds)
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDR, 7); // Request seconds, minutes, hours, day, date, month, year
if (Wire.available()) { // Also works when 'if' statement removed
seconds = bcdToDec(Wire.read() & 0x7F); // Mask the high bit of seconds
minutes = bcdToDec(Wire.read() & 0x7F);
hoursAMPM = Wire.read();
is12HourMode = hoursAMPM & 0x40; // Check if DS3231 is in 12-hour mode
if (is12HourMode) {
Serial.println("12-hour");
isPM = hoursAMPM & 0x20; // Check if it's PM
hour = bcdToDec(hoursAMPM & 0x1F); // Mask the high three bits for 12-hour mode
}
else {
Serial.println("24-hour");
hour = bcdToDec(hoursAMPM & 0x3F); // 24-hour mode, mask the high two bits
}
day = bcdToDec(Wire.read());
date = bcdToDec(Wire.read());
month = bcdToDec(Wire.read());
year = 2000 + bcdToDec(Wire.read());
sLSB = seconds % 10; // returns last digit of seconds
sMSB = seconds / 10 << 4; // returns first digit of seconds and shifts left 4 places
sVal = sMSB | sLSB; // using 'OR' returns value, 47 = 01000000 | 00000111 = 0100 0111
mLSB = minutes % 10;
mMSB = minutes / 10 << 4;
mVal = mLSB | mMSB;
hLSB = hour % 10;
hMSB = hour / 10 << 4;
hVal = hLSB | hMSB;
// Seconds shift register output
digitalWrite(sLatchPin, LOW);
shiftOut(sDataPin, sClockPin, MSBFIRST, sVal); // this commands dataPin to sync with clockPin, send most significant bit first.
digitalWrite(sLatchPin, HIGH);
// Minutes shift register output
digitalWrite(mLatchPin, LOW);
shiftOut(mDataPin, mClockPin, MSBFIRST, mVal); // this commands dataPin to sync with clockPin, send most significant bit first.
digitalWrite(mLatchPin, HIGH);
// Hours shift register output
digitalWrite(hLatchPin, LOW);
shiftOut(hDataPin, hClockPin, MSBFIRST, hVal); // this commands dataPin to sync with clockPin, send most significant bit first.
digitalWrite(hLatchPin, HIGH);
// Print to Serial Monitor
Serial.print("Time: ");
Serial.print(hour);
Serial.print("-");
Serial.print(hVal, BIN);
Serial.print(": ");
if (minutes < 10) Serial.print("0");
Serial.print(minutes);
Serial.print("-");
Serial.print(mVal, BIN);
Serial.print(": ");
if (seconds < 10) Serial.print("0"); // Add a '0' to seconds
Serial.print(seconds);
Serial.print("-");
Serial.print(sVal, BIN);
Serial.print(is12HourMode ? (isPM ? " PM" : " AM") : ""); // Empty string if in 24-hour mode
Serial.println();
}
delay(500);
}
// - - - - FUNCTIONS - - - -
byte bcdToDec(byte val) {
return ((val / 16 * 10) + (val % 16));
}
byte dectoBcd(byte val) {
return ((val / 10 * 16) + (val % 10)); // This works the same as below
//return ((val / 10 << 4) + (val % 10)); // This works the same as above
}
String dayOfWeekToStr(byte dayOfWeek) {
switch (dayOfWeek) {
case 1: return "Monday ";
case 2: return "Tuesday ";
case 3: return "Wednesday";
case 4: return "Thursday ";
case 5: return "Friday ";
case 6: return "Saturday ";
case 7: return "Sunday ";
default: return "Err ";
}
}