Hello!

Welcome to my random collection of LED projects. Hope you find something interesting, and if you make the clock or improve the code let me know!

Cheers!

Nick, London

60 thoughts on “Hello!

  1. Hi

    Came across your site and the Pong Clock, only problem is that I have the older LED Matrix boards. So………..any plans to release code for working with these boards.

    Thanks

  2. Hey i’m new to Electronic circuiting and I would like to know where to begin. I have a strong want to build and create but I have no idea where to begin. Can you help me??

    • I would look at some of the sites that do kits – e.g. sparkful electronics. Those will give you a good introduction.

      If you like the idea of programming, look at the Arduino kits. There are lots of interesting starter kits that let you do all sorts of cool things. Good luck!

      Nick

  3. Hey nick,
    I got my sure-16X24 board working. But the problems is that to turn on the single display i need to select both cs1 and cs2 dip switches. I think there is some thing wrong in my code. Can please send me your code. So that I can learn my mistakes. My id is dudedevil100@gmail.com

    Regards,
    Pratik .R. Bhagat

    • Hi Pratik, you can download my code from this pong clock page at the bottom if you want to have a look. Or else there are demos on the arduino site if you search for sure electronics.

      Nick

  4. hey, i was searching the web and came across this awsome pong clock so i decided to spend the money and do all ur steps but im confused im getting
    pongclock_v2_27.cpp:177:1: error: unterminated #ifndef
    pongclock_v2_27:50: error: redefinition of ‘class Button’
    C:\Program Files\Arduino\arduino-0022\libraries\Button/Button.h:32: error: previous definition of ‘class Button’
    pongclock_v2_27.cpp: In function ‘void gettime()’:
    pongclock_v2_27:142: error: expected `}’ at end of input

    when i try to compile can u please help me fix

    thanks alot it is so cool i cant wait to show it off

  5. Hi Nick,
    I’ve just received the displays for PONG from China and want to start this very interesting project soon.
    While compiling I got some nice messages like:

    In file included from pongclock_v2_27.ino:20:
    F:\Daten\Privat\Arduino\arduino-1.0.4\libraries\DS1307/DS1307.h:51: error: ‘boolean’ has not been declared
    F:\Daten\Privat\Arduino\arduino-1.0.4\libraries\DS1307/DS1307.h:52: error: ‘boolean’ has not been declared
    F:\Daten\Privat\Arduino\arduino-1.0.4\libraries\DS1307/DS1307.h:53: error: ‘boolean’ has not been declared
    F:\Daten\Privat\Arduino\arduino-1.0.4\libraries\DS1307/DS1307.h:57: error: ‘byte’ has not been declared
    F:\Daten\Privat\Arduino\arduino-1.0.4\libraries\DS1307/DS1307.h:58: error: ‘byte’ has not been declared
    F:\Daten\Privat\Arduino\arduino-1.0.4\libraries\DS1307/DS1307.h:59: error: ‘byte’ does not name a type
    F:\Daten\Privat\Arduino\arduino-1.0.4\libraries\DS1307/DS1307.h:60: error: ‘byte’ has not been declared
    F:\Daten\Privat\Arduino\arduino-1.0.4\libraries\DS1307/DS1307.h:63: error: ‘byte’ does not name a type
    In file included from pongclock_v2_27.ino:21:
    F:\Daten\Privat\Arduino\arduino-1.0.4\libraries\Button/Button.h:34: error: ‘LOW’ was not declared in this scope

    Any idea ??

    If PONG is working (with red LEDs) I will put it into a nice case and sure I will send you pictures.

    Best regards from good old and cold Germany

    • Hello from sunny London… I know, who would have thought!

      Have you got the right version of the arduino software… From the instructions:

      “Important! The pongclock code is not yet compatible with the latest version of the Arduino IDE called 1.0. To get the pongclock software to work, you need to download version 0023 of the Arduino IDE software.”

      Nick

  6. Hello Nick,

    Thanks for your support, I should have found it out by myself because it’s written in your project file…
    It’s working now and I will try to transfer it into German (month names etc.). Red display is looking great, I will put it behind a coloured Alu plate with red glass as front pane.

    However I did not yet find out how to set time, date or so. Maybe with my 61 years I’m a little bit too old. Can you give me a hint…
    I’m hardware professional but regarding arduino programming it’s only my 4th project.

    Regards
    Dieter

    • Hey, glad it’s working! To set the clock go to “set clk” in the menu, then use one button to advance the day, hour etc and the other button to step through the items to set. It could be better I admit!

      • Hi Nick,

        I promised to send you pictures of my Pong Clock construction. It’s working since several weeks and looks great.

        As you will see I have used two red acrylic plates. One holds the display and the other stuff and the other plate covers the srews. Recently I have closed the gap between the two plates by clear tape to protect the plates from dust inside. It looks better in reality than on the images.

        Thanks again for that great project

        Dieter

  7. Hey Nick,
    I built my own Pong Clock but am having some troubles setting the time!! Any help would be appreciated!!! Please Help!!!!
    -David

      • At first I omitted the coin cell battery just because I couldnt find the right one and decided that it can work without it. However yesterday I bought the coin cell and holder and its still not working. For some reason every time I set the time, it always goes back to the default setting of 00:00 or 12:00 depending if I set it on the 12 hour or 24 hour time. Ive racked my brain trying to think of a solution to why its not working. I know that 1 and 8 are opposite legs of the RTC chip and there was an issue with that in your diagram and I caught that so I know that’s not the problem, I just have no idea what it could be. Is there something you have to do in the coding before using it??
        -David

      • Yes you do need the battery – a few other people have tried without it and it doesn’t work.

        Does the clock time change at all? If you don’t set it, it should just work from 12pm on, even if you don’t do anything.

        If you don’t see that, and if the LED on the arduino on pin 13 doesn’t flash every second, you’ll know there may be a problem with the RTC chip in some way. If you look at it with the semi circle to your left then pin 1 is on the bottom left. Check all your soldering too,

        There is nothing you need to do change in the code either, and you don’t need to program the RTC in any way – the main code does that in setup.

        Another thing to try is to see if the power supply is dodgy. Try a different one, or try unplugging one matrix so it draws less power. Someone else had funny results and is was because of this.

        Good Luck!

      • For some reason I couldnt reply to your comment below so I really hope you see this one!!! Also I used several different RTC chips none of which worked, but I noticed that the light near Arduino pin 13 isnt blinking, it just stays lit. Anything you could think of to fix it??

      • Strange, I’ve never seen that behaviour reported before and am not too sure what could cause it. Try Dieter’s suggestion.

      • Well, in the beginning I faced similar problems. I changed the RTC and even the 32 kHz quartz without results. In the end I found out that the RTC needed any signal via the I2C lines (i.e. pressing a key) to start generating a pulse on the quartz inputs. This may take a while, but you will only have to do it once (because of the battery).

        Regards

        Dieter from Germany

      • So Dieter, Im a little confused on what to do, there is a key I have to press in order for the RTC to start working?? What exactly should I do??
        -David

      • Hi David,

        it was trial and error with my Pong clock. I remember however that the RTC only started to work after it received any signals from the Arduino. And even then it took time.

        Dieter

      • Hmm, that doesn’t sound right, it should just work straight off the bat.

        If the LED isn’t flashing it’s not getting time from the RTC. Could you hook the RTC up on a breadboard to check it? That would eliminate bad soldering etc.

      • in case it didnt work I used a breadboard from the start instead of soldering, its still not getting signals

  8. Hi,
    I had a problem a few months ago with my pong clock about not setting the time right and I fixed it! but now the time wont change! I dont know why! I read the troubleshooting and comments to see if I could get any ideas and I noticed the LED next to pin 13 isnt flashing and I dont know how to fix it. The RTC seems to be wired up correctly but I dont know what else I could do. Any Ideas????

    -David

    • Hey,

      Hard to say without looking unfortunately. Check the wiring, check the crystal is connected and the battery too – it wont work without those. Also try a different power supply, I’ve heard of funny behaviour with bad PSU’s.

      Nick

      • Hey Nick,

        So im pretty sure the wiring is all right and the crystal and battery are definitely hooked up. Besides a wall outlet and a computer USB, theres no other power supply I can really give it and it still doesnt seem to work. Is there a specific crystal oscillator I need?? Cause honestly I just picked one randomly off the internet to order…

        -David

      • Hey,

        Yes you need one that works with the DS1307 – if it never ever worked that could be a reason why.

        If you google DS1307 you should be able to find the correct crystal specs. Otherwise it’s hard to know what to suggest without having a look.

        Nick

      • Hey david,

        when I started with the clock construction I faced similar experiences. I used 2 SMD quartzes with nice gold plated housings which didn’t let the clock IC swing. Then I tried a very simple and cheap quartz which you can find in any wrist watch and it worked.
        Check the datasheet of the DS1307 in which you will find which capacity the quartz should have and choose the quartz accordingly
        It will surely work with the right quartz and you will not have to ajust the frequency, which we did 20 years ago with extra trimmers ;–))

        I ordered my quartzes on http://www.reichelt.de which is my favourite dealer. At least you will find any kind of specs there. I hope they have their website in English…

        Regards from Bavaria in good old Germany

        Dieter

      • Hey guys, thank you so much for all the help…I ordered a 32 kHz crystal and it came and i tried it out and it works!!! I am so happy thank you guys for everything and I would have never been able to figure this out without you guys!!!

  9. Hi David,

    Congratulations and well done ! Sometimes the cheapest crystal is the best…

    Best regards
    Dieter

  10. Found it. Just needed daylight and a cup of coffee. Nice clock, and looking forward to the arrival of displays for my pong clock.

    • Great to hear it’s working, and great you are making the pong clock too.

      Ah what did you have wrong with your displays? Martin (few posts below) had his displays 90degrees wrong – maybe it’s related?

      Cheers
      Nick

  11. Just the way my matrices were connected, with DIN on the right-hand side. I reordered the addresses in “void plot (byte x, byte y, byte val)”.

    Re: Martin. I’ve seen some matrix modules on ebay that were oriented off 90 degrees; I think they’re based on the DIP MAX7219, rather than the SMD version. If that’s not the issue, I would love to find a software solution to rotate numbers 90 degrees for a vertically oriented clock…

    Had to laugh when I saw “//// vain attempt to modify __TIME__ for fudge factor.” Have tried the same, settled for char* time = “06:25:00”; // set ahead to fudge for compile and upload
    ds1307.adjust(DateTime(__DATE__, time));

    Also highly recommend the DS3231 RTC. It’s almost drop-in with DS1307 libraries (one exception: if(! ds1307.isrunning()) won’t work) and much more accurate. Can also get approximate temperature from it. And no fussy crystal needed.

    Pong clock is great. Added a piezo beeper and some minor mods; your documentation is excellent and makes it easy. Thanks.

  12. Ah that makes sense! And that makes a lot of sense for Martin’s issue! I couldn’t think of a way that would happen unless the actual matrices were wired differently.

    If it helps, all my printing to the display is done through the: void plot subroutine. In there you can see how it picks which of the 4 displays depending on the x coordinate and then turns that coordinate into an x value of 0-7 range for the particular display.

    You’d just need to fiddle with this subroutine by swapping the x and y stuff around to rotate everything 90 degrees.

  13. Hey Nick,

    Great pong clock. I’m currently working on building one from your design. I do have question? If I wanted to add a temperature sensor how would I go about it and what coding would I need? I’m new to the world of Arduino.

    Regards,

    Bob

    • Hey,

      Really cool you are making it. Hard to say about the temperature stuff without doing the work, but I think you can get a temperature module that also runs on 12C. You may even be able to get one combined with a clock module.

      Then you’d have to read in the temp and add an extra menu item to show it, or maybe interrupt the time loops every X seconds to display it by calling your showTemp function.

      Finally you;d have to adapt one of the clock modes to actually show temperature. That shouldn’t be too hard as all the characters are there, just need to print them on the display.

      It is quite a bit of work to be honest, but not so hard if you are into the coding.

      I think someone out there might have done it already but I can’t remember who!

  14. Nick I have built the clock as per your instructions but I am not having much success. The seconds are displayed on the left most display both “:” are displayed on the 2 middle displays.
    Do you have any idea what I can do to solve the problem? Do you have an email address I can send a small movie of what’s happening?
    Adrian

  15. Ugh… I can even get past verifying the Pong Clock…..

    Is the 1.6.5 engine the problem??

    Build options changed, rebuilding all
    Using library ht1632c in folder: /Users/nick/Documents/Arduino/libraries/ht1632c (legacy)
    Using library Font in folder: /Users/nick/Documents/Arduino/libraries/Font (legacy)
    Using library Wire in folder: /Applications/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/Wire
    Using library RTClib in folder: /Users/nick/Documents/Arduino/libraries/RTClib (legacy)
    Using library Button in folder: /Users/nick/Documents/Arduino/libraries/Button (legacy)

    /Applications/Arduino.app/Contents/Java/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10605 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -I/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino -I/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/variants/standard -I/Users/nick/Documents/Arduino/libraries/ht1632c -I/Users/nick/Documents/Arduino/libraries/Font -I/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/Wire -I/Users/nick/Documents/Arduino/libraries/RTClib -I/Users/nick/Documents/Arduino/libraries/Button /var/folders/w0/1ypcl96j31q1y54h1b58fcnm0000gn/T/build7807232187475855979.tmp/pongclock5_1.cpp -o /var/folders/w0/1ypcl96j31q1y54h1b58fcnm0000gn/T/build7807232187475855979.tmp/pongclock5_1.cpp.o
    In file included from pongclock5_1.ino:45:0:
    /Users/nick/Documents/Arduino/libraries/Font/Font.h:4:35: error: variable ‘myfont’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’
    unsigned char PROGMEM myfont[80][5] = {
    ^
    /Users/nick/Documents/Arduino/libraries/Font/Font.h:94:39: error: variable ‘mybigfont’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’
    unsigned char PROGMEM mybigfont[10][20] = {
    ^
    /Users/nick/Documents/Arduino/libraries/Font/Font.h:108:38: error: variable ‘mytinyfont’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’
    unsigned int PROGMEM mytinyfont[42][3] = {
    ^
    Error compiling.

    • Yes I think that could be a potential problem, they do change things between versions. I think I wrote in the readme in the download what version I tested with (can’t check as not near a computer) but see if you can find it and use that version of the Arduino software.

      • That’s annoying. I will try and see about getting the code to work with the latest Arduino version later this week.

      • Nick – I have updated the code – can you test with Arduino v1.6.5 for me? Download the miniclock code again from the link on this page, then replace the FontLEDClock folder you already have in your libraries folder with the new one from the download. Let me know if it compiles OK!

  16. Hello Nick. Thanks for sharing all your hard work with everyone. I was wanting to give my mom one of these for her birthday and change the code to automatically be in 12 hr mode for her. however, when this is done from “bool ampm = 1;” , the colon gets formated wrong when the hour digits are less than 10 . one “static” looking colon on the right and one blinking seconds next to it on the left. When the am/pm mode is set on the clock it works fine . Any help would be greatly appreciated.

  17. Hola nick, soy de argentina, tengo mi cartel de les realizado, pero cuando lo conectó no funciona como si no manda la señal y no prenden las matrices, alguna idea? Y sabes programación en bascom avr?

  18. Hello,
    you could find the complete code here, with 90 rotation.
    fully fonctionned
    if problem, (sometimes wordpress format the reply), give me your email adress,
    bye

    /***********************************************************************

    Mini Clock v1.0, Jul 2014 by Nick Hall
    Distributed under the terms of the GPL.

    For help on how to build the clock see my blog:
    https://123led.wordpress.com/

    Tested on IDE v1.6.5

    ***********************************************************************/

    //include libraries:
    #include “LedControl.h”
    #include // Font library
    #include // DS1307 clock
    #include “RTClib.h” // DS1307 clock
    #include // Button library by Alexander Brevig

    // Setup LED Matrix

    // pin 12 is connected to the DataIn on the display
    // pin 11 is connected to the CLK on the display
    // pin 10 is connected to LOAD on the display
    LedControl lc = LedControl(12, 11, 10, 4); //sets the 3 pins as 12, 11 & 10 and then sets 4 displays (max is 8 displays)

    //global variables
    byte intensity = 3; // Default intensity/brightness (0-15)
    byte clock_mode = 2; // Default clock mode. Default = 0 (basic_mode)
    bool random_mode = 0; // Define random mode – changes the display type every few hours. Default = 0 (off)
    byte old_mode = clock_mode; // Stores the previous clock mode, so if we go to date or whatever, we know what mode to go back to after.
    bool ampm = 0; // Define 12 or 24 hour time. 0 = 24 hour. 1 = 12 hour
    byte change_mode_time = 0; // Holds hour when clock mode will next change if in random mode.
    unsigned long delaytime = 500; // We always wait a bit between updates of the display
    int rtc[7]; // Holds real time clock output

    char days[7][4] = {
    “Sun”, “Mon”, “Tue”, “Wed”, “Thu”, “Fri”, “Sat”
    }; //day array – used in slide, basic_mode and jumble modes (The DS1307 outputs 1-7 values for day of week)
    char daysfull[7][9] = {
    “Sunday”, “Monday”, “Tuesday”, “Wed”, “Thursday”, “Friday”, “Saturday”
    };
    char suffix[4][3] = {
    “st”, “nd”, “rd”, “th”
    }; //date suffix array, used in slide, basic_mode and jumble modes. e,g, 1st 2nd …

    //define constants
    #define NUM_DISPLAY_MODES 3 // Number display modes (conting zero as the first mode)
    #define NUM_SETTINGS_MODES 4 // Number settings modes = 6 (conting zero as the first mode)
    #define SLIDE_DELAY 20 // The time in milliseconds for the slide effect per character in slide mode. Make this higher for a slower effect
    #define cls clear_display // Clear display

    RTC_DS1307 ds1307; // Create RTC object

    Button buttonA = Button(2, BUTTON_PULLUP); // Setup button A (using button library)
    Button buttonB = Button(3, BUTTON_PULLUP); // Setup button B (using button library)

    void setup() {

    digitalWrite(2, HIGH); // turn on pullup resistor for button on pin 2
    digitalWrite(3, HIGH); // turn on pullup resistor for button on pin 3
    digitalWrite(4, HIGH); // turn on pullup resistor for button on pin 4

    Serial.begin(9600); //start serial

    //initialize the 4 matrix panels
    //we have already set the number of devices when we created the LedControl
    int devices = lc.getDeviceCount();
    //we have to init all devices in a loop
    for (int address = 0; address = 0 && x = 8 && x = 16 && x = 24 && x <= 31) {
    address = 3;
    x = x – 24;
    y=7-y;
    }

    if (val == 1) {
    lc.setLed(address, x, y, true);
    } else {
    lc.setLed(address, x, y, false);
    }
    }

    //clear screen
    void clear_display() {
    for (byte address = 0; address 0; i–) {
    for (byte address = 0; address < 4; address++) {
    lc.setIntensity(address, i);
    }
    delay(30); //change this to change fade down speed
    }

    clear_display(); //clear display completely (off)

    //reset intentsity to global val
    for (byte address = 0; address < 4; address++) {
    lc.setIntensity(address, intensity);
    }
    }

    //power up led test & display software version number
    void printver() {

    byte i = 0;
    char ver_a[9] = "Vers 1.0";
    char ver_b[9] = " Hello! ";

    //test all leds.
    for (byte x = 0; x <= 31; x++) {
    for (byte y = 0; y = ‘A’ && c = ‘a’ && c = ‘0’ && c <= '9') {
    c = (c – '0') + 32;
    }
    else if (c == ' ') {
    c = 0; // space
    }
    else if (c == '.') {
    c = 27; // full stop
    }
    else if (c == ':') {
    c = 28; // colon
    }
    else if (c == '\'') {
    c = 29; // single quote mark
    }
    else if (c == '!') {
    c = 30; // single quote mark
    }
    else if (c == '?') {
    c = 31; // single quote mark
    }

    for (byte col = 0; col < 3; col++) {
    dots = pgm_read_byte_near(&mytinyfont[c][col]);
    for (char row = 0; row > row))
    plot(x + col, y + row, 1);
    else
    plot(x + col, y + row, 0);
    }
    }
    }

    void putnormalchar(byte x, byte y, char c)
    {

    byte dots;
    // if (c >= ‘A’ && c = ‘a’ && c = ‘A’ && c = ‘a’ && c = ‘0’ && c ‘) {
    c = 30; // clock_mode selector arrow
    }
    else if (c >= -80 && c <= -67) {
    c *= -1;
    }

    for (char col = 0; col < 5; col++) {
    dots = pgm_read_byte_near(&myfont[c][col]);
    for (char row = 0; row = 0) && (x = 0) && (y > row)) { // only 7 rows.
    plot(x + col, y + row, 1);
    } else {
    plot(x + col, y + row, 0);
    }
    //}
    }
    }
    }

    //small_mode
    //show the time in small 3×5 characters with seconds display

    void small_mode() {

    char textchar[8]; // the 16 characters on the display
    byte mins = 100; //mins
    byte secs = rtc[0]; //seconds
    byte old_secs = secs; //holds old seconds value – from last time seconds were updated o display – used to check if seconds have changed

    cls();

    //run clock main loop as long as run_mode returns true
    while (run_mode()) {

    get_time();

    //check for button press
    if (buttonA.uniquePress()) {
    switch_mode();
    return;
    }
    if (buttonB.uniquePress()) {
    display_date();
    return;
    }

    //if secs changed then update them on the display
    secs = rtc[0];
    if (secs != old_secs) {

    //secs
    char buffer[3];
    itoa(secs, buffer, 10);

    //fix – as otherwise if num has leading zero, e.g. “03” secs, itoa coverts this to chars with space “3 “.
    if (secs 12) {
    hours = hours – ampm * 12;
    }
    if (hours < 1) {
    hours = hours + ampm * 12;
    }

    //byte dow = rtc[3]; // the DS1307 outputs 0 – 6 where 0 = Sunday0 – 6 where 0 = Sunday.
    //byte date = rtc[4];

    //set characters
    char buffer[3];
    itoa(hours, buffer, 10);

    //fix – as otherwise if num has leading zero, e.g. "03" hours, itoa coverts this to chars with space "3 ".
    if (hours < 10) {
    buffer[1] = buffer[0];
    //if we are in 12 hour mode blank the leading zero.
    if (ampm) {
    buffer[0] = ' ';
    }
    else {
    buffer[0] = '0';
    }
    }
    //set hours chars
    textchar[0] = buffer[0];
    textchar[1] = buffer[1];
    textchar[2] = ':';

    itoa (mins, buffer, 10);
    if (mins < 10) {
    buffer[1] = buffer[0];
    buffer[0] = '0';
    }
    //set mins characters
    textchar[3] = buffer[0];
    textchar[4] = buffer[1];

    //do seconds
    textchar[5] = ':';
    buffer[3];
    secs = rtc[0];
    itoa(secs, buffer, 10);

    //fix – as otherwise if num has leading zero, e.g. "03" secs, itoa coverts this to chars with space "3 ".
    if (secs < 10) {
    buffer[1] = buffer[0];
    buffer[0] = '0';
    }
    //set seconds
    textchar[6] = buffer[0];
    textchar[7] = buffer[1];

    byte x = 0;
    byte y = 0;

    //print each char
    for (byte x = 0; x 1:00am in 12 hour mode.

    //do 12/24 hour conversion if ampm set to 1
    byte hours = rtc[2];

    if (hours > 12) {
    hours = hours – ampm * 12;
    }
    if (hours < 1) {
    hours = hours + ampm * 12;
    }

    //do offset conversion
    if (ampm && hours 12) {
    hours = hours – ampm * 12;
    }
    if (hours < 1) {
    hours = hours + ampm * 12;
    }

    itoa(hours, buffer, 10);

    //if hours < 10 the num e.g. "3" hours, itoa coverts this to chars with space "3 " which we dont want
    if (hours < 10) {
    buffer[1] = buffer[0];
    buffer[0] = '0';
    }

    //print hours
    //if we in 12 hour mode and hours < 10, then don't print the leading zero, and set the offset so we centre the display with 3 digits.
    if (ampm && hours < 10) {
    offset = 2;

    //if the time is 1:00am clear the entire display as the offset changes at this time and we need to blank out the old 12:59
    if ((hours == 1 && mins == 0) ) {
    cls();
    }
    }
    else {
    //else no offset and print hours tens digit
    offset = 0;

    //if the time is 10:00am clear the entire display as the offset changes at this time and we need to blank out the old 9:59
    if (hours == 10 && mins == 0) {
    cls();
    }

    putnormalchar(1, 0, buffer[0]);
    }
    //print hours ones digit
    putnormalchar(7 – offset, 0, buffer[1]);

    //print mins
    //add leading zero if mins < 10
    itoa (mins, buffer, 10);
    if (mins 12) {
    hours = hours – ampm * 12;
    }
    if (hours < 1) {
    hours = hours + ampm * 12;
    }

    //split all date and time into individual digits – stick in digits_new array

    //rtc[0] = secs //array pos and digit stored
    //digits_new[0] = (rtc[0]%10); //0 – secs ones
    //digits_new[1] = ((rtc[0]/10)%10); //1 – secs tens
    //rtc[1] = mins
    digits_new[0] = (rtc[1] % 10); //2 – mins ones
    digits_new[1] = ((rtc[1] / 10) % 10); //3 – mins tens
    //rtc[2] = hours
    digits_new[2] = (hours % 10); //4 – hour ones
    digits_new[3] = ((hours / 10) % 10); //5 – hour tens
    //rtc[4] = date
    //digits_new[6] = (rtc[4]%10); //6 – date ones
    //digits_new[7] = ((rtc[4]/10)%10); //7 – date tens

    //draw initial screen of all chars. After this we just draw the changes.

    //compare digits 0 to 3 (mins and hours)
    for (byte i = 0; i <= 3; i++) {
    //see if digit has changed…
    if (digits_old[i] != digits_new[i]) {

    //run 9 step animation sequence for each in turn
    for (byte seq = 0; seq Feb 01 then ones digit doesn’t change
    if ((digits_old[6] != digits_new[6]) || (digits_old[7] != digits_new[7])) {
    //change the day shown. Loop below goes through each of the 3 chars in turn e.g. “MON”
    for (byte day_char = 0; day_char <=2 ; day_char++){
    //run the anim sequence for each char
    for (byte seq = 0; seq = 6; i–){
    if (digits_old[i] != digits_new[i]) {
    for (byte seq = 0; seq <=8 ; seq++){
    itoa(digits_old[i],old_char,10);
    itoa(digits_new[i],new_char,10);
    slideanim(digits_x_pos[i],8,seq,old_char[0],new_char[0]);
    delay(SLIDE_DELAY);
    }
    }
    }

    //print the day suffix "nd" "rd" "th" etc. First work out date 2 letter suffix – eg st, nd, rd, th
    byte s = 3; //the pos to read our suffix array from.
    byte date = rtc[4];
    if(date == 1 || date == 21 || date == 31) {
    s = 0;
    }
    else if (date == 2 || date == 22) {
    s = 1;
    }
    else if (date == 3 || date == 23) {
    s = 2;
    }

    for (byte suffix_char = 0; suffix_char <=1 ; suffix_char++){
    for (byte seq = 0; seq <=8 ; seq++){
    slideanim((suffix_char*6)+36,8,seq,old_chars[suffix_char+3],suffix[s][suffix_char]); // we pass in the old_char array char as the current char and the suffix array as the new char
    delay(SLIDE_DELAY);
    }
    //save the suffic char in the old chars array at array pos 3 and 5. We use these chars next time we change the suffix and feed it to the animation as the current char. The updated char is fed in as the new char.
    old_chars[suffix_char+3] = suffix[s][suffix_char];
    }
    }//end do date line
    */

    //save digita array tol old for comparison next loop
    for (byte i = 0; i <= 3; i++) {
    digits_old[i] = digits_new[i];
    }
    }//secs/oldsecs
    }//while loop
    fade_down();
    }

    //called by slide
    //this draws the animation of one char sliding on and the other sliding off. There are 8 steps in the animation, we call the function to draw one of the steps from 0-7
    //inputs are are char x and y, animation frame sequence (0-7) and the current and new chars being drawn.
    void slideanim(byte x, byte y, byte sequence, char current_c, char new_c) {

    // To slide one char off and another on we need 9 steps or frames in sequence…

    // seq# 0123456 <-rows of the display
    // | |||||||
    // seq0 0123456 START – all rows of the display 0-6 show the current characters rows 0-6
    // seq1 012345 current char moves down one row on the display. We only see it's rows 0-5. There are at display positions 1-6 There is a blank row inserted at the top
    // seq2 6 01234 current char moves down 2 rows. we now only see rows 0-4 at display rows 2-6 on the display. Row 1 of the display is blank. Row 0 shows row 6 of the new char
    // seq3 56 0123
    // seq4 456 012 half old / half new char
    // seq5 3456 01
    // seq6 23456 0
    // seq7 123456
    // seq8 0123456 END – all rows show the new char

    //from above we can see…
    //currentchar runs 0-6 then 0-5 then 0-4 all the way to 0. starting Y position increases by 1 row each time.
    //new char runs 6 then 5-6 then 4-6 then 3-6. starting Y position increases by 1 row each time.

    //if sequence number is below 7, we need to draw the current char
    if (sequence = ‘A’ && || (current_c >= ‘a’ && current_c = ‘A’ && current_c = ‘a’ && current_c = ‘0’ && current_c ‘) {
    current_c = 30; // clock_mode selector arrow
    }

    byte curr_char_row_max = 7 – sequence; //the maximum number of rows to draw is 6 – sequence number
    byte start_y = sequence; //y position to start at – is same as sequence number. We inc this each loop

    //plot each row up to row maximum (calculated from sequence number)
    for (byte curr_char_row = 0; curr_char_row <= curr_char_row_max; curr_char_row++) {
    for (byte col = 0; col > curr_char_row))
    plot(x + col, y + start_y, 1); //plot led on
    else
    plot(x + col, y + start_y, 0); //else plot led off
    }
    start_y++;//add one to y so we draw next row one down
    }
    }

    //draw a blank line between the characters if sequence is between 1 and 7. If we don’t do this we get the remnants of the current chars last position left on the display
    if (sequence >= 1 && sequence <= 8) {
    for (byte col = 0; col = 2) {

    //work out char
    byte dots;
    //if (new_c >= ‘A’ && new_c = ‘a’ && new_c = ‘A’ && new_c = ‘a’ && new_c = ‘0’ && new_c ‘) {
    new_c = 30; // clock_mode selector arrow
    }

    byte newcharrowmin = 6 – (sequence – 2); //minimumm row num to draw for new char – this generates an output of 6 to 0 when fed sequence numbers 2-8. This is the minimum row to draw for the new char
    byte start_y = 0; //y position to start at – is same as sequence number. we inc it each row

    //plot each row up from row minimum (calculated by sequence number) up to 6
    for (byte newcharrow = newcharrowmin; newcharrow <= 6; newcharrow++) {
    for (byte col = 0; col > newcharrow))
    plot(x + col, y + start_y, 1); //plot led on
    else
    plot(x + col, y + start_y, 0); //else plot led off
    }
    start_y++;//add one to y so we draw next row one down
    }
    }
    }

    //print a clock using words rather than numbers
    void word_clock() {

    cls();

    char numbers[19][10] = {
    “one”, “two”, “three”, “four”, “five”, “six”, “seven”, “eight”, “nine”, “ten”,
    “eleven”, “twelve”, “thirteen”, “fourteen”, “fifteen”, “sixteen”, “seventeen”, “eighteen”, “nineteen”
    };
    char numberstens[5][7] = {
    “ten”, “twenty”, “thirty”, “forty”, “fifty”
    };

    //potentially 3 lines to display
    char str_a[8];
    char str_b[8];
    char str_c[8];

    //byte hours_y, mins_y; //hours and mins and positions for hours and mins lines

    byte hours = rtc[2];
    if (hours > 12) {
    hours = hours – ampm * 12;
    }
    if (hours 12) {
    hours = hours – 12;
    }
    if (hours == 0) {
    hours = 12;
    }

    //split mins value up into two separate digits
    int minsdigit = rtc[1] % 10;
    byte minsdigitten = (rtc[1] / 10) % 10;

    //if mins <= 10 , then top line has to read "minsdigti past" and bottom line reads hours
    if (mins = 11 && mins <= 19) {
    if (mins 0){
    //check for button press
    if (buttonA.uniquePress()) {
    switch_mode();
    return;
    }
    if (buttonB.uniquePress()) {
    display_date();
    }
    delay(1);
    counter–;
    }
    fade_down();

    //print line b
    len = 0;
    while (str_b[len]) {
    len++;
    }; //get length of message
    offset_top = (31 – ((len – 1) * 4)) / 2;

    i = 0;
    while (str_b[i]) {
    puttinychar((i * 4) + offset_top, 1, str_b[i]);
    i++;
    }

    //hold display but check for button presses
    counter = 1000;
    while (counter > 0){
    if (buttonA.uniquePress()) {
    switch_mode();
    return;
    }
    if (buttonB.uniquePress()) {
    display_date();
    }
    delay(1);
    counter–;
    }
    fade_down();

    //print line c if there.
    len = 0;
    while (str_c[len]) {
    len++;
    }; //get length of message
    offset_top = (31 – ((len – 1) * 4)) / 2;

    i = 0;
    while (str_c[i]) {
    puttinychar((i * 4) + offset_top, 1, str_c[i]);
    i++;
    }
    counter = 1000;
    while (counter > 0){
    //check for button press
    if (buttonA.uniquePress()) {
    switch_mode();
    return;
    }
    if (buttonB.uniquePress()) {
    display_date();
    }
    delay(1);
    counter–;
    }
    fade_down();

    //hold display blank but check for button presses before starting again.
    counter = 1000;
    while (counter > 0){
    //check for button press
    if (buttonA.uniquePress()) {
    switch_mode();
    return;
    }
    if (buttonB.uniquePress()) {
    display_date();
    }
    delay(1);
    counter–;
    }
    }
    fade_down();
    }

    /// scroll message – not used at present – too slow.
    void scroll() {

    char message[] = {“Hello There “};

    cls();
    byte p = 6; //current pos in string
    byte chara[] = {0, 1, 2, 3, 4, 5}; //chars from string
    int x[] = {0, 6, 12, 18, 24, 30}; //xpos for each char
    byte y = 0; //y pos

    // clear_buffer();

    while (message[p] != ‘\0’) {

    //draw all 6 chars
    for (byte c = 0; c < 6; c++) {

    putnormalchar(x[c],y,message[ chara[c] ]);

    //draw a line of pixels turned off after each char,otherwise the gaps between the chars have pixels left in them from the previous char
    for (byte yy = 0 ; yy < 8; yy ++) {
    plot(x[c] + 5, yy, 0);
    }

    //take one off each chars position
    x[c] = x[c] – 1;
    }

    //reset a char if it's gone off screen
    for (byte i = 0; i <= 5; i++) {
    if (x[i] 9){
    suffixposx = 8;
    puttinychar(4+offset, 1, buffer[1]);
    offset = 8; //offset to centre text if 4 chars
    }

    //print the 2 suffix characters
    puttinychar(suffixposx+offset, 1, suffix[s][0]);
    puttinychar(suffixposx+4+offset, 1, suffix[s][1]);

    delay(1000);
    fade_down();

    //print the month name

    //get length of text in pixels, that way we can centre it on the display by divindin the remaining pixels b2 and using that as an offset
    len = 0;
    while(monthnames[month][len]) {
    len++;
    };
    offset = (31 – ((len-1)*4)) / 2; //our offset to centre up the text
    i = 0;
    while(monthnames[month][i])
    {
    puttinychar((i*4) +offset, 1, monthnames[month][i]);
    i++;
    }

    delay(1000);
    fade_down();
    }

    //dislpay menu to change the clock mode
    void switch_mode() {

    //remember mode we are in. We use this value if we go into settings mode, so we can change back from settings mode (6) to whatever mode we were in.
    old_mode = clock_mode;

    char* modes[] = {
    “Basic”, “Small”, “Slide”, “Words”, “Setup”
    };

    byte next_clock_mode;
    byte firstrun = 1;

    //loop waiting for button (timeout after 35 loops to return to mode X)
    for (int count = 0; count NUM_DISPLAY_MODES + 1 ) {
    clock_mode = 0;
    }

    //print arrown and current clock_mode name on line one and print next clock_mode name on line two
    char str_top[9];

    //strcpy (str_top, “-“);
    strcpy (str_top, modes[clock_mode]);

    next_clock_mode = clock_mode + 1;
    if (next_clock_mode > NUM_DISPLAY_MODES + 1 ) {
    next_clock_mode = 0;
    }

    byte i = 0;
    while (str_top[i]) {
    putnormalchar(i * 6, 0, str_top[i]);
    i++;
    }
    firstrun = 0;
    }
    delay(50);
    }
    }

    //run clock main loop as long as run_mode returns true
    byte run_mode() {

    //if random mode is on… check the hour when we change mode.
    if (random_mode) {
    //if hour value in change mode time = hours. then reurn false = i.e. exit mode.
    if (change_mode_time == rtc[2]) {
    //set the next random clock mode and time to change it
    set_next_random();
    //exit the current mode.
    return 0;
    }
    }
    //else return 1 – keep running in this mode
    return 1;
    }

    //set the next hour the clock will change mode when random mode is on
    void set_next_random() {

    //set the next hour the clock mode will change – current time plus 1 – 4 hours
    get_time();
    change_mode_time = rtc[2] + random (1, 5);

    //if change_mode_time now happens to be over 23, then set it to between 1 and 3am
    if (change_mode_time > 23) {
    change_mode_time = random (1, 4);
    }

    //set the new clock mode
    clock_mode = random(0, NUM_DISPLAY_MODES + 1); //pick new random clock mode
    }

    //dislpay menu to change the clock settings
    void setup_menu() {

    char* set_modes[] = {
    “Rndom”, “24 Hr”,”Set”, “Brght”, “Exit”};
    if (ampm == 0) {
    set_modes[1] = (“12 Hr”);
    }

    byte setting_mode = 0;
    byte next_setting_mode;
    byte firstrun = 1;

    //loop waiting for button (timeout after 35 loops to return to mode X)
    for(int count=0; count NUM_SETTINGS_MODES) {
    setting_mode = 0;
    }

    //print arrown and current clock_mode name on line one and print next clock_mode name on line two
    char str_top[9];

    strcpy (str_top, set_modes[setting_mode]);

    next_setting_mode = setting_mode + 1;
    if (next_setting_mode > NUM_SETTINGS_MODES) {
    next_setting_mode = 0;
    }

    byte i = 0;
    while(str_top[i]) {
    putnormalchar(i*6, 0, str_top[i]);
    i++;
    }

    firstrun = 0;
    }
    delay(50);
    }

    //pick the mode
    switch(setting_mode){
    case 0:
    set_random();
    break;
    case 1:
    set_ampm();
    break;
    case 2:
    set_time();
    break;
    case 3:
    set_intensity();
    break;
    case 4:
    //exit menu
    break;
    }

    //change the clock from mode 6 (settings) back to the one it was in before
    clock_mode=old_mode;
    }

    //toggle random mode – pick a different clock mode every few hours
    void set_random(){
    cls();

    char text_a[9] = “Off”;
    char text_b[9] = “On”;
    byte i = 0;

    //if random mode is on, turn it off
    if (random_mode){

    //turn random mode off
    random_mode = 0;

    //print a message on the display
    while(text_a[i]) {
    putnormalchar((i*6), 0, text_a[i]);
    i++;
    }
    } else {
    //turn randome mode on.
    random_mode = 1;

    //set hour mode will change
    set_next_random();

    //print a message on the display
    while(text_b[i]) {
    putnormalchar((i*6), 0, text_b[i]);
    i++;
    }
    }
    delay(1500); //leave the message up for a second or so
    }

    //set 12 or 24 hour clock
    void set_ampm() {

    // AM/PM or 24 hour clock mode – flip the bit (makes 0 into 1, or 1 into 0 for ampm mode)
    ampm = (ampm ^ 1);
    cls();
    }

    //change screen intensityintensity
    void set_intensity() {

    cls();

    byte i = 0;
    char text[7] = “Bright”;
    while(text[i]) {
    puttinychar((i*4)+4, 0, text[i]);
    i++;
    }

    //wait for button input
    while (!buttonA.uniquePress()) {

    levelbar (0,6,(intensity*2)+2,2); //display the intensity level as a bar
    while (buttonB.isPressed()) {

    if(intensity == 15) {
    intensity = 0;
    cls ();
    }
    else {
    intensity++;
    }
    //print the new value
    i = 0;
    while(text[i]) {
    puttinychar((i*4)+4, 0, text[i]);
    i++;
    }

    //display the intensity level as a bar
    levelbar (0,6,(intensity*2)+2,2);

    //change the brightness setting on the displays
    for (byte address = 0; address < 4; address++) {
    lc.setIntensity(address, intensity);
    }
    delay(150);
    }
    }
    }

    // display a horizontal bar on the screen at offset xposr by ypos with height and width of xbar, ybar
    void levelbar (byte xpos, byte ypos, byte xbar, byte ybar) {
    for (byte x = 0; x < xbar; x++) {
    for (byte y = 0; y <= ybar; y++) {
    plot(x+xpos, y+ypos, 1);
    }
    }
    }

    //set time and date routine
    void set_time() {

    cls();

    //fill settings with current clock values read from clock
    get_time();
    byte set_min = rtc[1];
    byte set_hr = rtc[2];
    byte set_date = rtc[4];
    byte set_mnth = rtc[5];
    int set_yr = rtc[6];

    //Set function – we pass in: which 'set' message to show at top, current value, reset value, and rollover limit.
    set_date = set_value(2, set_date, 1, 31);
    set_mnth = set_value(3, set_mnth, 1, 12);
    set_yr = set_value(4, set_yr, 2013, 2099);
    set_hr = set_value(1, set_hr, 0, 23);
    set_min = set_value(0, set_min, 0, 59);

    ds1307.adjust(DateTime(set_yr, set_mnth, set_date, set_hr, set_min));

    cls();
    }

    //used to set min, hr, date, month, year values. pass
    //message = which 'set' message to print,
    //current value = current value of property we are setting
    //reset_value = what to reset value to if to rolls over. E.g. mins roll from 60 to 0, months from 12 to 1
    //rollover limit = when value rolls over
    int set_value(byte message, int current_value, int reset_value, int rollover_limit){

    cls();
    char messages[6][17] = {
    "Set Mins", "Set Hour", "Set Day", "Set Mnth", "Set Year"};

    //Print "set xyz" top line
    byte i = 0;
    while(messages[message][i])
    {
    puttinychar(i*4 , 1, messages[message][i]);
    i++;
    }

    delay(2000);
    cls();

    //print digits bottom line
    char buffer[5] = " ";
    itoa(current_value,buffer,10);
    puttinychar(0 , 1, buffer[0]);
    puttinychar(4 , 1, buffer[1]);
    puttinychar(8 , 1, buffer[2]);
    puttinychar(12, 1, buffer[3]);

    delay(300);
    //wait for button input
    while (!buttonA.uniquePress()) {

    while (buttonB.isPressed()){

    if(current_value < rollover_limit) {
    current_value++;
    }
    else {
    current_value = reset_value;
    }
    //print the new value
    itoa(current_value, buffer ,10);
    puttinychar(0 , 1, buffer[0]);
    puttinychar(4 , 1, buffer[1]);
    puttinychar(8 , 1, buffer[2]);
    puttinychar(12, 1, buffer[3]);
    delay(150);
    }
    }
    return current_value;
    }

    void get_time()
    {
    //get time
    DateTime now = ds1307.now();
    //save time to array
    rtc[6] = now.year();
    rtc[5] = now.month();
    rtc[4] = now.day();
    rtc[3] = now.dayOfWeek(); //returns 0-6 where 0 = Sunday
    rtc[2] = now.hour();
    rtc[1] = now.minute();
    rtc[0] = now.second();

    //flash arduino led on pin 13 every second
    //if ( (rtc[0] % 2) == 0) {
    // digitalWrite(13, HIGH);
    //}
    //else {
    // digitalWrite(13, LOW);
    //}

    //print the time to the serial port – useful for debuging RTC issues
    /*
    Serial.print(rtc[2]);
    Serial.print(":");
    Serial.print(rtc[1]);
    Serial.print(":");
    Serial.println(rtc[0]);
    */
    }

  19. Hello,
    Build this clock on 8 matrices, had to redo the code completely for the digits and fonts.
    the display showed it all mirrored and 90 degrees tilted.
    Really enjoyed doing this and played around with the code, only thing left is to get the right day to display when the clock boot.
    here is the Youtube video.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s