Advertisement
Sebuahhobi98

clock max7219

Apr 14th, 2019
299
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 54.53 KB | None | 0 0
  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/ (original source code)
  6. ////=========== has been modified. Tested with Arduino-IDE v1.8.4
  7. ////======================================================================================================////
  8. ////=========== JAM, TANGGAL DAN TERMOMETER DIGITAL TAMPILAN DOT MATRIK MAX7219.
  9. ////=========== MENGGUNAKAN ARDUINO UNO ATAU YANG LAIN JUGA BISA.
  10. ////=========== HASIL DARI COPAS SANA-SINI, COMOT SANA-SINI, COLEK SANA-SINI
  11. ////=========== KEMUDIAN DIMODIFIKASI DAN DIPOLES SEDIKIT.
  12. ////======================================================================================================////
  13. #include "LedControl.h"
  14. #include "FontLEDClock.h"                
  15. #include "Wire.h"                        
  16. #include "RTClib.h"                      
  17. #include "Button.h"                      
  18.  
  19. //Include libraries for Tempebacem
  20. #include <OneWire.h>
  21. #include <DallasTemperature.h>
  22. #define ONE_WIRE_BUS 12                    // Data wire is plugged into pin 12 on the Arduino
  23. OneWire oneWire(ONE_WIRE_BUS);            // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
  24. DallasTemperature sensors(&oneWire);      // Pass our oneWire reference to Dallas Temperature.
  25. DeviceAddress tempDeviceAddress;         // We'll use this variable to store a found device address
  26.  
  27. // pin 11 ke DIN Modul Dot Matrix MAX7219     // SDA ke pin A4   // Tombol ke pin 2
  28. // pin 13 ke CLK Modul Dot Matrix MAX7219     // SCL ke pin A5   // Tombol ke pin 3
  29. // pin 10 ke CS  Modul Dot Matrix MAX7219
  30. LedControl lc = LedControl(11, 13, 10, 4); //sets the 3 pins as 12, 11 & 10 and then sets 4 displays (max is 8 displays)
  31.  
  32. //global variables
  33. byte intensity = 5;                      // Kecerahan Display (0-15)
  34. byte clock_mode = 0;                     // Mode Dasar. Default = 0 (basic_mode)
  35. bool random_mode = 0;                    // Define random mode - changes the display type every few hours. Default = 0 (off)
  36. 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.
  37. bool ampm = 0;                           // Define 12 or 24 hour time. 0 = 24 hour. 1 = 12 hour
  38. byte change_mode_time = 0;               // Holds hour when clock mode will next change if in random mode.
  39. unsigned long delaytime = 500;           // We always wait a bit between updates of the display
  40. int rtc[7];                              // Holds real time clock output
  41. char suhu[4];                            // Holds temperature-chars for displaying temp
  42. bool debug = true;                       // For debugging only, starts serial output (true/false)
  43. bool date_state = true;
  44.  
  45. char days[7][4] = {
  46.   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  47. }; //day array - used in slide, basic_mode and jumble modes (The DS1307 outputs 1-7 values for day of week)
  48. char daysfull[7][9] = {
  49.   "Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"
  50. };
  51.  
  52. //define constants
  53. #define NUM_DISPLAY_MODES 3              // Number display modes (conting zero as the first mode)
  54. #define NUM_SETTINGS_MODES 4             // Number settings modes = 6 (conting zero as the first mode)
  55. #define SLIDE_DELAY 20                   // The time in milliseconds for the slide effect per character in slide mode. Make this higher for a slower effect
  56. #define cls          clear_display       // Clear display
  57.  
  58. RTC_DS1307 ds1307;                              // Create RTC object
  59.  
  60. Button buttonA = Button(2, BUTTON_PULLUP);      // Setup button A (using button library)
  61. Button buttonB = Button(3, BUTTON_PULLUP);      // Setup button B (using button library)
  62.  
  63. void setup() {
  64.  
  65.   digitalWrite(2, HIGH);                 // turn on pullup resistor for button on pin 2
  66.   digitalWrite(3, HIGH);                 // turn on pullup resistor for button on pin 3
  67.   digitalWrite(4, HIGH);                 // turn on pullup resistor for button on pin 4
  68.    
  69.   Serial.begin(9600); //start serial
  70.   Serial.println("Arduino Digital Temperature // Serial Monitor Version"); //Print a message
  71.   sensors.begin();    //start sensor Ds18b20
  72.   sensors.getAddress(tempDeviceAddress, 0);                 // get the adress of the first DS18B20 Temp-Sensor
  73.   sensors.requestTemperaturesByAddress(tempDeviceAddress);  // sends command for one device to perform a temperature by address
  74.  
  75.   //initialize the 4 matrix panels
  76.   //we have already set the number of devices when we created the LedControl
  77.   int devices = lc.getDeviceCount();
  78.   //we have to init all devices in a loop
  79.   for (int address = 0; address < devices; address++) {
  80.   /*The MAX72XX is in power-saving mode on startup*/
  81.   lc.shutdown(address, false);
  82.   /* Set the brightness to a medium values */
  83.   lc.setIntensity(address, intensity);
  84.   /* and clear the display */
  85.   lc.clearDisplay(address);
  86.   }
  87.  
  88.   //Setup DS1307 RTC
  89.   #ifdef AVR
  90.   Wire.begin();
  91.   #else
  92.   Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino
  93.   #endif
  94.   ds1307.begin(); //start RTC Clock
  95.  
  96. /*
  97.   if (! ds1307.isrunning()) {
  98.     Serial.println("RTC is NOT running!");
  99.     ds1307.adjust(DateTime(__DATE__, __TIME__));  // sets the RTC to the date & time this sketch was compiled
  100.   }
  101. */
  102.   //Show Intro
  103.   //printver();
  104.    
  105.   //enable red led
  106.   digitalWrite(13, HIGH);
  107. }
  108.  
  109. void loop() {
  110.   basic_mode();
  111.   /*
  112.   //run the clock with whatever mode is set by clock_mode - the default is set at top of code.
  113.   switch (clock_mode){
  114.          
  115.   case 0:  
  116.     basic_mode();
  117.     break;  
  118.   case 1:  
  119.    small_mode();  
  120.     break;
  121.   case 2:  
  122.     slide();  
  123.     break;
  124.   case 3:  
  125.     word_clock();  
  126.     break;
  127.   case 4:  
  128.     setup_menu();  
  129.     break;
  130.   } /**/
  131. }  
  132.  
  133. //plot a point on the display
  134. void plot (byte x, byte y, byte val) {
  135.  
  136.   //select which matrix depending on the x coordinate
  137.   byte address;
  138.   if (x >= 0 && x <= 7)   {
  139.     address = 0;
  140.   }
  141.   if (x >= 8 && x <= 15)  {
  142.     address = 1;
  143.     x = x - 8;
  144.   }
  145.   if (x >= 16 && x <= 23) {
  146.     address = 2;
  147.     x = x - 16;
  148.   }
  149.   if (x >= 24 && x <= 31) {
  150.     address = 3;
  151.     x = x - 24;
  152.   }
  153.  
  154.   if (val == 1) {
  155.     lc.setLed(address, y, x, true);
  156.   } else {
  157.     lc.setLed(address, y, x, false);
  158.   }
  159. }
  160.  
  161. //clear screen
  162. void clear_display() {
  163.   for (byte address = 0; address < 4; address++) {
  164.     lc.clearDisplay(address);
  165.   }
  166. }
  167.  
  168. ///////////////////////////////display Temperatura ds18b20/////////////////////////////////////////
  169. void display_temperatur() {
  170.   cls();
  171.   measure_Temp(); //get the temp-values from the DS18B20-sensor  
  172.   char tempC[6];
  173.   tempC[0]=suhu[0];
  174.   tempC[1]=suhu[1];
  175.   tempC[2]=suhu[2];
  176.   tempC[3]=suhu[3];
  177. //tempC[4]= '?';   //dijadikan simbol derajat (degree-symbol) jika menggunakan font kecil
  178.   tempC[4]= 'Z';   //dijadikan simbol derajat (degree-symbol) jika menggunakan font Gedhe
  179.   tempC[5]= 'C';
  180.  
  181.   int date_delay = 80;  // delay between displaying next character
  182.  
  183. /*  
  184.   // print penempatan angka tempebacem menggunakan font kecil
  185.   byte offset = 6;      
  186.   puttinychar(0+offset, 1, tempC[0]);   //print the 1st temp number (10 degrees)
  187.   delay(date_delay);
  188.   puttinychar(4+offset, 1, tempC[1]);   //print the 2nd temp number (1 degrees)
  189.   delay(date_delay);
  190.   puttinychar(8+offset, 1, tempC[2]);   //print the 3rd temp number (.)
  191.   delay(date_delay);
  192.   puttinychar(10+offset, 1, tempC[3]);  //print the 4th temp number (first decimal place)
  193.   delay(date_delay);
  194.   puttinychar(14+offset, 1, tempC[4]);  //print degree-symbol
  195.   delay(date_delay);
  196.   puttinychar(18+offset, 1, tempC[5]);  //print the 6th temp number C(elsius)
  197.   delay(3000);  
  198. */
  199.    // print penempatan angka tempegoreng menggunakan font GEDHE
  200.   byte offset = 1;      
  201.   putnormalchar(0+offset, 0, tempC[0]);   //print the 1st temp number (10 degrees)
  202.   delay(date_delay);
  203.   putnormalchar(6+offset, 0, tempC[1]);   //print the 2nd temp number (1 degrees)
  204.   delay(date_delay);
  205.   putnormalchar(12+offset, 0, tempC[2]);   //print the 3rd temp number (.)
  206.   delay(date_delay);
  207.   putnormalchar(15+offset, 0, tempC[3]);  //print the 4th temp number (first decimal place)
  208.   delay(date_delay);
  209.   putnormalchar(21+offset, 0, tempC[4]);  //print the 5th degree-symbol
  210.   delay(date_delay);
  211.   putnormalchar(26+offset, 0, tempC[5]);  //print the 6th C(celsius)
  212.   delay(3000);  //lama tampilnya suhu sekitar 3 detik
  213. }
  214.  
  215. //Measure Temperature from DS18B20
  216. char measure_Temp(){
  217.  
  218.   sensors.requestTemperaturesByAddress(tempDeviceAddress);  // sends command for one device to perform a temperature by address
  219.   float TempC = sensors.getTempC(tempDeviceAddress);  
  220.   String stringTempC = "";           //data in buffer is copied to this string  
  221.   dtostrf(TempC, 4, 1, suhu);       //4 is mininum width, 1 is precision; float value is copied to buffer
  222.  
  223.       if (debug){
  224.         Serial.println("");
  225.         Serial.print("Temperatur: ");
  226.         Serial.println(sensors.getTempC(tempDeviceAddress)); // the first temp-sensor on I2C
  227.         Serial.print("          suhu[0]: ");
  228.         Serial.println(suhu[0]);
  229.         Serial.print("          suhu[1]: ");
  230.         Serial.println(suhu[1]);
  231.         Serial.print("          suhu[2]: ");
  232.         Serial.println(suhu[2]);
  233.         Serial.print("          suhu[3]: ");
  234.         Serial.println(suhu[3]);
  235.         Serial.println("");        
  236.       }
  237.    return  suhu[0], suhu[1], suhu[2], suhu[3];  
  238. }
  239. //  End of measure temperature
  240. ///////////////////////////////////////////////////////////////
  241. //fade screen down
  242. void fade_down() {
  243.  
  244.   //fade from global intensity to 1
  245.   for (byte i = intensity; i > 0; i--) {
  246.     for (byte address = 0; address < 4; address++) {
  247.       lc.setIntensity(address, i);
  248.     }
  249.     delay(50); //change this to change fade down speed
  250.   }
  251.  
  252.   clear_display(); //clear display completely (off)
  253.  
  254.   //reset intentsity to global val
  255.   for (byte address = 0; address < 4; address++) {
  256.     lc.setIntensity(address, intensity);
  257.   }
  258. }
  259.  
  260. //power up led test & display Intro
  261. void printver() {
  262.  
  263.   byte i = 0;
  264.   char ver_a[9] = "   Jam  ";
  265.   char ver_b[9] = " Digital";
  266.   char ver_c[9] = " Prolinx";
  267.  
  268.   //test all leds.
  269.   for (byte x = 0; x <= 31; x++) {
  270.     for (byte y = 0; y <= 7; y++) {
  271.       plot(x, y, 1);
  272.     }
  273.   }
  274.   delay(500);
  275.   fade_down();
  276.  
  277.   while (ver_a[i]) {
  278.     puttinychar((i * 4), 1, ver_a[i]);
  279.     delay(35);
  280.     i++;
  281.   }
  282.   delay(700);
  283.   fade_down();
  284.   i = 0;
  285.   while (ver_b[i]) {
  286.     puttinychar((i * 4), 1, ver_b[i]);
  287.     delay(35);
  288.     i++;
  289.   }
  290.   delay(700);
  291.   fade_down();
  292.   i = 0;
  293.   while (ver_c[i]) {
  294.     puttinychar((i * 4), 1, ver_c[i]);
  295.     delay(35);
  296.     i++;
  297.   }
  298.   delay(700);
  299.   fade_down();  
  300. }
  301.  
  302.  
  303. // puttinychar
  304. // Copy a 3x5 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate
  305. // This is unoptimized and simply uses plot() to draw each dot.
  306. void puttinychar(byte x, byte y, char c)
  307. {
  308.   byte dots;
  309.   if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) {
  310.     c &= 0x1F;   // A-Z maps to 1-26  dirubah jadi 7F semula 1F
  311.   }
  312.   else if (c >= '0' && c <= '9') {
  313.     c = (c - '0') + 32;   // dirubah jadi 33 semula 32
  314.   }
  315.   else if (c == ' ') {
  316.     c = 0; // space
  317.   }
  318.   else if (c == '.') {
  319.     c = 27; // full stop
  320.   }
  321.   else if (c == ':') {
  322.     c = 28; // colon
  323.   }
  324.   else if (c == '\'') {
  325.     c = 29; // single quote mark
  326.   }
  327.   else if (c == '!') {
  328.     c = 30; // single quote mark
  329.   }
  330.   else if (c == '?') {
  331.     c = 31; // single quote mark
  332.   }
  333.  
  334.   for (byte col = 0; col < 3; col++) {
  335.     dots = pgm_read_byte_near(&mytinyfont[c][col]);
  336.     for (char row = 0; row < 5; row++) {    // dirubah jadi row < 7 semula < 5 hanya 7 baris
  337.       if (dots & (16 >> row))               // dirubah jadi 64 semula 16
  338.         plot(x + col, y + row, 1);
  339.       else
  340.         plot(x + col, y + row, 0);
  341.     }
  342.   }
  343. }  
  344.  
  345. void putnormalchar(byte x, byte y, char c)
  346. {
  347.   byte dots;
  348.   //  if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) {
  349.   //    c &= 0x1F;   // A-Z maps to 1-26
  350.   //  }
  351.   if (c >= 'A' && c <= 'Z' ) {
  352.     c &= 0x1F;   // A-Z maps to 1-26
  353.   }
  354.   else if (c >= 'a' && c <= 'z') {
  355.     c = (c - 'a') + 41;   // A-Z maps to 41-67
  356.   }
  357.   else if (c >= '0' && c <= '9') {
  358.     c = (c - '0') + 31;
  359.   }
  360.   else if (c == ' ') {
  361.     c = 0; // space
  362.   }
  363.   else if (c == '.') {
  364.     c = 27; // full stop
  365.   }
  366.   else if (c == '\'') {
  367.     c = 28; // single quote mark
  368.   }
  369.   else if (c == ':') {
  370.     c = 29; // clock_mode selector arrow
  371.   }
  372.   else if (c == '>') {
  373.     c = 30; // clock_mode selector arrow
  374.   }
  375.   else if (c >= -80 && c <= -67) {
  376.     c *= -1;
  377.   }
  378.  
  379.   for (char col = 0; col < 5; col++) {
  380.     dots = pgm_read_byte_near(&myfont[c][col]);
  381.     for (char row = 0; row < 7; row++) {
  382.       //check coords are on screen before trying to plot
  383.       //if ((x >= 0) && (x <= 31) && (y >= 0) && (y <= 7)){
  384.  
  385.       if (dots & (64 >> row)) {   // only 7 rows.
  386.         plot(x + col, y + row, 1);
  387.       } else {
  388.         plot(x + col, y + row, 0);
  389.       }
  390.       //}
  391.     }
  392.   }
  393. }
  394.  
  395. //small_mode
  396. //show the time in small 3x5 characters with seconds display
  397.  
  398. void small_mode() {
  399.  
  400.   char textchar[8]; // the 16 characters on the display
  401.   byte mins = 100; //mins
  402.   byte secs = rtc[0]; //seconds
  403.   byte old_secs = secs; //holds old seconds value - from last time seconds were updated o display - used to check if seconds have changed
  404.    
  405.   cls();
  406.  
  407.   //run clock main loop as long as run_mode returns true
  408.   while (run_mode()) {
  409.     get_time();
  410.    
  411.     //check for button press
  412.     if (buttonA.uniquePress()) {switch_mode(); return; }
  413.     if (buttonB.uniquePress()) {display_date(); display_temperatur(); return;}
  414.    
  415.     //if secs changed then update them on the display
  416.     secs = rtc[0];
  417.     if (secs != old_secs) {
  418.  
  419.       bottomleds(secs); // plot seconds-dots at bottomline
  420.      
  421.       // display date and temperature every second is 40 and date state is true
  422.       if(rtc[0]==40  && date_state){
  423.       display_date();
  424.       display_temperatur();
  425.       return;    
  426.       }
  427.      
  428.       //secs
  429.       char buffer[3];
  430.       itoa(secs, buffer, 10);
  431.  
  432.       //fix - as otherwise if num has leading zero, e.g. "03" secs, itoa coverts this to chars with space "3 ".
  433.       if (secs < 10) {
  434.         buffer[1] = buffer[0];
  435.         buffer[0] = '0';
  436.       }
  437.  
  438.       puttinychar( 20, 1, ':'); //seconds colon ijo
  439.       puttinychar( 24, 1, buffer[0]); //seconds
  440.       puttinychar( 28, 1, buffer[1]); //seconds
  441.       old_secs = secs;
  442.     }
  443.  
  444.     //if minute changes change time
  445.     if (mins != rtc[1]) {
  446.  
  447.       //reset these for comparison next time
  448.       mins = rtc[1];
  449.       byte hours = rtc[2];
  450.       if (hours > 12) {
  451.         hours = hours - ampm * 12;
  452.       }
  453.       if (hours < 1) {
  454.         hours = hours + ampm * 12;
  455.       }
  456.  
  457.  
  458.       //byte dow  = rtc[3]; // the DS1307 outputs 0 - 6 where 0 = Sunday0 - 6 where 0 = Sunday.
  459.       //byte date = rtc[4];
  460.  
  461.       //set characters
  462.       char buffer[3];
  463.       itoa(hours, buffer, 10);
  464.  
  465.       //fix - as otherwise if num has leading zero, e.g. "03" hours, itoa coverts this to chars with space "3 ".
  466.       if (hours < 10) {
  467.         buffer[1] = buffer[0];
  468.         //if we are in 12 hour mode blank the leading zero.
  469.         if (ampm) {
  470.           buffer[0] = ' ';
  471.         }
  472.         else {
  473.           buffer[0] = '0';
  474.         }
  475.       }
  476.       //set hours chars
  477.       textchar[0] = buffer[0];
  478.       textchar[1] = buffer[1];
  479.       textchar[2] = ':';
  480.  
  481.       itoa (mins, buffer, 10);
  482.       if (mins < 10) {
  483.         buffer[1] = buffer[0];
  484.         buffer[0] = '0';
  485.       }
  486.       //set mins characters
  487.       textchar[3] = buffer[0];
  488.       textchar[4] = buffer[1];
  489.  
  490.       //do seconds
  491.       textchar[5] = ':';
  492.       buffer[3];
  493.       secs = rtc[0];
  494.       itoa(secs, buffer, 10);
  495.  
  496.       //fix - as otherwise if num has leading zero, e.g. "03" secs, itoa coverts this to chars with space "3 ".
  497.       if (secs < 10) {
  498.         buffer[1] = buffer[0];
  499.         buffer[0] = '0';
  500.       }
  501.       //set seconds
  502.       textchar[6] = buffer[0];
  503.       textchar[7] = buffer[1];
  504.  
  505.       byte x = 0;
  506.       byte y = 0;
  507.  
  508.       //print each char
  509.       for (byte x = 0; x < 6 ; x++) {
  510.         puttinychar( x * 4, 1, textchar[x]);
  511.       }
  512.     }
  513.     delay(50);
  514.   }
  515.   fade_down();
  516. }
  517.  
  518.  
  519. // basic_mode()
  520. // show the time in 5x7 characters
  521. void basic_mode()
  522. {
  523.   cls();
  524.  
  525.   char buffer[3];   //for int to char conversion to turn rtc values into chars we can print on screen
  526.   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
  527.   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.
  528.   int date_delay = 80;  // delay between displaying next character
  529.  
  530.   //do 12/24 hour conversion if ampm set to 1
  531.   byte hours = rtc[2];
  532.  
  533.   if (hours > 12) {
  534.     hours = hours - ampm * 12;
  535.   }
  536.   if (hours < 1) {
  537.     hours = hours + ampm * 12;
  538.   }
  539.  
  540.   //do offset conversion
  541.   if (ampm && hours < 10) {
  542.     offset = 2;
  543.   }
  544.    
  545.   //set the next minute we show the date at
  546.   //set_next_date();
  547.    
  548.   // 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
  549.   byte secs = 100;
  550.   byte mins = 100;
  551.   int count = 0;
  552.    
  553.   //run clock main loop as long as run_mode returns true
  554.   while (run_mode()) {
  555.  
  556.     //get the time from the clock chip
  557.     get_time();
  558.      
  559.     //check for button press
  560.     if (buttonA.uniquePress()) {
  561.       switch_mode();
  562.       return;
  563.     }
  564.  
  565.     if (buttonB.uniquePress()) // ini yang asli sebelum diedit
  566.     {  
  567.       display_date();
  568.       display_temperatur();
  569.       return;
  570.     }
  571.        if (secs == 45)  //tampil tanggal dan tempebacem setiap 45 detik hanya pada basic mode
  572.        {
  573.         display_date();
  574.         display_temperatur();
  575.         return;
  576.        }
  577.  
  578.     //check whether it's time to automatically display the date
  579.     //check_show_date();
  580.  
  581.     //draw the flashing : as on if the secs have changed.
  582.     if (secs != rtc[0]) {
  583.  
  584.       //update secs with new value
  585.       secs = rtc[0];
  586.  
  587.       //draw :
  588.       plot (15 - offset, 2, 1); //top point
  589.       plot (15 - offset, 5, 1); //bottom point
  590.       count = 400;
  591.     }
  592.  
  593.     //if count has run out, turn off the :
  594.     if (count == 0) {
  595.       plot (15 - offset, 2, 0); //top point
  596.       plot (15 - offset, 5, 0); //bottom point
  597.     }
  598.     else {
  599.       count--;
  600.     }
  601.  
  602.     //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)
  603.     if (mins != rtc[1]) {
  604.  
  605.       //update mins and hours with the new values
  606.       mins = rtc[1];
  607.       hours = rtc[2];
  608.  
  609.       //adjust hours of ampm set to 12 hour mode
  610.       if (hours > 12) {
  611.         hours = hours - ampm * 12;
  612.       }
  613.       if (hours < 1) {
  614.         hours = hours + ampm * 12;
  615.       }
  616.  
  617.       itoa(hours, buffer, 10);
  618.  
  619.       //if hours < 10 the num e.g. "3" hours, itoa coverts this to chars with space "3 " which we dont want
  620.       if (hours < 10) {
  621.         buffer[1] = buffer[0];
  622.         buffer[0] = '0';
  623.       }
  624.  
  625.       //print hours
  626.       //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.
  627.       if (ampm && hours < 10) {
  628.         offset = 2;
  629.  
  630.         //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
  631.         if ((hours == 1 && mins == 0) ) {
  632.           cls();
  633.         }
  634.       }
  635.       else {
  636.         //else no offset and print hours tens digit
  637.         offset = 0;
  638.  
  639.         //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
  640.         if (hours == 10 && mins == 0) {
  641.           cls();
  642.         }
  643.  
  644.         putnormalchar(1,  0, buffer[0]);       delay(date_delay);
  645.       }
  646.       //print hours ones digit
  647.       putnormalchar(7 - offset, 0, buffer[1]); delay(date_delay);
  648.  
  649.       //print mins
  650.       //add leading zero if mins < 10
  651.       itoa (mins, buffer, 10);
  652.       if (mins < 10) {
  653.         buffer[1] = buffer[0];
  654.         buffer[0] = '0';
  655.       }
  656.       //print mins tens and ones digits
  657.       putnormalchar(19 - offset, 0, buffer[0]); delay(date_delay);
  658.       putnormalchar(25 - offset, 0, buffer[1]);
  659.     }
  660.   }
  661.   fade_down();
  662. }
  663.  
  664.  
  665. //like basic_mode but with slide effect
  666. void slide() {
  667.  
  668.   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
  669.   byte digits_new[4]; //new digits time will slide to reveal
  670.   byte digits_x_pos[4] = {25, 19, 7, 1}; //x pos for which to draw each digit at
  671.  
  672.   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
  673.   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
  674.  
  675.   //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.
  676.   //We sent them as A initially, which are used when the clocl enters the mode and no last chars are stored.
  677.   //char old_chars[6] = "AAAAA";
  678.  
  679.   //plot the clock colon on the display
  680.   cls();
  681.   putnormalchar( 13, 0, ':');
  682.  
  683.   byte old_secs = rtc[0]; //store seconds in old_secs. We compare secs and old secs. WHen they are different we redraw the display
  684.  
  685.   //run clock main loop as long as run_mode returns true
  686.   while (run_mode()) {
  687.  
  688.     get_time();
  689.     byte secs =rtc[0];
  690.    
  691.     // display date, when second=30 and date_state = true
  692.     if(rtc[0]==30 && date_state){
  693.      display_date();
  694.      display_temperatur();
  695.      return;    
  696.     }
  697.      
  698.     //check for button press
  699.     if (buttonA.uniquePress()) {
  700.       switch_mode();
  701.       return;
  702.     }
  703.       if (buttonB.uniquePress()) {
  704.       display_date();
  705.       display_temperatur();
  706.        return;
  707.     }
  708.  
  709.        
  710.     //if secs have changed then update the display
  711.     if (rtc[0] != old_secs) {
  712.       //kedap-kedip "::"
  713.       if(old_secs % 2 == 0){      
  714.         plot(14, 4, 1);
  715.         plot(14, 2, 1);      
  716.         plot(16, 4, 0);
  717.         plot(16, 2, 0);        
  718.       }
  719.       else {
  720.         plot(16, 4, 1);
  721.         plot(16, 2, 1);
  722.         plot(14, 4, 0);
  723.         plot(14, 2, 0);      
  724.       }
  725.       old_secs = rtc[0];
  726.  
  727.       //do 12/24 hour conversion if ampm set to 1
  728.       byte hours = rtc[2];
  729.       if (hours > 12) {
  730.         hours = hours - ampm * 12;
  731.       }
  732.       if (hours < 1) {
  733.         hours = hours + ampm * 12;
  734.       }
  735.  
  736.       //split all date and time into individual digits - stick in digits_new array
  737.  
  738.       //rtc[0] = secs                        //array pos and digit stored
  739.       //digits_new[0] = (rtc[0]%10);           //0 - secs ones
  740.       //digits_new[1] = ((rtc[0]/10)%10);      //1 - secs tens
  741.       //rtc[1] = mins
  742.       digits_new[0] = (rtc[1] % 10);         //2 - mins ones
  743.       digits_new[1] = ((rtc[1] / 10) % 10);  //3 - mins tens
  744.       //rtc[2] = hours
  745.       digits_new[2] = (hours % 10);         //4 - hour ones
  746.       digits_new[3] = ((hours / 10) % 10);  //5 - hour tens
  747.       //rtc[4] = date
  748.       //digits_new[6] = (rtc[4]%10);           //6 - date ones
  749.       //digits_new[7] = ((rtc[4]/10)%10);      //7 - date tens
  750.  
  751.       //draw initial screen of all chars. After this we just draw the changes.
  752.  
  753.       //compare digits 0 to 3 (mins and hours)
  754.       for (byte i = 0; i <= 3; i++) {
  755.         //see if digit has changed...
  756.         if (digits_old[i] != digits_new[i]) {
  757.  
  758.           //run 9 step animation sequence for each in turn
  759.           for (byte seq = 0; seq <= 8 ; seq++) {
  760.  
  761.             //convert digit to string
  762.             itoa(digits_old[i], old_char, 10);
  763.             itoa(digits_new[i], new_char, 10);
  764.  
  765.             //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
  766.             if (ampm && i == 3) {
  767.               if (digits_new[3] == 0) {
  768.                 new_char[0] = ' ';
  769.               }
  770.               if (digits_old[3] == 0) {
  771.                 old_char[0] = ' ';
  772.               }
  773.             }
  774.             //draw the animation frame for each digit
  775.             slideanim(digits_x_pos[i], 0, seq, old_char[0], new_char[0]);
  776.             delay(SLIDE_DELAY);
  777.           }
  778.         }
  779.       }
  780.  
  781.       /*
  782.       //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
  783.       if ((digits_old[6] != digits_new[6]) || (digits_old[7] != digits_new[7])) {
  784.         //change the day shown. Loop below goes through each of the 3 chars in turn e.g. "MON"
  785.         for (byte day_char = 0; day_char <=2 ; day_char++){
  786.           //run the anim sequence for each char
  787.           for (byte seq = 0; seq <=8 ; seq++){
  788.             //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
  789.             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
  790.             delay(SLIDE_DELAY);
  791.           }
  792.           //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.
  793.           old_chars[day_char] = days[rtc[3]][day_char];
  794.         }
  795.  
  796.         //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.)
  797.         for (byte i = 7; i >= 6; i--){
  798.           if (digits_old[i] != digits_new[i]) {
  799.             for (byte seq = 0; seq <=8 ; seq++){
  800.               itoa(digits_old[i],old_char,10);
  801.               itoa(digits_new[i],new_char,10);
  802.               slideanim(digits_x_pos[i],8,seq,old_char[0],new_char[0]);
  803.               delay(SLIDE_DELAY);
  804.             }
  805.           }
  806.         }
  807.  
  808.         //print the day suffix "nd" "rd" "th" etc. First work out date 2 letter suffix - eg st, nd, rd, th
  809.         byte s = 3; //the pos to read our suffix array from.
  810.         byte date = rtc[4];
  811.         if(date == 1 || date == 21 || date == 31) {
  812.           s = 0;
  813.         }
  814.         else if (date == 2 || date == 22) {
  815.           s = 1;
  816.         }
  817.         else if (date == 3 || date == 23) {
  818.           s = 2;
  819.         }
  820.  
  821.         for (byte suffix_char = 0; suffix_char <=1 ; suffix_char++){
  822.           for (byte seq = 0; seq <=8 ; seq++){
  823.             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
  824.             delay(SLIDE_DELAY);
  825.           }
  826.           //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.
  827.           old_chars[suffix_char+3] = suffix[s][suffix_char];
  828.         }
  829.       }//end do date line
  830.       */
  831.  
  832.  
  833.       //save digita array tol old for comparison next loop
  834.       for (byte i = 0; i <= 3; i++) {
  835.         digits_old[i] =  digits_new[i];
  836.       }
  837.     }//secs/oldsecs
  838.   }//while loop
  839.   fade_down();
  840. }
  841.  
  842.  
  843. //called by slide
  844. //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
  845. //inputs are are char x and y, animation frame sequence (0-7) and the current and new chars being drawn.
  846. void slideanim(byte x, byte y, byte sequence, char current_c, char new_c) {
  847.  
  848.   //  To slide one char off and another on we need 9 steps or frames in sequence...
  849.  
  850.   //  seq# 0123456 <-rows of the display
  851.   //   |   |||||||
  852.   //  seq0 0123456  START - all rows of the display 0-6 show the current characters rows 0-6
  853.   //  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
  854.   //  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
  855.   //  seq3 56 0123
  856.   //  seq4 456 012  half old / half new char
  857.   //  seq5 3456 01
  858.   //  seq6 23456 0
  859.   //  seq7 123456
  860.   //  seq8 0123456  END - all rows show the new char
  861.  
  862.   //from above we can see...
  863.   //currentchar runs 0-6 then 0-5 then 0-4 all the way to 0. starting Y position increases by 1 row each time.
  864.   //new char runs 6 then 5-6 then 4-6 then 3-6. starting Y position increases by 1 row each time.
  865.  
  866.   //if sequence number is below 7, we need to draw the current char
  867.   if (sequence < 7) {
  868.     byte dots;
  869.     // if (current_c >= 'A' &&  || (current_c >= 'a' && current_c <= 'z') ) {
  870.     //   current_c &= 0x1F;   // A-Z maps to 1-26
  871.     // }
  872.     if (current_c >= 'A' && current_c <= 'Z' ) {
  873.       current_c &= 0x1F;   // A-Z maps to 1-26
  874.     }
  875.     else if (current_c >= 'a' && current_c <= 'z') {
  876.       current_c = (current_c - 'a') + 41;   // A-Z maps to 41-67
  877.     }
  878.     else if (current_c >= '0' && current_c <= '9') {
  879.       current_c = (current_c - '0') + 31;
  880.     }
  881.     else if (current_c == ' ') {
  882.       current_c = 0; // space
  883.     }
  884.     else if (current_c == '.') {
  885.       current_c = 27; // full stop
  886.     }
  887.     else if (current_c == '\'') {
  888.       current_c = 28; // single quote mark
  889.     }
  890.     else if (current_c == ':') {
  891.       current_c = 29; //colon
  892.     }
  893.     else if (current_c == '>') {
  894.       current_c = 30; // clock_mode selector arrow
  895.     }
  896.  
  897.     byte curr_char_row_max = 7 - sequence; //the maximum number of rows to draw is 6 - sequence number
  898.     byte start_y = sequence; //y position to start at - is same as sequence number. We inc this each loop
  899.  
  900.     //plot each row up to row maximum (calculated from sequence number)
  901.     for (byte curr_char_row = 0; curr_char_row <= curr_char_row_max; curr_char_row++) {
  902.       for (byte col = 0; col < 5; col++) {
  903.         dots = pgm_read_byte_near(&myfont[current_c][col]);
  904.         if (dots & (64 >> curr_char_row))
  905.           plot(x + col, y + start_y, 1); //plot led on
  906.         else
  907.           plot(x + col, y + start_y, 0); //else plot led off
  908.       }
  909.       start_y++;//add one to y so we draw next row one down
  910.     }
  911.   }
  912.  
  913.   //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
  914.   if (sequence >= 1 && sequence <= 8) {
  915.     for (byte col = 0; col < 5; col++) {
  916.       plot(x + col, y + (sequence - 1), 0); //the y position to draw the line is equivalent to the sequence number - 1
  917.     }
  918.   }
  919.  
  920.  
  921.  
  922.   //if sequence is above 2, we also need to start drawing the new char
  923.   if (sequence >= 2) {
  924.  
  925.     //work out char
  926.     byte dots;
  927.     //if (new_c >= 'A' && new_c <= 'Z' || (new_c >= 'a' && new_c <= 'z') ) {
  928.     //  new_c &= 0x1F;   // A-Z maps to 1-26
  929.     //}
  930.     if (new_c >= 'A' && new_c <= 'Z' ) {
  931.       new_c &= 0x1F;   // A-Z maps to 1-26
  932.     }
  933.     else if (new_c >= 'a' && new_c <= 'z') {
  934.       new_c = (new_c - 'a') + 41;   // A-Z maps to 41-67
  935.     }
  936.     else if (new_c >= '0' && new_c <= '9') {
  937.       new_c = (new_c - '0') + 31;
  938.     }
  939.     else if (new_c == ' ') {
  940.       new_c = 0; // space
  941.     }
  942.     else if (new_c == '.') {
  943.       new_c = 27; // full stop
  944.     }
  945.     else if (new_c == '\'') {
  946.       new_c = 28; // single quote mark
  947.     }
  948.     else if (new_c == ':') {
  949.       new_c = 29; // clock_mode selector arrow
  950.     }
  951.     else if (new_c == '>') {
  952.       new_c = 30; // clock_mode selector arrow
  953.     }
  954.  
  955.     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
  956.     byte start_y = 0; //y position to start at - is same as sequence number. we inc it each row
  957.  
  958.     //plot each row up from row minimum (calculated by sequence number) up to 6
  959.     for (byte newcharrow = newcharrowmin; newcharrow <= 6; newcharrow++) {
  960.       for (byte col = 0; col < 5; col++) {
  961.         dots = pgm_read_byte_near(&myfont[new_c][col]);
  962.         if (dots & (64 >> newcharrow))
  963.           plot(x + col, y + start_y, 1); //plot led on
  964.         else
  965.           plot(x + col, y + start_y, 0); //else plot led off
  966.       }
  967.       start_y++;//add one to y so we draw next row one down
  968.     }
  969.   }
  970. }
  971.  
  972.  
  973.  
  974. //print a clock using words rather than numbers
  975. void word_clock() {
  976.  
  977.   cls();
  978.  
  979.   char numbers[19][10]   = {
  980.     "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
  981.     "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
  982.   };
  983.   char numberstens[5][7] = {
  984.     "ten", "twenty", "thirty", "forty", "fifty"
  985.   };
  986.    
  987.   //potentially 3 lines to display
  988.   char str_a[8];
  989.   char str_b[8];
  990.   char str_c[8];
  991.  
  992.   //byte hours_y, mins_y; //hours and mins and positions for hours and mins lines
  993.  
  994.   byte hours = rtc[2];
  995.   if (hours > 12) {
  996.     hours = hours - ampm * 12;
  997.   }
  998.   if (hours < 1) {
  999.     hours = hours + ampm * 12;
  1000.   }
  1001.  
  1002.   get_time(); //get the time from the clock chip
  1003.   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.
  1004.   byte mins;
  1005.  
  1006.   //run clock main loop as long as run_mode returns true
  1007.   while (run_mode()) {
  1008.      
  1009.     //check for button press
  1010.     if (buttonA.uniquePress()) {
  1011.       switch_mode();
  1012.       return;
  1013.     }
  1014.     if (buttonB.uniquePress()) {
  1015.       display_date();
  1016.       display_temperatur();  
  1017.     }
  1018.  
  1019.     get_time(); //get the time from the clock chip
  1020.     mins = rtc[1];  //get mins
  1021.  
  1022.  
  1023.     //if mins is different from old_mins - redraw display
  1024.     if (mins != old_mins) {
  1025.  
  1026.       //update old_mins with current mins value
  1027.       old_mins = mins;
  1028.  
  1029.       //reset these for comparison next time
  1030.       mins = rtc[1];
  1031.       hours = rtc[2];
  1032.  
  1033.       //make hours into 12 hour format
  1034.       if (hours > 12) {
  1035.         hours = hours - 12;
  1036.       }
  1037.       if (hours == 0) {
  1038.         hours = 12;
  1039.       }
  1040.  
  1041.       //split mins value up into two separate digits
  1042.       int minsdigit = rtc[1] % 10;
  1043.       byte minsdigitten = (rtc[1] / 10) % 10;
  1044.  
  1045.       //if mins <= 10 , then top line has to read "minsdigti past" and bottom line reads hours
  1046.       if (mins < 10) {
  1047.         strcpy (str_a, numbers[minsdigit - 1]);
  1048.         strcpy (str_b, "PAST");
  1049.         strcpy (str_c, numbers[hours - 1]);
  1050.       }
  1051.  
  1052.       //if mins = 10, cant use minsdigit as above, so soecial case to print 10 past /n hour.
  1053.       if (mins == 10) {
  1054.         strcpy (str_a, numbers[9]);
  1055.         strcpy (str_b, " PAST");
  1056.         strcpy (str_c, numbers[hours - 1]);
  1057.       }
  1058.  
  1059.       //if time is not on the hour - i.e. both mins digits are not zero,
  1060.       //then make first line read "hours" and 2 & 3rd lines read "minstens"  "mins" e.g. "three /n twenty /n one"
  1061.       else if (minsdigitten != 0 && minsdigit != 0  ) {
  1062.  
  1063.         strcpy (str_a, numbers[hours - 1]);
  1064.  
  1065.         //if mins is in the teens, use teens from the numbers array for the 2nd line, e.g. "fifteen"
  1066.         //if (mins >= 11 && mins <= 19) {
  1067.         if (mins <= 19) {
  1068.           strcpy (str_b, numbers[mins - 1]);
  1069.         }
  1070.         else {
  1071.           strcpy (str_b, numberstens[minsdigitten - 1]);
  1072.  
  1073.           strcpy (str_c, numbers[minsdigit - 1]);
  1074.         }
  1075.       }
  1076.       // if mins digit is zero, don't print it. read read "hours" "minstens" e.g. "three /n twenty"
  1077.       else if (minsdigitten != 0 && minsdigit == 0  ) {
  1078.         strcpy (str_a, numbers[hours - 1]);
  1079.         strcpy (str_b, numberstens[minsdigitten - 1]);
  1080.         strcpy (str_c, "");
  1081.       }
  1082.  
  1083.       //if both mins are zero, i.e. it is on the hour, the top line reads "hours" and bottom line reads "o'clock"
  1084.       else if (minsdigitten == 0 && minsdigit == 0  ) {
  1085.         strcpy (str_a, numbers[hours - 1]);
  1086.         strcpy (str_b, "O'CLOCK");
  1087.         strcpy (str_c, "");
  1088.       }
  1089.  
  1090.     }//end worknig out time
  1091.  
  1092.     //run in a loop
  1093.     //print line a "twelve"
  1094.     byte len = 0;
  1095.     while (str_a[len]) {
  1096.       len++;
  1097.     }; //get length of message
  1098.     byte offset_top = (31 - ((len - 1) * 4)) / 2; //
  1099.  
  1100.     //plot hours line
  1101.     byte i = 0;
  1102.     while (str_a[i]) {
  1103.       puttinychar((i * 4) + offset_top, 1, str_a[i]);
  1104.       i++;
  1105.     }
  1106.      
  1107.     //hold display but check for button presses
  1108.     int counter = 1000;
  1109.     while (counter > 0){
  1110.       //check for button press
  1111.       if (buttonA.uniquePress()) {
  1112.         switch_mode();
  1113.         return;
  1114.       }
  1115.       if (buttonB.uniquePress()) {
  1116.         display_date();
  1117.       }
  1118.     delay(1);
  1119.     counter--;
  1120.     }
  1121.     fade_down();
  1122.  
  1123.     //print line b
  1124.     len = 0;
  1125.     while (str_b[len]) {
  1126.       len++;
  1127.     }; //get length of message
  1128.     offset_top = (31 - ((len - 1) * 4)) / 2;  
  1129.  
  1130.     i = 0;
  1131.     while (str_b[i]) {
  1132.       puttinychar((i * 4) + offset_top, 1, str_b[i]);
  1133.       i++;
  1134.     }
  1135.  
  1136.     //hold display but check for button presses
  1137.     counter = 1000;
  1138.     while (counter > 0){
  1139.       if (buttonA.uniquePress()) {
  1140.         switch_mode();
  1141.         return;
  1142.       }
  1143.       if (buttonB.uniquePress()) {
  1144.         display_date();
  1145.       }
  1146.       delay(1);
  1147.       counter--;
  1148.     }
  1149.     fade_down();
  1150.  
  1151.     //print line c if there.
  1152.     len = 0;
  1153.     while (str_c[len]) {
  1154.       len++;
  1155.     }; //get length of message
  1156.     offset_top = (31 - ((len - 1) * 4)) / 2;  
  1157.  
  1158.     i = 0;
  1159.     while (str_c[i]) {
  1160.       puttinychar((i * 4) + offset_top, 1, str_c[i]);
  1161.       i++;
  1162.     }
  1163.     counter = 1000;
  1164.     while (counter > 0){
  1165.       //check for button press
  1166.       if (buttonA.uniquePress()) {
  1167.         switch_mode();
  1168.         return;
  1169.       }
  1170.       if (buttonB.uniquePress()) {
  1171.         display_date();
  1172.       }  
  1173.       delay(1);
  1174.       counter--;
  1175.     }
  1176.     fade_down();
  1177.      
  1178.      
  1179.     //hold display blank but check for button presses before starting again.
  1180.     counter = 1000;
  1181.     while (counter > 0){
  1182.        //check for button press
  1183.       if (buttonA.uniquePress()) {
  1184.         switch_mode();
  1185.         return;
  1186.       }
  1187.       if (buttonB.uniquePress()) {
  1188.         display_date();
  1189.       }  
  1190.       delay(1);
  1191.       counter--;
  1192.     }
  1193.   }
  1194.   fade_down();
  1195. }
  1196.  
  1197.  
  1198.  
  1199. /// scroll message - not used at present - too slow.
  1200. void scroll() {
  1201.  
  1202.   char message[] = {"Hello There "};
  1203.  
  1204.   cls();
  1205.   byte p = 6;      //current pos in string
  1206.   byte chara[] = {0, 1, 2, 3, 4, 5}; //chars from string
  1207.   int x[] = {0, 6, 12, 18, 24, 30}; //xpos for each char
  1208.   byte y = 0;                   //y pos
  1209.  
  1210.   // clear_buffer();
  1211.  
  1212.   while (message[p] != '\0') {
  1213.  
  1214.     //draw all 6 chars
  1215.     for (byte c = 0; c < 6; c++) {
  1216.  
  1217.       putnormalchar(x[c],y,message[ chara[c] ]);
  1218.        
  1219.  
  1220.       //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
  1221.       for (byte yy = 0 ; yy < 8; yy ++) {
  1222.         plot(x[c] + 5, yy, 0);
  1223.       }
  1224.  
  1225.       //take one off each chars position
  1226.       x[c] = x[c] - 1;
  1227.     }
  1228.  
  1229.     //reset a char if it's gone off screen
  1230.     for (byte i = 0; i <= 5; i++) {
  1231.       if (x[i] < -5 ) {
  1232.         x[i] = 31;
  1233.         chara[i] = p;
  1234.         p++;
  1235.       }
  1236.     }
  1237.   }
  1238. }
  1239.  
  1240. //display_date - print the day of week, date and month with a flashing cursor effect
  1241. void display_date()
  1242. {
  1243.   cls();
  1244.   //read the date from the DS1307
  1245.   byte dow = rtc[3]; // day of week 0 = Sunday
  1246.   byte date = rtc[4];
  1247.   byte month = rtc[5] - 1;
  1248.   byte year = rtc[6] - 2000;  
  1249.   int date_delay = 80;  // delay between displaying next character
  1250.  
  1251.   //array of month names to print on the display. Some are shortened as we only have 8 characters across to play with
  1252.   char monthnames[12][9] = {
  1253.     "Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "Septmber", "Oktober", "November", "Desember"
  1254.   };
  1255.  
  1256.   //print the day name
  1257.    
  1258.   //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
  1259.   byte len = 0;
  1260.   while(daysfull[dow][len]) {  
  1261.     len++;  
  1262.   };  
  1263.   byte offset = (31 - ((len-1)*4)) / 2; //our offset to centre up the text
  1264.        
  1265.   //print the name      
  1266.   int i = 0;
  1267.   while(daysfull[dow][i]) {
  1268.     puttinychar((i*4) + offset , 1, daysfull[dow][i]);  
  1269.     i++;
  1270.     delay(date_delay);
  1271.   }
  1272.   delay(1500);
  1273.   fade_down();
  1274.   cls();
  1275.  
  1276.   // print date numerals
  1277.   char buffer[3];
  1278.   itoa(date,buffer,10);
  1279.   offset = 10;          //offset to centre text if 3 chars - e.g. 3rd
  1280.   /*********************
  1281.   // first work out date 2 letter suffix - eg st, nd, rd, th etc
  1282.   // char suffix[4][3]={"st", "nd", "rd", "th"  }; is defined at top of code
  1283.   byte s = 3;  
  1284.  
  1285.   if(date == 1 || date == 21 || date == 31) {
  1286.     s = 0;
  1287.   }  
  1288.   else if (date == 2 || date == 22) {
  1289.     s = 1;
  1290.   }  
  1291.   else if (date == 3 || date == 23) {
  1292.     s = 2;
  1293.   }  
  1294.   *******************/
  1295.   char teks[3];
  1296.   teks[0]='T';
  1297.   teks[1]='G';
  1298.   teks[2]='L';
  1299.   puttinychar(offset-8, 1, teks[0]);
  1300.   delay(date_delay);
  1301.   puttinychar(offset-4, 1, teks[1]);
  1302.   delay(date_delay);
  1303.   puttinychar(offset-0, 1, teks[2]);
  1304.   delay(date_delay);
  1305.  
  1306.   //print the 1st and 2nd date number
  1307.   puttinychar(10+offset, 1, buffer[0]); // tanggal font kecil puluhan
  1308.   delay(date_delay);
  1309.   puttinychar(14+offset, 1, buffer[1]); // tanggal font kecil satuan
  1310.  
  1311.   //putnormalchar(0+offset, 1, buffer[0]); // tanggal font GEDE puluhan
  1312.   //putnormalchar(4+offset, 1, buffer[1]); // tanggal font GEDE satuan
  1313.   /**************
  1314.   //if date is under 10 - then we only have 1 digit so set positions of sufix etc one character nearer
  1315.   byte suffixposx = 4;
  1316.  
  1317.   //if date over 9 then print second number and set xpos of suffix to be 1 char further away
  1318.   if (date > 9){
  1319.     suffixposx = 10;
  1320.     puttinychar(4+offset, 1, buffer[1]);
  1321.     offset = 10; //offset to centre text if 4 chars
  1322.   }
  1323.  
  1324.   //print the 2 suffix characters
  1325.   puttinychar(suffixposx+offset, 1, suffix[s][0]);  
  1326.   puttinychar(suffixposx+4+offset, 1, suffix[s][1]);  
  1327.   ***************/  
  1328.   delay(1500);
  1329.   fade_down();
  1330.  
  1331.   //print the month name    
  1332.   //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
  1333.   len = 0;
  1334.   while(monthnames[month][len]) {  
  1335.     len++;  
  1336.   };  
  1337.   offset = (31 - ((len-1)*4)) / 2; //our offset to centre up the text
  1338.   i = 0;
  1339.   while(monthnames[month][i])
  1340.   {  
  1341.     puttinychar((i*4) +offset, 1, monthnames[month][i]);  
  1342.     i++;
  1343.     delay(date_delay);  
  1344.   }
  1345.    
  1346.   delay(1500);
  1347.   fade_down();
  1348.  
  1349.  /******** Menampilkan Tahon ********/
  1350.   offset = 9;   //offset to centre text - e.g. 2018
  1351.   char buffer_y[3] = "20";
  1352.   puttinychar(0+offset , 1, buffer_y[0]);   //print the 1st year number: 2
  1353.   delay(date_delay);
  1354.   puttinychar(4+offset , 1, buffer_y[1]);   //print the 2nd year number: 0
  1355.   delay(date_delay);
  1356.   itoa(year,buffer,10);                     //if year < 10 add a 0
  1357.    if (year < 10) {
  1358.        buffer[1] = buffer[0];
  1359.        buffer[0] = '0';
  1360.       }
  1361.   puttinychar(8+offset, 1, buffer[0]);      //print the 1st year number
  1362.   delay(date_delay);
  1363.   puttinychar(12+offset, 1, buffer[1]);     //print the 2nd year number
  1364.   delay(1500);
  1365.   cls();
  1366. }
  1367.  
  1368. //dislpay menu to change the clock mode
  1369. void switch_mode() {
  1370.  
  1371.   //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.
  1372.   old_mode = clock_mode;
  1373.  
  1374.   char* modes[] = {
  1375.     "Basic", "Small", "Slide", "Words", "Setup"
  1376.   };
  1377.  
  1378.   byte next_clock_mode;
  1379.   byte firstrun = 1;
  1380.  
  1381.   //loop waiting for button (timeout after 35 loops to return to mode X)
  1382.   for (int count = 0; count < 35 ; count++) {
  1383.  
  1384.     //if user hits button, change the clock_mode
  1385.     if (buttonA.uniquePress() || firstrun == 1) {
  1386.  
  1387.       count = 0;
  1388.       cls();
  1389.  
  1390.       if (firstrun == 0) {
  1391.         clock_mode++;
  1392.       }
  1393.       if (clock_mode > NUM_DISPLAY_MODES + 1 ) {
  1394.         clock_mode = 0;
  1395.       }
  1396.  
  1397.       //print arrown and current clock_mode name on line one and print next clock_mode name on line two
  1398.       char str_top[9];
  1399.  
  1400.       //strcpy (str_top, "-");
  1401.       strcpy (str_top, modes[clock_mode]);
  1402.  
  1403.       next_clock_mode = clock_mode + 1;
  1404.       if (next_clock_mode >  NUM_DISPLAY_MODES + 1 ) {
  1405.         next_clock_mode = 0;
  1406.       }
  1407.  
  1408.       byte i = 0;
  1409.       while (str_top[i]) {
  1410.         putnormalchar(i * 6, 0, str_top[i]);
  1411.         i++;
  1412.       }
  1413.       firstrun = 0;
  1414.     }
  1415.     delay(50);
  1416.   }
  1417. }  
  1418.  
  1419. //run clock main loop as long as run_mode returns true
  1420. byte run_mode() {
  1421.  
  1422.   //if random mode is on... check the hour when we change mode.
  1423.   if (random_mode) {
  1424.     //if hour value in change mode time = hours. then reurn false = i.e. exit mode.
  1425.     if (change_mode_time == rtc[2]) {
  1426.       //set the next random clock mode and time to change it
  1427.       set_next_random();
  1428.       //exit the current mode.
  1429.       return 0;
  1430.     }
  1431.   }
  1432.   //else return 1 - keep running in this mode
  1433.   return 1;
  1434. }
  1435.  
  1436. //set the next hour the clock will change mode when random mode is on
  1437. void set_next_random() {
  1438.  
  1439.   //set the next hour the clock mode will change - current time plus 1 - 4 hours
  1440.   get_time();
  1441.   change_mode_time = rtc[2] + random (1, 5);
  1442.  
  1443.   //if change_mode_time now happens to be over 23, then set it to between 1 and 3am
  1444.   if (change_mode_time > 23) {
  1445.     change_mode_time = random (1, 4);
  1446.   }
  1447.  
  1448.   //set the new clock mode
  1449.   clock_mode = random(0, NUM_DISPLAY_MODES + 1);  //pick new random clock mode
  1450. }  
  1451.  
  1452. //dislpay menu to change the clock settings
  1453. void setup_menu() {
  1454.  
  1455.   char* set_modes[] = {
  1456.      "Rndom", "24 Hr","Set", "Brght", "Exit"};  
  1457.   if (ampm == 0) {  
  1458.     set_modes[1] = ("12 Hr");  
  1459.   }
  1460.  
  1461.   byte setting_mode = 0;
  1462.   byte next_setting_mode;
  1463.   byte firstrun = 1;
  1464.  
  1465.   //loop waiting for button (timeout after 35 loops to return to mode X)
  1466.   for(int count=0; count < 35 ; count++) {
  1467.  
  1468.     //if user hits button, change the clock_mode
  1469.     if(buttonA.uniquePress() || firstrun == 1){
  1470.  
  1471.       count = 0;
  1472.       cls();
  1473.  
  1474.       if (firstrun == 0) {  
  1475.         setting_mode++;  
  1476.       }  
  1477.       if (setting_mode > NUM_SETTINGS_MODES) {  
  1478.         setting_mode = 0;  
  1479.       }
  1480.  
  1481.       //print arrown and current clock_mode name on line one and print next clock_mode name on line two
  1482.       char str_top[9];
  1483.      
  1484.       strcpy (str_top, set_modes[setting_mode]);
  1485.  
  1486.       next_setting_mode = setting_mode + 1;
  1487.       if (next_setting_mode > NUM_SETTINGS_MODES) {  
  1488.         next_setting_mode = 0;  
  1489.       }
  1490.        
  1491.       byte i = 0;
  1492.       while(str_top[i]) {
  1493.         putnormalchar(i*6, 0, str_top[i]);  
  1494.         i++;
  1495.       }
  1496.  
  1497.       firstrun = 0;
  1498.     }
  1499.     delay(50);  
  1500.   }
  1501.    
  1502.   //pick the mode  
  1503.   switch(setting_mode){
  1504.     case 0:  
  1505.       set_random();  
  1506.       break;
  1507.     case 1:  
  1508.        set_ampm();  
  1509.       break;
  1510.     case 2:  
  1511.       set_time();  
  1512.       break;
  1513.     case 3:  
  1514.        set_intensity();  
  1515.       break;
  1516.     case 4:  
  1517.       //exit menu
  1518.       break;
  1519.   }
  1520.      
  1521.   //change the clock from mode 6 (settings) back to the one it was in before  
  1522.   clock_mode=old_mode;
  1523. }
  1524.  
  1525. //toggle random mode - pick a different clock mode every few hours
  1526. void set_random(){
  1527.   cls();
  1528.  
  1529.   char text_a[9] = "Off";
  1530.   char text_b[9] = "On";
  1531.   byte i = 0;
  1532.  
  1533.   //if random mode is on, turn it off
  1534.   if (random_mode){
  1535.  
  1536.     //turn random mode off
  1537.     random_mode = 0;
  1538.  
  1539.     //print a message on the display
  1540.     while(text_a[i]) {
  1541.       putnormalchar((i*6), 0, text_a[i]);
  1542.       i++;
  1543.     }
  1544.   } else {
  1545.     //turn randome mode on.  
  1546.     random_mode = 1;
  1547.      
  1548.     //set hour mode will change
  1549.     set_next_random();
  1550.    
  1551.     //print a message on the display
  1552.     while(text_b[i]) {
  1553.       putnormalchar((i*6), 0, text_b[i]);
  1554.       i++;
  1555.     }  
  1556.   }  
  1557.   delay(1500); //leave the message up for a second or so
  1558. }  
  1559.  
  1560. //set 12 or 24 hour clock
  1561. void set_ampm() {
  1562.  
  1563.   // AM/PM or 24 hour clock mode - flip the bit (makes 0 into 1, or 1 into 0 for ampm mode)
  1564.   ampm = (ampm ^ 1);
  1565.   cls();
  1566. }
  1567.  
  1568.  
  1569. //change screen intensityintensity
  1570. void set_intensity() {
  1571.  
  1572.   cls();
  1573.    
  1574.   byte i = 0;
  1575.   char text[7] = "Bright";
  1576.   while(text[i]) {
  1577.     puttinychar((i*4)+4, 0, text[i]);
  1578.     i++;
  1579.   }
  1580.  
  1581.   //wait for button input
  1582.   while (!buttonA.uniquePress()) {
  1583.  
  1584.     levelbar (0,6,(intensity*2)+2,2);    //display the intensity level as a bar
  1585.     while (buttonB.isPressed()) {
  1586.  
  1587.       if(intensity == 15) {  
  1588.         intensity = 0;
  1589.         cls ();  
  1590.       }  
  1591.       else {
  1592.         intensity++;  
  1593.       }
  1594.       //print the new value  
  1595.       i = 0;
  1596.       while(text[i]) {
  1597.         puttinychar((i*4)+4, 0, text[i]);
  1598.         i++;
  1599.       }
  1600.        
  1601.       //display the intensity level as a bar
  1602.       levelbar (0,6,(intensity*2)+2,2);    
  1603.        
  1604.       //change the brightness setting on the displays
  1605.       for (byte address = 0; address < 4; address++) {
  1606.         lc.setIntensity(address, intensity);
  1607.       }
  1608.       delay(150);
  1609.     }
  1610.   }
  1611. }
  1612.  
  1613.  
  1614. // display a horizontal bar on the screen at offset xposr by ypos with height and width of xbar, ybar
  1615. void levelbar (byte xpos, byte ypos, byte xbar, byte ybar) {
  1616.   for (byte x = 0; x < xbar; x++) {
  1617.     for (byte y = 0; y <= ybar; y++) {
  1618.       plot(x+xpos, y+ypos, 1);
  1619.     }
  1620.   }
  1621. }
  1622.  
  1623.  
  1624. //set time and date routine
  1625. void set_time() {
  1626.  
  1627.   cls();
  1628.  
  1629.   //fill settings with current clock values read from clock
  1630.   get_time();
  1631.   byte set_min   = rtc[1];
  1632.   byte set_hr    = rtc[2];
  1633.   byte set_date  = rtc[4];
  1634.   byte set_mnth  = rtc[5];
  1635.   int  set_yr    = rtc[6];  
  1636.  
  1637.   //Set function - we pass in: which 'set' message to show at top, current value, reset value, and rollover limit.
  1638.   set_date = set_value(2, set_date, 1, 31);
  1639.   set_mnth = set_value(3, set_mnth, 1, 12);
  1640.   set_yr   = set_value(4, set_yr, 2013, 2099);
  1641.   set_hr   = set_value(1, set_hr, 0, 23);
  1642.   set_min  = set_value(0, set_min, 0, 59);
  1643.  
  1644.   ds1307.adjust(DateTime(set_yr, set_mnth, set_date, set_hr, set_min));
  1645.    
  1646.   cls();
  1647. }
  1648.  
  1649. //used to set min, hr, date, month, year values. pass  
  1650. //message = which 'set' message to print,  
  1651. //current value = current value of property we are setting
  1652. //reset_value = what to reset value to if to rolls over. E.g. mins roll from 60 to 0, months from 12 to 1
  1653. //rollover limit = when value rolls over
  1654. int set_value(byte message, int current_value, int reset_value, int rollover_limit){
  1655.  
  1656.   cls();
  1657.   char messages[6][17]   = {
  1658.     "Set Mins", "Set Hour", "Set Day", "Set Mnth", "Set Year"};
  1659.  
  1660.   //Print "set xyz" top line
  1661.   byte i = 0;
  1662.   while(messages[message][i])
  1663.   {
  1664.     puttinychar(i*4 , 1, messages[message][i]);  
  1665.     i++;
  1666.   }
  1667.  
  1668.   delay(2000);
  1669.   cls();
  1670.  
  1671.   //print digits bottom line
  1672.   char buffer[5] = "    ";
  1673.   itoa(current_value,buffer,10);
  1674.   puttinychar(0 , 1, buffer[0]);  
  1675.   puttinychar(4 , 1, buffer[1]);  
  1676.   puttinychar(8 , 1, buffer[2]);  
  1677.   puttinychar(12, 1, buffer[3]);  
  1678.  
  1679.   delay(300);
  1680.   //wait for button input
  1681.   while (!buttonA.uniquePress()) {
  1682.  
  1683.     while (buttonB.isPressed()){
  1684.  
  1685.       if(current_value < rollover_limit) {  
  1686.         current_value++;
  1687.       }  
  1688.       else {
  1689.         current_value = reset_value;
  1690.       }
  1691.       //print the new value
  1692.       itoa(current_value, buffer ,10);
  1693.       puttinychar(0 , 1, buffer[0]);  
  1694.       puttinychar(4 , 1, buffer[1]);  
  1695.       puttinychar(8 , 1, buffer[2]);  
  1696.       puttinychar(12, 1, buffer[3]);    
  1697.       delay(150);
  1698.     }
  1699.   }
  1700.   return current_value;
  1701. }
  1702.  
  1703. void get_time()
  1704. {
  1705.   //get time
  1706.   DateTime now = ds1307.now();
  1707.   //save time to array
  1708.   rtc[6] = now.year();
  1709.   rtc[5] = now.month();
  1710.   rtc[4] = now.day();
  1711.   rtc[3] = now.dayOfWeek(); //returns 0-6 where 0 = Sunday
  1712.   rtc[2] = now.hour();
  1713.   rtc[1] = now.minute();
  1714.   rtc[0] = now.second();
  1715.  
  1716.   //flash arduino led on pin 13 every second
  1717.   //if ( (rtc[0] % 2) == 0) {
  1718.   //  digitalWrite(13, HIGH);
  1719.   //}
  1720.   //else {
  1721.   //  digitalWrite(13, LOW);
  1722.   //}
  1723.  
  1724.   //print the time to the serial port - useful for debuging RTC issues
  1725.   /*
  1726.   Serial.print(rtc[2]);
  1727.   Serial.print(":");
  1728.   Serial.print(rtc[1]);
  1729.   Serial.print(":");
  1730.   Serial.println(rtc[0]);
  1731.   */
  1732. }
  1733.  
  1734. // bottomleds: plot seconds-dots at bottomline
  1735. void bottomleds(byte secs){
  1736.  
  1737.       //switch on bottomleds from 1 to 30
  1738.       if(secs >=1 && secs <=30){                
  1739.         for(int i=0; i<=secs-1; i++){
  1740.              plot(i, 7, 1);
  1741.         }
  1742.       }
  1743.  
  1744.       //switch off bottomleds from 30 to 1  
  1745.       if(secs>=31){
  1746.         for(int i=0; i<=(30-(secs-30)); i++){
  1747.              plot(i, 7, 1);
  1748.         }
  1749.          plot(30-(secs-30), 7, 0);
  1750.        }
  1751.      
  1752.       //switch off bottomled 1      
  1753.       if(secs == 0){              
  1754.          plot(0, 7, 0);          
  1755.       }  
  1756. }
  1757.  
  1758. //===========================Selesai/End=======================
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement