Arduino WordClock

Hi Riva!

I did missed that link. Thanks for pointing me out. Actually, the RTC I have available right now for this project is the DS1307 which from your experience is not the best one for this kind of project. I'll change it...

Another thing that I will have to work is the Font. I need to add some "special" characters like ç, é, í, etc... From my understanding, I need to add their "design" to the Fonts you already included, in the first place. After this, is there anything else that I need to change to be able to use them in a scrolling message?

Still regarding the Fonts, can you explain to me what's the meaning of the last digit/couple of digits defined after each character? e.g.:

    B11001100, B00000000, //"
    B11001100, B00000000,
    B11001100, B00000000,
    B00000000, B00000000,
    B00000000, B00000000,
    B00000000, B00000000,
    B00000000, B00000000,
    8,

    B00110011, B00000000, //#
    B00110011, B00000000,
    B11111111, B11000000,
    B00110011, B00000000,
    B11111111, B11000000,
    B00110011, B00000000,
    B00110011, B00000000,
    12,

I am referring, in this example to the 8 and 12 in the last line of each character. Other characters have different codes.

Once more, thank you for all your help. When I get something that worth to show, I'll post some pictures.

saturno: Actually, the RTC I have available right now for this project is the DS1307 which from your experience is not the best one for this kind of project. I'll change it... You can get reasonably accurate with a DS1307 given a little time. For me the DS1307 was loosing about 8.5 seconds per day (It take several days to get a good average) so I just put in a bit of code to add 8.5 seconds at midnight each day.

Another thing that I will have to work is the Font. I need to add some "special" characters like ç, é, í, etc... From my understanding, I need to add their "design" to the Fonts you already included, in the first place. After this, is there anything else that I need to change to be able to use them in a scrolling message? If you want to add the characters into the correct position to match the extended ASCII table then you will need to define all the characters prior to the last one you need or at least put spaces in the chars you don't define else the loadBufferLong code won't work properly (It will also need altering to accept a larger font tabe as it's current upper limit is 0x7F). You could also define the extra characters to replace un-used characters in the current font (things like {}[]|<>).

Still regarding the Fonts, can you explain to me what's the meaning of the last digit/couple of digits defined after each character? The last number is used for kerning the font character. It is normally the bit number of the right most bit (start counting from the left of the two bytes) + 2 and defines how wide the character is. I have highlighted the right most bits in both examples and you will see the number is the bit position of the widest point (starting with left byte/bit) plus 2 bits. e.g.:

B11001100, B00000000, //" Bit position 6 (counting from left) highlighted in red B11001100, B00000000, B11001100, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, 8, // 6+2

B00110011, B00000000, //# B00110011, B00000000, B11111111, B11000000, // Bit position 10 (counting from left) highlighted in red B00110011, B00000000, B11111111, B11000000, B00110011, B00000000, B00110011, B00000000, 12, // 10+2

I am referring, in this example to the 8 and 12 in the last line of each character. Other characters have different codes.

Once more, thank you for all your help. When I get something that worth to show, I'll post some pictures. Will be nice to see someone else's work

Superb explanation!

As for the space reserved for the loadBufferLong, I understand that it needs to be increased to allow loading more characters. Since there are only few characters that I need to add, maybe I'll take your suggestion to replace some of the unused to the ones that I need to add.

Thank you.

Hello Riva,

After several hours around the build of the matrix (mine is 475 x 475 mm), I've just managed to see the result of half of the matrix (just one MAX completely connected by now). The result is not what I was expecting. Without thinking or questioning, I used the diagram presented in the file "Clock7.pdf" to wire the first max to the arduino and as I can now see, my assumption was not correct.

Here is what I have done: Since we usually read from left to right, I supposed that since you placed the IC1 at the right side of IC2, the schematic was drawn as seen from the back, i.e. when you see the watch from the front, the IC1 becomes the left and the IC2 on the right; and I wired my matrix exactly as in the schematic. At the moment, only the IC1 that, seen from the back of the watch, it is on the right side (right half) and when we turn around to see the "lights", it is on the left side.

Well the problem is that I missed something and now I have the initial string appearing from the left to the right (wrong) and, even worse all the characters are backwords (like mirrored). To see the characters correctly, I would need to turn around and see the watch from it's back... (I hope my explanation make sense).

So, the question is: Can I "fix" my matrix without the need of rewiring everything? What is the correct way to build the matrix? (I can upload a little video to show you the problem)

Thank you for any help.

saturno: After several hours around the build of the matrix (mine is 475 x 475 mm), I've just managed to see the result of half of the matrix (just one MAX completely connected by now). The result is not what I was expecting. Without thinking or questioning, I used the diagram presented in the file "Clock7.pdf" to wire the first max to the arduino and as I can now see, my assumption was not correct. The schematic was the one I used to build both clocks so should work. It is based on this article. What you may have done (I did it first time) is forget that when your wiring the back of the board the SegX are reversed. Here is what I have done: Since we usually read from left to right, I supposed that since you placed the IC1 at the right side of IC2, the schematic was drawn as seen from the back, i.e. when you see the watch from the front, the IC1 becomes the left and the IC2 on the right; and I wired my matrix exactly as in the schematic. At the moment, only the IC1 that, seen from the back of the watch, it is on the right side (right half) and when we turn around to see the "lights", it is on the left side. I'm not sure what the effect would be with only one chip as the matrix information is cascaded through one MAX into the next from right to left when LED's viewed from the front.

Well the problem is that I missed something and now I have the initial string appearing from the left to the right (wrong) and, even worse all the characters are backwords (like mirrored). To see the characters correctly, I would need to turn around and see the watch from it's back... All you need to do is reverse the order of the 8/16 SegX pins and it should come good.

That must be my mistake also. I will reverse the SegX wiring.

After some rest, I did a quick test viewing from the back, and everything showed correctly.

Just a quick question: When looking to the watch (front face after ready) what is the side of each IC? I suppose that IC2 controls the left side of the matrix and the IC1 the right side, correct?

Thank you.

saturno: Just a quick question: When looking to the watch (front face after ready) what is the side of each IC? I suppose that IC2 controls the left side of the matrix and the IC1 the right side, correct?

Correct. Looking at the front (clock face) IC1 is on the right and IC2 on the left.

Hi Riva,

After some early matrix wiring "orientation problems", here is a quick video to show you my wordclock matrix.

https://www.youtube.com/watch?v=Cl2p8FcFMuw&feature=youtu.be

The base is MDF, CNC machined 20 mm front / 5 mm back holes and since it is 475 x 475 mm I made the electronics independent: i.e.: 1 stripboard for the arduino, 2 stripboards for the MAX7219, 1 stripboard for the rotary encoder and the LDR is directly connected with a three wire cable (I need to see where I am going to place it at the final) Right now, everything is just wired together and suspended. When I figure how to fix everything to the clock's back, I'll post some pictures.

I had to uncomment the setBrightness function to be able to make the auto-adjustable brightness work. Is there any reason for the function to be disabled in the code? It seems that it is working correctly without any further adjustment...

Working on the translation to see some "meaningful words", I noticed that there are two ways to light up a led:

lc.setRow (0, 0, B01111000)
lc.Setled (0, 1, 2, true)

After some changes I am experiencing some slight flickering when some (already translated) words light up. When translation, I always used the function: lc.setRow (0, 0, B01111000) as it seemed easier to do the match between the clock face and the code.

Can you explain to me why and when should I use each of these functions?

Thank you

saturno: After some early matrix wiring "orientation problems", here is a quick video to show you my wordclock matrix.

https://www.youtube.com/watch?v=Cl2p8FcFMuw&feature=youtu.be The face looks good. Having access to CNC machine and creating the light wells is a good idea and should make the thing less susceptible to light bleeding from one cell to the next. Hence me having to use bits of black plastic straws.

The base is MDF, CNC machined 20 mm front / 5 mm back holes and since it is 475 x 475 mm I made the electronics independent: i.e.: 1 stripboard for the arduino, 2 stripboards for the MAX7219, 1 stripboard for the rotary encoder and the LDR is directly connected with a three wire cable (I need to see where I am going to place it at the final) Right now, everything is just wired together and suspended. When I figure how to fix everything to the clock's back, I'll post some pictures. Will be nice to see some finished pictures. You could probably have mounted all the electronics on one piece of stripboard to reduce the complexity. I don't envy the wiring looms you must have :)

I had to uncomment the setBrightness function to be able to make the auto-adjustable brightness work. Is there any reason for the function to be disabled in the code? It seems that it is working correctly without any further adjustment... setBrightness is still active but I moved it to the doTime routine so it only adjusts every minute as the clock face is changing. I found you could get into a brightness hunting condition sometimes where it originally was. The brightness would adjust every second between two brightness levels and as the MAX chips only have 16 levels you really noticed it.

After some changes I am experiencing some slight flickering when some (already translated) words light up. When translation, I always used the function: lc.setRow (0, 0, B01111000) as it seemed easier to do the match between the clock face and the code.

Can you explain to me why and when should I use each of these functions? I would use setRow if no other letters from potential previously illuminated words are in that row else I would use setLed to finish filling the row and then setRow or setLed for the next row if the word spread across more than one row. Your likely getting flickering because your setting a led/filling a row and then another word is using setrow on the same row at a later point and wiping the previous led settings.

Hello Everyone, Riva specially!

Finally, my wordclock is ready to be shown. It is not completely terminated, but it will probably remain like this until I can have some more time to do what I have in mind.

It consists in a 475 x 475 mm MDF panel, with an acrylic on the front (with a black vinyl sticker with the lettering), three MAX 7219 that drive the 132 5mm white leds, an LDR to change the led intensisty according to the ambient light and a rotary encoder to set it up (just like Riva’s).

Before I started this project I already had done a few experiments with the MAX7219 to drive a 7 segment display. So I took the strip-board that I’ve made and built two additional in order to be able to drive the remaining LEDs (132 total).

Right now everything follows very nearly the original project from Riva, besides the enclosure.
What I would like to do in the future is to change the rotary encoder with two capacitive touch buttons to make it real stealthy :wink:

In order to make it work with the three MAX7219, I had to modify the MAX library provided by Riva.
Initially, the library only supported 2 MAX ICs and to make the four corner leds work, I had to make it support all possible addresses of the three MAXes.
This one made me scratch my head a couple of hours. When I introduced the third MAX, at the beginning I started to see the corner leds light up but not in the way I was programming them. Test after test I started to realize that the leds were responding as they were controlled by the IC1. This led me to the solution as I stated for my own that it only could be a library related problem. After digging a little in the library I found that it was only prepared to manage addresses for 2 MAXes. Changed that and the corner leds started to work as expected! One per minute between each five minutes interval written with words

I just didn’t realize yet how I will introduce some extended ASCII characters.
I didn’t yet found where should I extend the loadBufferLong to accept all of the 255 characters. I think it is from the standard AVR library…
The other suggestion of replacing some unused characters of the fefault ASCII table is easier to implement. The only problem is that I did not figured yet how can I concatenate a character specified at the position 0x7f (for example) in an Birthday message or in a string of a Month…
I did see that for example you’ve used the character 0x7f (the 127 position) with the º character and that you’ve specified it’s use in the temperature string.
How can I use such a character in a month string? Let’s say “Março” that means March?

Thank you.

Ho! Here are some pictures:

2012-11-08 14.15.06 (Small).png

2012-11-08 14.15.18 (Small).jpg

2012-11-08 14.15.37 (Small).png

2013-02-24 22.48.24 (Small).jpg

A few more pictures:

2013-08-22 13.53.47 (Small).jpg

2013-08-22 13.53.58 (Small).jpg

2013-08-22 14.07.55 (Small).jpg

2013-08-25 22.30.15 (Small).jpg

A little more…

2013-08-28 10.31.01 (Small).jpg

2013-08-28 10.32.32 (Small).jpg

2013-09-23 16.54.53 (Small).jpg

2013-09-23 17.13.55 (Small).jpg

And the last batch.

2013-09-23 17.15.18 (Small).jpg

IMGP1082 (Small).JPG

IMGP1084 (Small).JPG

saturno: Right now everything follows very nearly the original project from Riva, besides the enclosure. What I would like to do in the future is to change the rotary encoder with two capacitive touch buttons to make it real stealthy ;-) I like that idea, it annoyed me so much having buttons sticking out the back on the first wordclock I built I went for the hidden rotary encoder on the second version. It means you have to remove the back to adjust the clock but I have not needed to do that for about 8 months now. The clock back almost sits on the encoder shaft so pressing the clock back will scroll the date & temperature.

In order to make it work with the three MAX7219, I had to modify the MAX library provided by Riva. Initially, the library only supported 2 MAX ICs and to make the four corner leds work, I had to make it support all possible addresses of the three MAXes. The library is just a cut down version of the LedControl library. I had cut it down because the original clock used a ATmega8 and I was running out of Flash memory. The current code has a constant to define how many MAX chips are connected and should work.

const int numDevices = 2;               // Number of MAX7219 LED Driver Chips (1-8)

I just didn't realize yet how I will introduce some extended ASCII characters. Just add then to this array.

prog_uchar font10x7 [] PROGMEM = {      // Large Ascii Font Matrix

I didn't yet found where should I extend the loadBufferLong to accept all of the 255 characters. I think it is from the standard AVR library... The loadBuferLong is not from the ARV library. Just change the 0x7F to the new upper limit on the characters in the font10x7 array.

void loadBufferLong(int ascii){
    if (ascii >= 0x20 && ascii <=0x7f){

You will also need to adjust this code to send pixel data to the extra MAX chip.

// Display Buffer on LED matrix
void printBufferLong(){
    for (int a=0;a<7;a++){                              // Loop 7 times for a 10x7 font
        unsigned long x = bufferLong [a];               // Get buffer entry
        int y = (x>>24) & 0xff;                         // Mask off left hand character
        lc.setRow(1,a,y);                               // Send row to relevent MAX7219 chip
        y = (x>>16) & 0xff;                             // Mask off right hand character
        lc.setRow(0,a,y);                               // Send row to relevent MAX7219 chip
    }
}

The other suggestion of replacing some unused characters of the fefault ASCII table is easier to implement. The only problem is that I did not figured yet how can I concatenate a character specified at the position 0x7f (for example) in an Birthday message or in a string of a Month... I did see that for example you've used the character 0x7f (the 127 position) with the º character and that you've specified it's use in the temperature string. How can I use such a character in a month string? Let's say "Março" that means March? If your using Windows then you could use character map to build the string up using the characters you need and then copy/paste into the sketch. As your matrix is a higher density you probably don't need the extra wide font I use and could maybe find/define the entire ASCII set with little problem.

Ho! Here are some pictures: Looking good, I like the higher density of LED's

In order to make it work with the three MAX7219, I had to modify the MAX library provided by Riva. Initially, the library only supported 2 MAX ICs and to make the four corner leds work, I had to make it support all possible addresses of the three MAXes.

The library is just a cut down version of the LedControl library. I had cut it down because the original clock used a ATmega8 and I was running out of Flash memory. The current code has a constant to define how many MAX chips are connected and should work. Code: const int numDevices = 2; // Number of MAX7219 LED Driver Chips (1-8)

Well, I did saw that constant and it was the first logic change I've made. What I described was what was happening after changing that constant. I now understand that the problem was the "stripped down" version of the MAX library...

I just didn't realize yet how I will introduce some extended ASCII characters.

Just add then to this array.

prog_uchar font10x7 [] PROGMEM = {      // Large Ascii Font Matrix

[/quote]

Well, that was what I have tried, but without success even after changing the upper limit from 0x7f (127) to 0xff (255) as you suggest below.

Here is what I did: After the last character you have in the font10x7 - the symbol º (that by the way is not in the correct position of the ASCII, but I understand that you put it there just for convenience), I created a new character that for this matter isn't relevant. That additional character will be in the 128 position (original 127 plus 1). The quick test I've made was to call that new character I've added (at the position 0x80) after the 0x7f (º) you concatenate at the end of the temperature scrolling string. The result is just a blank space...

I didn't yet found where should I extend the loadBufferLong to accept all of the 255 characters. I think it is from the standard AVR library...

The loadBuferLong is not from the ARV library. Just change the 0x7F to the new upper limit on the characters in the font10x7 array.

void loadBufferLong(int ascii){
    if (ascii >= 0x20 && ascii <=0x7f){

[/quote]

Yes, I did that. I changed the upper limit to 0xff which is 255 and the only position I used was after 0x7f which is 0x80 (which is position 128). I then changed the end of the temperature string to test the new character visibility, like so:

    int x=strlen(chrBuffer);
    hrBuffer[x++] = 0x7f; // the º character at the position 127
    chrBuffer[x++] = 0x80; // my new character at the position 128 which don't show in the scrolling text
    chrBuffer[x++] = ' ';
    chrBuffer[x++] = ' ';
    chrBuffer[x] = 0x0; 
    scrollRamMessage();
[/color]

You will also need to adjust this code to send pixel data to the extra MAX chip.

// Display Buffer on LED matrix
void printBufferLong(){
    for (int a=0;a<7;a++){                              // Loop 7 times for a 10x7 font
        unsigned long x = bufferLong [a];               // Get buffer entry
        int y = (x>>24) & 0xff;                         // Mask off left hand character
        lc.setRow(1,a,y);                               // Send row to relevent MAX7219 chip
        y = (x>>16) & 0xff;                             // Mask off right hand character
        lc.setRow(0,a,y);                               // Send row to relevent MAX7219 chip
    }
}

Thanks for the tip, but I think I don't need this because the third MAX only controls the four leds on each corner. It is not used to show anything when a message is scrolling.

The other suggestion of replacing some unused characters of the fefault ASCII table is easier to implement. The only problem is that I did not figured yet how can I concatenate a character specified at the position 0x7f (for example) in an Birthday message or in a string of a Month... I did see that for example you've used the character 0x7f (the 127 position) with the º character and that you've specified it's use in the temperature string. How can I use such a character in a month string? Let's say "Março" that means March?

If your using Windows then you could use character map to build the string up using the characters you need and then copy/paste into the sketch. As your matrix is a higher density you probably don't need the extra wide font I use and could maybe find/define the entire ASCII set with little problem.

I think I don't understand. Consider that the string you defined as March is written like this: Márch (acute in a). Consider that the "á" (acute a) is defined at the position 128 (0x80) and that you are able to show it alone in the scrolling text (I'm not at this moment). How do you redefine the code for March string in the following code so is shows as Márch (small a with acute) and not March?

prog_uchar Month03[] PROGMEM = {
    "March \0"};

Thanks for your time and help.

saturno:
How can I use such a character in a month string? Let’s say “Março” that means March?

If your using Windows then you could use character map to build the string up using the characters you need and then copy/paste into the sketch. As your matrix is a higher density you probably don’t need the extra wide font I use and could maybe find/define the entire ASCII set with little problem.

I think I don’t understand.
Consider that the string you defined as March is written like this: Márch (acute in a).
Consider that the “á” (acute a) is defined at the position 128 (0x80) and that you are able to show it alone in the scrolling text (I’m not at this moment).
How do you redefine the code for March string in the following code so is shows as Márch (small a with acute) and not March?

If you have defined the acute a (á) as character 0x80 then using Windows Character Map program just select the ‘System’ font and make up the string you need and then copy/paste it into your sketch. As an example I did this and end up with ‘M€rch’. In the system font the a looks like a vertical bar but in the forum font it looks like a euro currency sign.

Thanks for your time and help.
If I get time I will investigate the problem of going beyond character 0x7F
[/quote]

I'm sorry Riva I think I did not explain me correctly.

I am able to construct any string in my language as my keyboard have all those special characters. I think your suggestion about the windows character map was just to make me find that characters. The problem is that whatever character I made a string of - lets say Março (for March), the "ç" cedilla does not show in the rotating string because I can't call characters with values >= 0x7f and I don't know how can I concatenate whatever character position specified in the font10x7 into a month string or other message.

Something like this:

Assume I have replaced the character int font10x7 at position 0x7f with the character "ç". How would I change the code below in order to replace the fourth letter - the c, with the one (correct) I created at the position 0x7f?

prog_uchar Month03[] PROGMEM = {
    "Março \0"};

I know this is not the way, but you get the point ]:)

prog_uchar Month03[] PROGMEM = {
    "Mar"+0x7f+"o \0"};

What I was asking was if there was a simpler solution to define the strings I need with special characters (months and names in aniversaries) in a more friendly way than the one you use to put together the string for advertising the temperature:

void doTemperature(){
    chrBuffer[0] = ' ';
    chrBuffer[1] = ' ';
    chrBuffer[2] = 'I';
    chrBuffer[3] = 't';
    chrBuffer[4] = 's';
    chrBuffer[5] = ' ';
    chrBuffer[6] = 0x0;

If someday you want and find time to investigate this, I appreciate if you could share a possible solution with me. Thank you.

Home at last and after testing I can add more characters to the font10x7 definitions and then alter the 0x7f bound in loadBufferLong to display them. I’m not using the wordclock to display though (one is 400 miles away and the other my wife won’t allow me to play with any more) but am using a Rainbowduino with the same core code as used in the clock, just the rendering routine is different.
I knocked up an extended (0x20-0xff) double width font based on the Windows Terminal font while at work but it’s now 12x8 instead of 10x7 so will need a few more changes to get it working + not all the extended characters are correctly defined. I also had the original (pre double width) 6x8 version but unwittingly messed it up when doing a final search/replace to make it arduino compatible. I will do it again when I go back to work next week.
I used a free GLCD font creator from here to import and convert the terminal font and then knocked up a quick VB6 program to change the font program output from hex to binary and rotate the data through 90 degrees, another VB6 program I had already was then used to double the width.

Well, in that case I must be doing something wrong or missing something!

I've extended the loadBufferLong to support ascii codes until 255:

void loadBufferLong(int ascii){
    if (ascii >= 0x20 && ascii <= 0xff) {
   ...

and then, I've just added some test character to the end of the font10x7 definition. So, that additional character is now after 0x7f, so it is on the 0x80 position (at least I think so).

If I explicitly call that character for example in the code below, i don't see anything different in the new scrolling text... The first position of the array that should hold the new character 0x80, just don't display anything. It is just like a space...

void doTemperature(){
    chrBuffer[0] = 0x80;
    chrBuffer[1] = ' ';
    chrBuffer[2] = 'I';
    chrBuffer[3] = 't';
    chrBuffer[4] = 's';
    chrBuffer[5] = ' ';
    chrBuffer[6] = 0x0;

Thank you for the link for the GLCD font creator. I didn't knew it and I am going to try it out. From my quick review, It appears that it only exports to an hexadecimal format, that need a good amount of work to make it usable in this project.

Some time ago I came across The LED Matrix Studio here, but didn't did anything with it yet.

I really appreciate your help, support and time. Best regards

Riva,

Great work on the clock!
I’m midway through building one with a 6x16 array (6 rows high, 16 columns (two max7219 driving 6x8 each)).
I’ve got all the basics going great, thanks for the code.

However, the scrolling message doesn’t scroll from right to left across both arrays - it runs on both arrays independently (with a slight delay).

I have the MAX7219s cascaded (DOUT to DIN) with parallel load and clk

I can’t find why it is doing this. Could it be something to do with my matrix being 6x8 rather than 8x8?
I’ve tried other code that’s supposed to scroll correctly (http://forum.arduino.cc/index.php?topic=170043.msg1265321#msg1265321 and others) but all have the same effect.

Any help is appreciated.
Code attached.

Turns out I had the Max7219 in the wrong order. Riva pointed out in another post that the first Max7219 should be on the right side of the display (I had it on the left…). Swapped over wiring and all fixed!

Clock_v6006_mod.ino (51.4 KB)