J Koger
Published © GPL3+

Word Clock on the O-Watch

We'll build on the Simple RTC Watch to turn our O-Watch into a Mini Word Clock, which uses an 8 x 8 grid of letters to spell out the time.

BeginnerProtip1 hour1,670
Word Clock on the O-Watch

Things used in this project

Hardware components

O Watch Base Kit
O Watch Base Kit
×1

Story

Read more

Code

simple_word_watch.ino

Arduino
Code to display a mini Word Clock using an 8 x 8 letter grid on the O-Watch
/*
 * Simple Word Watch
 *
 * Demonstrates the use of the Arduino Zero Real-Time-Clock (RTC) library to make a simple 8 x 8 'Word Clock'
 * display of the current hours and minutes.
 * 
 * This type of display only shows the current minutes (to within 5 minutes) and current hour, using a grid of 8 x 8 letters. The letters
 * needed to display the current time (for example, 'HALF PAST TEN') are 'lit up' (drawn with a bright color like yellow), and the
 * unnneeded letters are 'turned off' (drawn with a dull color like gray).
 * 
 * Since the TinyScreen is 64 pixels high, the 8 x 8 grid of letters will take up most of the display, since the
 * smallest font provided on the O-Watch is 7 pixels tall (plus 1 pixel gap between rows): (7 + 1) * 8 = 64 pixels needed 
 * to display 8 rows. That doesn't leave any room for the date, day of the week, or seconds. It's also a bit hard to read
 * since the letters are pretty, well, tiny.
 *
 * Uses Arduino Zero RTC library https://www.arduino.cc/en/Reference/RTC
 * Maintained by Arturo Guadalupi https://github.com/arduino-libraries/RTCZero
 *
 * This code is for the TinyScreen+ board by TinyCircuits used by O Watch http://tiny-circuits.com 
 *
 * This example is based on the Simple Watch code created by O Watch on 6 March 2016 http://theowatch.com
 * Modified to use RTC, to set the display brightness based on time of day, and to use __DATE__ and __TIME__
 * to preset the watch's date and time by J Koger 13 March 2016
 * 
 * Modified to display time as an 8 x 8 character 'Micro Word Clock' by J Koger 16 March 2016, using a tweaked
 * version of the code from Daniel Rojas' https://github.com/formatc1702/Micro-Word-Clock
 * 
*/

#include <TinyScreen.h> //include TinyScreen library
#include <RTCZero.h> //include the Arduino Zero's Real Time Clock library
#include <stdio.h>  // include the C++ standard IO library

/* Create an rtc object */
RTCZero rtc;

// We'll dynamically change these values to set the current initial time
// No need to change them here.
byte seconds = 0;
byte minutes = 45;
byte hours = 9;

// We'll dynamically change these values to set the current initial date
// The preset values are only examples.
byte days = 13;
byte months = 3;
byte years = 16;

int brightness = 15; // We'll set it, 3 - 15 based on time of day

TinyScreen display = TinyScreen(TinyScreenPlus); //Create the TinyScreen object

// Our colors for letters that are off and
// for letters that are lit.
#define LETTER_OFF  TS_8b_Gray
#define LETTER_LIT  TS_8b_Yellow

// This is the 8 x 8 grid of letters used to display the current time.
// We'll only 'light up' the letters needed to show the current
// time, and draw all the other ones in a 'dark' color.

char wordClock[8][9] = { 
 "HATWENTY",
 "FIFVTEEN",
 "LF*PASTO",
 "NINEIGHT",
 "ONETHREE",
 "TWELEVEN",
 "FOURFIVE",
 "SIXSEVEN"
};

// This is an array used to determine which letters should be 'lit'
// to display the current minutes (or, really, the current 5-minute
// segment. There is one grid for each segment, and since there are 12
// 5-minute segments in an hour, there are 12 grids in the array.
//
// For example, if the current time is 10:06, then it is roughly
// 5 minutes past 10. So, we'll want the letters F I V E and P A S T
// to be lit. Look in the second grid for 'five past'; it has 1's for
// each of the wanted letters and 0's for all of the unused letters.
//
// The lit/unlit letter indicators are stored as bits within bytes
// (a byte holds 8 bits). We could use a byte for each letter, but
// bits only need 1/8 the space. And it'll give us an excuse to have
// some fun with bit comparisons later on!

unsigned char letterMinutes[12][8] ={
  { // o'clock
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  , { // five past
    0B00000000,
    0B11010100,
    0B00011110,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  , { // ten past
    0B00000000,
    0B00001101,
    0B00011110,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // fifteen past
    0B00000000,
    0B11101111,
    0B00011110,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // twenty past
    0B00111111,
    0B00000000,
    0B00011110,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // twentyfive past
    0B00111111,
    0B11010100,
    0B00011110,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // half past
    0B11000000,
    0B00000000,
    0B11011110,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // twentyfive to
    0B00111111,
    0B11010100,
    0B00000011,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // twenty to
    0B00111111,
    0B00000000,
    0B00000011,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // fifteen to
    0B00000000,
    0B11101111,
    0B00000011,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // ten to
    0B00000000,
    0B00001101,
    0B00000011,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // five to
    0B00000000,
    0B11010100,
    0B00000011,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
};

// These are the corresponding
// grids to determine which letters
// should be 'lit' to show the
// current hour, 1 grid for each of
// the 12 hours.

unsigned char letterHours[12][8] ={
  { // twelve
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B11110110,
    0B00000000,
    0B00000000
  }
  ,{ // one
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B11100000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // two
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B11000000,
    0B01000000,
    0B00000000
  }
  ,{ // three
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00011111,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // four
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B11110000,
    0B00000000
  }
  ,{ // five
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00001111,
    0B00000000
  }
  ,{ // six
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B11100000
  }
  ,{ // seven
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00011111
  }
  ,{ // eight
    0B00000000,
    0B00000000,
    0B00000000,
    0B00011111,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // nine
    0B00000000,
    0B00000000,
    0B00000000,
    0B11110000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000
  }
  ,{ // ten
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000001,
    0B00000001,
    0B00000001,
    0B00000000,
    0B00000000
  }
  ,{ // eleven
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00000000,
    0B00111111,
    0B00000000,
    0B00000000
  }
};



void setup()
{
  char s_month[5];
  int tmonth, tday, tyear, thour, tminute, tsecond;
  static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

  display.begin();                            //Initializes TinyScreen board
  display.setFlip(1);                         //Flips the TinyScreen rightside up for O Watch
  display.on();                               //Turns TinyScreen display on
  display.fontColor(LETTER_OFF, TS_8b_Black); //Set the font color, font background
  display.setFont(thinPixel7_10ptFontInfo);   //Set the font type


  rtc.begin(); // initialize RTC
  
  // Set the time and date. Change this to your current date and time.
  // setTime(16,19,00,12,3,2016);    //values in the order hr,min,sec,day,month,year

  // Let's be lazy and let the compiler set the current date and time for us.
  // This will be a few seconds off due to the time it takes to compile the
  // .ino file and upload the app. But pretty close.

  // __DATE__ is a C++ preprocessor string with the current date in it.
  // It will look something like 'Mar  13  2016'.
  // So we need to pull those values out and convert the month string to a number.
  sscanf(__DATE__, "%s %d %d", s_month, &tday, &tyear);

  // Similarly, __TIME__ will look something like '09:34:17' so get those numbers.
  sscanf(__TIME__, "%d:%d:%d", &thour, &tminute, &tsecond);

  // Find the position of this month's string inside month_names, do a little
  // pointer subtraction arithmetic to get the offset, and divide the
  // result by 3 since the month names are 3 chars long.
  tmonth = (strstr(month_names, s_month) - month_names) / 3;

  months = tmonth + 1;  // The RTC library expects months to be 1 - 12.
  days = tday;
  years = tyear - 2000; // The RTC library expects years to be from 2000.
  hours = thour;
  minutes = tminute;
  seconds = tsecond;

  rtc.setTime(hours, minutes, seconds);
  rtc.setDate(days, months, years);
}

void displayTime()
{

  display.on();                               //Turns TinyScreen display on
  
  for (int i = 1; i < 10; i++) // Display for 10*1000 milliseconds (5 seconds), update display each second
  {
    // To correctly handle switching date at midnight while the time display is on,
    // update -everything-, not just the seconds.

    // Get the time now since it's used for the brightness calculations.
    // We only need the hours and minutes, since they're all we have
    // room to display.
    hours = rtc.getHours();
    minutes = rtc.getMinutes();

    if (hours <= 12)
      brightness = hours + 3; // 0 hours = 3 brightness, noon = 15
    else if (hours >= 18)
      brightness = (24 - hours) * 2 + 2;  // 23 hours = 4 brightness, 18 hours = 14
    else
      brightness = 15; // full brightness all afternoon
    if (brightness < 3)
      brightness = 3;
    if (brightness > 15)
      brightness = 15;
    display.setBrightness(brightness);                  //Set display brightness 0 - 15

    // Convert 24-hour time into the 12-hour format for
    // the word clock.
    int wordHours, wordMinutes;
    wordHours = hours;
    if (minutes >= 35)   // After half-past the hour, the minute words start referencing the next hour.
      wordHours++;
    wordHours %= 12;    // Now 0 - 11, which is what we need for lookups in the grid.

    // Convert minutes to 5-minute segments
    wordMinutes = minutes / 5;

    // Get the letter-selection grids for the current hour and 5-minute segment.
    unsigned char *thisLetterMinute = letterMinutes[wordMinutes];
    unsigned char *thisLetterHour = letterHours[wordHours];
     
    for (int row = 0; row < 8; row++)   // Walk from the top to the bottom of the 8 x 8 word grid
    {
      // Look out, we're about to do some binary comparisons. As we walk from the left to the right
      // in the word grid, we'll compare the corresponding bit in each byte to determine if the
      // letter in that position should be lit or not. We'll start with the leftmost bit,
      // and shift it right once for each column.
      unsigned char letterColumn = B10000000;
      for (int column = 0; column < 8; column++, letterColumn = letterColumn >> 1)
      {
        // Set the drawing cursor to the position of the current letter.
        display.setCursor((column * 10) + 10, (row * 8));

        // Check to see if the current letter should be off or lit.
        if (((thisLetterMinute[row] & letterColumn) == 0) &&
            ((thisLetterHour[row] & letterColumn) == 0))
          display.fontColor(LETTER_OFF, TS_8b_Black);
        else
          display.fontColor(LETTER_LIT, TS_8b_Black);
          display.print(wordClock[row][column]);
      }
    }

    delay(1000); //display for 1 seconds
  }

  display.off();                               //Turns TinyScreen display off
}

void loop()
{
   if (display.getButtons())
   {
      displayTime();
   }
}

Credits

J Koger

J Koger

10 projects • 4 followers
Thanks to Daniel Rojas.

Comments