33浏览
查看: 33|回复: 4

[项目] 【Arduino 动手做】DIY Arduino全息矩阵时钟

[复制链接]
这是创建全息图的最简单方法,其中光源和屏幕以 45 度角放置。

这是我的一系列不寻常的 DIY 时钟中的另一个,这次是基于全息效果实现的。看起来真的非常有趣,你会感觉到数字漂浮在空中。

否则,这是创建全息图最简单的方法,其中光源和屏幕以45度角放置。当我们有文本或数字信息时,我们需要知道光源的信息应该是原始图像的镜像,我们应该在屏幕上看到原始图像。

对于光源,我使用了一个非常简单的矩阵时钟,它实际上是我之前的一个项目“ Arduino Nano mini LED 矩阵时钟”的修改版本,我修改了原始代码以获得镜像。

【Arduino 动手做】DIY Arduino全息矩阵时钟图1

驴友花雕  中级技神
 楼主|

发表于 昨天 09:14

【Arduino 动手做】DIY Arduino全息矩阵时钟

正如我提到的,时钟的构建非常简单,它由几个组件组成:

Arduino nano微控制器
DS3231实时时钟模块
8x32 LED矩阵模块
和两个按钮

【Arduino 动手做】DIY Arduino全息矩阵时钟图1

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 09:15

【Arduino 动手做】DIY Arduino全息矩阵时钟

这个小钟有各种各样的表面、工作模式和其他选项,您将在视频的后续部分看到。

对于该设备的机械结构,必须遵守几条规则:

- 通过改变光源和屏幕之间的距离,全息图像的高度会发生变化,因此我们必须通过实验确定这个距离。

如果按照上述建议设置了信号源和屏幕,全息图像就会出现在屏幕中间。我们可以通过两个按钮来调整各种选项。

我从一开始就对这个设备进行了改造,使其也能显示来自智能手机的全息图。为此,需要将智能手机的灯光调到最大,然后选择专门为全息图演示设计的视频。这些视频通常采用黑色背景,以便更突出全息图效果。

【Arduino 动手做】DIY Arduino全息矩阵时钟图4

【Arduino 动手做】DIY Arduino全息矩阵时钟图6

【Arduino 动手做】DIY Arduino全息矩阵时钟图7

【Arduino 动手做】DIY Arduino全息矩阵时钟图2

【Arduino 动手做】DIY Arduino全息矩阵时钟图5

【Arduino 动手做】DIY Arduino全息矩阵时钟图1

【Arduino 动手做】DIY Arduino全息矩阵时钟图3

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 09:19

【Arduino 动手做】DIY Arduino全息矩阵时钟

项目代码

  1. /***********************************************************************
  2. Mini Clock v1.0, Jul 2014 by Nick Hall
  3. Distributed under the terms of the GPL.
  4. For help on how to build the clock see my blog:
  5. http://123led.wordpress.com/
  6. Tested on IDE v1.6.5
  7. modified by Mirko Pavleski May 2023
  8. ***********************************************************************/
  9. //include libraries:
  10. #include "LedControl.h"
  11. #include <FontLEDClock.h>                // Font library
  12. #include <Wire.h>                        // DS1307 clock
  13. #include "RTClib.h"                      // DS1307 clock
  14. #include <Button.h>                      // Button library by Alexander Brevig
  15. // Setup LED Matrix
  16. // pin 10 is connected to the DataIn on the display
  17. // pin 12 is connected to the CLK on the display
  18. // pin 11 is connected to LOAD on the display(cs)
  19. LedControl lc = LedControl(10, 12, 11, 4); //sets the 3 pins as 12, 11 & 10 and then sets 4 displays (max is 8 displays)
  20. //global variables
  21. byte intensity = 7;                      // Default intensity/brightness (0-15)
  22. byte clock_mode = 0;                     // Default clock mode. Default = 0 (basic_mode)
  23. bool random_mode = 0;                    // Define random mode - changes the display type every few hours. Default = 0 (off)
  24. 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.
  25. bool ampm = 0;                           // Define 12 or 24 hour time. 0 = 24 hour. 1 = 12 hour
  26. byte change_mode_time = 0;               // Holds hour when clock mode will next change if in random mode.
  27. unsigned long delaytime = 500;           // We always wait a bit between updates of the display
  28. int rtc[7];                              // Holds real time clock output
  29. char days[7][4] = {
  30.   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  31. }; //day array - used in slide, basic_mode and jumble modes (The DS1307 outputs 1-7 values for day of week)
  32. char daysfull[7][9] = {
  33.   "Sunday", "Monday", "Tuesday", "Wed", "Thursday", "Friday", "Saturday"
  34. };
  35. char suffix[4][3] = {
  36.   "st", "nd", "rd", "th"
  37. };  //date suffix array, used in slide, basic_mode and jumble modes. e,g, 1st 2nd ...
  38. //define constants
  39. #define NUM_DISPLAY_MODES 3              // Number display modes (conting zero as the first mode)
  40. #define NUM_SETTINGS_MODES 4             // Number settings modes = 6 (conting zero as the first mode)
  41. #define SLIDE_DELAY 20                   // The time in milliseconds for the slide effect per character in slide mode. Make this higher for a slower effect
  42. #define cls          clear_display       // Clear display
  43. RTC_DS1307 ds1307;                              // Create RTC object
  44. Button buttonA = Button(2, BUTTON_PULLUP);      // Setup button A (using button library)
  45. Button buttonB = Button(3, BUTTON_PULLUP);      // Setup button B (using button library)
  46. void setup() {
  47.   digitalWrite(2, HIGH);                 // turn on pullup resistor for button on pin 2
  48.   digitalWrite(3, HIGH);                 // turn on pullup resistor for button on pin 3
  49.   digitalWrite(4, HIGH);                 // turn on pullup resistor for button on pin 4
  50.   
  51.   Serial.begin(9600); //start serial
  52.   //initialize the 4 matrix panels
  53.   //we have already set the number of devices when we created the LedControl
  54.   int devices = lc.getDeviceCount();
  55.   //we have to init all devices in a loop
  56.   for (int address = 0; address < devices; address++) {
  57.     /*The MAX72XX is in power-saving mode on startup*/
  58.     lc.shutdown(address, false);
  59.     /* Set the brightness to a medium values */
  60.     lc.setIntensity(address, intensity);
  61.     /* and clear the display */
  62.     lc.clearDisplay(address);
  63.   }
  64.   //Setup DS1307 RTC
  65. #ifdef AVR
  66.   Wire.begin();
  67. #else
  68.   Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino
  69. #endif
  70.   ds1307.begin(); //start RTC Clock
  71.   if (! ds1307.isrunning()) {
  72.     Serial.println("RTC is NOT running!");
  73.     ds1307.adjust(DateTime(__DATE__, __TIME__));  // sets the RTC to the date & time this sketch was compiled
  74.   }
  75.   //Show software version & hello message
  76.   printver();
  77.   
  78.   //enable red led
  79.   digitalWrite(13, HIGH);
  80. }
  81. void loop() {
  82.   
  83.   //run the clock with whatever mode is set by clock_mode - the default is set at top of code.
  84.   switch (clock_mode){
  85.         
  86.   case 0:
  87.     basic_mode();
  88.     break;
  89.   case 1:
  90.    small_mode();
  91.     break;
  92.   case 2:
  93.     slide();
  94.     break;
  95.   case 3:
  96.     word_clock();
  97.     break;
  98.   case 4:
  99.     setup_menu();
  100.     break;
  101.   }
  102. }
  103. //plot a point on the display
  104. void plot (byte x, byte y, byte val) {
  105.   //select which matrix depending on the x coord
  106.   byte address;
  107.   if (x >= 0 && x <= 7)   {
  108.     address = 3;
  109.   }
  110.   if (x >= 8 && x <= 15)  {
  111.     address = 2;
  112.     x = x - 8;
  113.   }
  114.   if (x >= 16 && x <= 23) {
  115.     address = 1;
  116.     x = x - 16;
  117.   }
  118.   if (x >= 24 && x <= 31) {
  119.     address = 0;
  120.     x = x - 24;
  121.   }
  122.   if (val == 1) {
  123.    // lc.setLed(address, y, x, true);
  124.    lc.setLed(address, 7-y, x, true);
  125.   } else {
  126.   //  lc.setLed(address, y, x, false);
  127.   lc.setLed(address, 7-y, x, false);
  128.   }
  129. }
  130. //clear screen
  131. void clear_display() {
  132.   for (byte address = 0; address < 4; address++) {
  133.     lc.clearDisplay(address);
  134.   }
  135. }
  136. //fade screen down
  137. void fade_down() {
  138.   //fade from global intensity to 1
  139.   for (byte i = intensity; i > 0; i--) {
  140.     for (byte address = 0; address < 4; address++) {
  141.       lc.setIntensity(address, i);
  142.     }
  143.     delay(30); //change this to change fade down speed
  144.   }
  145.   clear_display(); //clear display completely (off)
  146.   //reset intentsity to global val
  147.   for (byte address = 0; address < 4; address++) {
  148.     lc.setIntensity(address, intensity);
  149.   }
  150. }
  151. //power up led test & display software version number
  152. void printver() {
  153.   byte i = 0;
  154.   char ver_a[9] = "Vers 1.0";
  155.   char ver_b[9] = " Hello! ";
  156.   //test all leds.
  157.   for (byte x = 0; x <= 31; x++) {
  158.     for (byte y = 0; y <= 7; y++) {
  159.       plot(x, y, 1);
  160.     }
  161.   }
  162.   delay(500);
  163.   fade_down();
  164.   while (ver_a[i]) {
  165.     puttinychar((i * 4), 1, ver_a[i]);
  166.     delay(35);
  167.     i++;
  168.   }
  169.   delay(700);
  170.   fade_down();
  171.   i = 0;
  172.   while (ver_b[i]) {
  173.     puttinychar((i * 4), 1, ver_b[i]);
  174.     delay(35);
  175.     i++;
  176.   }
  177.   delay(700);
  178.   fade_down();
  179. }
  180. // puttinychar
  181. // Copy a 3x5 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate
  182. // This is unoptimized and simply uses plot() to draw each dot.
  183. void puttinychar(byte x, byte y, char c)
  184. {
  185.   byte dots;
  186.   if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) {
  187.     c &= 0x1F;   // A-Z maps to 1-26
  188.   }
  189.   else if (c >= '0' && c <= '9') {
  190.     c = (c - '0') + 32;
  191.   }
  192.   else if (c == ' ') {
  193.     c = 0; // space
  194.   }
  195.   else if (c == '.') {
  196.     c = 27; // full stop
  197.   }
  198.   else if (c == ':') {
  199.     c = 28; // colon
  200.   }
  201.   else if (c == '\'') {
  202.     c = 29; // single quote mark
  203.   }
  204.   else if (c == '!') {
  205.     c = 30; // single quote mark
  206.   }
  207.   else if (c == '?') {
  208.     c = 31; // single quote mark
  209.   }
  210.   for (byte col = 0; col < 3; col++) {
  211.     dots = pgm_read_byte_near(&mytinyfont[c][col]);
  212.     for (char row = 0; row < 5; row++) {
  213.       if (dots & (16 >> row))
  214.         plot(x + col, y + row, 1);
  215.       else
  216.         plot(x + col, y + row, 0);
  217.     }
  218.   }
  219. }
  220. void putnormalchar(byte x, byte y, char c)
  221. {
  222.   byte dots;
  223.   //  if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) {
  224.   //    c &= 0x1F;   // A-Z maps to 1-26
  225.   //  }
  226.   if (c >= 'A' && c <= 'Z' ) {
  227.     c &= 0x1F;   // A-Z maps to 1-26
  228.   }
  229.   else if (c >= 'a' && c <= 'z') {
  230.     c = (c - 'a') + 41;   // A-Z maps to 41-67
  231.   }
  232.   else if (c >= '0' && c <= '9') {
  233.     c = (c - '0') + 31;
  234.   }
  235.   else if (c == ' ') {
  236.     c = 0; // space
  237.   }
  238.   else if (c == '.') {
  239.     c = 27; // full stop
  240.   }
  241.   else if (c == '\'') {
  242.     c = 28; // single quote mark
  243.   }
  244.   else if (c == ':') {
  245.     c = 29; // clock_mode selector arrow
  246.   }
  247.   else if (c == '>') {
  248.     c = 30; // clock_mode selector arrow
  249.   }
  250.   else if (c >= -80 && c <= -67) {
  251.     c *= -1;
  252.   }
  253.   for (char col = 0; col < 5; col++) {
  254.     dots = pgm_read_byte_near(&myfont[c][col]);
  255.     for (char row = 0; row < 7; row++) {
  256.       //check coords are on screen before trying to plot
  257.       //if ((x >= 0) && (x <= 31) && (y >= 0) && (y <= 7)){
  258.       if (dots & (64 >> row)) {   // only 7 rows.
  259.         plot(x + col, y + row, 1);
  260.       } else {
  261.         plot(x + col, y + row, 0);
  262.       }
  263.       //}
  264.     }
  265.   }
  266. }
  267. //small_mode
  268. //show the time in small 3x5 characters with seconds display
  269. void small_mode() {
  270.   char textchar[8]; // the 16 characters on the display
  271.   byte mins = 100; //mins
  272.   byte secs = rtc[0]; //seconds
  273.   byte old_secs = secs; //holds old seconds value - from last time seconds were updated o display - used to check if seconds have changed
  274.   
  275.   cls();
  276.   //run clock main loop as long as run_mode returns true
  277.   while (run_mode()) {
  278.     get_time();
  279.   
  280.     //check for button press
  281.     if (buttonA.uniquePress()) {
  282.       switch_mode();
  283.       return;
  284.     }
  285.     if (buttonB.uniquePress()) {
  286.       display_date();
  287.       return;
  288.     }
  289.    
  290.     //if secs changed then update them on the display
  291.     secs = rtc[0];
  292.     if (secs != old_secs) {
  293.       //secs
  294.       char buffer[3];
  295.       itoa(secs, buffer, 10);
  296.       //fix - as otherwise if num has leading zero, e.g. "03" secs, itoa coverts this to chars with space "3 ".
  297.       if (secs < 10) {
  298.         buffer[1] = buffer[0];
  299.         buffer[0] = '0';
  300.       }
  301.       puttinychar( 20, 1, ':'); //seconds colon
  302.       puttinychar( 24, 1, buffer[0]); //seconds
  303.       puttinychar( 28, 1, buffer[1]); //seconds
  304.       old_secs = secs;
  305.     }
  306.     //if minute changes change time
  307.     if (mins != rtc[1]) {
  308.       //reset these for comparison next time
  309.       mins = rtc[1];
  310.       byte hours = rtc[2];
  311.       if (hours > 12) {
  312.         hours = hours - ampm * 12;
  313.       }
  314.       if (hours < 1) {
  315.         hours = hours + ampm * 12;
  316.       }
  317.       //byte dow  = rtc[3]; // the DS1307 outputs 0 - 6 where 0 = Sunday0 - 6 where 0 = Sunday.
  318.       //byte date = rtc[4];
  319.       //set characters
  320.       char buffer[3];
  321.       itoa(hours, buffer, 10);
  322.       //fix - as otherwise if num has leading zero, e.g. "03" hours, itoa coverts this to chars with space "3 ".
  323.       if (hours < 10) {
  324.         buffer[1] = buffer[0];
  325.         //if we are in 12 hour mode blank the leading zero.
  326.         if (ampm) {
  327.           buffer[0] = ' ';
  328.         }
  329.         else {
  330.           buffer[0] = '0';
  331.         }
  332.       }
  333.       //set hours chars
  334.       textchar[0] = buffer[0];
  335.       textchar[1] = buffer[1];
  336.       textchar[2] = ':';
  337.       itoa (mins, buffer, 10);
  338.       if (mins < 10) {
  339.         buffer[1] = buffer[0];
  340.         buffer[0] = '0';
  341.       }
  342.       //set mins characters
  343.       textchar[3] = buffer[0];
  344.       textchar[4] = buffer[1];
  345.       //do seconds
  346.       textchar[5] = ':';
  347.       buffer[3];
  348.       secs = rtc[0];
  349.       itoa(secs, buffer, 10);
  350.       //fix - as otherwise if num has leading zero, e.g. "03" secs, itoa coverts this to chars with space "3 ".
  351.       if (secs < 10) {
  352.         buffer[1] = buffer[0];
  353.         buffer[0] = '0';
  354.       }
  355.       //set seconds
  356.       textchar[6] = buffer[0];
  357.       textchar[7] = buffer[1];
  358.       byte x = 0;
  359.       byte y = 0;
  360.       //print each char
  361.       for (byte x = 0; x < 6 ; x++) {
  362.         puttinychar( x * 4, 1, textchar[x]);
  363.       }
  364.     }
  365.     delay(50);
  366.   }
  367.   fade_down();
  368. }
  369. // basic_mode()
  370. // show the time in 5x7 characters
  371. void basic_mode()
  372. {
  373.   cls();
  374.   char buffer[3];   //for int to char conversion to turn rtc values into chars we can print on screen
  375.   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
  376.   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.
  377.   //do 12/24 hour conversion if ampm set to 1
  378.   byte hours = rtc[2];
  379.   if (hours > 12) {
  380.     hours = hours - ampm * 12;
  381.   }
  382.   if (hours < 1) {
  383.     hours = hours + ampm * 12;
  384.   }
  385.   //do offset conversion
  386.   if (ampm && hours < 10) {
  387.     offset = 2;
  388.   }
  389.   
  390.   //set the next minute we show the date at
  391.   //set_next_date();
  392.   
  393.   // 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
  394.   byte secs = 100;
  395.   byte mins = 100;
  396.   int count = 0;
  397.   
  398.   //run clock main loop as long as run_mode returns true
  399.   while (run_mode()) {
  400.     //get the time from the clock chip
  401.     get_time();
  402.    
  403.     //check for button press
  404.     if (buttonA.uniquePress()) {
  405.       switch_mode();
  406.       return;
  407.     }
  408.     if (buttonB.uniquePress()) {
  409.       display_date();
  410.       return;
  411.     }
  412.     //check whether it's time to automatically display the date
  413.     //check_show_date();
  414.     //draw the flashing : as on if the secs have changed.
  415.     if (secs != rtc[0]) {
  416.       //update secs with new value
  417.       secs = rtc[0];
  418.       //draw :
  419.       plot (15 - offset, 2, 1); //top point
  420.       plot (15 - offset, 5, 1); //bottom point
  421.       count = 400;
  422.     }
  423.     //if count has run out, turn off the :
  424.     if (count == 0) {
  425.       plot (15 - offset, 2, 0); //top point
  426.       plot (15 - offset, 5, 0); //bottom point
  427.     }
  428.     else {
  429.       count--;
  430.     }
  431.     //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)
  432.     if (mins != rtc[1]) {
  433.       //update mins and hours with the new values
  434.       mins = rtc[1];
  435.       hours = rtc[2];
  436.       //adjust hours of ampm set to 12 hour mode
  437.       if (hours > 12) {
  438.         hours = hours - ampm * 12;
  439.       }
  440.       if (hours < 1) {
  441.         hours = hours + ampm * 12;
  442.       }
  443.       itoa(hours, buffer, 10);
  444.       //if hours < 10 the num e.g. "3" hours, itoa coverts this to chars with space "3 " which we dont want
  445.       if (hours < 10) {
  446.         buffer[1] = buffer[0];
  447.         buffer[0] = '0';
  448.       }
  449.       //print hours
  450.       //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.
  451.       if (ampm && hours < 10) {
  452.         offset = 2;
  453.         //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
  454.         if ((hours == 1 && mins == 0) ) {
  455.           cls();
  456.         }
  457.       }
  458.       else {
  459.         //else no offset and print hours tens digit
  460.         offset = 0;
  461.         //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
  462.         if (hours == 10 && mins == 0) {
  463.           cls();
  464.         }
  465.         putnormalchar(1,  0, buffer[0]);
  466.       }
  467.       //print hours ones digit
  468.       putnormalchar(7 - offset, 0, buffer[1]);
  469.       //print mins
  470.       //add leading zero if mins < 10
  471.       itoa (mins, buffer, 10);
  472.       if (mins < 10) {
  473.         buffer[1] = buffer[0];
  474.         buffer[0] = '0';
  475.       }
  476.       //print mins tens and ones digits
  477.       putnormalchar(19 - offset, 0, buffer[0]);
  478.       putnormalchar(25 - offset, 0, buffer[1]);
  479.     }
  480.   }
  481.   fade_down();
  482. }
  483. //like basic_mode but with slide effect
  484. void slide() {
  485.   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
  486.   byte digits_new[4]; //new digits time will slide to reveal
  487.   byte digits_x_pos[4] = {25, 19, 7, 1}; //x pos for which to draw each digit at
  488.   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
  489.   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
  490.   //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.
  491.   //We sent them as A initially, which are used when the clocl enters the mode and no last chars are stored.
  492.   //char old_chars[6] = "AAAAA";
  493.   //plot the clock colon on the display
  494.   cls();
  495.   putnormalchar( 13, 0, ':');
  496.   byte old_secs = rtc[0]; //store seconds in old_secs. We compare secs and old secs. WHen they are different we redraw the display
  497.   //run clock main loop as long as run_mode returns true
  498.   while (run_mode()) {
  499.     get_time();
  500.    
  501.     //check for button press
  502.     if (buttonA.uniquePress()) {
  503.       switch_mode();
  504.       return;
  505.     }
  506.       if (buttonB.uniquePress()) {
  507.       display_date();
  508.       return;
  509.     }
  510.     //if secs have changed then update the display
  511.     if (rtc[0] != old_secs) {
  512.       old_secs = rtc[0];
  513.       //do 12/24 hour conversion if ampm set to 1
  514.       byte hours = rtc[2];
  515.       if (hours > 12) {
  516.         hours = hours - ampm * 12;
  517.       }
  518.       if (hours < 1) {
  519.         hours = hours + ampm * 12;
  520.       }
  521.       //split all date and time into individual digits - stick in digits_new array
  522.       //rtc[0] = secs                        //array pos and digit stored
  523.       //digits_new[0] = (rtc[0]%10);           //0 - secs ones
  524.       //digits_new[1] = ((rtc[0]/10)%10);      //1 - secs tens
  525.       //rtc[1] = mins
  526.       digits_new[0] = (rtc[1] % 10);         //2 - mins ones
  527.       digits_new[1] = ((rtc[1] / 10) % 10);  //3 - mins tens
  528.       //rtc[2] = hours
  529.       digits_new[2] = (hours % 10);         //4 - hour ones
  530.       digits_new[3] = ((hours / 10) % 10);  //5 - hour tens
  531.       //rtc[4] = date
  532.       //digits_new[6] = (rtc[4]%10);           //6 - date ones
  533.       //digits_new[7] = ((rtc[4]/10)%10);      //7 - date tens
  534.       //draw initial screen of all chars. After this we just draw the changes.
  535.       //compare digits 0 to 3 (mins and hours)
  536.       for (byte i = 0; i <= 3; i++) {
  537.         //see if digit has changed...
  538.         if (digits_old[i] != digits_new[i]) {
  539.           //run 9 step animation sequence for each in turn
  540.           for (byte seq = 0; seq <= 8 ; seq++) {
  541.             //convert digit to string
  542.             itoa(digits_old[i], old_char, 10);
  543.             itoa(digits_new[i], new_char, 10);
  544.             //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
  545.             if (ampm && i == 3) {
  546.               if (digits_new[3] == 0) {
  547.                 new_char[0] = ' ';
  548.               }
  549.               if (digits_old[3] == 0) {
  550.                 old_char[0] = ' ';
  551.               }
  552.             }
  553.             //draw the animation frame for each digit
  554.             slideanim(digits_x_pos[i], 0, seq, old_char[0], new_char[0]);
  555.             delay(SLIDE_DELAY);
  556.           }
  557.         }
  558.       }
  559.       /*
  560.       //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
  561.       if ((digits_old[6] != digits_new[6]) || (digits_old[7] != digits_new[7])) {
  562.         //change the day shown. Loop below goes through each of the 3 chars in turn e.g. "MON"
  563.         for (byte day_char = 0; day_char <=2 ; day_char++){
  564.           //run the anim sequence for each char
  565.           for (byte seq = 0; seq <=8 ; seq++){
  566.             //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
  567.             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
  568.             delay(SLIDE_DELAY);
  569.           }
  570.           //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.
  571.           old_chars[day_char] = days[rtc[3]][day_char];
  572.         }
  573.         //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.)
  574.         for (byte i = 7; i >= 6; i--){
  575.           if (digits_old[i] != digits_new[i]) {
  576.             for (byte seq = 0; seq <=8 ; seq++){
  577.               itoa(digits_old[i],old_char,10);
  578.               itoa(digits_new[i],new_char,10);
  579.               slideanim(digits_x_pos[i],8,seq,old_char[0],new_char[0]);
  580.               delay(SLIDE_DELAY);
  581.             }
  582.           }
  583.         }
  584.         //print the day suffix "nd" "rd" "th" etc. First work out date 2 letter suffix - eg st, nd, rd, th
  585.         byte s = 3; //the pos to read our suffix array from.
  586.         byte date = rtc[4];
  587.         if(date == 1 || date == 21 || date == 31) {
  588.           s = 0;
  589.         }
  590.         else if (date == 2 || date == 22) {
  591.           s = 1;
  592.         }
  593.         else if (date == 3 || date == 23) {
  594.           s = 2;
  595.         }
  596.         for (byte suffix_char = 0; suffix_char <=1 ; suffix_char++){
  597.           for (byte seq = 0; seq <=8 ; seq++){
  598.             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
  599.             delay(SLIDE_DELAY);
  600.           }
  601.           //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.
  602.           old_chars[suffix_char+3] = suffix[s][suffix_char];
  603.         }
  604.       }//end do date line
  605.       */
  606.       //save digita array tol old for comparison next loop
  607.       for (byte i = 0; i <= 3; i++) {
  608.         digits_old[i] =  digits_new[i];
  609.       }
  610.     }//secs/oldsecs
  611.   }//while loop
  612.   fade_down();
  613. }
  614. //called by slide
  615. //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
  616. //inputs are are char x and y, animation frame sequence (0-7) and the current and new chars being drawn.
  617. void slideanim(byte x, byte y, byte sequence, char current_c, char new_c) {
  618.   //  To slide one char off and another on we need 9 steps or frames in sequence...
  619.   //  seq# 0123456 <-rows of the display
  620.   //   |   |||||||
  621.   //  seq0 0123456  START - all rows of the display 0-6 show the current characters rows 0-6
  622.   //  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
  623.   //  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
  624.   //  seq3 56 0123
  625.   //  seq4 456 012  half old / half new char
  626.   //  seq5 3456 01
  627.   //  seq6 23456 0
  628.   //  seq7 123456
  629.   //  seq8 0123456  END - all rows show the new char
  630.   //from above we can see...
  631.   //currentchar runs 0-6 then 0-5 then 0-4 all the way to 0. starting Y position increases by 1 row each time.
  632.   //new char runs 6 then 5-6 then 4-6 then 3-6. starting Y position increases by 1 row each time.
  633.   //if sequence number is below 7, we need to draw the current char
  634.   if (sequence < 7) {
  635.     byte dots;
  636.     // if (current_c >= 'A' &&  || (current_c >= 'a' && current_c <= 'z') ) {
  637.     //   current_c &= 0x1F;   // A-Z maps to 1-26
  638.     // }
  639.     if (current_c >= 'A' && current_c <= 'Z' ) {
  640.       current_c &= 0x1F;   // A-Z maps to 1-26
  641.     }
  642.     else if (current_c >= 'a' && current_c <= 'z') {
  643.       current_c = (current_c - 'a') + 41;   // A-Z maps to 41-67
  644.     }
  645.     else if (current_c >= '0' && current_c <= '9') {
  646.       current_c = (current_c - '0') + 31;
  647.     }
  648.     else if (current_c == ' ') {
  649.       current_c = 0; // space
  650.     }
  651.     else if (current_c == '.') {
  652.       current_c = 27; // full stop
  653.     }
  654.     else if (current_c == '\'') {
  655.       current_c = 28; // single quote mark
  656.     }
  657.     else if (current_c == ':') {
  658.       current_c = 29; //colon
  659.     }
  660.     else if (current_c == '>') {
  661.       current_c = 30; // clock_mode selector arrow
  662.     }
  663.     byte curr_char_row_max = 7 - sequence; //the maximum number of rows to draw is 6 - sequence number
  664.     byte start_y = sequence; //y position to start at - is same as sequence number. We inc this each loop
  665.     //plot each row up to row maximum (calculated from sequence number)
  666.     for (byte curr_char_row = 0; curr_char_row <= curr_char_row_max; curr_char_row++) {
  667.       for (byte col = 0; col < 5; col++) {
  668.         dots = pgm_read_byte_near(&myfont[current_c][col]);
  669.         if (dots & (64 >> curr_char_row))
  670.           plot(x + col, y + start_y, 1); //plot led on
  671.         else
  672.           plot(x + col, y + start_y, 0); //else plot led off
  673.       }
  674.       start_y++;//add one to y so we draw next row one down
  675.     }
  676.   }
  677.   //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
  678.   if (sequence >= 1 && sequence <= 8) {
  679.     for (byte col = 0; col < 5; col++) {
  680.       plot(x + col, y + (sequence - 1), 0); //the y position to draw the line is equivalent to the sequence number - 1
  681.     }
  682.   }
  683.   //if sequence is above 2, we also need to start drawing the new char
  684.   if (sequence >= 2) {
  685.     //work out char
  686.     byte dots;
  687.     //if (new_c >= 'A' && new_c <= 'Z' || (new_c >= 'a' && new_c <= 'z') ) {
  688.     //  new_c &= 0x1F;   // A-Z maps to 1-26
  689.     //}
  690.     if (new_c >= 'A' && new_c <= 'Z' ) {
  691.       new_c &= 0x1F;   // A-Z maps to 1-26
  692.     }
  693.     else if (new_c >= 'a' && new_c <= 'z') {
  694.       new_c = (new_c - 'a') + 41;   // A-Z maps to 41-67
  695.     }
  696.     else if (new_c >= '0' && new_c <= '9') {
  697.       new_c = (new_c - '0') + 31;
  698.     }
  699.     else if (new_c == ' ') {
  700.       new_c = 0; // space
  701.     }
  702.     else if (new_c == '.') {
  703.       new_c = 27; // full stop
  704.     }
  705.     else if (new_c == '\'') {
  706.       new_c = 28; // single quote mark
  707.     }
  708.     else if (new_c == ':') {
  709.       new_c = 29; // clock_mode selector arrow
  710.     }
  711.     else if (new_c == '>') {
  712.       new_c = 30; // clock_mode selector arrow
  713.     }
  714.     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
  715.     byte start_y = 0; //y position to start at - is same as sequence number. we inc it each row
  716.     //plot each row up from row minimum (calculated by sequence number) up to 6
  717.     for (byte newcharrow = newcharrowmin; newcharrow <= 6; newcharrow++) {
  718.       for (byte col = 0; col < 5; col++) {
  719.         dots = pgm_read_byte_near(&myfont[new_c][col]);
  720.         if (dots & (64 >> newcharrow))
  721.           plot(x + col, y + start_y, 1); //plot led on
  722.         else
  723.           plot(x + col, y + start_y, 0); //else plot led off
  724.       }
  725.       start_y++;//add one to y so we draw next row one down
  726.     }
  727.   }
  728. }
  729. //print a clock using words rather than numbers
  730. void word_clock() {
  731.   cls();
  732.   char numbers[19][10]   = {
  733.     "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
  734.     "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
  735.   };
  736.   char numberstens[5][7] = {
  737.     "ten", "twenty", "thirty", "forty", "fifty"
  738.   };
  739.   
  740.   //potentially 3 lines to display
  741.   char str_a[8];
  742.   char str_b[8];
  743.   char str_c[8];
  744.   //byte hours_y, mins_y; //hours and mins and positions for hours and mins lines
  745.   byte hours = rtc[2];
  746.   if (hours > 12) {
  747.     hours = hours - ampm * 12;
  748.   }
  749.   if (hours < 1) {
  750.     hours = hours + ampm * 12;
  751.   }
  752.   get_time(); //get the time from the clock chip
  753.   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.
  754.   byte mins;
  755.   //run clock main loop as long as run_mode returns true
  756.   while (run_mode()) {
  757.    
  758.     //check for button press
  759.     if (buttonA.uniquePress()) {
  760.       switch_mode();
  761.       return;
  762.     }
  763.     if (buttonB.uniquePress()) {
  764.       display_date();
  765.     }
  766.     get_time(); //get the time from the clock chip
  767.     mins = rtc[1];  //get mins
  768.     //if mins is different from old_mins - redraw display
  769.     if (mins != old_mins) {
  770.       //update old_mins with current mins value
  771.       old_mins = mins;
  772.       //reset these for comparison next time
  773.       mins = rtc[1];
  774.       hours = rtc[2];
  775.       //make hours into 12 hour format
  776.       if (hours > 12) {
  777.         hours = hours - 12;
  778.       }
  779.       if (hours == 0) {
  780.         hours = 12;
  781.       }
  782.       //split mins value up into two separate digits
  783.       int minsdigit = rtc[1] % 10;
  784.       byte minsdigitten = (rtc[1] / 10) % 10;
  785.       //if mins <= 10 , then top line has to read "minsdigti past" and bottom line reads hours
  786.       if (mins < 10) {
  787.         strcpy (str_a, numbers[minsdigit - 1]);
  788.         strcpy (str_b, "PAST");
  789.         strcpy (str_c, numbers[hours - 1]);
  790.       }
  791.       //if mins = 10, cant use minsdigit as above, so soecial case to print 10 past /n hour.
  792.       if (mins == 10) {
  793.         strcpy (str_a, numbers[9]);
  794.         strcpy (str_b, " PAST");
  795.         strcpy (str_c, numbers[hours - 1]);
  796.       }
  797.       //if time is not on the hour - i.e. both mins digits are not zero,
  798.       //then make first line read "hours" and 2 & 3rd lines read "minstens"  "mins" e.g. "three /n twenty /n one"
  799.       else if (minsdigitten != 0 && minsdigit != 0  ) {
  800.         strcpy (str_a, numbers[hours - 1]);
  801.         //if mins is in the teens, use teens from the numbers array for the 2nd line, e.g. "fifteen"
  802.         //if (mins >= 11 && mins <= 19) {
  803.         if (mins <= 19) {
  804.           strcpy (str_b, numbers[mins - 1]);
  805.         }
  806.         else {
  807.           strcpy (str_b, numberstens[minsdigitten - 1]);
  808.           strcpy (str_c, numbers[minsdigit - 1]);
  809.         }
  810.       }
  811.       // if mins digit is zero, don't print it. read read "hours" "minstens" e.g. "three /n twenty"
  812.       else if (minsdigitten != 0 && minsdigit == 0  ) {
  813.         strcpy (str_a, numbers[hours - 1]);
  814.         strcpy (str_b, numberstens[minsdigitten - 1]);
  815.         strcpy (str_c, "");
  816.       }
  817.       //if both mins are zero, i.e. it is on the hour, the top line reads "hours" and bottom line reads "o'clock"
  818.       else if (minsdigitten == 0 && minsdigit == 0  ) {
  819.         strcpy (str_a, numbers[hours - 1]);
  820.         strcpy (str_b, "O'CLOCK");
  821.         strcpy (str_c, "");
  822.       }
  823.     }//end worknig out time
  824.     //run in a loop
  825.     //print line a "twelve"
  826.     byte len = 0;
  827.     while (str_a[len]) {
  828.       len++;
  829.     }; //get length of message
  830.     byte offset_top = (31 - ((len - 1) * 4)) / 2; //
  831.     //plot hours line
  832.     byte i = 0;
  833.     while (str_a[i]) {
  834.       puttinychar((i * 4) + offset_top, 1, str_a[i]);
  835.       i++;
  836.     }
  837.    
  838.     //hold display but check for button presses
  839.     int counter = 1000;
  840.     while (counter > 0){
  841.       //check for button press
  842.       if (buttonA.uniquePress()) {
  843.         switch_mode();
  844.         return;
  845.       }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 09:28

【Arduino 动手做】DIY Arduino全息矩阵时钟

附录
【Arduino 动手做】DIY Arduino全息矩阵时钟
项目链接:https://www.hackster.io/mircemk/ ... matrix-clock-c35b5e
项目作者:北马其顿 米尔塞姆克(Mirko Pavleski)

项目视频 :https://www.youtube.com/watch?v=Z04ZxXR_4F8&t=2s
项目代码:https://www.hackster.io/code_files/643589/download

【Arduino 动手做】DIY Arduino全息矩阵时钟图1

【Arduino 动手做】DIY Arduino全息矩阵时钟图2

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail