15浏览
查看: 15|回复: 2

[项目] 【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟

[复制链接]
一个简单易构建的时钟,具有许多功能。

在“Nick's LED Projects”页面上,我发现时钟项目女巫在 4 个矩阵上显示带有 8x8 LED 的时间。他用销售矩阵模块面板 DIY 套件的“ICStation”商店的矩阵制作了时钟。
只需对代码进行最小的更改,我就用点阵模块 icrocontroller 四合一显示器制作了我的时钟MAX7219它完全折叠,而且便宜得多。我从速卖通购买的。
时钟有很多特点:
- 大数字的基本模式
- 数字在屏幕上滚动的滑动模式
- 带秒模式的小数字
- 时间用文字写成,例如“十二点十点”
- 日期显示
- 12/24 小时选项
- 亮度选项
- 随机时钟模式选项,每隔几个小时更改一次显示模式。
- 用于设置和显示选择的按钮驱动菜单。

正如您在电路上看到的,除了矩阵之外,我们还需要一个 Arduino 板、一个实时时钟模块和两个用于设置的按钮。您可以通过以下链接下载库和修改后的代码。

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟图1

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟图2

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟图3

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟图4

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟图5

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟图6

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟图7

驴友花雕  中级技神
 楼主|

发表于 7 小时前

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟

项目代码

  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. ***********************************************************************/
  8. //include libraries:
  9. #include "LedControl.h"
  10. #include <FontLEDClock.h>                // Font library
  11. #include <Wire.h>                        // DS1307 clock
  12. #include "RTClib.h"                      // DS1307 clock
  13. #include <Button.h>                      // Button library by Alexander Brevig
  14. // Setup LED Matrix
  15. // pin 12 is connected to the DataIn on the display
  16. // pin 11 is connected to the CLK on the display
  17. // pin 10 is connected to LOAD on the display
  18. LedControl lc = LedControl(12, 11, 10, 4); //sets the 3 pins as 12, 11 & 10 and then sets 4 displays (max is 8 displays)
  19. //global variables
  20. byte intensity = 7;                      // Default intensity/brightness (0-15)
  21. byte clock_mode = 0;                     // Default clock mode. Default = 0 (basic_mode)
  22. bool random_mode = 0;                    // Define random mode - changes the display type every few hours. Default = 0 (off)
  23. 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.
  24. bool ampm = 0;                           // Define 12 or 24 hour time. 0 = 24 hour. 1 = 12 hour
  25. byte change_mode_time = 0;               // Holds hour when clock mode will next change if in random mode.
  26. unsigned long delaytime = 500;           // We always wait a bit between updates of the display
  27. int rtc[7];                              // Holds real time clock output
  28. char days[7][4] = {
  29.   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  30. }; //day array - used in slide, basic_mode and jumble modes (The DS1307 outputs 1-7 values for day of week)
  31. char daysfull[7][9] = {
  32.   "Sunday", "Monday", "Tuesday", "Wed", "Thursday", "Friday", "Saturday"
  33. };
  34. char suffix[4][3] = {
  35.   "st", "nd", "rd", "th"
  36. };  //date suffix array, used in slide, basic_mode and jumble modes. e,g, 1st 2nd ...
  37. //define constants
  38. #define NUM_DISPLAY_MODES 3              // Number display modes (conting zero as the first mode)
  39. #define NUM_SETTINGS_MODES 4             // Number settings modes = 6 (conting zero as the first mode)
  40. #define SLIDE_DELAY 20                   // The time in milliseconds for the slide effect per character in slide mode. Make this higher for a slower effect
  41. #define cls          clear_display       // Clear display
  42. RTC_DS1307 ds1307;                              // Create RTC object
  43. Button buttonA = Button(2, BUTTON_PULLUP);      // Setup button A (using button library)
  44. Button buttonB = Button(3, BUTTON_PULLUP);      // Setup button B (using button library)
  45. void setup() {
  46.   digitalWrite(2, HIGH);                 // turn on pullup resistor for button on pin 2
  47.   digitalWrite(3, HIGH);                 // turn on pullup resistor for button on pin 3
  48.   digitalWrite(4, HIGH);                 // turn on pullup resistor for button on pin 4
  49.   
  50.   Serial.begin(9600); //start serial
  51.   //initialize the 4 matrix panels
  52.   //we have already set the number of devices when we created the LedControl
  53.   int devices = lc.getDeviceCount();
  54.   //we have to init all devices in a loop
  55.   for (int address = 0; address < devices; address++) {
  56.     /*The MAX72XX is in power-saving mode on startup*/
  57.     lc.shutdown(address, false);
  58.     /* Set the brightness to a medium values */
  59.     lc.setIntensity(address, intensity);
  60.     /* and clear the display */
  61.     lc.clearDisplay(address);
  62.   }
  63.   //Setup DS1307 RTC
  64. #ifdef AVR
  65.   Wire.begin();
  66. #else
  67.   Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino
  68. #endif
  69.   ds1307.begin(); //start RTC Clock
  70.   if (! ds1307.isrunning()) {
  71.     Serial.println("RTC is NOT running!");
  72.     ds1307.adjust(DateTime(__DATE__, __TIME__));  // sets the RTC to the date & time this sketch was compiled
  73.   }
  74.   //Show software version & hello message
  75.   printver();
  76.   
  77.   //enable red led
  78.   digitalWrite(13, HIGH);
  79. }
  80. void loop() {
  81.   
  82.   //run the clock with whatever mode is set by clock_mode - the default is set at top of code.
  83.   switch (clock_mode){
  84.         
  85.   case 0:
  86.     basic_mode();
  87.     break;
  88.   case 1:
  89.    small_mode();
  90.     break;
  91.   case 2:
  92.     slide();
  93.     break;
  94.   case 3:
  95.     word_clock();
  96.     break;
  97.   case 4:
  98.     setup_menu();
  99.     break;
  100.   }
  101. }
  102. //plot a point on the display
  103. void plot (byte x, byte y, byte val) {
  104.   //select which matrix depending on the x coord
  105.   byte address;
  106.   if (x >= 0 && x <= 7)   {
  107.     address = 3;
  108.   }
  109.   if (x >= 8 && x <= 15)  {
  110.     address = 2;
  111.     x = x - 8;
  112.   }
  113.   if (x >= 16 && x <= 23) {
  114.     address = 1;
  115.     x = x - 16;
  116.   }
  117.   if (x >= 24 && x <= 31) {
  118.     address = 0;
  119.     x = x - 24;
  120.   }
  121.   if (val == 1) {
  122.     lc.setLed(address, y, x, true);
  123.   } else {
  124.     lc.setLed(address, y, x, false);
  125.   }
  126. }
  127. //clear screen
  128. void clear_display() {
  129.   for (byte address = 0; address < 4; address++) {
  130.     lc.clearDisplay(address);
  131.   }
  132. }
  133. //fade screen down
  134. void fade_down() {
  135.   //fade from global intensity to 1
  136.   for (byte i = intensity; i > 0; i--) {
  137.     for (byte address = 0; address < 4; address++) {
  138.       lc.setIntensity(address, i);
  139.     }
  140.     delay(30); //change this to change fade down speed
  141.   }
  142.   clear_display(); //clear display completely (off)
  143.   //reset intentsity to global val
  144.   for (byte address = 0; address < 4; address++) {
  145.     lc.setIntensity(address, intensity);
  146.   }
  147. }
  148. //power up led test & display software version number
  149. void printver() {
  150.   byte i = 0;
  151.   char ver_a[9] = "Vers 1.0";
  152.   char ver_b[9] = " Hello! ";
  153.   //test all leds.
  154.   for (byte x = 0; x <= 31; x++) {
  155.     for (byte y = 0; y <= 7; y++) {
  156.       plot(x, y, 1);
  157.     }
  158.   }
  159.   delay(500);
  160.   fade_down();
  161.   while (ver_a[i]) {
  162.     puttinychar((i * 4), 1, ver_a[i]);
  163.     delay(35);
  164.     i++;
  165.   }
  166.   delay(700);
  167.   fade_down();
  168.   i = 0;
  169.   while (ver_b[i]) {
  170.     puttinychar((i * 4), 1, ver_b[i]);
  171.     delay(35);
  172.     i++;
  173.   }
  174.   delay(700);
  175.   fade_down();
  176. }
  177. // puttinychar
  178. // Copy a 3x5 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate
  179. // This is unoptimized and simply uses plot() to draw each dot.
  180. void puttinychar(byte x, byte y, char c)
  181. {
  182.   byte dots;
  183.   if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) {
  184.     c &= 0x1F;   // A-Z maps to 1-26
  185.   }
  186.   else if (c >= '0' && c <= '9') {
  187.     c = (c - '0') + 32;
  188.   }
  189.   else if (c == ' ') {
  190.     c = 0; // space
  191.   }
  192.   else if (c == '.') {
  193.     c = 27; // full stop
  194.   }
  195.   else if (c == ':') {
  196.     c = 28; // colon
  197.   }
  198.   else if (c == '\'') {
  199.     c = 29; // single quote mark
  200.   }
  201.   else if (c == '!') {
  202.     c = 30; // single quote mark
  203.   }
  204.   else if (c == '?') {
  205.     c = 31; // single quote mark
  206.   }
  207.   for (byte col = 0; col < 3; col++) {
  208.     dots = pgm_read_byte_near(&mytinyfont[c][col]);
  209.     for (char row = 0; row < 5; row++) {
  210.       if (dots & (16 >> row))
  211.         plot(x + col, y + row, 1);
  212.       else
  213.         plot(x + col, y + row, 0);
  214.     }
  215.   }
  216. }
  217. void putnormalchar(byte x, byte y, char c)
  218. {
  219.   byte dots;
  220.   //  if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) {
  221.   //    c &= 0x1F;   // A-Z maps to 1-26
  222.   //  }
  223.   if (c >= 'A' && c <= 'Z' ) {
  224.     c &= 0x1F;   // A-Z maps to 1-26
  225.   }
  226.   else if (c >= 'a' && c <= 'z') {
  227.     c = (c - 'a') + 41;   // A-Z maps to 41-67
  228.   }
  229.   else if (c >= '0' && c <= '9') {
  230.     c = (c - '0') + 31;
  231.   }
  232.   else if (c == ' ') {
  233.     c = 0; // space
  234.   }
  235.   else if (c == '.') {
  236.     c = 27; // full stop
  237.   }
  238.   else if (c == '\'') {
  239.     c = 28; // single quote mark
  240.   }
  241.   else if (c == ':') {
  242.     c = 29; // clock_mode selector arrow
  243.   }
  244.   else if (c == '>') {
  245.     c = 30; // clock_mode selector arrow
  246.   }
  247.   else if (c >= -80 && c <= -67) {
  248.     c *= -1;
  249.   }
  250.   for (char col = 0; col < 5; col++) {
  251.     dots = pgm_read_byte_near(&myfont[c][col]);
  252.     for (char row = 0; row < 7; row++) {
  253.       //check coords are on screen before trying to plot
  254.       //if ((x >= 0) && (x <= 31) && (y >= 0) && (y <= 7)){
  255.       if (dots & (64 >> row)) {   // only 7 rows.
  256.         plot(x + col, y + row, 1);
  257.       } else {
  258.         plot(x + col, y + row, 0);
  259.       }
  260.       //}
  261.     }
  262.   }
  263. }
  264. //small_mode
  265. //show the time in small 3x5 characters with seconds display
  266. void small_mode() {
  267.   char textchar[8]; // the 16 characters on the display
  268.   byte mins = 100; //mins
  269.   byte secs = rtc[0]; //seconds
  270.   byte old_secs = secs; //holds old seconds value - from last time seconds were updated o display - used to check if seconds have changed
  271.   
  272.   cls();
  273.   //run clock main loop as long as run_mode returns true
  274.   while (run_mode()) {
  275.     get_time();
  276.   
  277.     //check for button press
  278.     if (buttonA.uniquePress()) {
  279.       switch_mode();
  280.       return;
  281.     }
  282.     if (buttonB.uniquePress()) {
  283.       display_date();
  284.       return;
  285.     }
  286.    
  287.     //if secs changed then update them on the display
  288.     secs = rtc[0];
  289.     if (secs != old_secs) {
  290.       //secs
  291.       char buffer[3];
  292.       itoa(secs, buffer, 10);
  293.       //fix - as otherwise if num has leading zero, e.g. "03" secs, itoa coverts this to chars with space "3 ".
  294.       if (secs < 10) {
  295.         buffer[1] = buffer[0];
  296.         buffer[0] = '0';
  297.       }
  298.       puttinychar( 20, 1, ':'); //seconds colon
  299.       puttinychar( 24, 1, buffer[0]); //seconds
  300.       puttinychar( 28, 1, buffer[1]); //seconds
  301.       old_secs = secs;
  302.     }
  303.     //if minute changes change time
  304.     if (mins != rtc[1]) {
  305.       //reset these for comparison next time
  306.       mins = rtc[1];
  307.       byte hours = rtc[2];
  308.       if (hours > 12) {
  309.         hours = hours - ampm * 12;
  310.       }
  311.       if (hours < 1) {
  312.         hours = hours + ampm * 12;
  313.       }
  314.       //byte dow  = rtc[3]; // the DS1307 outputs 0 - 6 where 0 = Sunday0 - 6 where 0 = Sunday.
  315.       //byte date = rtc[4];
  316.       //set characters
  317.       char buffer[3];
  318.       itoa(hours, buffer, 10);
  319.       //fix - as otherwise if num has leading zero, e.g. "03" hours, itoa coverts this to chars with space "3 ".
  320.       if (hours < 10) {
  321.         buffer[1] = buffer[0];
  322.         //if we are in 12 hour mode blank the leading zero.
  323.         if (ampm) {
  324.           buffer[0] = ' ';
  325.         }
  326.         else {
  327.           buffer[0] = '0';
  328.         }
  329.       }
  330.       //set hours chars
  331.       textchar[0] = buffer[0];
  332.       textchar[1] = buffer[1];
  333.       textchar[2] = ':';
  334.       itoa (mins, buffer, 10);
  335.       if (mins < 10) {
  336.         buffer[1] = buffer[0];
  337.         buffer[0] = '0';
  338.       }
  339.       //set mins characters
  340.       textchar[3] = buffer[0];
  341.       textchar[4] = buffer[1];
  342.       //do seconds
  343.       textchar[5] = ':';
  344.       buffer[3];
  345.       secs = rtc[0];
  346.       itoa(secs, buffer, 10);
  347.       //fix - as otherwise if num has leading zero, e.g. "03" secs, itoa coverts this to chars with space "3 ".
  348.       if (secs < 10) {
  349.         buffer[1] = buffer[0];
  350.         buffer[0] = '0';
  351.       }
  352.       //set seconds
  353.       textchar[6] = buffer[0];
  354.       textchar[7] = buffer[1];
  355.       byte x = 0;
  356.       byte y = 0;
  357.       //print each char
  358.       for (byte x = 0; x < 6 ; x++) {
  359.         puttinychar( x * 4, 1, textchar[x]);
  360.       }
  361.     }
  362.     delay(50);
  363.   }
  364.   fade_down();
  365. }
  366. // basic_mode()
  367. // show the time in 5x7 characters
  368. void basic_mode()
  369. {
  370.   cls();
  371.   char buffer[3];   //for int to char conversion to turn rtc values into chars we can print on screen
  372.   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
  373.   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.
  374.   //do 12/24 hour conversion if ampm set to 1
  375.   byte hours = rtc[2];
  376.   if (hours > 12) {
  377.     hours = hours - ampm * 12;
  378.   }
  379.   if (hours < 1) {
  380.     hours = hours + ampm * 12;
  381.   }
  382.   //do offset conversion
  383.   if (ampm && hours < 10) {
  384.     offset = 2;
  385.   }
  386.   
  387.   //set the next minute we show the date at
  388.   //set_next_date();
  389.   
  390.   // 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
  391.   byte secs = 100;
  392.   byte mins = 100;
  393.   int count = 0;
  394.   
  395.   //run clock main loop as long as run_mode returns true
  396.   while (run_mode()) {
  397.     //get the time from the clock chip
  398.     get_time();
  399.    
  400.     //check for button press
  401.     if (buttonA.uniquePress()) {
  402.       switch_mode();
  403.       return;
  404.     }
  405.     if (buttonB.uniquePress()) {
  406.       display_date();
  407.       return;
  408.     }
  409.     //check whether it's time to automatically display the date
  410.     //check_show_date();
  411.     //draw the flashing : as on if the secs have changed.
  412.     if (secs != rtc[0]) {
  413.       //update secs with new value
  414.       secs = rtc[0];
  415.       //draw :
  416.       plot (15 - offset, 2, 1); //top point
  417.       plot (15 - offset, 5, 1); //bottom point
  418.       count = 400;
  419.     }
  420.     //if count has run out, turn off the :
  421.     if (count == 0) {
  422.       plot (15 - offset, 2, 0); //top point
  423.       plot (15 - offset, 5, 0); //bottom point
  424.     }
  425.     else {
  426.       count--;
  427.     }
  428.     //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)
  429.     if (mins != rtc[1]) {
  430.       //update mins and hours with the new values
  431.       mins = rtc[1];
  432.       hours = rtc[2];
  433.       //adjust hours of ampm set to 12 hour mode
  434.       if (hours > 12) {
  435.         hours = hours - ampm * 12;
  436.       }
  437.       if (hours < 1) {
  438.         hours = hours + ampm * 12;
  439.       }
  440.       itoa(hours, buffer, 10);
  441.       //if hours < 10 the num e.g. "3" hours, itoa coverts this to chars with space "3 " which we dont want
  442.       if (hours < 10) {
  443.         buffer[1] = buffer[0];
  444.         buffer[0] = '0';
  445.       }
  446.       //print hours
  447.       //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.
  448.       if (ampm && hours < 10) {
  449.         offset = 2;
  450.         //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
  451.         if ((hours == 1 && mins == 0) ) {
  452.           cls();
  453.         }
  454.       }
  455.       else {
  456.         //else no offset and print hours tens digit
  457.         offset = 0;
  458.         //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
  459.         if (hours == 10 && mins == 0) {
  460.           cls();
  461.         }
  462.         putnormalchar(1,  0, buffer[0]);
  463.       }
  464.       //print hours ones digit
  465.       putnormalchar(7 - offset, 0, buffer[1]);
  466.       //print mins
  467.       //add leading zero if mins < 10
  468.       itoa (mins, buffer, 10);
  469.       if (mins < 10) {
  470.         buffer[1] = buffer[0];
  471.         buffer[0] = '0';
  472.       }
  473.       //print mins tens and ones digits
  474.       putnormalchar(19 - offset, 0, buffer[0]);
  475.       putnormalchar(25 - offset, 0, buffer[1]);
  476.     }
  477.   }
  478.   fade_down();
  479. }
  480. //like basic_mode but with slide effect
  481. void slide() {
  482.   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
  483.   byte digits_new[4]; //new digits time will slide to reveal
  484.   byte digits_x_pos[4] = {25, 19, 7, 1}; //x pos for which to draw each digit at
  485.   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
  486.   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
  487.   //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.
  488.   //We sent them as A initially, which are used when the clocl enters the mode and no last chars are stored.
  489.   //char old_chars[6] = "AAAAA";
  490.   //plot the clock colon on the display
  491.   cls();
  492.   putnormalchar( 13, 0, ':');
  493.   byte old_secs = rtc[0]; //store seconds in old_secs. We compare secs and old secs. WHen they are different we redraw the display
  494.   //run clock main loop as long as run_mode returns true
  495.   while (run_mode()) {
  496.     get_time();
  497.    
  498.     //check for button press
  499.     if (buttonA.uniquePress()) {
  500.       switch_mode();
  501.       return;
  502.     }
  503.       if (buttonB.uniquePress()) {
  504.       display_date();
  505.       return;
  506.     }
  507.     //if secs have changed then update the display
  508.     if (rtc[0] != old_secs) {
  509.       old_secs = rtc[0];
  510.       //do 12/24 hour conversion if ampm set to 1
  511.       byte hours = rtc[2];
  512.       if (hours > 12) {
  513.         hours = hours - ampm * 12;
  514.       }
  515.       if (hours < 1) {
  516.         hours = hours + ampm * 12;
  517.       }
  518.       //split all date and time into individual digits - stick in digits_new array
  519.       //rtc[0] = secs                        //array pos and digit stored
  520.       //digits_new[0] = (rtc[0]%10);           //0 - secs ones
  521.       //digits_new[1] = ((rtc[0]/10)%10);      //1 - secs tens
  522.       //rtc[1] = mins
  523.       digits_new[0] = (rtc[1] % 10);         //2 - mins ones
  524.       digits_new[1] = ((rtc[1] / 10) % 10);  //3 - mins tens
  525.       //rtc[2] = hours
  526.       digits_new[2] = (hours % 10);         //4 - hour ones
  527.       digits_new[3] = ((hours / 10) % 10);  //5 - hour tens
  528.       //rtc[4] = date
  529.       //digits_new[6] = (rtc[4]%10);           //6 - date ones
  530.       //digits_new[7] = ((rtc[4]/10)%10);      //7 - date tens
  531.       //draw initial screen of all chars. After this we just draw the changes.
  532.       //compare digits 0 to 3 (mins and hours)
  533.       for (byte i = 0; i <= 3; i++) {
  534.         //see if digit has changed...
  535.         if (digits_old[i] != digits_new[i]) {
  536.           //run 9 step animation sequence for each in turn
  537.           for (byte seq = 0; seq <= 8 ; seq++) {
  538.             //convert digit to string
  539.             itoa(digits_old[i], old_char, 10);
  540.             itoa(digits_new[i], new_char, 10);
  541.             //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
  542.             if (ampm && i == 3) {
  543.               if (digits_new[3] == 0) {
  544.                 new_char[0] = ' ';
  545.               }
  546.               if (digits_old[3] == 0) {
  547.                 old_char[0] = ' ';
  548.               }
  549.             }
  550.             //draw the animation frame for each digit
  551.             slideanim(digits_x_pos[i], 0, seq, old_char[0], new_char[0]);
  552.             delay(SLIDE_DELAY);
  553.           }
  554.         }
  555.       }
  556.       /*
  557.       //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
  558.       if ((digits_old[6] != digits_new[6]) || (digits_old[7] != digits_new[7])) {
  559.         //change the day shown. Loop below goes through each of the 3 chars in turn e.g. "MON"
  560.         for (byte day_char = 0; day_char <=2 ; day_char++){
  561.           //run the anim sequence for each char
  562.           for (byte seq = 0; seq <=8 ; seq++){
  563.             //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
  564.             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
  565.             delay(SLIDE_DELAY);
  566.           }
  567.           //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.
  568.           old_chars[day_char] = days[rtc[3]][day_char];
  569.         }
  570.         //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.)
  571.         for (byte i = 7; i >= 6; i--){
  572.           if (digits_old[i] != digits_new[i]) {
  573.             for (byte seq = 0; seq <=8 ; seq++){
  574.               itoa(digits_old[i],old_char,10);
  575.               itoa(digits_new[i],new_char,10);
  576.               slideanim(digits_x_pos[i],8,seq,old_char[0],new_char[0]);
  577.               delay(SLIDE_DELAY);
  578.             }
  579.           }
  580.         }
  581.         //print the day suffix "nd" "rd" "th" etc. First work out date 2 letter suffix - eg st, nd, rd, th
  582.         byte s = 3; //the pos to read our suffix array from.
  583.         byte date = rtc[4];
  584.         if(date == 1 || date == 21 || date == 31) {
  585.           s = 0;
  586.         }
  587.         else if (date == 2 || date == 22) {
  588.           s = 1;
  589.         }
  590.         else if (date == 3 || date == 23) {
  591.           s = 2;
  592.         }
  593.         for (byte suffix_char = 0; suffix_char <=1 ; suffix_char++){
  594.           for (byte seq = 0; seq <=8 ; seq++){
  595.             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
  596.             delay(SLIDE_DELAY);
  597.           }
  598.           //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.
  599.           old_chars[suffix_char+3] = suffix[s][suffix_char];
  600.         }
  601.       }//end do date line
  602.       */
  603.       //save digita array tol old for comparison next loop
  604.       for (byte i = 0; i <= 3; i++) {
  605.         digits_old[i] =  digits_new[i];
  606.       }
  607.     }//secs/oldsecs
  608.   }//while loop
  609.   fade_down();
  610. }
  611. //called by slide
  612. //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
  613. //inputs are are char x and y, animation frame sequence (0-7) and the current and new chars being drawn.
  614. void slideanim(byte x, byte y, byte sequence, char current_c, char new_c) {
  615.   //  To slide one char off and another on we need 9 steps or frames in sequence...
  616.   //  seq# 0123456 <-rows of the display
  617.   //   |   |||||||
  618.   //  seq0 0123456  START - all rows of the display 0-6 show the current characters rows 0-6
  619.   //  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
  620.   //  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
  621.   //  seq3 56 0123
  622.   //  seq4 456 012  half old / half new char
  623.   //  seq5 3456 01
  624.   //  seq6 23456 0
  625.   //  seq7 123456
  626.   //  seq8 0123456  END - all rows show the new char
  627.   //from above we can see...
  628.   //currentchar runs 0-6 then 0-5 then 0-4 all the way to 0. starting Y position increases by 1 row each time.
  629.   //new char runs 6 then 5-6 then 4-6 then 3-6. starting Y position increases by 1 row each time.
  630.   //if sequence number is below 7, we need to draw the current char
  631.   if (sequence < 7) {
  632.     byte dots;
  633.     // if (current_c >= 'A' &&  || (current_c >= 'a' && current_c <= 'z') ) {
  634.     //   current_c &= 0x1F;   // A-Z maps to 1-26
  635.     // }
  636.     if (current_c >= 'A' && current_c <= 'Z' ) {
  637.       current_c &= 0x1F;   // A-Z maps to 1-26
  638.     }
  639.     else if (current_c >= 'a' && current_c <= 'z') {
  640.       current_c = (current_c - 'a') + 41;   // A-Z maps to 41-67
  641.     }
  642.     else if (current_c >= '0' && current_c <= '9') {
  643.       current_c = (current_c - '0') + 31;
  644.     }
  645.     else if (current_c == ' ') {
  646.       current_c = 0; // space
  647.     }
  648.     else if (current_c == '.') {
  649.       current_c = 27; // full stop
  650.     }
  651.     else if (current_c == '\'') {
  652.       current_c = 28; // single quote mark
  653.     }
  654.     else if (current_c == ':') {
  655.       current_c = 29; //colon
  656.     }
  657.     else if (current_c == '>') {
  658.       current_c = 30; // clock_mode selector arrow
  659.     }
  660.     byte curr_char_row_max = 7 - sequence; //the maximum number of rows to draw is 6 - sequence number
  661.     byte start_y = sequence; //y position to start at - is same as sequence number. We inc this each loop
  662.     //plot each row up to row maximum (calculated from sequence number)
  663.     for (byte curr_char_row = 0; curr_char_row <= curr_char_row_max; curr_char_row++) {
  664.       for (byte col = 0; col < 5; col++) {
  665.         dots = pgm_read_byte_near(&myfont[current_c][col]);
  666.         if (dots & (64 >> curr_char_row))
  667.           plot(x + col, y + start_y, 1); //plot led on
  668.         else
  669.           plot(x + col, y + start_y, 0); //else plot led off
  670.       }
  671.       start_y++;//add one to y so we draw next row one down
  672.     }
  673.   }
  674.   //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
  675.   if (sequence >= 1 && sequence <= 8) {
  676.     for (byte col = 0; col < 5; col++) {
  677.       plot(x + col, y + (sequence - 1), 0); //the y position to draw the line is equivalent to the sequence number - 1
  678.     }
  679.   }
  680.   //if sequence is above 2, we also need to start drawing the new char
  681.   if (sequence >= 2) {
  682.     //work out char
  683.     byte dots;
  684.     //if (new_c >= 'A' && new_c <= 'Z' || (new_c >= 'a' && new_c <= 'z') ) {
  685.     //  new_c &= 0x1F;   // A-Z maps to 1-26
  686.     //}
  687.     if (new_c >= 'A' && new_c <= 'Z' ) {
  688.       new_c &= 0x1F;   // A-Z maps to 1-26
  689.     }
  690.     else if (new_c >= 'a' && new_c <= 'z') {
  691.       new_c = (new_c - 'a') + 41;   // A-Z maps to 41-67
  692.     }
  693.     else if (new_c >= '0' && new_c <= '9') {
  694.       new_c = (new_c - '0') + 31;
  695.     }
  696.     else if (new_c == ' ') {
  697.       new_c = 0; // space
  698.     }
  699.     else if (new_c == '.') {
  700.       new_c = 27; // full stop
  701.     }
  702.     else if (new_c == '\'') {
  703.       new_c = 28; // single quote mark
  704.     }
  705.     else if (new_c == ':') {
  706.       new_c = 29; // clock_mode selector arrow
  707.     }
  708.     else if (new_c == '>') {
  709.       new_c = 30; // clock_mode selector arrow
  710.     }
  711.     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
  712.     byte start_y = 0; //y position to start at - is same as sequence number. we inc it each row
  713.     //plot each row up from row minimum (calculated by sequence number) up to 6
  714.     for (byte newcharrow = newcharrowmin; newcharrow <= 6; newcharrow++) {
  715.       for (byte col = 0; col < 5; col++) {
  716.         dots = pgm_read_byte_near(&myfont[new_c][col]);
  717.         if (dots & (64 >> newcharrow))
  718.           plot(x + col, y + start_y, 1); //plot led on
  719.         else
  720.           plot(x + col, y + start_y, 0); //else plot led off
  721.       }
  722.       start_y++;//add one to y so we draw next row one down
  723.     }
  724.   }
  725. }
  726. //print a clock using words rather than numbers
  727. void word_clock() {
  728.   cls();
  729.   char numbers[19][10]   = {
  730.     "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
  731.     "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
  732.   };
  733.   char numberstens[5][7] = {
  734.     "ten", "twenty", "thirty", "forty", "fifty"
  735.   };
  736.   
  737.   //potentially 3 lines to display
  738.   char str_a[8];
  739.   char str_b[8];
  740.   char str_c[8];
  741.   //byte hours_y, mins_y; //hours and mins and positions for hours and mins lines
  742.   byte hours = rtc[2];
  743.   if (hours > 12) {
  744.     hours = hours - ampm * 12;
  745.   }
  746.   if (hours < 1) {
  747.     hours = hours + ampm * 12;
  748.   }
  749.   get_time(); //get the time from the clock chip
  750.   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.
  751.   byte mins;
  752.   //run clock main loop as long as run_mode returns true
  753.   while (run_mode()) {
  754.    
  755.     //check for button press
  756.     if (buttonA.uniquePress()) {
  757.       switch_mode();
  758.       return;
  759.     }
  760.     if (buttonB.uniquePress()) {
  761.       display_date();
  762.     }
  763.     get_time(); //get the time from the clock chip
  764.     mins = rtc[1];  //get mins
  765.     //if mins is different from old_mins - redraw display
  766.     if (mins != old_mins) {
  767.       //update old_mins with current mins value
  768.       old_mins = mins;
  769.       //reset these for comparison next time
  770.       mins = rtc[1];
  771.       hours = rtc[2];
  772.       //make hours into 12 hour format
  773.       if (hours > 12) {
  774.         hours = hours - 12;
  775.       }
  776.       if (hours == 0) {
  777.         hours = 12;
  778.       }
  779.       //split mins value up into two separate digits
  780.       int minsdigit = rtc[1] % 10;
  781.       byte minsdigitten = (rtc[1] / 10) % 10;
  782.       //if mins <= 10 , then top line has to read "minsdigti past" and bottom line reads hours
  783.       if (mins < 10) {
  784.         strcpy (str_a, numbers[minsdigit - 1]);
  785.         strcpy (str_b, "PAST");
  786.         strcpy (str_c, numbers[hours - 1]);
  787.       }
  788.       //if mins = 10, cant use minsdigit as above, so soecial case to print 10 past /n hour.
  789.       if (mins == 10) {
  790.         strcpy (str_a, numbers[9]);
  791.         strcpy (str_b, " PAST");
  792.         strcpy (str_c, numbers[hours - 1]);
  793.       }
  794.       //if time is not on the hour - i.e. both mins digits are not zero,
  795.       //then make first line read "hours" and 2 & 3rd lines read "minstens"  "mins" e.g. "three /n twenty /n one"
  796.       else if (minsdigitten != 0 && minsdigit != 0  ) {
  797.         strcpy (str_a, numbers[hours - 1]);
  798.         //if mins is in the teens, use teens from the numbers array for the 2nd line, e.g. "fifteen"
  799.         //if (mins >= 11 && mins <= 19) {
  800.         if (mins <= 19) {
  801.           strcpy (str_b, numbers[mins - 1]);
  802.         }
  803.         else {
  804.           strcpy (str_b, numberstens[minsdigitten - 1]);
  805.           strcpy (str_c, numbers[minsdigit - 1]);
  806.         }
  807.       }
  808.       // if mins digit is zero, don't print it. read read "hours" "minstens" e.g. "three /n twenty"
  809.       else if (minsdigitten != 0 && minsdigit == 0  ) {
  810.         strcpy (str_a, numbers[hours - 1]);
  811.         strcpy (str_b, numberstens[minsdigitten - 1]);
  812.         strcpy (str_c, "");
  813.       }
  814.       //if both mins are zero, i.e. it is on the hour, the top line reads "hours" and bottom line reads "o'clock"
  815.       else if (minsdigitten == 0 && minsdigit == 0  ) {
  816.         strcpy (str_a, numbers[hours - 1]);
  817.         strcpy (str_b, "O'CLOCK");
  818.         strcpy (str_c, "");
  819.       }
  820.     }//end worknig out time
  821.     //run in a loop
  822.     //print line a "twelve"
  823.     byte len = 0;
  824.     while (str_a[len]) {
  825.       len++;
  826.     }; //get length of message
  827.     byte offset_top = (31 - ((len - 1) * 4)) / 2; //
  828.     //plot hours line
  829.     byte i = 0;
  830.     while (str_a[i]) {
  831.       puttinychar((i * 4) + offset_top, 1, str_a[i]);
  832.       i++;
  833.     }
  834.    
  835.     //hold display but check for button presses
  836.     int counter = 1000;
  837.     while (counter > 0){
  838.       //check for button press
  839.       if (buttonA.uniquePress()) {
  840.         switch_mode();
  841.         return;
  842.       }
  843.       if (buttonB.uniquePress()) {
  844.         display_date();
  845.       }
  846.     delay(1);
  847.     counter--;
  848.     }
  849.     fade_down();
  850.     //print line b
  851.     len = 0;
  852.     while (str_b[len]) {
  853.       len++;
  854.     }; //get length of message
  855.     offset_top = (31 - ((len - 1) * 4)) / 2;
  856.     i = 0;
  857.     while (str_b[i]) {
  858.       puttinychar((i * 4) + offset_top, 1, str_b[i]);
  859.       i++;
  860.     }
  861.     //hold display but check for button presses
  862.     counter = 1000;
  863.     while (counter > 0){
  864.       if (buttonA.uniquePress()) {
  865.         switch_mode();
  866.         return;
  867.       }
  868.       if (buttonB.uniquePress()) {
  869.         display_date();
  870.       }
  871.       delay(1);
  872.       counter--;
  873.     }
  874.     fade_down();
  875.     //print line c if there.
  876.     len = 0;
  877.     while (str_c[len]) {
  878.       len++;
  879.     }; //get length of message
  880.     offset_top = (31 - ((len - 1) * 4)) / 2;
  881.     i = 0;
  882.     while (str_c[i]) {
  883.       puttinychar((i * 4) + offset_top, 1, str_c[i]);
  884.       i++;
  885.     }
  886.     counter = 1000;
  887.     while (counter > 0){
  888.       //check for button press
  889.       if (buttonA.uniquePress()) {
  890.         switch_mode();
  891.         return;
  892.       }
  893.       if (buttonB.uniquePress()) {
  894.         display_date();
  895.       }  
  896.       delay(1);
  897.       counter--;
  898.     }
  899.     fade_down();
  900.    
  901.    
  902.     //hold display blank but check for button presses before starting again.
  903.     counter = 1000;
  904.     while (counter > 0){
  905.        //check for button press
  906.       if (buttonA.uniquePress()) {
  907.         switch_mode();
  908.         return;
  909.       }
  910.       if (buttonB.uniquePress()) {
  911.         display_date();
  912.       }  
  913.       delay(1);
  914.       counter--;
  915.     }
  916.   }
  917.   fade_down();
  918. }
  919. /// scroll message - not used at present - too slow.
  920. void scroll() {
  921.   char message[] = {"Hello There "};
  922.   cls();
  923.   byte p = 6;      //current pos in string
  924.   byte chara[] = {0, 1, 2, 3, 4, 5}; //chars from string
  925.   int x[] = {0, 6, 12, 18, 24, 30}; //xpos for each char
  926.   byte y = 0;                   //y pos
  927.   // clear_buffer();
  928.   while (message[p] != '\0') {
  929.     //draw all 6 chars
  930.     for (byte c = 0; c < 6; c++) {
  931.       putnormalchar(x[c],y,message[ chara[c] ]);
  932.       
  933.       //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
  934.       for (byte yy = 0 ; yy < 8; yy ++) {
  935.         plot(x[c] + 5, yy, 0);
  936.       }
  937.       //take one off each chars position
  938.       x[c] = x[c] - 1;
  939.     }
  940.     //reset a char if it's gone off screen
  941.     for (byte i = 0; i <= 5; i++) {
  942.       if (x[i] < -5 ) {
  943.         x[i] = 31;
  944.         chara[i] = p;
  945.         p++;
  946.       }
  947.     }
  948.   }
  949. }
  950. //display_date - print the day of week, date and month with a flashing cursor effect
  951. void display_date()
  952. {
  953.   cls();
  954.   //read the date from the DS1307
  955.   byte dow = rtc[3]; // day of week 0 = Sunday
  956.   byte date = rtc[4];
  957.   byte month = rtc[5] - 1;
  958.   //array of month names to print on the display. Some are shortened as we only have 8 characters across to play with
  959.   char monthnames[12][9] = {
  960.     "January", "February", "March", "April", "May", "June", "July", "August", "Sept", "October", "November", "December"
  961.   };
  962.   //print the day name
  963.   
  964.   //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
  965.   byte len = 0;
  966.   while(daysfull[dow][len]) {
  967.     len++;
  968.   };
  969.   byte offset = (31 - ((len-1)*4)) / 2; //our offset to centre up the text
  970.       
  971.   //print the name     
  972.   int i = 0;
  973.   while(daysfull[dow][i])
  974.   {
  975.     puttinychar((i*4) + offset , 1, daysfull[dow][i]);
  976.     i++;
  977.   }
  978.   delay(1000);
  979.   fade_down();
  980.   cls();
  981.   
  982.   // print date numerals
  983.   char buffer[3];
  984.   itoa(date,buffer,10);
  985.   offset = 10; //offset to centre text if 3 chars - e.g. 3rd
  986.   
  987.   // first work out date 2 letter suffix - eg st, nd, rd, th etc
  988.   // char suffix[4][3]={"st", "nd", "rd", "th"  }; is defined at top of code
  989.   byte s = 3;
  990.   if(date == 1 || date == 21 || date == 31) {
  991.     s = 0;
  992.   }
  993.   else if (date == 2 || date == 22) {
  994.     s = 1;
  995.   }
  996.   else if (date == 3 || date == 23) {
  997.     s = 2;
  998.   }
  999.   //print the 1st date number
  1000.   puttinychar(0+offset, 1, buffer[0]);
  1001.   //if date is under 10 - then we only have 1 digit so set positions of sufix etc one character nearer
  1002.   byte suffixposx = 4;
  1003.   //if date over 9 then print second number and set xpos of suffix to be 1 char further away
  1004.   if (date > 9){
  1005.     suffixposx = 8;
  1006.     puttinychar(4+offset, 1, buffer[1]);
  1007.     offset = 8; //offset to centre text if 4 chars
  1008.   }
  1009.   //print the 2 suffix characters
  1010.   puttinychar(suffixposx+offset, 1, suffix[s][0]);
  1011.   puttinychar(suffixposx+4+offset, 1, suffix[s][1]);
  1012.   delay(1000);
  1013.   fade_down();
  1014.   
  1015.   //print the month name
  1016.   
  1017.   //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
  1018.   len = 0;
  1019.   while(monthnames[month][len]) {
  1020.     len++;
  1021.   };
  1022.   offset = (31 - ((len-1)*4)) / 2; //our offset to centre up the text
  1023.   i = 0;
  1024.   while(monthnames[month][i])
  1025.   {  
  1026.     puttinychar((i*4) +offset, 1, monthnames[month][i]);
  1027.     i++;
  1028.   }
  1029.   
  1030.   delay(1000);
  1031.   fade_down();
  1032. }
  1033. //dislpay menu to change the clock mode
  1034. void switch_mode() {
  1035.   //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.
  1036.   old_mode = clock_mode;
  1037.   char* modes[] = {
  1038.     "Basic", "Small", "Slide", "Words", "Setup"
  1039.   };
  1040.   byte next_clock_mode;
  1041.   byte firstrun = 1;
  1042.   //loop waiting for button (timeout after 35 loops to return to mode X)
  1043.   for (int count = 0; count < 35 ; count++) {
  1044.     //if user hits button, change the clock_mode
  1045.     if (buttonA.uniquePress() || firstrun == 1) {
  1046.       count = 0;
  1047.       cls();
  1048.       if (firstrun == 0) {
  1049.         clock_mode++;
  1050.       }
  1051.       if (clock_mode > NUM_DISPLAY_MODES + 1 ) {
  1052.         clock_mode = 0;
  1053.       }
  1054.       //print arrown and current clock_mode name on line one and print next clock_mode name on line two
  1055.       char str_top[9];
  1056.       //strcpy (str_top, "-");
  1057.       strcpy (str_top, modes[clock_mode]);
  1058.       next_clock_mode = clock_mode + 1;
  1059.       if (next_clock_mode >  NUM_DISPLAY_MODES + 1 ) {
  1060.         next_clock_mode = 0;
  1061.       }
  1062.       byte i = 0;
  1063.       while (str_top[i]) {
  1064.         putnormalchar(i * 6, 0, str_top[i]);
  1065.         i++;
  1066.       }
  1067.       firstrun = 0;
  1068.     }
  1069.     delay(50);
  1070.   }
  1071. }
  1072. //run clock main loop as long as run_mode returns true
  1073. byte run_mode() {
  1074.   //if random mode is on... check the hour when we change mode.
  1075.   if (random_mode) {
  1076.     //if hour value in change mode time = hours. then reurn false = i.e. exit mode.
  1077.     if (change_mode_time == rtc[2]) {
  1078.       //set the next random clock mode and time to change it
  1079.       set_next_random();
  1080.       //exit the current mode.
  1081.       return 0;
  1082.     }
  1083.   }
  1084.   //else return 1 - keep running in this mode
  1085.   return 1;
  1086. }
  1087. //set the next hour the clock will change mode when random mode is on
  1088. void set_next_random() {
  1089.   //set the next hour the clock mode will change - current time plus 1 - 4 hours
  1090.   get_time();
  1091.   change_mode_time = rtc[2] + random (1, 5);
  1092.   //if change_mode_time now happens to be over 23, then set it to between 1 and 3am
  1093.   if (change_mode_time > 23) {
  1094.     change_mode_time = random (1, 4);
  1095.   }
  1096.   //set the new clock mode
  1097.   clock_mode = random(0, NUM_DISPLAY_MODES + 1);  //pick new random clock mode
  1098. }
  1099. //dislpay menu to change the clock settings
  1100. void setup_menu() {
  1101.   char* set_modes[] = {
  1102.      "Rndom", "24 Hr","Set", "Brght", "Exit"};
  1103.   if (ampm == 0) {
  1104.     set_modes[1] = ("12 Hr");
  1105.   }
  1106.   byte setting_mode = 0;
  1107.   byte next_setting_mode;
  1108.   byte firstrun = 1;
  1109.   //loop waiting for button (timeout after 35 loops to return to mode X)
  1110.   for(int count=0; count < 35 ; count++) {
  1111.     //if user hits button, change the clock_mode
  1112.     if(buttonA.uniquePress() || firstrun == 1){
  1113.       count = 0;
  1114.       cls();
  1115.       if (firstrun == 0) {
  1116.         setting_mode++;
  1117.       }
  1118.       if (setting_mode > NUM_SETTINGS_MODES) {
  1119.         setting_mode = 0;
  1120.       }
  1121.       //print arrown and current clock_mode name on line one and print next clock_mode name on line two
  1122.       char str_top[9];
  1123.    
  1124.       strcpy (str_top, set_modes[setting_mode]);
  1125.       next_setting_mode = setting_mode + 1;
  1126.       if (next_setting_mode > NUM_SETTINGS_MODES) {
  1127.         next_setting_mode = 0;
  1128.       }
  1129.       
  1130.       byte i = 0;
  1131.       while(str_top[i]) {
  1132.         putnormalchar(i*6, 0, str_top[i]);
  1133.         i++;
  1134.       }
  1135.       firstrun = 0;
  1136.     }
  1137.     delay(50);
  1138.   }
  1139.   
  1140.   //pick the mode
  1141.   switch(setting_mode){
  1142.     case 0:
  1143.       set_random();
  1144.       break;
  1145.     case 1:
  1146.        set_ampm();
  1147.       break;
  1148.     case 2:
  1149.       set_time();
  1150.       break;
  1151.     case 3:
  1152.        set_intensity();
  1153.       break;
  1154.     case 4:
  1155.       //exit menu
  1156.       break;
  1157.   }
  1158.    
  1159.   //change the clock from mode 6 (settings) back to the one it was in before
  1160.   clock_mode=old_mode;
  1161. }
  1162. //toggle random mode - pick a different clock mode every few hours
  1163. void set_random(){
  1164.   cls();
  1165.   char text_a[9] = "Off";
  1166.   char text_b[9] = "On";
  1167.   byte i = 0;
  1168.   //if random mode is on, turn it off
  1169.   if (random_mode){
  1170.     //turn random mode off
  1171.     random_mode = 0;
  1172.     //print a message on the display
  1173.     while(text_a[i]) {
  1174.       putnormalchar((i*6), 0, text_a[i]);
  1175.       i++;
  1176.     }
  1177.   } else {
  1178.     //turn randome mode on.
  1179.     random_mode = 1;
  1180.    
  1181.     //set hour mode will change
  1182.     set_next_random();
  1183.   
  1184.     //print a message on the display
  1185.     while(text_b[i]) {
  1186.       putnormalchar((i*6), 0, text_b[i]);
  1187.       i++;
  1188.     }  
  1189.   }
  1190.   delay(1500); //leave the message up for a second or so
  1191. }
  1192. //set 12 or 24 hour clock
  1193. void set_ampm() {
  1194.   // AM/PM or 24 hour clock mode - flip the bit (makes 0 into 1, or 1 into 0 for ampm mode)
  1195.   ampm = (ampm ^ 1);
  1196.   cls();
  1197. }
  1198. //change screen intensityintensity
  1199. void set_intensity() {
  1200.   cls();
  1201.   
  1202.   byte i = 0;
  1203.   char text[7] = "Bright";
  1204.   while(text[i]) {
  1205.     puttinychar((i*4)+4, 0, text[i]);
  1206.     i++;
  1207.   }
  1208.   //wait for button input
  1209.   while (!buttonA.uniquePress()) {
  1210.     levelbar (0,6,(intensity*2)+2,2);    //display the intensity level as a bar
  1211.     while (buttonB.isPressed()) {
  1212.       if(intensity == 15) {
  1213.         intensity = 0;
  1214.         cls ();
  1215.       }
  1216.       else {
  1217.         intensity++;
  1218.       }
  1219.       //print the new value
  1220.       i = 0;
  1221.       while(text[i]) {
  1222.         puttinychar((i*4)+4, 0, text[i]);
  1223.         i++;
  1224.       }
  1225.       
  1226.       //display the intensity level as a bar
  1227.       levelbar (0,6,(intensity*2)+2,2);   
  1228.       
  1229.       //change the brightness setting on the displays
  1230.       for (byte address = 0; address < 4; address++) {
  1231.         lc.setIntensity(address, intensity);
  1232.       }
  1233.       delay(150);
  1234.     }
  1235.   }
  1236. }
  1237. // display a horizontal bar on the screen at offset xposr by ypos with height and width of xbar, ybar
  1238. void levelbar (byte xpos, byte ypos, byte xbar, byte ybar) {
  1239.   for (byte x = 0; x < xbar; x++) {
  1240.     for (byte y = 0; y <= ybar; y++) {
  1241.       plot(x+xpos, y+ypos, 1);
  1242.     }
  1243.   }
  1244. }
  1245. //set time and date routine
  1246. void set_time() {
  1247.   cls();
  1248.   //fill settings with current clock values read from clock
  1249.   get_time();
  1250.   byte set_min   = rtc[1];
  1251.   byte set_hr    = rtc[2];
  1252.   byte set_date  = rtc[4];
  1253.   byte set_mnth  = rtc[5];
  1254.   int  set_yr    = rtc[6];
  1255.   //Set function - we pass in: which 'set' message to show at top, current value, reset value, and rollover limit.
  1256.   set_date = set_value(2, set_date, 1, 31);
  1257.   set_mnth = set_value(3, set_mnth, 1, 12);
  1258.   set_yr   = set_value(4, set_yr, 2013, 2099);
  1259.   set_hr   = set_value(1, set_hr, 0, 23);
  1260.   set_min  = set_value(0, set_min, 0, 59);
  1261.   ds1307.adjust(DateTime(set_yr, set_mnth, set_date, set_hr, set_min));
  1262.   
  1263.   cls();
  1264. }
  1265. //used to set min, hr, date, month, year values. pass
  1266. //message = which 'set' message to print,
  1267. //current value = current value of property we are setting
  1268. //reset_value = what to reset value to if to rolls over. E.g. mins roll from 60 to 0, months from 12 to 1
  1269. //rollover limit = when value rolls over
  1270. int set_value(byte message, int current_value, int reset_value, int rollover_limit){
  1271.   cls();
  1272.   char messages[6][17]   = {
  1273.     "Set Mins", "Set Hour", "Set Day", "Set Mnth", "Set Year"};
  1274.   //Print "set xyz" top line
  1275.   byte i = 0;
  1276.   while(messages[message][i])
  1277.   {
  1278.     puttinychar(i*4 , 1, messages[message][i]);
  1279.     i++;
  1280.   }
  1281.   delay(2000);
  1282.   cls();
  1283.   //print digits bottom line
  1284.   char buffer[5] = "    ";
  1285.   itoa(current_value,buffer,10);
  1286.   puttinychar(0 , 1, buffer[0]);
  1287.   puttinychar(4 , 1, buffer[1]);
  1288.   puttinychar(8 , 1, buffer[2]);
  1289.   puttinychar(12, 1, buffer[3]);
  1290.   delay(300);
  1291.   //wait for button input
  1292.   while (!buttonA.uniquePress()) {
  1293.     while (buttonB.isPressed()){
  1294.       if(current_value < rollover_limit) {
  1295.         current_value++;
  1296.       }
  1297.       else {
  1298.         current_value = reset_value;
  1299.       }
  1300.       //print the new value
  1301.       itoa(current_value, buffer ,10);
  1302.       puttinychar(0 , 1, buffer[0]);
  1303.       puttinychar(4 , 1, buffer[1]);
  1304.       puttinychar(8 , 1, buffer[2]);
  1305.       puttinychar(12, 1, buffer[3]);   
  1306.       delay(150);
  1307.     }
  1308.   }
  1309.   return current_value;
  1310. }
  1311. void get_time()
  1312. {
  1313.   //get time
  1314.   DateTime now = ds1307.now();
  1315.   //save time to array
  1316.   rtc[6] = now.year();
  1317.   rtc[5] = now.month();
  1318.   rtc[4] = now.day();
  1319.   rtc[3] = now.dayOfWeek(); //returns 0-6 where 0 = Sunday
  1320.   rtc[2] = now.hour();
  1321.   rtc[1] = now.minute();
  1322.   rtc[0] = now.second();
  1323.   //flash arduino led on pin 13 every second
  1324.   //if ( (rtc[0] % 2) == 0) {
  1325.   //  digitalWrite(13, HIGH);
  1326.   //}
  1327.   //else {
  1328.   //  digitalWrite(13, LOW);
  1329.   //}
  1330.   //print the time to the serial port - useful for debuging RTC issues
  1331.   /*
  1332.   Serial.print(rtc[2]);
  1333.   Serial.print(":");
  1334.   Serial.print(rtc[1]);
  1335.   Serial.print(":");
  1336.   Serial.println(rtc[0]);
  1337.   */
  1338. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 小时前

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟
项目链接:https://www.hackster.io/mircemk/mini-led-matrix-clock-d4f5f5
项目作者:北马其顿 米尔塞姆克(Mirko Pavleski)

项目视频 :https://www.youtube.com/watch?v=QSL-3XlccsM
项目代码:https://www.hackster.io/code_files/264103/download

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟图1

【Arduino 动手做】多功能 Mini LED 矩阵模块 32x8 时钟图2

回复

使用道具 举报

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

本版积分规则

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

硬件清单

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

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

mail