Hardware components | ||||||
| × | 1 |
Now that our O-Watches can keep and display accurate time, let's go one step further and use the TinyScreen font features to display a mini Word Clock!
It is strongly recommended that you get the previous Simple RTC Watch working before trying this.
Note: This watch face is now included in Mult-O-Watch.
A Word Clock uses a grid of letters to spell out the time. We'll use the 8 x 8 letter grid developed by Daniel Rojas for our mini Word Clock. But instead of lighting up printed letters with LEDs, we'll 'light up' our letters by drawing them in a bright color, and show the unused letters as 'off' by drawing them in a dark color.
HATWENTY
FIFVTEEN
LF*PASTO
NINEIGHT
ONETHREE
TWELEVEN
FOURFIVE
SIXSEVEN
Because the smallest font provided on the O-Watch is 7 pixels high (plus 1 pixel spacing between rows of letters) and the TinyScreen is 64 pixels high, our Word Clock will use up the entire screen.
This means that we won't be able to display the date, day of the week or seconds. Also, we'll only be able to display the minutes down to the nearest 5-minute segment. But that's OK, because Word Clocks are cool!
Our code will store the grids used to determine which letters to 'light up' and which to 'turn off' in very compact bit arrays. We'll then use bit-wise comparisons to figure out which letters to light or not.
simple_word_watch.ino
Arduino/*
* 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();
}
}
Comments