Arduino Wiring Code to Set & Modify DS3231
/*
* Utility to set/modify DS3231 RTC I2C module using Arduino LCD keypad shield
* By Mike Seiler, MSEE
* This will also ALMOST work with DS1307. The year is off by a century.
*/
#include <Wire.h>
#include “ds3231.h”
#include <LiquidCrystal.h>
#define BUFF_MAX 128
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
#define YES 1
#define NO 0
uint8_t time[8]; // time array for DS3231
unsigned long prev, interval = 500; // only refresh display every half second
byte attrib_select = 0; // count of which time attribute to modify
byte debounce = YES; // make sure to only process button press once
int isLeapYear; // leap year flag for calculating month
LiquidCrystal lcd(8,9,4,5,6,7); // intialize LCD
void setup()
{
Wire.begin(); // for communicating with DS3231
DS3231_init(DS3231_INTCN); // intialize DS3231
lcd.begin(16, 2); // intialize LCD
lcd.clear();
lcd.cursor();
lcd.setCursor(0,1);
}
void loop()
{
unsigned long now = millis();
unsigned int button_value;
struct ts t;
// show time once in a while
if (now – prev > interval) {
DS3231_get(&t); //Get time
isLeapYear = t.year % 4; // leap year calculation need for day of month calc.
// display the time – essentially a long format statment
lcd.clear();
lcd.setCursor(0,0);
printMonth(t.mon);
lcd.print(t.mday);
lcd.print(” “);
lcd.print(t.year);
lcd.setCursor(14,0);
lcd.print(t.wday); //day of week
lcd.setCursor(0,1); //Go to second line of the LCD Screen
lcd.print(t.hour);
lcd.print(“:”);
if(t.min<10)
{
lcd.print(“0”);
}
lcd.print(t.min);
lcd.print(“:”);
if(t.sec<10)
{
lcd.print(“0”);
}
lcd.print(t.sec);
prev = now;
}
button_value = read_LCD_buttons(); // see if a button is pressed
if (button_value == btnNONE) debounce = YES; // only process a button press once
if (debounce == YES) {
button_value = read_LCD_buttons();
if (button_value == btnRIGHT) {attrib_select++ ; debounce = NO;}
if (button_value == btnLEFT) {attrib_select– ; debounce = NO;}
if (button_value == btnUP) {inc_value(attrib_select); debounce = NO;}
if (button_value == btnDOWN) {dec_value(attrib_select); debounce = NO;}
if (button_value == btnSELECT) debounce = NO;
}
// print which time attribute is currently being modified
lcd.setCursor(10,1);
switch(attrib_select){
case 0:
lcd.print(“Year “);
break;
case 1:
lcd.print(“Month “);
break;
case 2:
lcd.print(“Day “);
break;
case 3:
lcd.print(“Hour “);
break;
case 4:
lcd.print(“Minute”);
break;
case 5:
lcd.print(“Second”);
break;
default:
attrib_select =0; // keep value from getting out of bounds
break;
}
}
// increment the selected time attribute
void inc_value(unsigned short time_attrib)
{
struct ts t;
int daysInMonth;
switch(attrib_select){
case 0: //year
DS3231_get(&t); //Get time
t.year ++;
DS3231_set(t); //Set new time
break;
case 1: //month
DS3231_get(&t); //Get time
t.mon ++; if (t.mon>12) t.mon=1;
DS3231_set(t); //Set new time
break;
case 2:
DS3231_get(&t); //Get time
t.mday ++;
daysInMonth = 31 – ((t.mon == 2) ? (3 – isLeapYear) : ((t.mon – 1) % 7 % 2));
if (t.mday > daysInMonth) t.mday = 1;
DS3231_set(t); //Set new time
break;
case 3: //hour
DS3231_get(&t); //Get time
t.hour ++; if (t.hour>24) t.hour =0;
DS3231_set(t); //Set new time
break;
case 4: // minute
DS3231_get(&t); //Get time
t.min ++; if (t.min > 59) t.min =0;
DS3231_set(t); //Set new time
break;
case 5: // second
DS3231_get(&t); //Get time
t.sec ++; if (t.sec > 59) t.sec =0;
DS3231_set(t); //Set new time
break;
default:
lcd.print(“Error “);
break;
}
t.wday=DayOfWeek(t.year,t.mon,t.mday); // calculate the day of the week
DS3231_set(t);
}
// decrement the selected time attribute
void dec_value(unsigned short time_attrib)
{
struct ts t;
switch(attrib_select){
case 0: //year
DS3231_get(&t); //Get time
t.year –;
DS3231_set(t); //Set new time
break;
case 1: //month
DS3231_get(&t); //Get time
t.mon –; if (t.mon <1) t.mon = 12;
DS3231_set(t); //Set new time
break;
case 2: // calender day
DS3231_get(&t); //Get time
t.mday –; if (t.mday <1) t.mday = 31 – ((t.mon == 2) ? (3 – isLeapYear) : ((t.mon – 1) % 7 % 2));
DS3231_set(t); //Set new time
break;
case 3: //hour
DS3231_get(&t); //Get time
t.hour –; if (t.hour <0) t.hour = 0;
DS3231_set(t); //Set new time
break;
case 4: // minute
DS3231_get(&t); //Get time
t.min –; if (t.min <0) t.min = 0;
DS3231_set(t); //Set new time
break;
case 5: // second
DS3231_get(&t); //Get time
t.sec –; if (t.sec <0) t.sec = 0;
DS3231_set(t); //Set new time
break;
default:
lcd.print(“Error “);
break;
}
t.wday=DayOfWeek(t.year,t.mon,t.mday); // calculate the day of the week
DS3231_set(t);
}
// interace to RTC
void parse_cmd(char *cmd, int cmdsize)
{
uint8_t i;
uint8_t reg_val;
char buff[BUFF_MAX];
struct ts t;
if (cmd[0] == 84 && cmdsize == 16) {
//T355720619112011
t.sec = inp2toi(cmd, 1);
t.min = inp2toi(cmd, 3);
t.hour = inp2toi(cmd, 5);
t.wday = inp2toi(cmd, 7);
t.mday = inp2toi(cmd, 8);
t.mon = inp2toi(cmd, 10);
t.year = inp2toi(cmd, 12) * 100 + inp2toi(cmd, 14);
DS3231_set(t);
} else if (cmd[0] == 49 && cmdsize == 1) { // “1” get alarm 1
DS3231_get_a1(&buff[0], 59);
} else if (cmd[0] == 50 && cmdsize == 1) { // “2” get alarm 1
DS3231_get_a2(&buff[0], 59);
} else if (cmd[0] == 51 && cmdsize == 1) { // “3” get aging register
} else if (cmd[0] == 65 && cmdsize == 9) { // “A” set alarm 1
DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);
//ASSMMHHDD
for (i = 0; i < 4; i++) {
time[i] = (cmd[2 * i + 1] – 48) * 10 + cmd[2 * i + 2] – 48; // ss, mm, hh, dd
}
byte flags[5] = { 0, 0, 0, 0, 0 };
DS3231_set_a1(time[0], time[1], time[2], time[3], flags);
DS3231_get_a1(&buff[0], 59);
} else if (cmd[0] == 66 && cmdsize == 7) { // “B” Set Alarm 2
DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);
//BMMHHDD
for (i = 0; i < 4; i++) {
time[i] = (cmd[2 * i + 1] – 48) * 10 + cmd[2 * i + 2] – 48; // mm, hh, dd
}
byte flags[5] = { 0, 0, 0, 0, 0 };
DS3231_set_a2(time[0], time[1], time[2], flags);
DS3231_get_a2(&buff[0], 59);
} else if (cmd[0] == 67 && cmdsize == 1) { // “C” – get temperature register
} else if (cmd[0] == 68 && cmdsize == 1) { // “D” – reset status register alarm flags
reg_val = DS3231_get_sreg();
reg_val &= B11111100;
DS3231_set_sreg(reg_val);
} else if (cmd[0] == 70 && cmdsize == 1) { // “F” – custom fct
reg_val = DS3231_get_addr(0x5);
} else if (cmd[0] == 71 && cmdsize == 1) { // “G” – set aging status register
DS3231_set_aging(0);
} else if (cmd[0] == 83 && cmdsize == 1) { // “S” – get status register
} else {
}
}
// Implementation of day of week due to Tomohiko Sakamoto
byte DayOfWeek(int y, byte m, byte d) { // y > 1752, 1 <= m <= 12
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
return ((y + y/4 – y/100 + y/400 + t[m-1] + d) % 7) + 1; // 01 – 07, 01 = Sunday
}
void printMonth(int month)
{
switch(month)
{
case 1: lcd.print(“Jan. “);break;
case 2: lcd.print(“Feb. “);break;
case 3: lcd.print(“March “);break;
case 4: lcd.print(“April “);break;
case 5: lcd.print(“May “);break;
case 6: lcd.print(“June “);break;
case 7: lcd.print(“July “);break;
case 8: lcd.print(“Aug. “);break;
case 9: lcd.print(“Sept. “);break;
case 10: lcd.print(“Oct. “);break;
case 11: lcd.print(“Nov. “);break;
case 12: lcd.print(“Dec. “);break;
default: lcd.print(“Error “);break;
}
}
// read the 5 buttons
int read_LCD_buttons()
{
unsigned int adc_key_in;
adc_key_in = analogRead(0); // read the value from the sensor
// my buttons when read are centered at these valies: 0, 144, 329, 504, 741
// we add approx 50 to those values and check to see if we are close
if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE; // when all others fail, return this…
}