|
Arduino Nano R3 |
x 1 | |
|
DS3231SN#Analog Devices Inc./Maxim Integrated
|
x 1 | |
|
8x32 MAX7219 Led matrix module |
x 1 | |
|
Pushbutton Switch |
x 2 |
![]() |
arduino IDEArduino
|
|
![]() |
Soldering Iron Kit |
DIY Arduino Holographic Matrix Clock
This is another in my series of unusual DIY clocks, this time realized based on the holographic effect.It's really very interesting to watch, and you get the impression that the numbers are floating in the air.
Otherwise, this is the simplest way of creating a hologram, where the light source and the screen are placed at an angle of 45 degrees. In case when we have a text or a numerical message, we need to know that the information of the light source should be a mirror of the original image which we should see on the screen.
For the light source I use a very simple to build matrix clock, which is actually a modified version of one of my previous projects entitled "Arduino Nano mini LED matrix clock" , where I modified the original code to get a mirrored image.
As I mentioned the clock is really simple to build, and consists of several components:
- Arduino nano microcontroller
- DS3231 Realtime clock module
- 8x32 Led matrix module
- and two buttons
If you want to make a PCB for this project, or for any other electronic project, PCBway (www.pcbway.com) is a great choice for you. PCBway is one of the most experienced PCB manufacturing company in China in field of PCB prototype and fabrication. They provide completed PCB assembly service with worldwide free shipping , and ISO9001 quality control system. Also, on their site there is an online gerber viewer where you can upload your gerber and drill files to render your board.
This little clock is full of different faces, work modes, and other options that you will be able to see in the continuation of the video.
As for the mechanical construction of the device, it is necessary to observe several rules:
- The primary light source should be positioned so that it cannot be seen from the front of the device.
- The screen should be placed at an angle of 45 degrees with respect to the plane of the light source.
- Also, The screen should be as thin as possible, but also strong enough to keep its shape. If ordinary glass with a thickness of 3 or 4 mm is used, the light will be refracted twice, so the image will be blurred.
- The entire device should be covered with black matte wallpaper or paint, in order to have as little reflected light as possible on the surrounding parts, for a more realistic appearance.
- By changing the distance between the source and the screen, the height of the hologram image changes, so we have to determine this distance experimentally.
If the source and screen are set according to the recommendations given above, the hologram image appears in the middle of the screen. With two buttons we can adjust the various options.
I adapted this device from the beginning so that it can also displays holograms from a smartphone. For this purpose, the light of the smartphone should be set to maximum, and then a video specially designed for the hologram presentation should be selected. These videos are usually with a black background, so that the hologram effect is more emphasized.
/*********************************************************************** 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: http://123led.wordpress.com/ Tested on IDE v1.6.5 modified by Mirko Pavleski May 2023 ***********************************************************************/ //include libraries: #include "LedControl.h" #include <FontLEDClock.h> // Font library #include <Wire.h> // DS1307 clock #include "RTClib.h" // DS1307 clock #include <Button.h> // Button library by Alexander Brevig // Setup LED Matrix // pin 10 is connected to the DataIn on the display // pin 12 is connected to the CLK on the display // pin 11 is connected to LOAD on the display(cs) LedControl lc = LedControl(10, 12, 11, 4); //sets the 3 pins as 12, 11 & 10 and then sets 4 displays (max is 8 displays) //global variables byte intensity = 7; // Default intensity/brightness (0-15) byte clock_mode = 0; // 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 < devices; address++) { /*The MAX72XX is in power-saving mode on startup*/ lc.shutdown(address, false); /* Set the brightness to a medium values */ lc.setIntensity(address, intensity); /* and clear the display */ lc.clearDisplay(address); } //Setup DS1307 RTC #ifdef AVR Wire.begin(); #else Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino #endif ds1307.begin(); //start RTC Clock if (! ds1307.isrunning()) { Serial.println("RTC is NOT running!"); ds1307.adjust(DateTime(__DATE__, __TIME__)); // sets the RTC to the date & time this sketch was compiled } //Show software version & hello message printver(); //enable red led digitalWrite(13, HIGH); } void loop() { //run the clock with whatever mode is set by clock_mode - the default is set at top of code. switch (clock_mode){ case 0: basic_mode(); break; case 1: small_mode(); break; case 2: slide(); break; case 3: word_clock(); break; case 4: setup_menu(); break; } } //plot a point on the display void plot (byte x, byte y, byte val) { //select which matrix depending on the x coord byte address; if (x >= 0 && x <= 7) { address = 3; } if (x >= 8 && x <= 15) { address = 2; x = x - 8; } if (x >= 16 && x <= 23) { address = 1; x = x - 16; } if (x >= 24 && x <= 31) { address = 0; x = x - 24; } if (val == 1) { // lc.setLed(address, y, x, true); lc.setLed(address, 7-y, x, true); } else { // lc.setLed(address, y, x, false); lc.setLed(address, 7-y, x, false); } } //clear screen void clear_display() { for (byte address = 0; address < 4; address++) { lc.clearDisplay(address); } } //fade screen down void fade_down() { //fade from global intensity to 1 for (byte i = intensity; i > 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 <= 7; y++) { plot(x, y, 1); } } delay(500); fade_down(); while (ver_a[i]) { puttinychar((i * 4), 1, ver_a[i]); delay(35); i++; } delay(700); fade_down(); i = 0; while (ver_b[i]) { puttinychar((i * 4), 1, ver_b[i]); delay(35); i++; } delay(700); fade_down(); } // puttinychar // Copy a 3x5 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate // This is unoptimized and simply uses plot() to draw each dot. void puttinychar(byte x, byte y, char c) { byte dots; if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) { c &= 0x1F; // A-Z maps to 1-26 } else if (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 < 5; row++) { if (dots & (16 >> 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 <= 'Z' || (c >= 'a' && c <= 'z') ) { // c &= 0x1F; // A-Z maps to 1-26 // } if (c >= 'A' && c <= 'Z' ) { c &= 0x1F; // A-Z maps to 1-26 } else if (c >= 'a' && c <= 'z') { c = (c - 'a') + 41; // A-Z maps to 41-67 } else if (c >= '0' && c <= '9') { c = (c - '0') + 31; } else if (c == ' ') { c = 0; // space } else if (c == '.') { c = 27; // full stop } else if (c == '\'') { c = 28; // single quote mark } else if (c == ':') { c = 29; // clock_mode selector arrow } else if (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 < 7; row++) { //check coords are on screen before trying to plot //if ((x >= 0) && (x <= 31) && (y >= 0) && (y <= 7)){ if (dots & (64 >> row)) { // only 7 rows. plot(x + col, y + row, 1); } else { plot(x + col, y + row, 0); } //} } } } //small_mode //show the time in small 3x5 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 < 10) { buffer[1] = buffer[0]; buffer[0] = '0'; } puttinychar( 20, 1, ':'); //seconds colon puttinychar( 24, 1, buffer[0]); //seconds puttinychar( 28, 1, buffer[1]); //seconds old_secs = secs; } //if minute changes change time if (mins != rtc[1]) { //reset these for comparison next time mins = rtc[1]; byte hours = rtc[2]; if (hours > 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 < 6 ; x++) { puttinychar( x * 4, 1, textchar[x]); } } delay(50); } fade_down(); } // basic_mode() // show the time in 5x7 characters void basic_mode() { cls(); char buffer[3]; //for int to char conversion to turn rtc values into chars we can print on screen byte offset = 0; //used to offset the x postition of the digits and centre the display when we are in 12 hour mode and the clock shows only 3 digits. e.g. 3:21 byte x, y; //used to draw a clear box over the left hand "1" of the display when we roll from 12:59 -> 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 < 10) { offset = 2; } //set the next minute we show the date at //set_next_date(); // initially set mins to value 100 - so it wll never equal rtc[1] on the first loop of the clock, meaning we draw the clock display when we enter the function byte secs = 100; byte mins = 100; int count = 0; //run clock main loop as long as run_mode returns true while (run_mode()) { //get the time from the clock chip get_time(); //check for button press if (buttonA.uniquePress()) { switch_mode(); return; } if (buttonB.uniquePress()) { display_date(); return; } //check whether it's time to automatically display the date //check_show_date(); //draw the flashing : as on if the secs have changed. if (secs != rtc[0]) { //update secs with new value secs = rtc[0]; //draw : plot (15 - offset, 2, 1); //top point plot (15 - offset, 5, 1); //bottom point count = 400; } //if count has run out, turn off the : if (count == 0) { plot (15 - offset, 2, 0); //top point plot (15 - offset, 5, 0); //bottom point } else { count--; } //re draw the display if button pressed or if mins != rtc[1] i.e. if the time has changed from what we had stored in mins, (also trigggered on first entering function when mins is 100) if (mins != rtc[1]) { //update mins and hours with the new values mins = rtc[1]; hours = rtc[2]; //adjust hours of ampm set to 12 hour mode if (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 < 10) { buffer[1] = buffer[0]; buffer[0] = '0'; } //print mins tens and ones digits putnormalchar(19 - offset, 0, buffer[0]); putnormalchar(25 - offset, 0, buffer[1]); } } fade_down(); } //like basic_mode but with slide effect void slide() { byte digits_old[4] = {99, 99, 99, 99}; //old values we store time in. Set to somthing that will never match the time initially so all digits get drawn wnen the mode starts byte digits_new[4]; //new digits time will slide to reveal byte digits_x_pos[4] = {25, 19, 7, 1}; //x pos for which to draw each digit at char old_char[2]; //used when we use itoa to transpose the current digit (type byte) into a char to pass to the animation function char new_char[2]; //used when we use itoa to transpose the new digit (type byte) into a char to pass to the animation function //old_chars - stores the 5 day and date suffix chars on the display. e.g. "mon" and "st". We feed these into the slide animation as the current char when these chars are updated. //We sent them as A initially, which are used when the clocl enters the mode and no last chars are stored. //char old_chars[6] = "AAAAA"; //plot the clock colon on the display cls(); putnormalchar( 13, 0, ':'); byte old_secs = rtc[0]; //store seconds in old_secs. We compare secs and old secs. WHen they are different we redraw the display //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 have changed then update the display if (rtc[0] != old_secs) { old_secs = rtc[0]; //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; } //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 <= 8 ; seq++) { //convert digit to string itoa(digits_old[i], old_char, 10); itoa(digits_new[i], new_char, 10); //if set to 12 hour mode and we're on digit 2 (hours tens mode) then check to see if this is a zero. If it is, blank it instead so we get 2.00pm not 02.00pm if (ampm && i == 3) { if (digits_new[3] == 0) { new_char[0] = ' '; } if (digits_old[3] == 0) { old_char[0] = ' '; } } //draw the animation frame for each digit slideanim(digits_x_pos[i], 0, seq, old_char[0], new_char[0]); delay(SLIDE_DELAY); } } } /* //compare date digit 6 (ones) and (7) tens - if either of these change we need to update the date line. We compare date tens as say from Jan 31 -> 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 <=8 ; seq++){ //the day (0 - 6) Read this number into the days char array. the seconds number in the array 0-2 gets the 3 chars of the day name, e.g. m o n slideanim(6*day_char,8,seq,old_chars[day_char],days[rtc[3]][day_char]); //6 x day_char gives us the x pos for the char delay(SLIDE_DELAY); } //save the old day chars into the old_chars array at array pos 0-2. We use this next time we change the day and feed it to the animation as the current char. The updated char is fed in as the new char. old_chars[day_char] = days[rtc[3]][day_char]; } //change the date tens digit (if needed) and ones digit. (the date ones digit wil alwaus change, but putting this in the 'if' loop makes it a bit neater code wise.) for (byte i = 7; i >= 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 < 7) { byte dots; // if (current_c >= 'A' && || (current_c >= 'a' && current_c <= 'z') ) { // current_c &= 0x1F; // A-Z maps to 1-26 // } if (current_c >= 'A' && current_c <= 'Z' ) { current_c &= 0x1F; // A-Z maps to 1-26 } else if (current_c >= 'a' && current_c <= 'z') { current_c = (current_c - 'a') + 41; // A-Z maps to 41-67 } else if (current_c >= '0' && current_c <= '9') { current_c = (current_c - '0') + 31; } else if (current_c == ' ') { current_c = 0; // space } else if (current_c == '.') { current_c = 27; // full stop } else if (current_c == '\'') { current_c = 28; // single quote mark } else if (current_c == ':') { current_c = 29; //colon } else if (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 < 5; col++) { dots = pgm_read_byte_near(&myfont[current_c][col]); if (dots & (64 >> 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 < 5; col++) { plot(x + col, y + (sequence - 1), 0); //the y position to draw the line is equivalent to the sequence number - 1 } } //if sequence is above 2, we also need to start drawing the new char if (sequence >= 2) { //work out char byte dots; //if (new_c >= 'A' && new_c <= 'Z' || (new_c >= 'a' && new_c <= 'z') ) { // new_c &= 0x1F; // A-Z maps to 1-26 //} if (new_c >= 'A' && new_c <= 'Z' ) { new_c &= 0x1F; // A-Z maps to 1-26 } else if (new_c >= 'a' && new_c <= 'z') { new_c = (new_c - 'a') + 41; // A-Z maps to 41-67 } else if (new_c >= '0' && new_c <= '9') { new_c = (new_c - '0') + 31; } else if (new_c == ' ') { new_c = 0; // space } else if (new_c == '.') { new_c = 27; // full stop } else if (new_c == '\'') { new_c = 28; // single quote mark } else if (new_c == ':') { new_c = 29; // clock_mode selector arrow } else if (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 < 5; col++) { dots = pgm_read_byte_near(&myfont[new_c][col]); if (dots & (64 >> 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 < 1) { hours = hours + ampm * 12; } get_time(); //get the time from the clock chip byte old_mins = 100; //store mins in old_mins. We compare mins and old mins & when they are different we redraw the display. Set this to 100 initially so display is drawn when mode starts. byte mins; //run clock main loop as long as run_mode returns true while (run_mode()) { //check for button press if (buttonA.uniquePress()) { switch_mode(); return; } if (buttonB.uniquePress()) { display_date(); } get_time(); //get the time from the clock chip mins = rtc[1]; //get mins //if mins is different from old_mins - redraw display if (mins != old_mins) { //update old_mins with current mins value old_mins = mins; //reset these for comparison next time mins = rtc[1]; hours = rtc[2]; //make hours into 12 hour format 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 < 10) { strcpy (str_a, numbers[minsdigit - 1]); strcpy (str_b, "PAST"); strcpy (str_c, numbers[hours - 1]); } //if mins = 10, cant use minsdigit as above, so soecial case to print 10 past /n hour. if (mins == 10) { strcpy (str_a, numbers[9]); strcpy (str_b, " PAST"); strcpy (str_c, numbers[hours - 1]); } //if time is not on the hour - i.e. both mins digits are not zero, //then make first line read "hours" and 2 & 3rd lines read "minstens" "mins" e.g. "three /n twenty /n one" else if (minsdigitten != 0 && minsdigit != 0 ) { strcpy (str_a, numbers[hours - 1]); //if mins is in the teens, use teens from the numbers array for the 2nd line, e.g. "fifteen" //if (mins >= 11 && mins <= 19) { if (mins <= 19) { strcpy (str_b, numbers[mins - 1]); } else { strcpy (str_b, numberstens[minsdigitten - 1]); strcpy (str_c, numbers[minsdigit - 1]); } } // if mins digit is zero, don't print it. read read "hours" "minstens" e.g. "three /n twenty" else if (minsdigitten != 0 && minsdigit == 0 ) { strcpy (str_a, numbers[hours - 1]); strcpy (str_b, numberstens[minsdigitten - 1]); strcpy (str_c, ""); } //if both mins are zero, i.e. it is on the hour, the top line reads "hours" and bottom line reads "o'clock" else if (minsdigitten == 0 && minsdigit == 0 ) { strcpy (str_a, numbers[hours - 1]); strcpy (str_b, "O'CLOCK"); strcpy (str_c, ""); } }//end worknig out time //run in a loop //print line a "twelve" byte len = 0; while (str_a[len]) { len++; }; //get length of message byte offset_top = (31 - ((len - 1) * 4)) / 2; // //plot hours line byte i = 0; while (str_a[i]) { puttinychar((i * 4) + offset_top, 1, str_a[i]); i++; } //hold display but check for button presses int counter = 1000; while (counter > 0){ //check for button press if (buttonA.uniquePress()) { switch_mode(); return; } ... This file has been truncated, please download it to see its full contents.

DIY Arduino Holographic Matrix Clock

Raspberry Pi 5 7 Inch Touch Screen IPS 1024x600 HD LCD HDMI-compatible Display for RPI 4B 3B+ OPI 5 AIDA64 PC Secondary Screen(Without Speaker)
BUY NOW
ESP32-S3 4.3inch Capacitive Touch Display Development Board, 800×480, 5-point Touch, 32-bit LX7 Dual-core Processor
BUY NOW
Raspberry Pi 5 7 Inch Touch Screen IPS 1024x600 HD LCD HDMI-compatible Display for RPI 4B 3B+ OPI 5 AIDA64 PC Secondary Screen(Without Speaker)
BUY NOW- Comments(0)
- Likes(0)

- 0 USER VOTES
- YOUR VOTE 0.00 0.00
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
More by Mirko Pavleski
-
Tug of War Arduino Game on WS2812 Led strip A Tug of War is a classic team-based game where two opposing teams compete to pull a rope in opposi...
-
DIY ESP32 Bioresonance Rife Machine with ZAPPER function Rife machine therapy is an alternative treatment developed by Dr. Royal Raymond Rife in the 1930s. H...
-
Arduino VFO Project with a Large LCD Display A Variable Frequency Oscillator (VFO) is an electronic oscillator whose output frequency can be adj...
-
Exploring the Tesla Coil Driver Board, Full Review & Test Results Some time ago I presented you a video in which I analyzed a super cheap Tesla Coil driver that cost...
-
Arduino Eatrthquake alarm and protection system with D7S seismic Sensor Earthquakes are extremely common events around the world. On average, there are fifty earthquakes a...
-
Review and Comparison of Three Inexpensive Metal Detector Kits A metal detector is a device used to detect the presence of metal objects in the ground or other ma...
-
Arduino 3D Printed self Balancing Cube Self-balancing devices are electronic devices that use sensors and motors to keep themselves balanc...
-
Arduino flame detector with alarms and automatic fire extinguishing A flame detector is an electronic device designed to sense the presence of flames or fire. There ar...
-
OpenWebRX - Simplest Rasprberry Pi + RTLSDR Web SDR Radio Software-Defined Radio is a radio communication system where components that have traditionally bee...
-
Colorful Arduino Tetris Game - WS2812B LED Matrix Tutorial Tetris is a puzzle video game created in 1985 by Alexey Pajitnov. Players manipulate falling geomet...
-
Ultra cheap Ultrasonic levitation Device - functionality and testing Ultrasonic levitation is phenomenon where objects are suspended in mid-air using the power of sound ...
-
DIY -Spirit PI- ESP32 + Smartphone Sensitive Metal Detector Pulse Induction (PI) metal detector operates on a principle based on sending short pulses of electr...
-
ESP32 Analog style VU meter with GC9A01 Round Dispalys + Peak Meters A typical VU meter measures audio signals and displays them with a visual indicator. In the classic...
-
Arduino two weel self Balancing Robot Self Balancing Robot is device that can balance itself from falling to the ground. Its function is ...
-
ELECROW CrowPanel ESP32 4.2” E-paper Wi-Fi Info-Dispaly Project An e-paper display (also known as an electronic paper display or E Ink display) is a type of screen...
-
ESP32 Fluid simulation on 16x16 Led Matrix Fluid simulation is a way of replicating the movement and behavior of liquids and gases in differen...
-
Simple GU50 VTTC Tesla Coil with MOT (25+cm Spark) Vacuum Tube Tesla Coils are a common choice for homebuilders for several practical reasons. At Soli...
-
Hourglass ESP8266 Code A hourglass, also known as an sand clock, is a device used to measure the passage of time. It consi...
-
Tug of War Arduino Game on WS2812 Led strip A Tug of War is a classic team-based game where two opposing teams compete to pull a rope in opposi...
-
DIY ESP32 Bioresonance Rife Machine with ZAPPER function Rife machine therapy is an alternative treatment developed by Dr. Royal Raymond Rife in the 1930s. H...
-
Arduino VFO Project with a Large LCD Display A Variable Frequency Oscillator (VFO) is an electronic oscillator whose output frequency can be adj...
-
Exploring the Tesla Coil Driver Board, Full Review & Test Results Some time ago I presented you a video in which I analyzed a super cheap Tesla Coil driver that cost...
-
Arduino Eatrthquake alarm and protection system with D7S seismic Sensor Earthquakes are extremely common events around the world. On average, there are fifty earthquakes a...
-
Review and Comparison of Three Inexpensive Metal Detector Kits A metal detector is a device used to detect the presence of metal objects in the ground or other ma...
-
Arduino 3D Printed self Balancing Cube Self-balancing devices are electronic devices that use sensors and motors to keep themselves balanc...
-
Arduino flame detector with alarms and automatic fire extinguishing A flame detector is an electronic device designed to sense the presence of flames or fire. There ar...
-
OpenWebRX - Simplest Rasprberry Pi + RTLSDR Web SDR Radio Software-Defined Radio is a radio communication system where components that have traditionally bee...
-
Colorful Arduino Tetris Game - WS2812B LED Matrix Tutorial Tetris is a puzzle video game created in 1985 by Alexey Pajitnov. Players manipulate falling geomet...
-
Ultra cheap Ultrasonic levitation Device - functionality and testing Ultrasonic levitation is phenomenon where objects are suspended in mid-air using the power of sound ...
-
DIY -Spirit PI- ESP32 + Smartphone Sensitive Metal Detector Pulse Induction (PI) metal detector operates on a principle based on sending short pulses of electr...
-
Commodore 64 1541-II 1581 Floppy Disk Drive C64 Power Supply Unit USB-C 5V 12V DIN connector 5.25
164 1 3 -
Easy to print simple stacking organizer with drawers
87 0 0 -
-
-
-
Modifying a Hotplate to a Reflow Solder Station
1137 1 6 -
MPL3115A2 Barometric Pressure, Altitude, and Temperature Sensor
638 0 1 -
-
Nintendo 64DD Replacement Shell
494 0 2 -
V2 Commodore AMIGA USB-C Power Sink Delivery High Efficiency Supply Triple Output 5V ±12V OLED display ATARI compatible shark 100W
1439 4 3