Hackster is hosting Hackster Holidays, Finale: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Tuesday!Stream Hackster Holidays, Finale on Tuesday!
frenchy22
Published © GPL3+

Graphical tide clock

This tide clock will help you organize your seaside activities.

IntermediateFull instructions provided2 hours198
Graphical tide clock

Things used in this project

Hardware components

Arduino Nano Every
Arduino Nano Every
×1
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
×1
voltage translator
×1
RTC module DS1302
×1
Omron Electronic Components LLC pushbutton 6mm
×4
Solderless Breadboard Full Size
Solderless Breadboard Full Size
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Tide clock schematics

Code

Tide clock

C/C++
Adapt line 12 to your own OLED display
/********** Tide Clock **********/

/* If you do not want the moon phase display,
   comment or suppress the next line */
#define moonDisplayActive

#include <U8g2lib.h>
#include <RTClib.h>
#include <Fsm.h>
#include <EEPROM.h>

U8G2_SSD1306_128X64_NONAME_F_HW_I2C
  u8g2(U8G2_R0);

int displayWidth, displayHeight;
int HMiddle, VMiddle;

const int plusButtonPin=2;
const int minusButtonPin=3;
const int modeButtonPin=4;
const int selectButtonPin=5;
const int RTC_CLK=8;
const int RTC_DAT=7;
const int RTC_RST=6;

DS1302 rtc(RTC_RST, RTC_CLK, RTC_DAT);

unsigned long tideSeconds=0;
const unsigned long tidePeriod=44714;
/* Number of seconds of the moon
   half period i. e. 12 h 25 mn 14 s */

DateTime current;
DateTime highTideRef;
int year, month, day, hour, minute;

enum
{
  EEPROMId0,
  EEPROMId1,
  EEPROMId2,
  EEPROMYear,
  EEPROMMonth,
  EEPROMDay,
  EEPROMHour,
  EEPROMMinute
};

enum
{
  selYear, selMonth, selDay,
  selHour, selMinute
};
int selected;

bool plusPressed=false,
     minusPressed=false,
     buttonPressed=false;
volatile bool modePressed=false,
              selectPressed=false;

/*
   Objects of the class stopWatch are used to
   perform time dependant actions without
   blocking the program by delay functions.
*/
class stopWatch
{
  unsigned long previousTime, currentTime;
  public :
  unsigned long elapsed;
  void init();
  void now();
  stopWatch();  
};

void stopWatch::init()
{
  currentTime=millis();
  previousTime=currentTime;
}

void stopWatch::now()
{
   currentTime=millis();
  if (currentTime<previousTime)
    elapsed=0xFFFFFFFFul-previousTime+
              currentTime;
  else 
    elapsed=currentTime-previousTime;
}

stopWatch::stopWatch()
{
  currentTime=millis();
  previousTime=currentTime;
}

/***** Functions to manage pushbuttons *******/

/*
   The Mode and Select pushbuttons are treated
   by interrupts because they are used by
   single presses.
   The + and - pushbuttons are treated by
   program because they can be held down to
   repeat their actions.
*/
void interruptRoutineReadMode(void)
{
  noInterrupts();
  delayMicroseconds(10000);
  if(digitalRead(modeButtonPin)==LOW)
    modePressed=true;
  interrupts();
}

void interruptRoutineReadSelect(void)
{
  noInterrupts();
  delayMicroseconds(10000);
  if(digitalRead(selectButtonPin)==LOW)
    selectPressed=true;
  interrupts();
}

void buttonsManagement(void)
{  
  const int debounce=20;
  const int repeatPeriod=300;
  const int beginRepeatTime=1000;
  static stopWatch plusButtonStopWatch,
                   minusButtonStopWatch;
  static stopWatch plusRepeatStopWatch,
                   minusRepeatStopWatch;
  int plusButton, minusButton;
  static int nbPlusButton=0,
             nbMinusButton=0;

  plusButton=digitalRead(plusButtonPin);
  minusButton=digitalRead(minusButtonPin);

  if(plusButton==HIGH)
  {
    plusButtonStopWatch.init();
    nbPlusButton=0;
  }
  else
  {
    plusButtonStopWatch.now();
    switch(nbPlusButton)
    {
      case 0 :
        if(plusButtonStopWatch.elapsed>
             debounce)
        {
          plusPressed=true;
          buttonPressed=true;
          nbPlusButton=1;
        }
        break;
      case 1 :
        if(plusButtonStopWatch.elapsed>
             beginRepeatTime)
        {
          plusPressed=true;
          nbPlusButton=2;
          plusRepeatStopWatch.init();
        }
        break;
      default :
        plusRepeatStopWatch.now();
        if(plusRepeatStopWatch.elapsed>
             repeatPeriod)
        {
          plusPressed=true;
          plusRepeatStopWatch.init();
        }
        break;
    }    
  }
    
  if(minusButton==HIGH)
  {
    minusButtonStopWatch.init();
    nbMinusButton=0;
  }
  else
  {
    minusButtonStopWatch.now();
    switch(nbMinusButton)
    {
      case 0 :
        if(minusButtonStopWatch.elapsed>
             debounce)
        {
          minusPressed=true;
          buttonPressed=true;
          nbMinusButton=1;
        }
        break;
      case 1 :
        if(minusButtonStopWatch.elapsed>
             beginRepeatTime)
        {
          minusPressed=true;
          nbMinusButton=2;
          minusRepeatStopWatch.init();
        }
        break;
      default :
        minusRepeatStopWatch.now();
        if(minusRepeatStopWatch.elapsed>
             repeatPeriod)
        {
          minusPressed=true;
          minusRepeatStopWatch.init();
        }
        break;
    }    
  } 
}

/********* Display functions *********/

/*
  Display of round tide clock
*/
void backgroundDisplay(void)
{
  float angle, arrowAngle;
  float radius;
  int leftRight;
  
// Central dot:
  u8g2.drawDisc(HMiddle, VMiddle, 1);

// Graduations:
  radius=min(displayWidth, displayHeight)/2-1;
  for(int i=0; i<12; i++)
  {
    angle=PI/6*i;
    u8g2.drawLine(HMiddle+radius*sin(angle),
                VMiddle-radius*cos(angle),
                HMiddle+(radius-4)*sin(angle),
                VMiddle-(radius-4)*cos(angle));
  }

/* Arrow to show the rotation direction. It is
   drawn on the opposite side of the hand: */
  radius=min(displayWidth, displayHeight)*0.24;
  if(tideSeconds>tidePeriod/2)
    leftRight=1;
  else
    leftRight=-1;
  for(int i=-10; i<=10; i++)
  {
    u8g2.drawPixel(HMiddle+
         radius*sin(leftRight*PI/2+i*PI/80),
               VMiddle-
         radius*cos(leftRight*PI/2+i*PI/80));
  }
  arrowAngle=leftRight*PI/2+PI/8;
  u8g2.drawLine(HMiddle+radius*sin(arrowAngle),
                VMiddle-radius*cos(arrowAngle),
                HMiddle+radius*sin(arrowAngle)+
                  leftRight*4,
                VMiddle-radius*cos(arrowAngle)-
                  leftRight*2);
  u8g2.drawLine(HMiddle+radius*sin(arrowAngle),
                VMiddle-radius*cos(arrowAngle),
                HMiddle+radius*sin(arrowAngle)-
                  leftRight*2,
                VMiddle-radius*cos(arrowAngle)-
                  leftRight*3);

// Texts "high" and "low":
  u8g2.setFont(u8g2_font_5x7_mf);
  u8g2.setCursor(HMiddle-
                 u8g2.getStrWidth("high")/2,
                 15);
  u8g2.print("high");
  u8g2.setCursor(HMiddle-
                 u8g2.getStrWidth("low")/2,
                 displayHeight-9);
  u8g2.print("low");
}

void handDisplay(void)
{
  float handAngle;
  int handLength=min(HMiddle, VMiddle)-8;

  handAngle=2*PI*tideSeconds/tidePeriod;
  u8g2.drawCircle(HMiddle+sin(handAngle)*6,
                VMiddle-cos(handAngle)*6, 4);
  u8g2.drawCircle(HMiddle+sin(handAngle)*13,
                VMiddle-cos(handAngle)*13, 2);
  u8g2.drawLine(HMiddle+sin(handAngle)*16,
            VMiddle-cos(handAngle)*16,
            HMiddle+sin(handAngle)*handLength,
            VMiddle-cos(handAngle)*handLength);
}

void tideClockDisplay(void)
{
  current=rtc.now();
  tideSeconds=(current.unixtime()-
                 highTideRef.unixtime())%
                 tidePeriod;
  u8g2.clearBuffer();
  backgroundDisplay();
  handDisplay();
  u8g2.sendBuffer();
  Serial.println(tideSeconds);
}

/*
  Display of daily tide. A sine curve shows
  the evolution of the tide along the current
  day, and a vertical line shows the tide
  at the current time.
*/
void dayTideDisplay(void)
{
  current=rtc.now();
  DateTime currentDay(current.year(),
                      current.month(),
                      current.day(),
                      0, 0, 0);

/* Rounded display width and offset are used
   to display the daily clock on a reduced
   and centered screen in order to have
   regular hour graduations.   
 */
  int rdDisplayWidth=24*(displayWidth/24);
  int offs=(displayWidth-rdDisplayWidth)/2;

  u8g2.clearBuffer();
// Sinus curve:
  for(int i=0; i<rdDisplayWidth; i++)
  {
    tideSeconds=((currentDay+((long)i*86400/
                  rdDisplayWidth)).unixtime()-
                  highTideRef.unixtime())%
                  tidePeriod;
    u8g2.drawPixel(i+offs, 
        (1-cos(2*PI*tideSeconds/tidePeriod))*
           (displayHeight-15)/2);
  }

// Vertical line:
  int x=((long)rdDisplayWidth*
              ((current.hour()*60+
               current.minute())))/1440+offs;
  for(int i=0; i<displayHeight-15; i++)
    u8g2.drawPixel(x, i);

// Time indications:    
  u8g2.setFont(u8g2_font_5x7_mf);
  u8g2.setCursor(rdDisplayWidth/6-
                 u8g2.getStrWidth("4h")/2+
                   offs,
                 displayHeight);
  u8g2.print("4h");
  u8g2.setCursor(rdDisplayWidth/2-
                 u8g2.getStrWidth("12h")/2+
                   offs,
                 displayHeight);
  u8g2.print("12h");
  u8g2.setCursor(rdDisplayWidth*5/6-
                 u8g2.getStrWidth("20h")/2+
                   offs,
                 displayHeight);
  u8g2.print("20h");
  for(int i=0; i<24; i++)
    u8g2. drawLine(i*rdDisplayWidth/24+offs,
                   displayHeight-9,
                   i*rdDisplayWidth/24+offs,
                   displayHeight-11);
  for(int i=4; i<24; i+=8)
    u8g2.drawPixel(i*rdDisplayWidth/24+offs,
                   displayHeight-12);
  
  u8g2.sendBuffer();
}

void myDrawDisc(int xCenter, int yCenter,
                int R)
{
  for(int x=0; x<displayWidth; x++)
    for(int y=0; y<displayHeight; y++)
      if(((long)x-(long)xCenter)*
         ((long)x-(long)xCenter)+
         ((long)y-(long)yCenter)*
         ((long)y-(long)yCenter)<=
         (long)R*(long)R)
         u8g2.drawPixel(x, y);
}

/* Moon display */
void moonDisplay()
{
/* first new moon since 01/01/2000 */
  DateTime orgNewMoon(2000, 1, 6, 18, 14, 0);
/* Moon period : 29 days, 12 hours,
                 44 minutes, 2,9 seconds 
                 ie 2551443 seconds*/
  const unsigned long moonPeriod=2551443;
  unsigned long moonSeconds, moonPixelsDelay;
  int moonRadius=min(displayWidth,
                     displayHeight)/2-2;
  int shadowRadius;
  int shadowDistance; //from moon center

  current=rtc.now();
  moonSeconds=(current.unixtime()-
               orgNewMoon.unixtime())%
               moonPeriod;
  moonPixelsDelay=4*moonRadius*moonSeconds/
                    moonPeriod;
  u8g2.clearBuffer();

  if(moonPixelsDelay<=moonRadius)
  // new moon -> first quarter
  {
    u8g2.setDrawColor(1);
    shadowDistance=moonRadius-moonPixelsDelay;
    shadowRadius=moonRadius/
             sin(PI-2*atan2(moonRadius, 
                            shadowDistance));
    u8g2.drawDisc(HMiddle, VMiddle,
                      moonRadius);
    u8g2.setDrawColor(0);
    if(shadowDistance>0)
      myDrawDisc(HMiddle+shadowDistance-
                     shadowRadius, VMiddle,
                     shadowRadius);
    else
      u8g2.drawBox(0, 0, displayWidth/2,
                         displayHeight); 
  }

  else if(moonPixelsDelay<=2*moonRadius)
  // first quarter -> full moon
  {
    u8g2.setDrawColor(1);
    shadowDistance=moonPixelsDelay-moonRadius;
    shadowRadius=moonRadius/
             sin(PI-2*atan2(moonRadius, 
                            shadowDistance));
    if(shadowDistance>0)
    {
      myDrawDisc(HMiddle-shadowDistance+
                     shadowRadius, VMiddle,
                     shadowRadius);
      u8g2.setDrawColor(0);
      for(int x=0; x<displayWidth; x++)
        for(int y=0; y<displayHeight; y++)
          if((x-HMiddle)*(x-HMiddle)+
             (y-VMiddle)*(y-VMiddle)>
             moonRadius*moonRadius)
            u8g2.drawPixel(x,y);     
    }
    else
      u8g2.drawDisc(HMiddle, VMiddle,
                      moonRadius,
                      U8G2_DRAW_UPPER_RIGHT |
                      U8G2_DRAW_LOWER_RIGHT); 
  }

  else if(moonPixelsDelay<=3*moonRadius)
  // full moon -> last quarter
  {
    u8g2.setDrawColor(1);
    shadowDistance=3*moonRadius-
                   moonPixelsDelay;
    shadowRadius=moonRadius/
             sin(PI-2*atan2(moonRadius, 
                            shadowDistance));
    if(shadowDistance>0)
    {
      myDrawDisc(HMiddle+shadowDistance-
                     shadowRadius, VMiddle,
                     shadowRadius);
      u8g2.setDrawColor(0);
      for(int x=0; x<displayWidth; x++)
        for(int y=0; y<displayHeight; y++)
          if((x-HMiddle)*(x-HMiddle)+
             (y-VMiddle)*(y-VMiddle)>
             moonRadius*moonRadius)
            u8g2.drawPixel(x,y);
    }
    else
      u8g2.drawDisc(HMiddle, VMiddle,
                      moonRadius,
                      U8G2_DRAW_UPPER_LEFT |
                      U8G2_DRAW_LOWER_LEFT);
  }

  else
  // last quarter -> new moon
  {
    u8g2.setDrawColor(1);
    shadowDistance=moonPixelsDelay-
                     3*moonRadius;
    shadowRadius=moonRadius/
             sin(PI-2*atan2(moonRadius, 
                            shadowDistance));
    u8g2.drawDisc(HMiddle, VMiddle,
                    moonRadius);
    u8g2.setDrawColor(0);
    if(shadowDistance>0)
      myDrawDisc(HMiddle-shadowDistance+
                     shadowRadius, VMiddle,
                     shadowRadius);
    else
      u8g2.drawBox(HMiddle, 0,
             displayWidth/2, displayHeight); 
  }
  u8g2.setDrawColor(1);
  u8g2.drawCircle(HMiddle, VMiddle, 
                  moonRadius);
  u8g2.sendBuffer();                          
}

/*
  This function is used to display the date
  and the time for the current time and for
  the reference high tide time. One of the
  5 displayed values is highlighted, the one
  that is selected.
*/
void dateTimeAdjustDisplay(void)
{  
  u8g2.setFont(u8g2_font_9x15_mf);
  u8g2.setCursor(
  (displayWidth-u8g2.getStrWidth
                ("2021/07/26"))/2, 37);
  u8g2.setDrawColor(1);
  if(selected==selYear) u8g2.setDrawColor(0);
  u8g2.print(year);
  u8g2.setDrawColor(1);
  u8g2.print("/");
  if(selected==selMonth) u8g2.setDrawColor(0);
  if(month<10) u8g2.print("0");
  u8g2.print(month);
  u8g2.setDrawColor(1);
  u8g2.print("/");
  if(selected==selDay) u8g2.setDrawColor(0);
  if(day<10) u8g2.print("0");
  u8g2.print(day);
  u8g2.setDrawColor(1);
  u8g2.setCursor(
    (displayWidth-u8g2.getStrWidth
                  ("08:39"))/2, 60);
  if(selected==selHour) u8g2.setDrawColor(0);
  if(hour<10) u8g2.print("0");
  u8g2.print(hour);
  u8g2.setDrawColor(1);
  u8g2.print(":");
  if(selected==selMinute) u8g2.setDrawColor(0);
  if(minute<10) u8g2.print("0");
  u8g2.print(minute);
  u8g2.setDrawColor(1);
}

void currentTimeDisplay(void)
{
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_7x13_mf);
  u8g2.setCursor(
    (displayWidth-u8g2.getStrWidth
                  ("Current time"))/2, 13);
  u8g2.print("Current time");
  dateTimeAdjustDisplay();
  u8g2.sendBuffer();  
}

void highTideRefDisplay(void)
{
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_7x13_mf);
  u8g2.setCursor(
    (displayWidth-u8g2.getStrWidth
                  ("Ref. high tide"))/2, 13);
  u8g2.print("Ref. high tide");
  dateTimeAdjustDisplay();
  u8g2.sendBuffer();  
}

/*
  This function is called to adjust the 5
  values of the current time or of the
  reference high tide time with the +/-
  pushbuttons. Several tests are made to
  prevent from displaying an impossible date
  such as february the 30th.
*/
void dateTimeAdjust(void)
{
  int numberOfDays;

  buttonsManagement();
  switch(selected)
  {
    case selYear :
      if(plusPressed && year<2100)
        year++;
      if(minusPressed && year>2000)
        year--;
      break;

    case selMonth :
      if(plusPressed)
      {
        month++;
        if(month>12) month=1;
      }
      if(minusPressed)
      {
        month--;
        if(month<1) month=12;
      }
      if(plusPressed || minusPressed)
      {
        if ((month==4 || month==6 ||
             month==9 ||month==11) &&
             day==31)
          day=30;
        if (month==2 && day>28)
          day=28;
      }      
      break;

    case selDay :
      numberOfDays=31;
      if(plusPressed) day++;
      if(minusPressed) day--;
      if(plusPressed || minusPressed)
      {
        if (month==4 || month==6 ||
            month==9 || month == 11)
          numberOfDays=30;
        if (month==2)
          if (year%4!=0 ||
              (year%100==0 && year%400!=0))
            numberOfDays=28;
          else
            numberOfDays=29;
        if(day<1) day=numberOfDays;
        if(day>numberOfDays) day=1;
      }
      break;

    case selHour :
      if(plusPressed) ++hour%=24;
      if(minusPressed)
        if(hour>0) hour--;
        else hour=23;
      break;

    case selMinute :
      if(plusPressed) ++minute%=60;
      if(minusPressed)
        if(minute>0) minute--;
        else minute=59;
      break;
  }
  plusPressed=false;
  minusPressed=false;
}

/*
  Functions called by the Finite State Machine
  to adjust current time and reference high
  tide time.
*/
void currentTimeSetEnter(void)
{
  selected=selYear;
  current=rtc.now();
  year=current.year();
  month=current.month();
  day=current.day();
  hour=current.hour();
  minute=current.minute();
  currentTimeDisplay();
  buttonPressed=false;
}

void currentTimeSet(void)
{
  dateTimeAdjust();
  currentTimeDisplay();  
}

void currentTimeSetExit(void)
{
/* The RTC is set to the displayed time only
   if the + or - pushbutton has been pressed.
   Otherwise, the RTC is still up to date.
*/
  if(buttonPressed)
    rtc.adjust(DateTime(year, month, day,
               hour, minute, 0));
}

void highTideRefSetEnter(void)
{
  selected=selYear;
  year=highTideRef.year();
  month=highTideRef.month();
  day=highTideRef.day();
  hour=highTideRef.hour();
  minute=highTideRef.minute();
  highTideRefDisplay();
}

void highTideRefSet(void)
{
  dateTimeAdjust();
  highTideRefDisplay();
}

void highTideRefSetExit(void)
{
  highTideRef.setyear(year);
  highTideRef.setmonth(month);
  highTideRef.setday(day);
  highTideRef.sethour(hour);
  highTideRef.setminute(minute);
  highTideRef.setsecond(0);

  EEPROM.update(EEPROMYear, year%100);
  EEPROM.update(EEPROMMonth, month);
  EEPROM.update(EEPROMDay, day);
  EEPROM.update(EEPROMHour, hour);
  EEPROM.update(EEPROMMinute, minute);
}

void readEEPROM(void)
{
  if(EEPROM.read(EEPROMId0)==byte('t') &&
     EEPROM.read(EEPROMId1)==byte('i') &&
     EEPROM.read(EEPROMId2)==byte('d'))
  {
    highTideRef.setyear(EEPROM.read
                         (EEPROMYear));
    highTideRef.setmonth(EEPROM.read
                         (EEPROMMonth));
    highTideRef.setday(EEPROM.read
                         (EEPROMDay));
    highTideRef.sethour(EEPROM.read
                         (EEPROMHour));
    highTideRef.setminute(EEPROM.read
                         (EEPROMMinute));
  }
  else
  {
    EEPROM.update(EEPROMId0, 't');
    EEPROM.update(EEPROMId1, 'i');
    EEPROM.update(EEPROMId2, 'd');
    highTideRef.setyear(2021);
    EEPROM.update(EEPROMYear,
                   highTideRef.year()%100); 
    highTideRef.setmonth(7);
    EEPROM.update(EEPROMMonth,
                   highTideRef.month());
    highTideRef.setday(26);
    EEPROM.update(EEPROMDay,
                   highTideRef.day());
    highTideRef.sethour(8);
    EEPROM.update(EEPROMHour,
                   highTideRef.hour());
    highTideRef.setminute(39);
    EEPROM.update(EEPROMYear,
                   highTideRef.minute());
  }
}

/* 
   A Finite State Machine is used to navigate
   between the 5 display modes thanks to the
   Mode pushbutton.
*/
State tideClockDisplayState(&tideClockDisplay,
                            NULL, NULL);
State dayTideDisplayState(&dayTideDisplay,
                            NULL, NULL);
State moonDisplayState(&moonDisplay,
                        NULL, NULL);
State currentTimeSetState(&currentTimeSetEnter,
                          &currentTimeSet,
                          &currentTimeSetExit);
State higtTideRefSetState(&highTideRefSetEnter,
                          &highTideRefSet,
                          &highTideRefSetExit);
Fsm modeFsm(&tideClockDisplayState);

void setTransitions(void)
{
  modeFsm.add_transition(
               &tideClockDisplayState,
               &dayTideDisplayState,
               1, NULL);
#ifdef moonDisplayActive
  modeFsm.add_transition(
               &dayTideDisplayState,
               &moonDisplayState,
               1, NULL);
  modeFsm.add_transition(
               &moonDisplayState,
               &currentTimeSetState,
               1, NULL);
#else
  modeFsm.add_transition(
               &dayTideDisplayState,
               &currentTimeSetState,
               1, NULL);
#endif
  modeFsm.add_transition(
               &currentTimeSetState,
               &higtTideRefSetState,
               1, NULL);
  modeFsm.add_transition(
               &higtTideRefSetState,
               &tideClockDisplayState,
               1, NULL);

/* These two transitions are used to refresh
   the two clock displays every 10 seconds.
*/
  modeFsm.add_timed_transition(
               &tideClockDisplayState,
               &tideClockDisplayState,
               10000,
               NULL);
  modeFsm.add_timed_transition(
               &dayTideDisplayState,
               &dayTideDisplayState,
               10000,
               NULL);
  modeFsm.add_timed_transition(
               &moonDisplayState,
               &moonDisplayState,
               10000,
               NULL);
}

void setup()
{
  u8g2.begin();
  displayWidth=u8g2.getDisplayWidth();
  displayHeight=u8g2.getDisplayHeight();
  HMiddle=displayWidth/2;
  VMiddle=displayHeight/2;
  Serial.begin(9600);
  rtc.begin();
  if (!rtc.isrunning())
  {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the 
    // date & time this sketch was compiled
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }
  pinMode(plusButtonPin, INPUT_PULLUP);
  pinMode(minusButtonPin, INPUT_PULLUP);
  pinMode(modeButtonPin, INPUT_PULLUP);
  pinMode(selectButtonPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt
                   (modeButtonPin),
         interruptRoutineReadMode,FALLING);
  attachInterrupt(digitalPinToInterrupt
                   (selectButtonPin),
         interruptRoutineReadSelect, FALLING);
/*
   If Mode and Select pushbuttons are pressed
   simultaneously during power on, the
   reference high tide time is reset to
   its default value.
*/
  if(digitalRead(modeButtonPin)==LOW &&
     digitalRead(selectButtonPin)==LOW)
  {
    EEPROM.update(EEPROMId0, 0xFF);
    EEPROM.update(EEPROMId1, 0xFF);
    EEPROM.update(EEPROMId2, 0xFF);
  }
  readEEPROM();
  setTransitions();
}

void loop()
{
  int event=0;

  noInterrupts();
  if(modePressed)
  {
    event=1;
    modePressed=false;
  }
  if(selectPressed)
  {
    ++selected%=5;
    selectPressed=false; 
  }
  interrupts();
  modeFsm.run_machine();
  modeFsm.trigger(event);
}

Credits

frenchy22
6 projects • 3 followers

Comments