How to Make Arduino Word Clock (detailed Code Explanation)

by dziubym in Circuits > Arduino

4955 Views, 52 Favorites, 0 Comments

How to Make Arduino Word Clock (detailed Code Explanation)

Creating Arduino Word Clock version LITE - No technical boring details, just joy of creation
ThumbLite.png

Here is the complete tutorial on how to make 8x8 character word clock. What is word clock? Obviously it is a kind of clock that tells time. It is called a wordclock as it displays the current time not with digits but with words.

Wordclock Concept

Time components.png

The wordclock does not show the time precisely. It has 5 min accuracy.

Representation of time consists of three major components

  • Minutes

Its optional and is not display if we are on a full hour.

  • Reference to the hour

Either the one that has just past ("PAST"), or the hour we are heading to ("TO"). This component is also optional.

  • Hour

In the picture you can see few examples.

The word clocks may differ in size and word layout. I am going for the basic 8x8 character one. We have an 8x8 matrix of letters and among them, all needed time components are hidden.

In the top half of the matrix you will find elements for representing minutes. In the middle you will find references "PAST" and "TO" . And in the lower half you will find all posible hours. Since the matrix is only 8x8 some of the words need to be scattered across single or even multiple rows. If you go for larger size you can have all elements as full words as well as you can add some additional components like, PM AM, o'clock, in the evening, in the afternoon , in the morning, at night.

Supplies

nano.png
IMG_3182.png
ds3231.png

To build the circuit we would need following components

  • Arduino Nano
  • 5V WS2811 LED strip (64 LEDs)

Leds on that strip are individually addressable so you can lit any led you want in any color that you want.

  • DS3231 RTC module

This is RTC module that connects to Arduino via I2C bus. It is more reliable then any other RTC modules that I worked with like DS1302. It also has a built in temperature sensor

Writing the Core Part of the Code (Part 1)

Serial.png

So we do not have clock device ready yet but we can already start writing the code that is going to be the core of this clock. We can build the table with string representation of all possible time components

<pre>String Time_Comp[19]{ "ONE",                      "TWO",                      "THREE",                      "FOUR",                      "FIVE",                      "SIX",                      "SEVEN",                      "EIGHT",                      "NINE",                      "TEN",                      "ELEVEN",                      "TWELVE",                      "PAST",                                        "TO",                      "FIVE",                       "TEN",                      "QUARTER",                      "TWENTY",                      "HALF"};

And then write the code that would read time from RTC module and convert it to word representation of that time using time components from that table as building blocks. We can check if the code works well by outputting that text representation to the serial monitor.

Then when we have the clock device ready and we have leds properly positioned then we can change this table that currently has pointers to strings representing each time component, to having pointers to led assigments instead. Now lets look at the code that we will use to do a dry run of our clock.

  • We start with Library declarations.
#include <Wire.h>#include <DS3231.h>

We have library for real time clock and I2C communciation minutes and hours.

  • Next we declare the RTC module
DS3231 clock;RTCDateTime dt;
  • Then we declare couple of variables for storing minutes and hours
int dtminutes;int dthours;int minutes;int hours;int CurrentTime[4];
  • In a setup function

- we open serial monitor

- we initialise the RTC module

- set the time to sketch compilation time.

void setup() { Serial.begin(9600); clock.begin(); clock.setDateTime(__DATE__, __TIME__);}

Writing the Core Part of the Code (Part 2)

5to3.png
  • In the main loop

We read time off the RTC module.

We adjust minutes reading to 5 min accuracy and save it into minutes varaible If minutes reading is below 35 then we assign current hour to hours variable. So when building word representation of time we can say how many minutes past since that hour.

If the minutes reading is higher then 35 we assign next hour to hours variable so when building word time representation we can say how many more minutes are left to reach next full hour.

void loop() {  dt = clock.getDateTime();  minutes=int((dt.minute)/5)*5;  if (minutes<35 and minutes>=0) hours=dt.hour ;else hours=dt.hour+1 ;

CurrentTime table is the table that holds pointers to up to 4 strings in the Time_Comp table that we will used to construct word representation of time.

First two poiters are identifying minutes. The second minute component would only be used when minutes reading is 25 as only in this case we need two string components to represent minutes ("Twenty" and "Five". Third pointer is selecting "past" or "two", and the fourth pointer is identifying the hour we either just past or we are heading to.

We have a sequence of if statements that based on the value of minutes variable identify which minutes poiters should be selected.

So if minutes is equal to 0 we have a full hour so no minutes componnets . Value 99 indicates that component is not used.

if (minutes==0)                      {CurrentTime[0]=99;CurrentTime[1]=99;}

When minutes is equal to 5 then we assige the value 14 to the first minute poiter , which identifies string "Five". The second minutes pointer is set to 99 as it is not used.

if ((minutes==5)  or (minutes==55))  {CurrentTime[0]=14;CurrentTime[1]=99;}

We proceed with next possible values of minutes variable.

if ((minutes==10) or (minutes==50))  {CurrentTime[0]=15;CurrentTime[1]=99;}if ((minutes==15) or (minutes==45))  {CurrentTime[0]=16;CurrentTime[1]=99;}if ((minutes==20) or (minutes==40))  {CurrentTime[0]=17;CurrentTime[1]=99;}if ((minutes==25) or (minutes==35))  {CurrentTime[0]=17;CurrentTime[1]=14;}if (minutes==30)                     {CurrentTime[0]=18;CurrentTime[1]=99;}

You see that in case of value 25 we use both minutes components.


Then depending on the value of minutes we select the pointer to either "past" or "to" reference to an hour. If minutes value is 0 then then that component is not used at all. And finally we assign pointer to the hour. Please mind that the word clock is 12 h clock so we need to convert pm hours e.g 18:00 to 6:00 or 22:00 to 11:00 etc.

if (minutes>= 5 and minutes<35)  CurrentTime[2]=12; <br>if (minutes>=35 and minutes<=59) CurrentTime[2]=13;if (minutes==0)   CurrentTime[2]=99;CurrentTime[3]=hours - int(hours/12)*12-1;

Then we have series of commands that will send word representation of time to a serial monitor

  Serial.print(dt.hour);<br>  Serial.print(":");  Serial.print(dt.minute);  Serial.print("-");  Serial.print(hours);  Serial.print(":");  Serial.print(minutes);  Serial.print("-");  if (CurrentTime[0]!=99) {Serial.print(Time_Comp[CurrentTime[0]]);Serial.print(" ");}  if (CurrentTime[1]!=99) {Serial.print(Time_Comp[CurrentTime[1]]);Serial.print(" ");}  if (CurrentTime[2]!=99) {Serial.print(Time_Comp[CurrentTime[2]]);Serial.print(" ");}  Serial.println(Time_Comp[CurrentTime[3]]);

We wait 10 s before we repeat loop function execution

delay(10000)

Work Clock Design - Case

frame.png

Apart from the techincal concept for this project equally challenging is coming up with the its design. How it would looklike.

I found ideal casing for this clock. It is a thick 30x30cm wooden picture frame.

Word Clock Design - Front Panel Design

frame4.png
frame1.png
front panel.png
frame3.png

Next was to come up with the 3d design for the front panel of the clock.

I need to to create 8x8 matrix of letters. I had to install special font for CNC Laser cut outs. To make sure the layout for this is perfenct I created a grid that helped me make sure that all the letters were positioned properly.

Then next challenge was that my 3dprinter bed is only 20cm by 20cm and I would not fit the whole panel onto it. So I had to divide this panel into four separate parts.

The design of this part was done in Tinkercad (free online 3d design software). After the design was finished if can be exported into STL format. The exported file can be opened in Cura application and from it send to the 3d printer.

Word Clock Design - Front Panel Assembly

Assembly2.png
Assembly.png
Assembly1.png

With all parts of the front panel printed lets turn them around. I printed small connectors to join all four parts together.

Word Clock Design - Diffusion Panel

diff3.png
diff.png
diff1.png
diff2.png

Now that is done we can start working on diffusion panel. It will provide white fronts for letter cutouts as well as isolate light emited by each led so it lits just one letter.

Design was also created in Tinkercad and it was, just as front panel, divided into 4 parts. Each front panel part would have its dedicated diffusion panel.

The printout of each part takes approx. 3h so you need in access of 12 h to print the whole diffusion panel.

Word Clock Design - Led Matrix

leds3.png
leds.png
leds1.png
leds2.png

With this out of the way we create the led matrix. I cut out the piece of the fibreboard that has the same size as the inside of the frame.

The led strip I would use is 5v WS2811 led strip . I cut it into strips containg 8 leds each. Then I solder them together to form eight by eight matrix.

Time to connect it to Arduino.

  • LED strip GND and 5V to Arduino GND and 5V
  • LED singnal goes via 200Ohm resistor to Arduino Pin 5.

I am powering the strip from Arduino as I would be Lighting just individual LEDs so 0,5Amp that Arduino can provide would be sufficient.

You can write a simple code to test if all leds work fine and also test the colors I will use in the final project.

#include <FastLED.h>#define LED_PIN     5#define NUM_LEDS    64#define BRIGHTNESS  140#define LED_TYPE    WS2811#define COLOR_ORDER GRBCRGB leds[NUM_LEDS];CRGB Colors [13]{CRGB::Gray,CRGB::Orange,CRGB::Maroon,CRGB::Red,CRGB::Cyan,CRGB::Lime,CRGB::Green,CRGB::Purple,                     CRGB::Yellow,CRGB::White,CRGB::Blue};void setup() {    delay( 3000 ); // power-up safety delay    FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );    FastLED.setBrightness(  BRIGHTNESS );    }void loop(){for (int j=0;j<13;j++)    for (int i=0;i<65;i++){    leds[i]=  Colors[j];    FastLED.show();    delay(50);    leds[i]=CHSV( 0 , 0, 0);    FastLED.show();  }}<br>

Connecting All Components

diag.png
finish.png
finish1.png

It is time to connect all components

  • Lets start with connecting Arduino 5V to LED 5V and RTC module VCC pin.
  • Then we connect all the grounds.
  • Next we connect led strip signal pin to Arduino digital pin 5 through 220Ohm resistor
  • The RTC module I am using is DS3231 which is the I2C device so we connect Clock pin to Analog Pin A5 and Data pin to analog pin A4.

Adjusting the Code to Work With LED Matrix

eleven.png

Previously we created the sketch that was creating word representation of time but rather then controlling leds it was outputting appropriate strings to the serial monitor.

Lets add Fast LED components to it

We need fast LED library

<pre>#include <FastLED.h>

Then we have several values needed to declare LED strip

Like the pin to which LED strip is connected, Brightness, LED type etc

Then we declare the table of 64 leds . Each entry provides color detail for the corresponding led.

#define LED_PIN     5<br>#define NUM_LEDS    64#define BRIGHTNESS  80#define LED_TYPE    WS2811#define COLOR_ORDER GRBCRGB leds[NUM_LEDS];

I also added a pointer table just like CurreentTime table that would store previously read time so we can compare it agains current time and redisplay time only upon time change.

int PreviousTime[4];

And finaly we have three variables that store pointers the colors of minutes, pastto and hour components. They point to a colors table that store 11 colors I selected for this project

int ColorMinutes;<br>int ColorPastTo;int ColorHour;
CRGB Colors[11]{CRGB::Chartreuse,CRGB::Orange,CRGB::BlueViolet,CRGB::Red,CRGB::Cyan,CRGB::Pink,<br>                CRGB::Green,CRGB::Purple,CRGB::Yellow,CRGB::White,CRGB::Blue}; 

Previously Time_Comp table I used stored all possible words that can be used when displaying time and can be found in the letter matrix.

We need to change the strings into LED assigments.

int Time_Comp[19][7]{ {62,59,56,99,99,99,99},                      {48,49,62,99,99,99,99},                      {44,43,42,41,40,99,99},                      {63,62,61,60,99,99,99},                      {32,33,34,35,99,99,99},                      {47,46,45,99,99,99,99},                      {47,52,53,54,55,99,99},                      {35,36,37,38,39,99,99},                      {59,58,57,56,99,99,99},                      {39,40,55,99,99,99,99},                      {50,51,52,53,54,55,99},                      {48,49,50,51,53,54,99},                      {30,29,28,27,99,99,99},                       {27,26,99,99,99,99,99},                                    {16,17,18,19,99,99,99},                       { 1, 3, 4,99,99,99,99},                       {15,14,13,12,11,10, 9},                       { 1, 2, 3, 4, 5, 6,99},                      {20,21,22,23,99,99,99}};

Each led has its index that can be seen in the attached picture. So lets take word Eleven as an example. To display it we need to lit leds with hollowing indexes.

50,51,52,53,54,55,99

And that information is available in the appropriate row of the Time_Comp table.

In setup function we add led strip initialisation and set up led strip brightness

void setup() {    Serial.begin(9600);    clock.begin();    //clock.setDateTime(__DATE__, __TIME__);    delay( 3000 ); // power-up safety delay    FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );    FastLED.setBrightness(  BRIGHTNESS );    }

Now we have the loop function with the core code That we have creted previously.

This code was reading time of RTC module and filling in current time table with pointers to Time_Comp table to select the right strings to compose word representation of time. Here the pointers would select right led assigments.

void loop(){  PreviousTime[0]=CurrentTime[0];  PreviousTime[1]=CurrentTime[1];  PreviousTime[2]=CurrentTime[2];  PreviousTime[3]=CurrentTime[3];  dt = clock.getDateTime();  minutes=int((dt.minute)/5)*5;  if (minutes<35 and minutes>=0) hours=dt.hour ;else hours=dt.hour+1 ;  if (minutes==0)                      {CurrentTime[0]=99;CurrentTime[1]=99;}  if ((minutes==5)  or (minutes==55))  {CurrentTime[0]=14;CurrentTime[1]=99;}  if ((minutes==10) or (minutes==50))  {CurrentTime[0]=15;CurrentTime[1]=99;}  if ((minutes==15) or (minutes==45))  {CurrentTime[0]=16;CurrentTime[1]=99;}  if ((minutes==20) or (minutes==40))  {CurrentTime[0]=17;CurrentTime[1]=99;}  if ((minutes==25) or (minutes==35))  {CurrentTime[0]=17;CurrentTime[1]=14;}  if (minutes==30)                     {CurrentTime[0]=18;CurrentTime[1]=99;}    if (minutes>= 5 and minutes<35)  CurrentTime[2]=12;   if (minutes>=35 and minutes<=59) CurrentTime[2]=13;  if (minutes==0)   CurrentTime[2]=99;  CurrentTime[3]=hours - int(hours/12)*12-1; 

Please note that at the beginning we added few lines to save the previously read time to PreviousTime table just before we read new time of RTC module

After reading time and filling in the CurrentTime table with up to date information we can check if minutes components have changed, which would indicate the change of time.

If they did. We assign black color to the leds belonging to previous time which would turn them off next time we run command FastLED.show.

if (PreviousTime[0]!=99) for (int j=0;j<7;j++)   leds[Time_Comp[PreviousTime[0]][j]]=CHSV( 0 , 0, 0); <br>if (PreviousTime[1]!=99) for (int j=0;j<7;j++) leds[Time_Comp[PreviousTime[1]][j]]=CHSV( 0 , 0, 0);if (PreviousTime[2]!=99) for (int j=0;j<7;j++)   leds[Time_Comp[PreviousTime[2]][j]]=CHSV( 0 , 0, 0); if (PreviousTime[3]!=99) for (int j=0;j<7;j++)   leds[Time_Comp[PreviousTime[3]][j]]=CHSV( 0 , 0, 0);

Then we use random function to select the color in which minutes would be displayed.

And when done we assign this color to leds that correspond to the current minute. The change is not immediately visible without running the command fastled.show.

Then we generate the color for the "past" "to" components. We make sure that we generate this color until we get the value that is different to the color we just picked for the minutes component. Then we set that color to all relevant leds.

We repeat those actions for hour component , also getting the unique color and updating table for relevant leds.

Finally we run fastledshow.show command to lit the leds as defined in leds table.

if (PreviousTime[0]!=CurrentTime[0]or PreviousTime[1]!=CurrentTime[1]) {delay(2000);  if (PreviousTime[0]!=99) for (int j=0;j<7;j++)   leds[Time_Comp[PreviousTime[0]][j]]=CHSV( 0 , 0, 0); if (PreviousTime[1]!=99) for (int j=0;j<7;j++)   leds[Time_Comp[PreviousTime[1]][j]]=CHSV( 0 , 0, 0);if (PreviousTime[2]!=99) for (int j=0;j<7;j++)   leds[Time_Comp[PreviousTime[2]][j]]=CHSV( 0 , 0, 0); if (PreviousTime[3]!=99) for (int j=0;j<7;j++)   leds[Time_Comp[PreviousTime[3]][j]]=CHSV( 0 , 0, 0);  ColorMinutes=random(0,10);if (CurrentTime[0]!=99) for (int j=0;j<7;j++)   leds[Time_Comp[CurrentTime[0]][j]]=Colors[ColorMinutes];if (CurrentTime[1]!=99) for (int j=0;j<7;j++)   leds[Time_Comp[CurrentTime[1]][j]]=Colors[ColorMinutes];  ColorPastTo=random(0,10);while (ColorPastTo==ColorMinutes){  ColorPastTo=random(0,10);} if (CurrentTime[2]!=99) for (int j=0;j<7;j++)   leds[Time_Comp[CurrentTime[2]][j]]=Colors[ColorPastTo];   ColorHour=random(0,10);while ( ColorHour==ColorPastTo or ColorHour==ColorMinutes ){  ColorHour=random(0,10);}   for (int j=0;j<7;j++)     leds[Time_Comp[CurrentTime[3]][j]]=Colors[ColorHour];  FastLED.show();        }}

Lets load this scetch to Arduino to see if it works.

Final Result

final.png
Creating Arduino Wordclock Part 1 - Concept and Design
Creating Arduino Wordclock Part 2 - Put the words where your time is:)

Here is the final result

Thanks for spending your time going through this tutorial.

You can find the code here

https://create.arduino.cc/projecthub/mdraber/creat...

You can also find video version of this instructable here:

  • Creating Arduino Wordclock Part 1 - Concept and Design
  • Creating Arduino Wordclock Part 2 - Put the words where your time is:)

Enjoy And don't forget to show you appreciation when you like those videos with likes and subscriptions

You can also support me through

my Patreon webpage
https://www.patreon.com/MariosIdeas

Or Paypal

https://www.paypal.com/cgi-bin/webscr?cmd=_s-xcli...