Digital Clock (USB Serial)

Use your idle Arduboy as a digital clock!

Clock.hex

(Doesn’t work properly in the emulator, no serial input!)

Although the Arduboy lacks a real time clock, updates are provided via the usb serial port and kept in sync once a minute. (The drift isn’t quite that bad, but it keeps it in check)

It uses the Arduino Time Library:

And uses the processing sketch contained within examples to do the updates.

If you wanted to get serious with it then making an even smaller application that lives in the tray would be a cool upgrade.

Also works nice on the XL

/*

  Clock.ino

  Demonstrates a clock-like display with a very huge font.
  Also shows usage of u8x8_u8toa().

  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)

  Copyright (c) 2016, olikraus@gmail.com
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification,
  are permitted provided that the following conditions are met:

    Redistributions of source code must retain the above copyright notice, this list
    of conditions and the following disclaimer.

    Redistributions in binary form must reproduce the above copyright notice, this
    list of conditions and the following disclaimer in the documentation and/or other
    materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#include <TimeLib.h>

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif



#define TIME_HEADER  "T"   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message 


U8G2_SSD1306_128X64_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 12, /* dc=*/ 4, /* reset=*/ 6);  // Arduboy (Production, Kickstarter Edition)

tmElements_t tm;

void setup(void) {

  u8g2.begin();
  Serial.begin(9600);
  blankClockDisplay();
  while (!Serial) ; // Needed for Leonardo only
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println("Waiting for sync message");

}

uint8_t m = 24;
int tHour, tMin, tSec;
bool PM;
bool flicker;
int dotX = 32;
int startX;
int clockY = 48;
uint8_t syncTimer = 0;
const char monthInWords[13][10] = {" ", "January", "February", "March", "April", "May", "June",
                                   "July", "August", "September", "October", "November", "December"
                                  };

void loop(void) {

  if (Serial.available()) {
    processSyncMessage();
  }
  if (timeStatus() != timeNotSet) {
    //serialClockDisplay();
    digitalClockDisplay();
  }
  else {
    blankClockDisplay();
  }

  syncTimer++;
  if (syncTimer > 60) {
    requestSync(); // update every minute
    syncTimer = 0;
  }

  delay(1000);

  flicker = !flicker;

}


void digitalClockDisplay() {

  char m_str[3];
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_logisoso32_tn);
    char buf[12];
    int fHour;
    fHour = hour();
    if (hour() > 12) {
      fHour -= 12;
      PM = true;
    }
    else if (hour() == 12) {
      PM = true;
    }
    else {
      PM = false;
    }
    if (fHour > 9) {
      startX = -7;
    }
    else {
      startX = 16;
    }

    u8g2.drawStr(startX, clockY, itoa(fHour, buf, 10));
    if (flicker) u8g2.drawStr(dotX, clockY, ":");
    char m_str[3];
    strcpy(m_str, u8x8_u8toa(minute(), 2));
    u8g2.drawStr(dotX + 8, clockY, m_str);
    u8g2.setFont(u8g2_font_logisoso16_tf );
    strcpy(m_str, u8x8_u8toa(second(), 2));
    u8g2.drawStr(dotX + 50, clockY, m_str);
    if (PM) {
      u8g2.drawStr(dotX + 74, clockY, "PM");
    }
    else {
      u8g2.drawStr(dotX + 74, clockY, "AM");
    }

    u8g2.setFont(u8g2_font_helvB08_tf);

    char dayWord[3];

    if (day() == 1) {
      strcpy(dayWord, "st");
    }
    else if (day() == 2) {
      strcpy(dayWord, "nd");
    }
    else if (day() == 3) {
      strcpy(dayWord, "rd");
    }
    else if (day() >= 4 && day() <= 20) {
      strcpy(dayWord, "th");
    }
    else if (day() == 21) {
      strcpy(dayWord, "st");
    }
    else if (day() == 22) {
      strcpy(dayWord, "nd");
    }
    else if (day() == 23) {
      strcpy(dayWord, "rd");
    }
    else if (day() >= 24 && day() <= 30) {
      strcpy(dayWord, "th");
    }
    else if (day() == 31) {
      strcpy(dayWord, "st");
    }

    char todayInWords[80];
    sprintf(todayInWords, "%s %i%s %i", monthInWords[month()], day(), dayWord, year());

    u8g2.drawStr(0, 63, todayInWords);

  } while ( u8g2.nextPage() );

}


void blankClockDisplay() {

  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_logisoso32_tn);
    char buf[12];
    int fHour;
    fHour = 12;
    PM = false;

    startX = -7;

    u8g2.drawStr(startX, clockY, "12");
    if (flicker) u8g2.drawStr(dotX, clockY, ":");

    u8g2.drawStr(dotX + 7, clockY, "00");
    u8g2.setFont(u8g2_font_logisoso16_tf );

    u8g2.drawStr(dotX + 49, clockY, "00");
    u8g2.drawStr(dotX + 73, clockY, "AM");

  } while ( u8g2.nextPage() );

}


void serialClockDisplay() {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year());
  Serial.println();
}

void printDigits(int digits) {
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}


void processSyncMessage() {
  unsigned long pctime;
  const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013
  //Serial.println("timesyncattempt");
  if (Serial.find(TIME_HEADER)) {
    pctime = Serial.parseInt();
    if ( pctime >= DEFAULT_TIME) { // check the integer is a valid time (greater than Jan 1 2013)
      setTime(pctime); // Sync Arduino clock to the time received on the serial port
      //Serial.println("timeset");
    }
  }
}

time_t requestSync()
{
  Serial.write(TIME_REQUEST);
  delay(50);
  return 0; // the time will be sent later in response to serial mesg
}
4 Likes

Very nice and it’s could be perfect if we could add a little usb dongle with a real clock to update it via usb when moving if it’s technically possible.

Hah an RTC with an SAMD21? just to update time?

Actually, I had a thought to add an RTC to the Arduboy FX but I’m afraid it’s too late and would add another month or so.

Sure but it’s could be a good add and we could have Tamagushi like and other games running on Arduboy… Have Arduboy to wakeup (Arduboy could pause and switch on to play a good little music to wake up…) :slight_smile: Else the screensaver could shown the date / time… Some game could use hour to activate some part (like Pokemons or even a city simulator with day / night activity…). It’s a gadget but we like gadgets…

If I woulda thought about it months ago then sure but it’s too late.

If you want an RTC on the Arduboy FX, then make some games that support the FX so I can do an FX SE, color the PCB fun colors and add the RTC.

1 Like

it’s a good answer and a good challenge :slight_smile: