Adventures in Engineering Trade-Offs

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…

}