Components and supplies
Speaker: 0.25W, 8 ohms
Humidity and Temperature Sensor
Adafruit RC D3231
Pushbutton Switch, Momentary
Adafruit FX 2mb Soundboard with built in amplifier
Red Acrylic face plate
Resistor 10k ohm
Arduino Mega 2560
LED Matrix 7219 four module display
Wooden Box for enclosure
Photo resistor
Project description
Code
LED Matrix clock
arduino
Arduino code for clock
1 2 3 4/* 5 Clock project using two MX7219 matrix displays and the AdaFruit FX Soundboard 6 Provides date, time, temp, humidity and event notifications in rotating order 7 Also can chime in multiple ways, including Westminster chimes 8 Chimes are provided by Adafruit FX Soundboard in GPIO mode 9 10*/ 11 12 13 14 15// Code to set up the clock 16// Pushbutton 1 is the toggler , cycle between year, month, day, hours, minutes, seconds 17// Pushbutton 2 is the increment up one 18// Pushbutton 3 is the decrement down one 19 20// Chime setup for toggle switch 21// Center = No chimes 22// Up = Westminster hours + quarterly 23// Down = Simple Bell (hours and 1/2 hour) 24 25// Comment out next line to leave out the little show 26 27#define showoffcode // include "show off" graphics at startup 28 29// include the libraries for LCD Display, DHT-11 Temperature/humidity sensor and DS3231 RTC and 30// include libraries for bigger seven segment display with backpack 31#include "DHT.h" 32#include <Wire.h> 33#include "RTClib.h" 34#include <MD_MAX72xx.h> 35// uncomment next two lines to use UART for SoundBoard rather than GPIO 36//#include <Adafruit_Soundboard.h> 37//#include <SoftwareSerial.h> 38 39 40// Set up output functions 41 42#define DHTPIN 9 //Temp Humidity sensor on pin 9 43#define DHTTYPE DHT11 // DHT 11 because the sensor is that type 44 45// Initialize DHT sensor for normal 16mhz Arduino 46DHT dht(DHTPIN, DHTTYPE); 47 48// Initialize for Adafruit DS3231 RTC real time clock 49RTC_DS3231 rtc; 50 51// uncomment next set of lines to use UART for SoundBoard 52/* 53 // Choose any two pins that can be used with SoftwareSerial to RX & TX for UART SoundBoard 54 //#define SFX_TX 5 55 //#define SFX_RX 6 56 // Connect to the RST pin on the Sound Board 57 #define SFX_RST 4 58 // You can also monitor the ACT pin for when audio is playing! 59 // we'll be using software serial 60 //SoftwareSerial ss = SoftwareSerial(SFX_TX, SFX_RX); 61 // pass the software serial to Adafruit_soundboard, the second 62 // argument is the debug port (not used really) and the third 63 // arg is the reset pin 64 //Adafruit_Soundboard sfx = Adafruit_Soundboard(&ss, NULL, SFX_RST); 65 // can also try hardware serial with 66 // Adafruit_Soundboard sfx = Adafruit_Soundboard(&Serial1, NULL, SFX_RST); 67*/ 68 69// Define the number of devices we have in the chain and the hardware interface 70// NOTE: These pin numbers will probably not work with your hardware and may 71// need to be adapted 72#define HARDWARE_TYPE MD_MAX72XX::FC16_HW // NOTE: This parameter differs by vendor 73#define MAX_DEVICES 8 // 2 x 4 matrices per unit 74 75//Pins for Arduino Uno 76//#define CLK_PIN 13 // or SCK (this is for the UNO, different for the Mega 77//#define DATA_PIN 11 // or MOSI 78//#define CS_PIN 10 // or SS 79 80 81//Pins for Arduino Mega 82#define CLK_PIN 52 // or SCK 13 83#define DATA_PIN 51 // or MOSI 11 84#define CS_PIN 53 // or SS 10 85 86 87// SPI hardware interface 88MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); 89 90// We always wait a bit between updates of the display 91#define DELAYTIME 100 // in milliseconds 92 93// Text parameters 94#define CHAR_SPACING 1 // pixels between characters 95//const int CHAR_PIXELS = 6; // Pixels taken by each character (including trailing space) 96//const int MAX_CHARS = (MAX_DEVICES*COL_SIZE)/ CHAR_PIXELS; // Maximum characters at once (happens to be 10 btw) 97//const int LEFT_OVER = (MAX_DEVICES*COL_SIZE)- (CHAR_PIXELS*MAX_CHARS); //Since its not 'even' additional pad from front on printText 98const int BufferStringLength = 31; 99char BufferString [BufferStringLength]; //used to construct printouts 100#define DecToAscii 48 // convert number to ascii (add as a constant) 101#define DegreeSign 0x0090 // for display of 'degrees' after temperature 102int TDigits[4] = {0, 0, 0, 0}; // used to convert four digits to four chacacters 103#define TDOnes 3 // positions in arrays and templates 104#define TDTens 2 105#define TDHundreds 1 106#define TDThousands 0 107#define sunday 0 // used for events, floating events and holidays 108#define monday 1 // just for readability 109#define thursday 4 110#define january 1 111#define february 2 112#define march 3 113#define april 4 114#define may 5 115#define june 6 116#define july 7 117#define august 8 118#define september 9 119#define october 10 120#define november 11 121#define december 12 122 123//Template Strings and pointers 124 125const int LOTS = 13; // Length of TimeString (without terminator) 126char TimeString[LOTS + 1 ] = {' ', ' ', '1', '2', ':', '3', '1', ':', '4', '5', ' ', 'P', 'M', '\\0'}; 127char DateString[ ] = {'1', '2', '/', '3', '1', '/', '2', '0', '1', '9', '\\0'}; 128char TempString[ ] = {'T', 'e', 'm', 'p', ' ', '7', '2', '.', '0', DegreeSign, 'F', '\\0'}; 129char HumidString[ ] = {'H', 'u', 'm', ' ', '2', '5', '.', '0', '%', '\\0'}; 130const int THptr = 2; // Pointers within the strings 131const int TMptr = 5; // for loading values 132const int TSptr = 8; 133const int TAMPMptr = 11; 134const int DMptr = 0; 135const int DDptr = 3; 136const int DYptr = 6; 137const int TEMPptr = 5; 138const int HUMIDptr = 4; 139 140// Differentiated Displays 141 142const int DisplayTime = 0; 143const int DisplayDate = 2; 144const int DisplayDOW = 1; 145const int DisplayTemp = 3; 146const int DisplayHumid = 4; 147const int DisplayEvent = 5; 148const int DisplayEventRepeat = 2; //times to repeat the scrolling 'event' display 149const int DisplaySize = 6; // Nunber of different displays 150int DisplayIndex = DisplayTime; // display we are on at the time 151const int DisplayDelayArray[DisplaySize] = {100, 50, 30, 30, 30, 20}; // multiplier for each event 152const int DisplayDelay = 100; // milliseconds to leave each display * its multiplier 153unsigned long DisplayTimer; // used to time each matrix display 154 155 156 157char daysOfTheWeek[7][12 ] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 158 159// Event arrays 160// Load with month of 'event', day of event and description to be displayed 161 162const int eventnumber = 21; // number of events and remember: No strings longer than 30 characters! 163int eventmonth [eventnumber] = {june, april, november, february, july, december, november, june, december, june, march, december, january, 164 september, october, march, february, february, july,december, february}; 165int eventday [eventnumber] = {11, 1, 23, 12, 4, 3, 12, 29, 25, 18, 17, 31, 1, 3, 31, 17, 14, 2, 14, 30,12}; 166char* eventdescription [eventnumber] = 167{ "Dana's Anniversary", "April Fool's Day", "Joan's Birthday", "Sydney's Birthday", "Happy July 4th!", "Dana's Birthday", 168 "David's Birthday", "Our Anniversary", "Merry Christmas", "Leah's Birthday", "St Patrick's Day", "New Year's Eve", "New Year's Day", 169 "Forrest's Birthday", "Happy Halloween", "Saint Patrick's Day", "Valentine's Day", "Groundhog Day", "Bastille Day", "Linsey's Birthday", 170 "Irwin's Birthday" 171}; 172 173bool event; // logic flag "on" = event found 174int eventindex; // and the event we found 175const int maxevents = 3; // maximum of three events (real and floating combined) 176char* eventstrings[maxevents] ; // used to store displayed events 177String floatstring = " "; // used for floating events (e.g., Thanksgiving) 178 179#define pb1pin 2 // Pin assignments for reset, increment and decrement 180#define pb2pin 3 181#define pb3pin 4 182 183#define showoffbuttonpin 7 // invoke showing off the matrix display 184 185#define DoWestminster 5 186#define DoHoursOnly 6 187#define silent 0 // no chiming at all 188#define hoursonly 1 // no prelude, just chime number of hours and half hour single chime 189#define westminster 2 // hours + Westminster prelude per quarter 190int ChimeValue = silent; // default to silent 191 192 193const int LEDpin = A0; // Pin assignment for analog reading LDR for LED brightness 194const int minbright = 0; // MAX_BRIGHT for this module is 15 195const int midbright = 2; // but these values "seem" to work 196const int maxbright = 4; 197 198 199 200 201int setupindex = 0; // first thing to set if required 202bool insetupmode = false; // and assume RTC is set, OK, etc., and no 'set' required 203bool setinsetup = false; // flag set to true at interrupt level to go back into setup mode 204 205// date time array for setting, reading, displaying 206 207#define setsize 6 // size of the setting array 208#define setyear 0 // index name for each element 209#define setmonth 1 210#define setday 2 211#define sethour 3 212#define setminute 4 213#define setsecond 5 214 215int setarray [setsize] = {2019, 1, 1, 1, 1, 0}; // set year, month, day, hour, minutes, seconds 216int lowlimit [setsize] = {2019, 1, 1, 0, 1, 0}; // lower limit for each 217int highlimit [setsize] = {2080, 12, 31, 23, 59, 59}; //high limit for each 218const int setdesclength = 4; // maximum length of 'set' descriptor 219char setdesc [setsize] [setdesclength] = {"Yr ", "Mon", "Day", "Hr ", "Min", "Sec"}; 220 221 222#define cqtr0 1 // Chime the hour 223#define cqtr1 2 // Chime the quarter hour 224#define cqtr2 3 // Chime the half hour 225#define cqtr3 4 // Chime the 3/4 hour 226 227// Definitions for the Sound Board 228#define SoundTruncatedSingle 0 // Truncated Single Westminster 229#define SoundQ1 1 // First Quarter 230#define SoundQ2 2 // Second Quarter 231#define SoundQ3 3 // Third 232#define SoundQ4 4 // Fourth (before hour chime) 233#define SoundTrailingSingle 5 // Finish Westminster string of chimes with longer sound tail 234#define SoundTruncatedBell 6 // Simple Bell 235#define SoundTrailingBell 7 // Final Bell (like single, has longer 'tail') 236#define SoundStartup 8 // startup sound 237#define SoundShowOff 9 // Play during show off of matrix 238#define FirstSoundPin 30 // first pin to use for soundboard (0-10 available on soundboard); 239#define SizeSoundPin 10 // number of pins used (must be consecutive) 240#define fxset 150 // Time soundboard must be held LOW to register (documentation says 125 ms) 241#define SoundBusyPin 8 // Soundboard pin that goes LOW when board is active 242 243const int SizeQueue = 15; // Assume Q4+12 bells is the maximum that'll be in the queue at any point 244int SoundQueue[SizeQueue]; // Circular Queue for waiting sounds 245int SoundQueuePtr = -1; //pointer for Queue fill Position 246int SoundPlayPtr = -1; //pointer for Queue play Position 247int SoundQueueCtr = 0; // number of items in the queue 248 249int setstrike = -1; // Chime/strike flag 250byte alreadychimed = false ; // Used to keep from chiming multiple times during the "hot" second 251const int BounceDelay = 250; // Not really 'bounce', its a change of state detection 252 253 254 255int i; // generic index variable 256 257int dayoftheweek; // stored day of the week (0-6, 0 = Sunday) 258 259int phours; // for print conversion of military time 260 261float temperaturef; // farenheit temperature back 262int temperature; // integer version of temperature for matrix 263float temperaturec; // centrigade temperature back (not used) 264 265float humidityf; // and humidity 266int humidity ; // and same as temp 267 268float tempadjust = -2.0; // temperature adjustment for sensor (I found it didn't read right against 'comps') 269byte degreesymbol = 223; // LCD output of 'degree' symbol 270 271#define DDT 272 273#ifdef DDT // debugging tools 274void DDTl(String st, int vt) { // Print descriptor and value and new line 275 DDTs(st, vt); 276 Serial.println(" "); 277} 278void DDTs(String st, int vt) { // Print descriptor and value 279 Serial.print(" "); 280 Serial.print(st); 281 Serial.print(" "); 282 Serial.print(vt); 283} 284#endif //DDT// 285 286 287void setup() 288// put your setup code here, to run once: 289 290{ 291 Wire.begin(); // initialize I2C interface 292 dht.begin(); // initialize the temp/humidity sensor 293 mx.begin(); // and MX7219 display 294 Serial.begin (9600); //Terminal monitor printing for debugging 295 296 // softwareserial at 9600 baud (uncomment this line and next for UART control of sound board 297 // ss.begin(9600); 298 299 300 pinMode(pb1pin, INPUT_PULLUP); // The three pushbuttons - reset 301 pinMode(pb2pin, INPUT_PULLUP); // increment 302 pinMode(pb3pin, INPUT_PULLUP); // decrement 303 304 pinMode (DoWestminster, INPUT_PULLUP); // When pulled 'low' we want Westminster chimes 305 pinMode (DoHoursOnly , INPUT_PULLUP); // When pulled 'low' we want hours and 1/2 bell (neither is 'silent') 306 307 #ifdef showoffcode 308 pinMode(showoffbuttonpin, INPUT_PULLUP) ; // if show off matrix is there, initialize pin 309 #endif //showoffcode// 310 311 for (i = FirstSoundPin; i < FirstSoundPin + SizeSoundPin; i++) { // pins for sound board 312 pinMode(i, OUTPUT); // each an output 313 digitalWrite(i, HIGH); // and initialize high (off) 314 } 315 316 // set up interupt for PB1 // if PB1 is pushed, it'll pick up on next release from Matrix display 317 attachInterrupt(digitalPinToInterrupt(pb1pin), SetToSetup, FALLING); // and re-enter setup mode (after the end of current display) 318 319#ifdef showoffcode 320// ShowOff(); // Show off a little (uncomment to give initial showoff at beginning) 321#endif //showoffcode// 322 323 QueueSound(SoundStartup); // play boot up sound 324 PlaySound(); 325 326 if (! rtc.begin()) { // check that clock is there 327 scrollText("Couldn't find RTC"); // clock missing is a fatal error 328 while (1); 329 } 330 331 if (rtc.lostPower()) { // if power lost force a setup, else load 'current' values and 332 scrollText("RTC lost power!"); 333 delay(1000); 334 scrollText("Replace battery?"); 335 delay(1000); 336 scrollText("Setup Mode: "); 337 setupindex = setyear - 1; // setup differently (becuase it will increment) 338 insetupmode = true; 339 for (i = 0; i < setsize; i++) { 340 setarray[i] = lowlimit[i]; 341 } 342 } else // else reload from RTC 343 { DateTime (setarray[setyear], setarray[setmonth], setarray[setday], setarray[sethour], setarray[setminute], setarray[setsecond]) = rtc.now(); 344 insetupmode = false; // not in setup mode, and 345 setinsetup = false; //no interrupt 346 } 347 348 // Two alternative modes of setting date and time (for debugging, just un-comment): 349 // This line sets the RTC to the date & time this sketch was compiled 350 // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 351 // This line sets the RTC with an explicit date & time, for example to set 352 // January 21, 2014 at 3am you would call: 353 // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 354 LEDBrightness(); // Do an initial check for room brightness 355} // end of setup 356 357void loop() { // Main code divided into setup mode and non-setup mode 358 359 while (insetupmode) { // code for setting time, date set, etc. 360 361 // Read the increment button 362 363 if (digitalRead(pb2pin) == LOW) { 364 setarray[setupindex]++; // read increment of current item 365 delay(BounceDelay); 366 if (setarray[setupindex] > highlimit[setupindex]) { 367 setarray[setupindex] = lowlimit[setupindex]; 368 } 369 ShowValue(setupindex, setdesc[setupindex]); // and display description and value 370 } 371 372 // Read the decrement Button 373 if (digitalRead(pb3pin) == LOW) { 374 setarray[setupindex]--; // read decrement of value 375 delay(BounceDelay); 376 if (setarray[setupindex] < lowlimit[setupindex]) { 377 setarray[setupindex] = highlimit[setupindex]; 378 } 379 ShowValue(setupindex, setdesc[setupindex]); // and display description and value 380 } 381 382 // Read for another increment of index 383 384 if (digitalRead(pb1pin) == LOW) { // Rolling through Chime, Year, Month, Day, Hour, Minutes, Seconds 385 setupindex++ ; // increment index 386 delay(BounceDelay); 387 if (setupindex < setsize) { 388 ShowValue(setupindex, setdesc[setupindex]); // show description and value if in bounds 389 } 390 if (setupindex >= setsize) { // and finally exiting setup mode after setting chime, date and time 391 rtc.adjust(DateTime(setarray[setyear], setarray[setmonth], setarray[setday], setarray[sethour], setarray[setminute], setarray[setsecond])); 392 insetupmode = false; 393 DisplayIndex = DisplayTime; 394 } //exit setup mode when done 395 } 396 397 } // End of "While" for setup 398 399 // Begin regular loop for date, time, temp humidity and event display 400 401 while (!insetupmode) { 402 403 GetTempandHumid(); // read temperature and humidity from sensor 404 405 ChimeValue = ReadChimeSetting(); // read SPDT Center off switch for silent, westminster or hours only (and 1/2) 406 407 GetTheDate(); // load date array from RTC for a chime/bell check 408 409 CheckForChime(); // Check for a chime event between displays 410 411 CheckForEvent(setarray[setmonth], setarray[setday], dayoftheweek); // check for static and floating events 412 413 MatrixDisplay(); // Do whatever display is required on the MX7219 414 415 LEDBrightness(); // Good place to check for change in room brightness 416 417 // end of display update logic 418 419 // Read a potential request for an entry into setup from PB 1 420 if ((digitalRead(pb1pin) == LOW) || setinsetup) { // to see if we go back to setup mode 421 insetupmode = true; // via a pushbutton or the interrupt 422 setinsetup = false; // clear the interrupt flag 423 setupindex = 0; // re-initialize to 'Year' in setup 424 DisplayIndex = DisplayTime; // and go back to time display when exit setup 425 scrollText("Setup Mode: "); 426 delay(2000); 427 ShowValue(setupindex, setdesc[setupindex]); // show the first setup item (Year) 428 delay(BounceDelay); 429 } 430 #ifdef showoffcode 431 if (digitalRead(showoffbuttonpin) == LOW) {ShowOff();} // check for want to show off matrix 432 #endif //showoffcode// 433 434 } // end of not in setup 435} // end of sketch 436 437void MatrixDisplay() { // Main display routine for display sequences 438 439 Scrollup(); // Clear last display 440 if (DisplayIndex >= DisplaySize) { 441 DisplayIndex = DisplayTime; // reset if at the end 442 } 443 DisplayTimer = DisplayDelayArray[DisplayIndex] * DisplayDelay; // set individual display time 444 445 switch (DisplayIndex) { // and do next display 446 447 case DisplayTime: // Dislay the time 448 do // time is different in that there's a constant 449 { // update of time during display and also play chime, bell etc. 450 GetTheDate(); // Get Current Time 451 CheckForChime(); // Check for a chime event 452 LoadNumber(phours); // Load the 4 digit character array from number 453 TimeString[THptr] = TDigits[TDTens]; // left digit of the two digit hour 454 TimeString[THptr + 1] = TDigits[TDOnes]; // rightmost digit 455 if (TimeString[THptr] == '0') { 456 TimeString[THptr] = ' '; // eliminate leading zero 457 } 458 LoadNumber(setarray[setminute]); // do same for minutes 459 TimeString[TMptr] = TDigits[TDTens]; // except no need to do space for zero 460 TimeString[TMptr + 1] = TDigits[TDOnes]; 461 LoadNumber(setarray[setsecond]); // seconds then 462 TimeString[TSptr] = TDigits[TDTens]; 463 TimeString[TSptr + 1] = TDigits[TDOnes]; 464 if (setarray[sethour] < 12) // and AM vs PM 465 { 466 TimeString[TAMPMptr] = 'A'; 467 } 468 else 469 { 470 TimeString[TAMPMptr] = 'P'; 471 } 472 printText(TimeString, LOTS, false); // Keep position (no centering) because time keeps updating during display and chimes 473 PlaySound(); // Play any chimes or bells 474 if (SoundQueueCtr == 0) { 475 DisplayTimer = DisplayTimer - DisplayDelay; // if no sound, use display delay logic 476 delay(DisplayDelay); 477 } 478 } while ((DisplayTimer > 0) || (SoundQueueCtr > 0)); // leave this display when no sound or no delay left 479 DisplayIndex++ ; // then move on to next display item 480 break; 481 482 case DisplayDate: // Month, Day and Year Display 483 LoadNumber(setarray[setmonth]); 484 DateString[DMptr] = TDigits[TDTens]; 485 if (DateString[DMptr] == '0') { 486 DateString[DMptr] = ' '; 487 } 488 DateString[DMptr + 1] = TDigits[TDOnes]; 489 LoadNumber(setarray[setday]); 490 DateString[DDptr] = TDigits[TDTens]; 491 DateString[DDptr + 1] = TDigits[TDOnes]; 492 LoadNumber(setarray[setyear]); 493 for (int i = 0; i < 4; i++) { 494 DateString[DYptr + i] = TDigits[i]; 495 } 496 printCenter(DateString); 497 CommonDelay(DisplayTimer); 498 DisplayIndex++ ; 499 break; 500 501 case DisplayDOW: // Just display the day of week string 502 printCenter(daysOfTheWeek[dayoftheweek]); 503 CommonDelay(DisplayTimer); 504 DisplayIndex++ ; 505 break; 506 507 case DisplayTemp: // Temperature display 508 LoadNumber(temperature); 509 TempString[TEMPptr] = TDigits[TDHundreds]; 510 TempString[TEMPptr + 1] = TDigits[TDTens]; 511 TempString[TEMPptr + 3] = TDigits[TDOnes]; 512 printCenter(TempString); 513 CommonDelay(DisplayTimer); 514 DisplayIndex++ ; 515 break; 516 517 case DisplayHumid: // Humidity display 518 LoadNumber(humidity); 519 HumidString[HUMIDptr] = TDigits[TDHundreds]; 520 HumidString[HUMIDptr + 1] = TDigits[TDTens]; 521 HumidString[HUMIDptr + 3] = TDigits[TDOnes]; 522 printCenter(HumidString); 523 CommonDelay(DisplayTimer); 524 DisplayIndex++ ; 525 break; 526 527 case DisplayEvent: // Event Display 528 if (event) { // "Real" events repeat 3 times 529 if (eventindex > 0 ) { // for case where there is more than one event 530 while (eventindex >= 0) 531 {scrollText(eventstrings[eventindex]); // scroll each of them once 532 if (eventindex > 0) { 533 delay(DisplayDelay * 6); 534 printCenter("and"); 535 delay(DisplayDelay * 6);} 536 eventindex--; // and decrement 537 delay(DisplayDelay * 2); 538 } 539 } 540 else { // case of only one event -- repeat it for readability 541 for (int i = 1; i <= DisplayEventRepeat; i++) { // scroll either static or floating event 542 scrollText(eventstrings[eventindex]); // the index is 0 (greater than zero if multiple events) 543 } 544 delay(DisplayDelay * 2); 545 } 546 } // end of "if event" logic 547 if (!event){ // Scroll Default message only once 548 if (setarray[sethour] >= 6 && setarray[sethour] <= 11) { 549 scrollText("Good Morning ");} 550 else if (setarray[sethour] >= 12 && setarray[sethour] <= 16) { 551 scrollText("Good Afternoon");} 552 else if (setarray[sethour] >= 17 && setarray[sethour] <= 21) { 553 scrollText("Good Evening");} else{scrollText("Good Night"); } 554 } 555 CommonDelay(DisplayTimer); 556 DisplayIndex++ ; 557 break; 558 559 default: 560 scrollText("Should never get here"); 561 while (1); 562 563 } // End of Switch 564 565} // End of MatrixDisplay 566 567void GetTheDate() { // Read RTC into array 568 DateTime now = rtc.now(); 569 setarray[setyear] = now.year(); 570 setarray[setmonth] = now.month(); 571 setarray[setday] = now.day(); 572 setarray[sethour] = now.hour(); 573 setarray[setminute] = now.minute(); 574 setarray[setsecond] = now.second(); 575 dayoftheweek = now.dayOfTheWeek(); 576 if (setarray[sethour] <= 12) // convert military time to am pm 577 { 578 phours = setarray[sethour]; 579 } 580 else 581 {phours = setarray[sethour] - 12;} 582 if (phours <= 0) { phours = 12; } // don't print 0 for midnite, print "12" 583 584} // End of Get The Date 585 586void GetTempandHumid(){ // Temperature and humidity update 587 588 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) 589 humidityf = dht.readHumidity(); 590 591 // Read temperature as Fahrenheit 592 temperaturef = (dht.readTemperature(true)) + tempadjust; // read and correct for inaccuracy in sensor 593 594 // Check if any reads failed and exit early (to try again). 595 if (isnan(humidityf) || isnan(temperaturec) || isnan(temperaturef)) { 596 temperaturef = 0; // use 0 as a no-read 597 humidityf = 0; // error indication 598 } 599 temperature = temperaturef * 10.0; // get read for matrix printout 600 humidity = humidityf * 10.0; 601} // end of Temperature and Humidity update 602 603void SetToSetup() { // interrupt level back to setup 604 if ((!insetupmode) && (!setinsetup)) { // skip if we are already in Setup mode or have seen the interrupt 605 setinsetup = true; // Go back into setup at next loop 606 DisplayTimer = 0; 607 } // and zero the timer to speed that up if you can 608} // SetToSetup 609 610void CommonDelay(long int MyDelay) { // Common delay routine 611 DisplayTimer = MyDelay; 612 do { 613 DisplayTimer = DisplayTimer - DisplayDelay; 614 delay(DisplayDelay); 615 GetTheDate(); // load date array from RTC for a chime/bell check 616 CheckForChime(); // if a chime happens, setup to end delay 617 } while ((DisplayTimer > 0) && (!setinsetup) && (SoundQueueCtr <= 0)); // repeat while still time and no interrupt and no sound waiting 618 if (SoundQueueCtr > 0){DisplayIndex = DisplayTime-1;} // if leaving due to chime, go directly to time 619} // End of CommonDelay 620 621 622int ReadChimeSetting() { 623 int returnvalue = silent; // Assume 'silent' (Center position) 624 if (digitalRead(DoWestminster) == LOW) { 625 returnvalue = westminster; 626 } else if (digitalRead(DoHoursOnly) == LOW) { 627 returnvalue = hoursonly; 628 } 629 return returnvalue; 630} 631 632// Routine to deal with combinations of chime type, time of day and the current hour 633// called parameters are chime type (e.g., Westminster), Strike type (hour, qtr, half, 3/4) and the hour in military time 634// Note for delays and print cycles: You need to call this at least once during the 'golden' minute (0,15,30,45) 635 636void CheckForChime() { // Logic for chiming 637 638 setstrike = -1; // initialize 'strike' flag to "no strike" 639 640 if (ChimeValue != silent) // if silenced due to setting silent, skip the whole thing 641 { 642 if (setarray[setminute] == 0) { // Look for 'on the hour' 643 setstrike = cqtr0; 644 } else if (setarray[setminute] == 15 ) { // Look for on the quarter hour 645 setstrike = cqtr1; 646 } else if (setarray[setminute] == 30 ) { // Look for on the 1/2 hour 647 setstrike = cqtr2; 648 } 649 else if (setarray[setminute] == 45 ) { // Look for on the three-quarter hour 650 setstrike = cqtr3; 651 } 652 else { 653 alreadychimed = false; // none of the above, reset ability to chime 654 } 655 656 if (setstrike > 0 && !alreadychimed ) { 657 chime(ChimeValue, setstrike, setarray[sethour]); // call chiming with 'type of chime'; 0,15,30,45 ; and # hours 658 DisplayIndex = DisplayTime; // force display of time while chiming 659 alreadychimed = true; // we will be here multiple times but only chime once 660 } 661 } // end of logic for chiming 662} // end of CheckForChime 663 664void chime (int chimetype, int strikeflag, int chour) { 665 666 int chour1; // am pm variable\\ 667 668 if (chour <= 12) { 669 chour1 = chour; // convert military time to am pm 670 } else { 671 chour1 = chour - 12; 672 } 673 674 675 if (chour1 <= 0) { 676 chour1 = 12; // don't chime 0 for midnite, chime 12 677 } 678 if (chimetype == hoursonly && strikeflag == cqtr2) { 679 QueueSound(SoundTrailingBell); // 1/2 hour only, do single 'ding' 680 } 681 else if ( chimetype == hoursonly && strikeflag == cqtr0) { 682 for (int i = 1; i < chour1; i++) { 683 QueueSound(SoundTruncatedBell); // Ding once less than hours 684 } 685 QueueSound(SoundTrailingBell); 686 } // and follow by trailing bell as last 'ding' (if used) 687 else if (((chimetype == westminster) ) && strikeflag == cqtr1) { 688 QueueSound(SoundQ1); // First Quarter 689 } 690 else if (((chimetype == westminster) ) && strikeflag == cqtr2) { 691 QueueSound(SoundQ2); // Second Quarter 692 } 693 else if (((chimetype == westminster)) && strikeflag == cqtr3) { 694 QueueSound(SoundQ3); // Third Quarter 695 } 696 else if (((chimetype == westminster)) && strikeflag == cqtr0) { 697 QueueSound(SoundQ4); 698 for (int i = 1; i < chour1; i++) { 699 QueueSound(SoundTruncatedSingle); // Chime once less than hours 700 } 701 QueueSound(SoundTrailingSingle); 702 } // Chime Westminster final hours 703 704 705} // end of Chime 706 707 708// Routine to check for 'real' (static) events and floating events (e.g., Memorial Day, Thanksgiving, Mother's Day and Fathers Day) 709 710/* Memorial Day is Last Monday in May 711 Thanksgiving is 4th Thursday in November 712 Mother's Day is 2nd Sunday in May 713 Father's Day is 3rd Sunday in June 714 MLK Day is 3rd Monday in February 715 Memorial Day is last Monday in May 716 Labor Day is first Monday in September 717 Daylight Savings Times starts 2nd Sunday in March 718 Daylight Savings Times ends first Sunday in November 719 Indigenous People's Day is second Monday in October (also its Columbus Day) 720 721*/ 722 723void CheckForEvent(int m, int d, int dow) { // called with Month, Day within month and day of the week (0 = Sunday) 724 725 event = false; // assume neither static or floating 726 eventindex = -1; // initial index to eventstrings 727 728 // Static event check 729 730 for (int i = 0; i < eventnumber; i++) { // then check the static events 731 if ((setarray[setmonth] == eventmonth[i]) && (setarray[setday] == eventday[i])) 732 { event = true; // set if match on month and day 733 eventindex++; // found one! 734 eventstrings[eventindex] = eventdescription[i]; // store pointer to static event description 735 } 736 } 737 738 // Floating event check 739 740 floatstring = "none"; // initialize string 741 742 if ((dow == thursday) && (m == november) && (d >= 22) && (d <= 28)) { // Thanksgiving 743 floatstring = "Thanksgiving"; 744 } 745 else if ((dow == sunday) && (m == may) && (d >= 8) && (d <= 14)) { // Mother's Day 746 floatstring = "Mother's Day"; 747 } 748 else if ((dow == sunday) && (m == june) && (d >= 15) && (d <= 21)) { //Father's Day 749 floatstring = "Father's Day"; 750 } 751 else if ((dow == monday) && (m == january) && (d >= 15) && (d <= 21)) { //MLK Day 752 floatstring = "Martin Luther King Day"; 753 } 754 else if ((dow == monday) && (m == february) && (d >= 15) && (d <= 21)) { //President's Day 755 floatstring = "President's Day!"; 756 } 757 else if ((dow == monday) && (m == september) && (d <= 7) ) { //Labor Day 758 floatstring = "Labor Day"; 759 } 760 else if ((dow == monday) && (m == october) && (d >= 8) && (d <= 14) ) { //Indigenous People's Day 761 floatstring = "Indigenous People's Day"; 762 } 763 else if ((dow == monday) && (m == may) && (d + 7 > 31) ) { //Memorial Day 764 floatstring = "Memorial Day"; 765 } 766 else if ((dow == sunday) && (m == march) && (d >= 8) && (d <= 14)) { // DST begins 767 floatstring = "DST Begins"; 768 } 769 else if ((dow == sunday) && (m == november) && (d <= 7) ) { //DST ends 770 floatstring = "DST Ends"; 771 } 772 773 if (floatstring != "none" ) { // did we load anything? 774 event = true; // if so, then we have one 775 eventindex++; // so load it into event display queue 776 eventstrings[eventindex] = floatstring.c_str(); // store pointer to static event description 777 } 778 779} // end of floatingevent 780 781void LEDBrightness() { 782 int LEDvalue; 783 LEDvalue = analogRead(LEDpin); // Read LDR value (may need to play with values) 784 DDTs("LED value",LEDvalue); 785 LEDvalue = map(LEDvalue, 0, 1023, 0, MAX_INTENSITY); //map to valid value for brightness (max intensity is 15 btw) 786 if (LEDvalue <= 11) { 787 mx.control(MD_MAX72XX::INTENSITY, minbright);} 788 else if (LEDvalue > 13 ) { 789 mx.control(MD_MAX72XX::INTENSITY, maxbright); } 790 else 791 {mx.control(MD_MAX72XX::INTENSITY, midbright); } 792 DDTl("Mapped LED value", LEDvalue); 793 794 795 796} //end of LEDbrightness 797 798void Scrollup() { // used to 'wipe' previous display 799 for (uint8_t i = 0; i < 8; i++) { 800 mx.transform(MD_MAX72XX::TSU); delay(2 * DELAYTIME); 801 delay(DELAYTIME); 802 } 803} // End of Scrollup 804 805 806void scrollText(char *p) // copied from library 807{ 808 uint8_t charWidth; 809 uint8_t cBuf[8]; // this should be ok for all built-in fonts 810 mx.clear(); 811 while (*p != '\\0') 812 { 813 charWidth = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf); 814 815 for (uint8_t i = 0; i <= charWidth; i++) // allow space between characters 816 {mx.transform(MD_MAX72XX::TSL); 817 if (i < charWidth) 818 mx.setColumn(0, cBuf[i]); 819 delay(DELAYTIME);} 820 } 821} // End of Scroll Text 822 823void printText(char *pMsg, int LOS, bool CenterJustify) // copied and modified from library 824// Print the text string to the LED matrix modules specified. 825// Message area is padded with blank columns after printing. 826// And center justified if third argument is "true" 827{ 828 uint8_t modStart = 0; 829 uint8_t modEnd = MAX_DEVICES - 1; 830 uint8_t state = 0; 831 uint8_t curLen; 832 uint16_t showLen; 833 uint8_t cBuf[8]; 834 int16_t col = ((modEnd + 1) * COL_SIZE) - 1; 835 int pixelcount = 0; 836 int ccounter = LOS; 837 838 mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 839 840 do // finite state machine to print the characters in the space available 841 { switch (state) 842 { 843 case 0: // Load the next character from the font table 844 // if we reached end of message, reset the message pointer 845 if (*pMsg == '\\0') 846 { 847 showLen = col - (modEnd * COL_SIZE); // padding characters 848 state = 2; 849 break; 850 } 851 852 // retrieve the next character form the font file 853 854 showLen = mx.getChar(*pMsg++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf); 855 if (ccounter > 0) { 856 pixelcount = (pixelcount + showLen) + CHAR_SPACING; 857 ccounter--; 858 } 859 curLen = 0; 860 state++; 861 // !! deliberately fall through to next state to start displaying 862 863 case 1: // display the next part of the character 864 mx.setColumn(col--, cBuf[curLen++]); 865 866 // done with font character, now display the space between chars 867 if (curLen == showLen) 868 { 869 showLen = CHAR_SPACING; 870 state = 2; 871 } 872 break; 873 874 case 2: // initialize state for displaying empty columns 875 876 curLen = 0; 877 878 state++; 879 // fall through 880 881 case 3: // display inter-character spacing or end of message padding (blank columns) 882 mx.setColumn(col--, 0); 883 curLen++; 884 if (curLen == showLen) 885 state = 0; 886 break; 887 888 default: 889 col = -1; // this definitely ends the do loop 890 } 891 } while (col >= (modStart * COL_SIZE)); 892 893 if (CenterJustify) { 894 for (int i = 1; i <= (((MAX_DEVICES * COL_SIZE) - pixelcount) / 2); i++) { 895 mx.transform( MD_MAX72XX::TSR); 896 } 897 } 898 mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON); 899} 900void printCenter(String StringtoPrint) // Loads the print buffer and centers it 901{ 902 int LOS = StringtoPrint.length(); // Get the string's length 903 for (int i = 0; i < BufferStringLength; i++) { 904 BufferString[i] = ' '; // clear buffer 905 } 906 for (int i = 0; i < LOS; i++) { 907 BufferString[i] = StringtoPrint[i]; // transfer 908 printText(BufferString, LOS, true); // Print, providing length of string and "Yes, center" 909 910 } 911} // End of Center and Load 912 913void ShowValue(int myindex, String setdescription) // Display while in setup mode 914{ // shows what item is setting and its value 915 916 for (int i = 0; i < BufferStringLength; i++) {BufferString[i] = ' ';} // clear buffer 917 setdescription.toCharArray(BufferString, setdesclength); // move description to output buffer 918 LoadNumber(setarray[setupindex]); 919 BufferString[setdesclength-1] = ' '; 920 for (int i = 0; i <setdesclength; i++) {BufferString[i + setdesclength] = TDigits[i];} 921 if (myindex != setyear) { // only the year is 4 digits, else 2 922 BufferString[4] = ' '; 923 BufferString[5] = ' '; 924 if (BufferString[6] == '0') {BufferString[6] = ' ';} // and suppress leading 0 for 2 digit numbers too 925 } 926 BufferString[8] = '\\0'; // and terminate 927 printText(BufferString, 7, false); 928 929 930} // End of Show Value 931 932void LoadNumber(int numtoload) { // Converts number to four digit Ascii array 933 int tempnum = numtoload; 934 for (int i = 3; i >= 0; i--) { 935 TDigits[i] = (tempnum % 10) + DecToAscii;; 936 tempnum = tempnum / 10; 937 } 938} // end of LoadNumber 939 940void QueueSound(int SoundFile) { // place a sound to be played into sequence 941 942 if ((SoundQueuePtr == SizeQueue) || (SoundQueueCtr <= 0)) { 943 SoundQueuePtr = -1; // Dont overflow the queue 944 } 945 SoundQueuePtr++; // Increment pointer 946 SoundQueue[SoundQueuePtr] = SoundFile; // and store the sound chosen 947 SoundQueueCtr++; // and increment # sounds in queue 948} // end of Queue Sound File 949 950void PlaySound() { // Plays appropriate Sound file 951 if (SoundQueueCtr > 0) { // if nothing in the queue, just return 952 if (digitalRead(SoundBusyPin) == LOW) { //or if sound card busy, just return 953 return; 954 } //until idle 955 if (SoundPlayPtr == SizeQueue) { 956 SoundPlayPtr = -1; // Dont go past the queue 957 } 958 SoundPlayPtr++; // Increment pointer 959 digitalWrite(FirstSoundPin + SoundQueue[SoundPlayPtr], LOW); //Play the sound 960 delay(fxset); // hold to start the sound 961 digitalWrite(FirstSoundPin + SoundQueue[SoundPlayPtr], HIGH); //Turn off the sound 962 delay(fxset); // Ensure its set 963 SoundQueueCtr--; // and decrement sounds yet to be played 964 if (SoundQueueCtr <= 0) { 965 SoundPlayPtr = -1; 966 }; // reset play pointer when queue is empty 967 } 968 969} // end of PlaySound 970/* 971 void PlaySoundUART() // uncomment for FX sound board UART use 972 973 // sfx.playTrack(name); } 974 { 975 Serial.print("\ 976Playing track \\""); Serial.print(name); Serial.print("\\""); 977 if (! sfx.playTrack(name) ) { 978 Serial.println("Failed to play track?"); 979 } 980 } 981*/ 982 983 984#ifdef showoffcode 985 986void ShowOff() { // Played at startup -- just the MX Panel Test Graphics 987 QueueSound(SoundShowOff); // play Game of Thones theme as sound 988 PlaySound(); 989 scrollText("Showing Off"); 990 rows(); 991 columns(); 992 cross(); 993 checkboard(); 994 bullseye(); 995 bounce(); 996 stripe(); 997 stripe(); 998 transformation1(); 999 transformation2(); 1000 bullseye(); 1001 spiral(); 1002 delay(2000); 1003 DisplayIndex = DisplayTime; // force display of time after showing off display 1004} // end of Show Off 1005 1006void rows() // these routines are all 1007// Demonstrates the use of setRow() // from the MX library 1008{mx.clear(); 1009 for (uint8_t row = 0; row < ROW_SIZE; row++) 1010 { 1011 mx.setRow(row, 0xff); 1012 delay(2 * DELAYTIME); 1013 mx.setRow(row, 0x00); 1014 } 1015} 1016 1017void checkboard() 1018// nested rectangles spanning the entire display 1019{ 1020 uint8_t chkCols[][2] = { { 0x55, 0xaa }, { 0x33, 0xcc }, { 0x0f, 0xf0 }, { 0xff, 0x00 } }; 1021 mx.clear(); 1022 for (uint8_t pattern = 0; pattern < sizeof(chkCols) / sizeof(chkCols[0]); pattern++) 1023 { 1024 uint8_t col = 0; 1025 uint8_t idx = 0; 1026 uint8_t rep = 1 << pattern; 1027 1028 while (col < mx.getColumnCount()) 1029 { 1030 for (uint8_t r = 0; r < rep; r++) 1031 mx.setColumn(col++, chkCols[pattern][idx]); // use odd/even column masks 1032 idx++; 1033 if (idx > 1) idx = 0; 1034 } 1035 delay(10 * DELAYTIME); 1036 } 1037} // end of Checkboard 1038 1039void columns() 1040// Demonstrates the use of setColumn() 1041{ 1042 1043 mx.clear(); 1044 1045 for (uint8_t col = 0; col < mx.getColumnCount(); col++) 1046 { 1047 mx.setColumn(col, 0xff); 1048 delay(DELAYTIME / MAX_DEVICES); 1049 mx.setColumn(col, 0x00); 1050 } 1051} 1052 1053void cross() 1054// Combination of setRow() and setColumn() with user controlled 1055// display updates to ensure concurrent changes. 1056{ 1057 1058 mx.clear(); 1059 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 1060 1061 // diagonally down the display R to L 1062 for (uint8_t i = 0; i < ROW_SIZE; i++) 1063 { 1064 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1065 { 1066 mx.setColumn(j, i, 0xff); 1067 mx.setRow(j, i, 0xff); 1068 } 1069 mx.update(); 1070 delay(DELAYTIME); 1071 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1072 { 1073 mx.setColumn(j, i, 0x00); 1074 mx.setRow(j, i, 0x00); 1075 } 1076 } 1077 1078 // moving up the display on the R 1079 for (int8_t i = ROW_SIZE - 1; i >= 0; i--) 1080 { 1081 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1082 { 1083 mx.setColumn(j, i, 0xff); 1084 mx.setRow(j, ROW_SIZE - 1, 0xff); 1085 } 1086 mx.update(); 1087 delay(DELAYTIME); 1088 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1089 { 1090 mx.setColumn(j, i, 0x00); 1091 mx.setRow(j, ROW_SIZE - 1, 0x00); 1092 } 1093 } 1094 1095 // diagonally up the display L to R 1096 for (uint8_t i = 0; i < ROW_SIZE; i++) 1097 { 1098 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1099 { 1100 mx.setColumn(j, i, 0xff); 1101 mx.setRow(j, ROW_SIZE - 1 - i, 0xff); 1102 } 1103 mx.update(); 1104 delay(DELAYTIME); 1105 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1106 { 1107 mx.setColumn(j, i, 0x00); 1108 mx.setRow(j, ROW_SIZE - 1 - i, 0x00); 1109 } 1110 } 1111 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON); 1112} 1113 1114void bullseye() 1115// Demonstrate the use of buffer based repeated patterns 1116// across all devices. 1117{ 1118 1119 mx.clear(); 1120 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 1121 1122 for (uint8_t n = 0; n < 3; n++) 1123 { 1124 byte b = 0xff; 1125 int i = 0; 1126 1127 while (b != 0x00) 1128 { 1129 for (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1130 { 1131 mx.setRow(j, i, b); 1132 mx.setColumn(j, i, b); 1133 mx.setRow(j, ROW_SIZE - 1 - i, b); 1134 mx.setColumn(j, COL_SIZE - 1 - i, b); 1135 } 1136 mx.update(); 1137 delay(3 * DELAYTIME); 1138 for (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1139 { 1140 mx.setRow(j, i, 0); 1141 mx.setColumn(j, i, 0); 1142 mx.setRow(j, ROW_SIZE - 1 - i, 0); 1143 mx.setColumn(j, COL_SIZE - 1 - i, 0); 1144 } 1145 1146 bitClear(b, i); 1147 bitClear(b, 7 - i); 1148 i++; 1149 } 1150 1151 while (b != 0xff) 1152 { 1153 for (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1154 { 1155 mx.setRow(j, i, b); 1156 mx.setColumn(j, i, b); 1157 mx.setRow(j, ROW_SIZE - 1 - i, b); 1158 mx.setColumn(j, COL_SIZE - 1 - i, b); 1159 } 1160 mx.update(); 1161 delay(3 * DELAYTIME); 1162 for (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1163 { 1164 mx.setRow(j, i, 0); 1165 mx.setColumn(j, i, 0); 1166 mx.setRow(j, ROW_SIZE - 1 - i, 0); 1167 mx.setColumn(j, COL_SIZE - 1 - i, 0); 1168 } 1169 1170 i--; 1171 bitSet(b, i); 1172 bitSet(b, 7 - i); 1173 } 1174 } 1175 1176 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON); 1177} 1178 1179void spiral() 1180// setPoint() used to draw a spiral across the whole display 1181{ 1182 1183 int rmin = 0, rmax = ROW_SIZE - 1; 1184 int cmin = 0, cmax = (COL_SIZE * MAX_DEVICES) - 1; 1185 1186 mx.clear(); 1187 while ((rmax > rmin) && (cmax > cmin)) 1188 { 1189 // do row 1190 for (int i = cmin; i <= cmax; i++) 1191 { 1192 mx.setPoint(rmin, i, true); 1193 delay(DELAYTIME / MAX_DEVICES); 1194 } 1195 rmin++; 1196 1197 // do column 1198 for (uint8_t i = rmin; i <= rmax; i++) 1199 { 1200 mx.setPoint(i, cmax, true); 1201 delay(DELAYTIME / MAX_DEVICES); 1202 } 1203 cmax--; 1204 1205 // do row 1206 for (int i = cmax; i >= cmin; i--) 1207 { 1208 mx.setPoint(rmax, i, true); 1209 delay(DELAYTIME / MAX_DEVICES); 1210 } 1211 rmax--; 1212 1213 // do column 1214 for (uint8_t i = rmax; i >= rmin; i--) 1215 { 1216 mx.setPoint(i, cmin, true); 1217 delay(DELAYTIME / MAX_DEVICES); 1218 } 1219 cmin++; 1220 } 1221} 1222 1223void bounce() 1224// Animation of a bouncing ball 1225{ 1226 const int minC = 0; 1227 const int maxC = mx.getColumnCount() - 1; 1228 const int minR = 0; 1229 const int maxR = ROW_SIZE - 1; 1230 1231 int nCounter = 0; 1232 1233 int r = 0, c = 2; 1234 int8_t dR = 1, dC = 1; // delta row and column 1235 1236 1237 mx.clear(); 1238 1239 while (nCounter++ < 200) 1240 { 1241 mx.setPoint(r, c, false); 1242 r += dR; 1243 c += dC; 1244 mx.setPoint(r, c, true); 1245 delay(DELAYTIME / 2); 1246 1247 if ((r == minR) || (r == maxR)) 1248 dR = -dR; 1249 if ((c == minC) || (c == maxC)) 1250 dC = -dC; 1251 } 1252} 1253void stripe() 1254// Demonstrates animation of a diagonal stripe moving across the display 1255// with points plotted outside the display region ignored. 1256{ 1257 const uint16_t maxCol = MAX_DEVICES*ROW_SIZE; 1258 const uint8_t stripeWidth = 10; 1259 1260 mx.clear(); 1261 1262 for (uint16_t col=0; col<maxCol + ROW_SIZE + stripeWidth; col++) 1263 { 1264 for (uint8_t row=0; row < ROW_SIZE; row++) 1265 { 1266 mx.setPoint(row, col-row, true); 1267 mx.setPoint(row, col-row - stripeWidth, false); 1268 } 1269 delay(DELAYTIME); 1270 } 1271} 1272 1273void transformation1() 1274// Demonstrates the use of transform() to move bitmaps on the display 1275// In this case a user defined bitmap is created and animated. 1276{ 1277 uint8_t arrow[COL_SIZE] = 1278 { 1279 0b00001000, 1280 0b00011100, 1281 0b00111110, 1282 0b01111111, 1283 0b00011100, 1284 0b00011100, 1285 0b00111110, 1286 0b00000000 1287 }; 1288 1289 MD_MAX72XX::transformType_t t[] = 1290 { 1291 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1292 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1293 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1294 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1295 MD_MAX72XX::TFLR, 1296 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1297 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1298 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1299 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1300 MD_MAX72XX::TRC, 1301 MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, 1302 MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, 1303 MD_MAX72XX::TFUD, 1304 MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, 1305 MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, 1306 MD_MAX72XX::TINV, 1307 MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, 1308 MD_MAX72XX::TINV 1309 }; 1310 1311 // transformation 1312 1313 mx.clear(); 1314 1315 // use the arrow bitmap 1316 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 1317 for (uint8_t j=0; j<mx.getDeviceCount(); j++) 1318 mx.setBuffer(((j+1)*COL_SIZE)-1, COL_SIZE, arrow); 1319 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON); 1320 delay(DELAYTIME); 1321 1322 // run through the transformations 1323 mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::ON); 1324 for (uint8_t i=0; i<(sizeof(t)/sizeof(t[0])); i++) 1325 { 1326 mx.transform(t[i]); 1327 delay(DELAYTIME*4); 1328 } 1329 mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::OFF); 1330} 1331 1332void transformation2() 1333// Demonstrates the use of transform() to move bitmaps on the display 1334// In this case font characters are loaded into the display for animation. 1335{ 1336 MD_MAX72XX::transformType_t t[] = 1337 { 1338 MD_MAX72XX::TINV, 1339 MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, 1340 MD_MAX72XX::TINV, 1341 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1342 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1343 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1344 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1345 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1346 MD_MAX72XX::TSD, MD_MAX72XX::TSU, MD_MAX72XX::TSD, MD_MAX72XX::TSU, 1347 MD_MAX72XX::TFLR, MD_MAX72XX::TFLR, MD_MAX72XX::TFUD, MD_MAX72XX::TFUD 1348 };} 1349#endif //showoffcode// 1350
LED Matrix clock
arduino
Arduino code for clock
1 2 3 4/* 5 Clock project using two MX7219 matrix displays and 6 the AdaFruit FX Soundboard 7 Provides date, time, temp, humidity and event notifications 8 in rotating order 9 Also can chime in multiple ways, including Westminster chimes 10 11 Chimes are provided by Adafruit FX Soundboard in GPIO mode 12 13*/ 14 15 16 17 18// 19 Code to set up the clock 20// Pushbutton 1 is the toggler , cycle between year, 21 month, day, hours, minutes, seconds 22// Pushbutton 2 is the increment up one 23// 24 Pushbutton 3 is the decrement down one 25 26// Chime setup for toggle switch 27// 28 Center = No chimes 29// Up = Westminster hours + quarterly 30// Down = Simple 31 Bell (hours and 1/2 hour) 32 33// Comment out next line to leave out the 34 little show 35 36#define showoffcode // 37 include "show off" graphics at startup 38 39// include the libraries for LCD 40 Display, DHT-11 Temperature/humidity sensor and DS3231 RTC and 41// include libraries 42 for bigger seven segment display with backpack 43#include "DHT.h" 44#include 45 <Wire.h> 46#include "RTClib.h" 47#include <MD_MAX72xx.h> 48// uncomment next 49 two lines to use UART for SoundBoard rather than GPIO 50//#include <Adafruit_Soundboard.h> 51//#include 52 <SoftwareSerial.h> 53 54 55// Set up output functions 56 57#define DHTPIN 9 58 //Temp Humidity sensor on pin 9 59#define DHTTYPE DHT11 // DHT 11 because 60 the sensor is that type 61 62// Initialize DHT sensor for normal 16mhz Arduino 63DHT 64 dht(DHTPIN, DHTTYPE); 65 66// Initialize for Adafruit DS3231 RTC real time clock 67RTC_DS3231 68 rtc; 69 70// uncomment next set of lines to use UART for SoundBoard 71/* 72 73 // Choose any two pins that can be used with SoftwareSerial to RX & TX for UART 74 SoundBoard 75 //#define SFX_TX 5 76 //#define SFX_RX 6 77 // Connect to the 78 RST pin on the Sound Board 79 #define SFX_RST 4 80 // You can also monitor the 81 ACT pin for when audio is playing! 82 // we'll be using software serial 83 //SoftwareSerial 84 ss = SoftwareSerial(SFX_TX, SFX_RX); 85 // pass the software serial to Adafruit_soundboard, 86 the second 87 // argument is the debug port (not used really) and the third 88 89 // arg is the reset pin 90 //Adafruit_Soundboard sfx = Adafruit_Soundboard(&ss, 91 NULL, SFX_RST); 92 // can also try hardware serial with 93 // Adafruit_Soundboard 94 sfx = Adafruit_Soundboard(&Serial1, NULL, SFX_RST); 95*/ 96 97// Define the number 98 of devices we have in the chain and the hardware interface 99// NOTE: These pin 100 numbers will probably not work with your hardware and may 101// need to be adapted 102#define 103 HARDWARE_TYPE MD_MAX72XX::FC16_HW // NOTE: This parameter 104 differs by vendor 105#define MAX_DEVICES 8 // 106 2 x 4 matrices per unit 107 108//Pins for Arduino Uno 109//#define CLK_PIN 13 110 // or SCK (this is for the UNO, different for the Mega 111//#define DATA_PIN 112 11 // or MOSI 113//#define CS_PIN 10 // or SS 114 115 116//Pins for Arduino 117 Mega 118#define CLK_PIN 52 // or SCK 13 119#define DATA_PIN 51 // or MOSI 11 120#define 121 CS_PIN 53 // or SS 10 122 123 124// SPI hardware interface 125MD_MAX72XX mx = 126 MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); 127 128// We always wait a bit between 129 updates of the display 130#define DELAYTIME 100 // in milliseconds 131 132// 133 Text parameters 134#define CHAR_SPACING 1 // pixels between characters 135//const 136 int CHAR_PIXELS = 6; // Pixels taken by each character (including trailing 137 space) 138//const int MAX_CHARS = (MAX_DEVICES*COL_SIZE)/ CHAR_PIXELS; // Maximum 139 characters at once (happens to be 10 btw) 140//const int LEFT_OVER = (MAX_DEVICES*COL_SIZE)- 141 (CHAR_PIXELS*MAX_CHARS); //Since its not 'even' additional pad from front on 142 printText 143const int BufferStringLength = 31; 144char BufferString [BufferStringLength]; 145 //used to construct printouts 146#define DecToAscii 48 // 147 convert number to ascii (add as a constant) 148#define DegreeSign 0x0090 // 149 for display of 'degrees' after temperature 150int TDigits[4] = {0, 0, 0, 0}; // 151 used to convert four digits to four chacacters 152#define TDOnes 3 // 153 positions in arrays and templates 154#define TDTens 2 155#define TDHundreds 1 156#define 157 TDThousands 0 158#define sunday 0 // used for events, floating 159 events and holidays 160#define monday 1 // just for readability 161#define 162 thursday 4 163#define january 1 164#define february 2 165#define march 3 166#define 167 april 4 168#define may 5 169#define june 6 170#define july 7 171#define august 8 172#define 173 september 9 174#define october 10 175#define november 11 176#define december 12 177 178//Template 179 Strings and pointers 180 181const int LOTS = 13; // Length of 182 TimeString (without terminator) 183char TimeString[LOTS + 1 ] = {' ', ' ', '1', 184 '2', ':', '3', '1', ':', '4', '5', ' ', 'P', 'M', '\\0'}; 185char DateString[ ] 186 = {'1', '2', '/', '3', '1', '/', '2', '0', '1', '9', '\\0'}; 187char TempString[ 188 ] = {'T', 'e', 'm', 'p', ' ', '7', '2', '.', '0', DegreeSign, 'F', '\\0'}; 189char 190 HumidString[ ] = {'H', 'u', 'm', ' ', '2', '5', '.', '0', '%', '\\0'}; 191const 192 int THptr = 2; // Pointers within 193 the strings 194const int TMptr = 5; // 195 for loading values 196const int TSptr = 8; 197const int TAMPMptr = 11; 198const 199 int DMptr = 0; 200const int DDptr = 3; 201const int DYptr = 6; 202const int TEMPptr 203 = 5; 204const int HUMIDptr = 4; 205 206// Differentiated Displays 207 208const int 209 DisplayTime = 0; 210const int DisplayDate = 2; 211const int DisplayDOW = 1; 212const 213 int DisplayTemp = 3; 214const int DisplayHumid = 4; 215const int DisplayEvent = 216 5; 217const int DisplayEventRepeat = 2; //times to repeat 218 the scrolling 'event' display 219const int DisplaySize = 6; // 220 Nunber of different displays 221int DisplayIndex = DisplayTime; // 222 display we are on at the time 223const int DisplayDelayArray[DisplaySize] = {100, 224 50, 30, 30, 30, 20}; // multiplier for each event 225const int DisplayDelay = 100; 226 // milliseconds to leave each display * its multiplier 227unsigned 228 long DisplayTimer; // used to time each matrix display 229 230 231 232char 233 daysOfTheWeek[7][12 ] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", 234 "Friday", "Saturday"}; 235 236// Event arrays 237// Load with month of 'event', 238 day of event and description to be displayed 239 240const int eventnumber = 21; 241 // number of events and remember: No strings longer than 30 characters! 242int 243 eventmonth [eventnumber] = {june, april, november, february, july, december, november, 244 june, december, june, march, december, january, 245 september, 246 october, march, february, february, july,december, february}; 247int eventday [eventnumber] 248 = {11, 1, 23, 12, 4, 3, 12, 29, 25, 18, 17, 31, 1, 3, 31, 17, 14, 2, 14, 30,12}; 249char* 250 eventdescription [eventnumber] = 251{ "Dana's Anniversary", "April Fool's Day", 252 "Joan's Birthday", "Sydney's Birthday", "Happy July 4th!", "Dana's Birthday", 253 254 "David's Birthday", "Our Anniversary", "Merry Christmas", "Leah's Birthday", 255 "St Patrick's Day", "New Year's Eve", "New Year's Day", 256 "Forrest's Birthday", 257 "Happy Halloween", "Saint Patrick's Day", "Valentine's Day", "Groundhog Day", 258 "Bastille Day", "Linsey's Birthday", 259 "Irwin's Birthday" 260}; 261 262bool 263 event; // logic flag "on" = event found 264int eventindex; 265 // and the event we found 266const int maxevents = 3; // 267 maximum of three events (real and floating combined) 268char* eventstrings[maxevents] 269 ; // used to store displayed events 270String floatstring = " "; 271 // used for floating events (e.g., Thanksgiving) 272 273#define pb1pin 2 // 274 Pin assignments for reset, increment and decrement 275#define pb2pin 3 276#define 277 pb3pin 4 278 279#define showoffbuttonpin 7 // invoke 280 showing off the matrix display 281 282#define DoWestminster 5 283#define DoHoursOnly 284 6 285#define silent 0 // no chiming at all 286#define 287 hoursonly 1 // no prelude, just chime number of hours 288 and half hour single chime 289#define westminster 2 // 290 hours + Westminster prelude per quarter 291int ChimeValue = silent; // 292 default to silent 293 294 295const int LEDpin = A0; // 296 Pin assignment for analog reading LDR for LED brightness 297const int minbright 298 = 0; // MAX_BRIGHT for this module is 15 299const int midbright = 2; 300 // but these values "seem" to work 301const int maxbright = 4; 302 303 304 305 306int 307 setupindex = 0; // first thing to set if required 308bool insetupmode 309 = false; // and assume RTC is set, OK, etc., and no 'set' required 310bool 311 setinsetup = false; // flag set to true at interrupt level to go back 312 into setup mode 313 314// date time array for setting, reading, displaying 315 316#define 317 setsize 6 // size of the setting array 318#define setyear 0 // 319 index name for each element 320#define setmonth 1 321#define setday 2 322#define 323 sethour 3 324#define setminute 4 325#define setsecond 5 326 327int setarray 328 [setsize] = {2019, 1, 1, 1, 1, 0}; // set year, month, day, hour, minutes, seconds 329int 330 lowlimit [setsize] = {2019, 1, 1, 0, 1, 0}; // lower limit for each 331int highlimit 332 [setsize] = {2080, 12, 31, 23, 59, 59}; //high limit for each 333const int setdesclength 334 = 4; // maximum length of 'set' descriptor 335char setdesc 336 [setsize] [setdesclength] = {"Yr ", "Mon", "Day", "Hr ", "Min", "Sec"}; 337 338 339#define 340 cqtr0 1 // Chime the hour 341#define cqtr1 2 // Chime the quarter 342 hour 343#define cqtr2 3 // Chime the half hour 344#define cqtr3 4 // 345 Chime the 3/4 hour 346 347// Definitions for the Sound Board 348#define SoundTruncatedSingle 349 0 // Truncated Single Westminster 350#define SoundQ1 1 // 351 First Quarter 352#define SoundQ2 2 // Second Quarter 353#define 354 SoundQ3 3 // Third 355#define SoundQ4 4 // 356 Fourth (before hour chime) 357#define SoundTrailingSingle 5 // 358 Finish Westminster string of chimes with longer sound tail 359#define SoundTruncatedBell 360 6 // Simple Bell 361#define SoundTrailingBell 7 // 362 Final Bell (like single, has longer 'tail') 363#define SoundStartup 8 // 364 startup sound 365#define SoundShowOff 9 // Play during 366 show off of matrix 367#define FirstSoundPin 30 // first pin 368 to use for soundboard (0-10 available on soundboard); 369#define SizeSoundPin 10 370 // number of pins used (must be consecutive) 371#define 372 fxset 150 // Time soundboard must be held LOW to 373 register (documentation says 125 ms) 374#define SoundBusyPin 8 // 375 Soundboard pin that goes LOW when board is active 376 377const int SizeQueue = 15; 378 // Assume Q4+12 bells is the maximum that'll be in the 379 queue at any point 380int SoundQueue[SizeQueue]; // Circular 381 Queue for waiting sounds 382int SoundQueuePtr = -1; //pointer 383 for Queue fill Position 384int SoundPlayPtr = -1; //pointer 385 for Queue play Position 386int SoundQueueCtr = 0; // 387 number of items in the queue 388 389int setstrike = -1; // 390 Chime/strike flag 391byte alreadychimed = false ; // Used to keep 392 from chiming multiple times during the "hot" second 393const int BounceDelay = 394 250; // Not really 'bounce', its a change of state detection 395 396 397 398int 399 i; // generic index variable 400 401int dayoftheweek; // 402 stored day of the week (0-6, 0 = Sunday) 403 404int phours; // 405 for print conversion of military time 406 407float temperaturef; // 408 farenheit temperature back 409int temperature; // integer version 410 of temperature for matrix 411float temperaturec; // centrigade temperature 412 back (not used) 413 414float humidityf; // and humidity 415int humidity 416 ; // and same as temp 417 418float tempadjust = -2.0; // temperature 419 adjustment for sensor (I found it didn't read right against 'comps') 420byte degreesymbol 421 = 223; // LCD output of 'degree' symbol 422 423#define DDT 424 425#ifdef DDT // 426 debugging tools 427void DDTl(String st, int vt) { // Print descriptor 428 and value and new line 429 DDTs(st, vt); 430 Serial.println(" "); 431} 432void 433 DDTs(String st, int vt) { // Print descriptor and value 434 435 Serial.print(" "); 436 Serial.print(st); 437 Serial.print(" "); 438 Serial.print(vt); 439} 440#endif 441 //DDT// 442 443 444void setup() 445// put your setup code here, to run once: 446 447{ 448 449 Wire.begin(); // initialize I2C interface 450 dht.begin(); 451 // initialize the temp/humidity sensor 452 mx.begin(); // 453 and MX7219 display 454 Serial.begin (9600); //Terminal monitor printing 455 for debugging 456 457 // softwareserial at 9600 baud (uncomment this line and next 458 for UART control of sound board 459 // ss.begin(9600); 460 461 462 pinMode(pb1pin, 463 INPUT_PULLUP); // The three pushbuttons - reset 464 pinMode(pb2pin, INPUT_PULLUP); 465 // increment 466 pinMode(pb3pin, INPUT_PULLUP); // decrement 467 468 pinMode 469 (DoWestminster, INPUT_PULLUP); // When pulled 'low' we want Westminster 470 chimes 471 pinMode (DoHoursOnly , INPUT_PULLUP); // When pulled 'low' 472 we want hours and 1/2 bell (neither is 'silent') 473 474 #ifdef showoffcode 475 476 pinMode(showoffbuttonpin, INPUT_PULLUP) ; // if show off matrix 477 is there, initialize pin 478 #endif //showoffcode// 479 480 for (i = FirstSoundPin; 481 i < FirstSoundPin + SizeSoundPin; i++) { // pins for sound board 482 pinMode(i, 483 OUTPUT); // each an output 484 digitalWrite(i, 485 HIGH); // and initialize high (off) 486 487 } 488 489 // set up interupt for PB1 // 490 if PB1 is pushed, it'll pick up on next release from Matrix display 491 attachInterrupt(digitalPinToInterrupt(pb1pin), 492 SetToSetup, FALLING); // and re-enter setup mode (after the end of current display) 493 494#ifdef 495 showoffcode 496// ShowOff(); // Show off a 497 little (uncomment to give initial showoff at beginning) 498#endif //showoffcode// 499 500 501 QueueSound(SoundStartup); // play boot up sound 502 503 PlaySound(); 504 505 if (! rtc.begin()) { // check 506 that clock is there 507 scrollText("Couldn't find RTC"); // clock missing 508 is a fatal error 509 while (1); 510 } 511 512 if (rtc.lostPower()) { // 513 if power lost force a setup, else load 'current' values and 514 scrollText("RTC 515 lost power!"); 516 delay(1000); 517 scrollText("Replace battery?"); 518 519 delay(1000); 520 scrollText("Setup Mode: "); 521 setupindex = setyear 522 - 1; // setup differently (becuase it will increment) 523 insetupmode 524 = true; 525 for (i = 0; i < setsize; i++) { 526 setarray[i] = lowlimit[i]; 527 528 } 529 } else // else 530 reload from RTC 531 { DateTime (setarray[setyear], setarray[setmonth], setarray[setday], 532 setarray[sethour], setarray[setminute], setarray[setsecond]) = rtc.now(); 533 insetupmode 534 = false; // not in setup 535 mode, and 536 setinsetup = false; //no 537 interrupt 538 } 539 540 // Two alternative modes of setting date and time (for 541 debugging, just un-comment): 542 // This line sets the RTC to the date & time this 543 sketch was compiled 544 // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 545 546 // This line sets the RTC with an explicit date & time, for example to set 547 548 // January 21, 2014 at 3am you would call: 549 // rtc.adjust(DateTime(2014, 550 1, 21, 3, 0, 0)); 551 LEDBrightness(); // 552 Do an initial check for room brightness 553} // end of setup 554 555void loop() 556 { // Main code divided 557 into setup mode and non-setup mode 558 559 while (insetupmode) { // 560 code for setting time, date set, etc. 561 562 // Read the increment button 563 564 565 if (digitalRead(pb2pin) == LOW) { 566 setarray[setupindex]++; // 567 read increment of current item 568 delay(BounceDelay); 569 if (setarray[setupindex] 570 > highlimit[setupindex]) { 571 setarray[setupindex] = lowlimit[setupindex]; 572 573 } 574 ShowValue(setupindex, setdesc[setupindex]); // 575 and display description and value 576 } 577 578 // Read the decrement Button 579 580 if (digitalRead(pb3pin) == LOW) { 581 setarray[setupindex]--; // 582 read decrement of value 583 delay(BounceDelay); 584 if (setarray[setupindex] 585 < lowlimit[setupindex]) { 586 setarray[setupindex] = highlimit[setupindex]; 587 588 } 589 ShowValue(setupindex, setdesc[setupindex]); // 590 and display description and value 591 } 592 593 // Read for another increment 594 of index 595 596 if (digitalRead(pb1pin) == LOW) { // Rolling through 597 Chime, Year, Month, Day, Hour, Minutes, Seconds 598 setupindex++ ; // 599 increment index 600 delay(BounceDelay); 601 if (setupindex < setsize) 602 { 603 ShowValue(setupindex, setdesc[setupindex]); // show description and 604 value if in bounds 605 } 606 if (setupindex >= setsize) { // 607 and finally exiting setup mode after setting chime, date and time 608 rtc.adjust(DateTime(setarray[setyear], 609 setarray[setmonth], setarray[setday], setarray[sethour], setarray[setminute], setarray[setsecond])); 610 611 insetupmode = false; 612 DisplayIndex = DisplayTime; 613 } //exit 614 setup mode when done 615 } 616 617 } // End of "While" for setup 618 619 620 // Begin regular loop for date, time, temp humidity and event display 621 622 623 while (!insetupmode) { 624 625 GetTempandHumid(); // 626 read temperature and humidity from sensor 627 628 ChimeValue = ReadChimeSetting(); 629 // read SPDT Center off switch for silent, westminster 630 or hours only (and 1/2) 631 632 GetTheDate(); // 633 load date array from RTC for a chime/bell check 634 635 CheckForChime(); 636 // Check for a chime event between 637 displays 638 639 CheckForEvent(setarray[setmonth], setarray[setday], dayoftheweek); 640 // check for static and floating events 641 642 MatrixDisplay(); 643 // Do whatever display is required 644 on the MX7219 645 646 LEDBrightness(); // 647 Good place to check for change in room brightness 648 649 // end of display update 650 logic 651 652 // Read a potential request for an entry into setup from PB 1 653 654 if ((digitalRead(pb1pin) == LOW) || setinsetup) { // to see if 655 we go back to setup mode 656 insetupmode = true; // 657 via a pushbutton or the interrupt 658 setinsetup = false; // 659 clear the interrupt flag 660 setupindex = 0; // 661 re-initialize to 'Year' in setup 662 DisplayIndex = DisplayTime; // 663 and go back to time display when exit setup 664 scrollText("Setup Mode: "); 665 666 delay(2000); 667 ShowValue(setupindex, setdesc[setupindex]); // 668 show the first setup item (Year) 669 delay(BounceDelay); 670 } 671 #ifdef 672 showoffcode 673 if (digitalRead(showoffbuttonpin) == LOW) {ShowOff();} // 674 check for want to show off matrix 675 #endif //showoffcode// 676 677 } // 678 end of not in setup 679} // end of sketch 680 681void MatrixDisplay() { // 682 Main display routine for display sequences 683 684 Scrollup(); // 685 Clear last display 686 if (DisplayIndex >= DisplaySize) { 687 DisplayIndex = 688 DisplayTime; // reset if at the end 689 } 690 DisplayTimer = DisplayDelayArray[DisplayIndex] 691 * DisplayDelay; // set individual display time 692 693 switch (DisplayIndex) 694 { // and do next display 695 696 697 case DisplayTime: // Dislay the time 698 do // 699 time is different in that there's a constant 700 { // 701 update of time during display and also play chime, bell etc. 702 GetTheDate(); 703 // Get Current Time 704 705 CheckForChime(); // 706 Check for a chime event 707 LoadNumber(phours); // 708 Load the 4 digit character array from number 709 TimeString[THptr] = TDigits[TDTens]; 710 // left digit of the two digit hour 711 712 TimeString[THptr + 1] = TDigits[TDOnes]; // 713 rightmost digit 714 if (TimeString[THptr] == '0') { 715 TimeString[THptr] 716 = ' '; // eliminate leading zero 717 } 718 LoadNumber(setarray[setminute]); 719 // do same for minutes 720 TimeString[TMptr] 721 = TDigits[TDTens]; // except no need to 722 do space for zero 723 TimeString[TMptr + 1] = TDigits[TDOnes]; 724 LoadNumber(setarray[setsecond]); 725 // seconds then 726 TimeString[TSptr] 727 = TDigits[TDTens]; 728 TimeString[TSptr + 1] = TDigits[TDOnes]; 729 if 730 (setarray[sethour] < 12) // and 731 AM vs PM 732 { 733 TimeString[TAMPMptr] = 'A'; 734 } 735 736 else 737 { 738 TimeString[TAMPMptr] = 'P'; 739 } 740 741 printText(TimeString, LOTS, false); // 742 Keep position (no centering) because time keeps updating during display and chimes 743 744 PlaySound(); // 745 Play any chimes or bells 746 if (SoundQueueCtr == 0) { 747 DisplayTimer 748 = DisplayTimer - DisplayDelay; // if no sound, use display delay logic 749 750 delay(DisplayDelay); 751 } 752 } while ((DisplayTimer > 0) 753 || (SoundQueueCtr > 0)); // leave this display when no sound 754 or no delay left 755 DisplayIndex++ ; // 756 then move on to next display item 757 break; 758 759 case DisplayDate: // 760 Month, Day and Year Display 761 LoadNumber(setarray[setmonth]); 762 DateString[DMptr] 763 = TDigits[TDTens]; 764 if (DateString[DMptr] == '0') { 765 DateString[DMptr] 766 = ' '; 767 } 768 DateString[DMptr + 1] = TDigits[TDOnes]; 769 LoadNumber(setarray[setday]); 770 771 DateString[DDptr] = TDigits[TDTens]; 772 DateString[DDptr + 1] = TDigits[TDOnes]; 773 774 LoadNumber(setarray[setyear]); 775 for (int i = 0; i < 4; i++) { 776 777 DateString[DYptr + i] = TDigits[i]; 778 } 779 printCenter(DateString); 780 781 CommonDelay(DisplayTimer); 782 DisplayIndex++ ; 783 break; 784 785 786 case DisplayDOW: // 787 Just display the day of week string 788 printCenter(daysOfTheWeek[dayoftheweek]); 789 790 CommonDelay(DisplayTimer); 791 DisplayIndex++ ; 792 break; 793 794 795 case DisplayTemp: // 796 Temperature display 797 LoadNumber(temperature); 798 TempString[TEMPptr] 799 = TDigits[TDHundreds]; 800 TempString[TEMPptr + 1] = TDigits[TDTens]; 801 TempString[TEMPptr 802 + 3] = TDigits[TDOnes]; 803 printCenter(TempString); 804 CommonDelay(DisplayTimer); 805 806 DisplayIndex++ ; 807 break; 808 809 case DisplayHumid: // 810 Humidity display 811 LoadNumber(humidity); 812 HumidString[HUMIDptr] = 813 TDigits[TDHundreds]; 814 HumidString[HUMIDptr + 1] = TDigits[TDTens]; 815 HumidString[HUMIDptr 816 + 3] = TDigits[TDOnes]; 817 printCenter(HumidString); 818 CommonDelay(DisplayTimer); 819 820 DisplayIndex++ ; 821 break; 822 823 case DisplayEvent: // 824 Event Display 825 if (event) { // 826 "Real" events repeat 3 times 827 if (eventindex > 0 ) { // 828 for case where there is more than one event 829 while (eventindex 830 >= 0) 831 {scrollText(eventstrings[eventindex]); // 832 scroll each of them once 833 if (eventindex > 0) { 834 delay(DisplayDelay 835 * 6); 836 printCenter("and"); 837 delay(DisplayDelay 838 * 6);} 839 eventindex--; // 840 and decrement 841 delay(DisplayDelay * 2); 842 } 843 844 } 845 else { // 846 case of only one event -- repeat it for readability 847 for (int i = 848 1; i <= DisplayEventRepeat; i++) { // scroll either static or floating 849 event 850 scrollText(eventstrings[eventindex]); // 851 the index is 0 (greater than zero if multiple events) 852 } 853 delay(DisplayDelay 854 * 2); 855 } 856 } // 857 end of "if event" logic 858 if (!event){ // 859 Scroll Default message only once 860 if (setarray[sethour] >= 6 && 861 setarray[sethour] <= 11) { 862 scrollText("Good Morning ");} 863 864 else if (setarray[sethour] >= 12 && setarray[sethour] <= 16) { 865 866 scrollText("Good Afternoon");} 867 else if (setarray[sethour] 868 >= 17 && setarray[sethour] <= 21) { 869 scrollText("Good Evening");} 870 else{scrollText("Good Night"); } 871 } 872 873 CommonDelay(DisplayTimer); 874 DisplayIndex++ ; 875 break; 876 877 878 default: 879 scrollText("Should never get here"); 880 while (1); 881 882 883 } // End of Switch 884 885} // End of MatrixDisplay 886 887void GetTheDate() 888 { // Read RTC into array 889 890 DateTime now = rtc.now(); 891 setarray[setyear] = now.year(); 892 setarray[setmonth] 893 = now.month(); 894 setarray[setday] = now.day(); 895 setarray[sethour] = now.hour(); 896 897 setarray[setminute] = now.minute(); 898 setarray[setsecond] = now.second(); 899 900 dayoftheweek = now.dayOfTheWeek(); 901 if (setarray[sethour] <= 12) // 902 convert military time to am pm 903 { 904 phours = setarray[sethour]; 905 } 906 907 else 908 {phours = setarray[sethour] - 12;} 909 if (phours <= 0) { phours = 910 12; } // don't print 0 for midnite, print "12" 911 912} // End 913 of Get The Date 914 915void GetTempandHumid(){ // Temperature 916 and humidity update 917 918 // Sensor readings may also be up to 2 seconds 'old' 919 (its a very slow sensor) 920 humidityf = dht.readHumidity(); 921 922 // Read 923 temperature as Fahrenheit 924 temperaturef = (dht.readTemperature(true)) + tempadjust; 925 // read and correct for inaccuracy in sensor 926 927 // Check if any reads 928 failed and exit early (to try again). 929 if (isnan(humidityf) || isnan(temperaturec) 930 || isnan(temperaturef)) { 931 temperaturef = 0; // use 0 as a 932 no-read 933 humidityf = 0; // error indication 934 } 935 936 temperature = temperaturef * 10.0; // get read for matrix printout 937 938 humidity = humidityf * 10.0; 939} // end of Temperature and Humidity update 940 941void 942 SetToSetup() { // interrupt level back to setup 943 944 if ((!insetupmode) && (!setinsetup)) { // skip if 945 we are already in Setup mode or have seen the interrupt 946 setinsetup = true; 947 // Go back into setup at next loop 948 DisplayTimer 949 = 0; 950 } // and zero the timer to speed that up 951 if you can 952} // SetToSetup 953 954void CommonDelay(long int MyDelay) { // 955 Common delay routine 956 DisplayTimer = MyDelay; 957 do { 958 DisplayTimer 959 = DisplayTimer - DisplayDelay; 960 delay(DisplayDelay); 961 GetTheDate(); 962 // load date array from RTC for 963 a chime/bell check 964 CheckForChime(); // 965 if a chime happens, setup to end delay 966 } while ((DisplayTimer > 0) && (!setinsetup) 967 && (SoundQueueCtr <= 0)); // repeat while still time and no interrupt and no 968 sound waiting 969 if (SoundQueueCtr > 0){DisplayIndex = DisplayTime-1;} // 970 if leaving due to chime, go directly to time 971} // End of CommonDelay 972 973 974int 975 ReadChimeSetting() { 976 int returnvalue = silent; // Assume 977 'silent' (Center position) 978 if (digitalRead(DoWestminster) == LOW) { 979 returnvalue 980 = westminster; 981 } else if (digitalRead(DoHoursOnly) == LOW) { 982 returnvalue 983 = hoursonly; 984 } 985 return returnvalue; 986} 987 988// Routine to deal with 989 combinations of chime type, time of day and the current hour 990// called parameters 991 are chime type (e.g., Westminster), Strike type (hour, qtr, half, 3/4) and the hour 992 in military time 993// Note for delays and print cycles: You need to call this at 994 least once during the 'golden' minute (0,15,30,45) 995 996void CheckForChime() { 997 // Logic for chiming 998 999 setstrike = -1; // 1000 initialize 'strike' flag to "no strike" 1001 1002 if (ChimeValue != silent) // 1003 if silenced due to setting silent, skip the whole thing 1004 { 1005 if (setarray[setminute] 1006 == 0) { // Look for 'on the hour' 1007 setstrike = cqtr0; 1008 } else 1009 if (setarray[setminute] == 15 ) { // Look for on the quarter hour 1010 setstrike 1011 = cqtr1; 1012 } else if (setarray[setminute] == 30 ) { // Look for on the 1/2 1013 hour 1014 setstrike = cqtr2; 1015 } 1016 else if (setarray[setminute] == 1017 45 ) { // Look for on the three-quarter hour 1018 setstrike = cqtr3; 1019 } 1020 1021 else { 1022 alreadychimed = false; // none of the above, reset ability to 1023 chime 1024 } 1025 1026 if (setstrike > 0 && !alreadychimed ) { 1027 chime(ChimeValue, 1028 setstrike, setarray[sethour]); // call chiming with 'type of chime'; 0,15,30,45 1029 ; and # hours 1030 DisplayIndex = DisplayTime; // 1031 force display of time while chiming 1032 alreadychimed = true; // 1033 we will be here multiple times but only chime once 1034 } 1035 } // end 1036 of logic for chiming 1037} // end of CheckForChime 1038 1039void chime (int chimetype, 1040 int strikeflag, int chour) { 1041 1042 int chour1; // 1043 am pm variable\\ 1044 1045 if (chour <= 12) { 1046 chour1 = chour; // convert military 1047 time to am pm 1048 } else { 1049 chour1 = chour - 12; 1050 } 1051 1052 1053 if 1054 (chour1 <= 0) { 1055 chour1 = 12; // don't chime 0 for midnite, chime 12 1056 } 1057 1058 if (chimetype == hoursonly && strikeflag == cqtr2) { 1059 QueueSound(SoundTrailingBell); 1060 // 1/2 hour only, do single 'ding' 1061 } 1062 else if ( chimetype == hoursonly 1063 && strikeflag == cqtr0) { 1064 for (int i = 1; i < chour1; i++) { 1065 QueueSound(SoundTruncatedBell); 1066 // Ding once less than hours 1067 } 1068 QueueSound(SoundTrailingBell); 1069 1070 } // and follow by trailing bell 1071 as last 'ding' (if used) 1072 else if (((chimetype == westminster) ) && strikeflag 1073 == cqtr1) { 1074 QueueSound(SoundQ1); // First Quarter 1075 } 1076 else if (((chimetype 1077 == westminster) ) && strikeflag == cqtr2) { 1078 QueueSound(SoundQ2); // Second 1079 Quarter 1080 } 1081 else if (((chimetype == westminster)) && strikeflag == cqtr3) 1082 { 1083 QueueSound(SoundQ3); // Third Quarter 1084 } 1085 else if (((chimetype 1086 == westminster)) && strikeflag == cqtr0) { 1087 QueueSound(SoundQ4); 1088 for 1089 (int i = 1; i < chour1; i++) { 1090 QueueSound(SoundTruncatedSingle); // Chime 1091 once less than hours 1092 } 1093 QueueSound(SoundTrailingSingle); 1094 } // 1095 Chime Westminster final hours 1096 1097 1098} // end of Chime 1099 1100 1101// Routine 1102 to check for 'real' (static) events and floating events (e.g., Memorial Day, Thanksgiving, 1103 Mother's Day and Fathers Day) 1104 1105/* Memorial Day is Last Monday in May 1106 Thanksgiving 1107 is 4th Thursday in November 1108 Mother's Day is 2nd Sunday in May 1109 Father's 1110 Day is 3rd Sunday in June 1111 MLK Day is 3rd Monday in February 1112 Memorial 1113 Day is last Monday in May 1114 Labor Day is first Monday in September 1115 Daylight 1116 Savings Times starts 2nd Sunday in March 1117 Daylight Savings Times ends first 1118 Sunday in November 1119 Indigenous People's Day is second Monday in October (also 1120 its Columbus Day) 1121 1122*/ 1123 1124void CheckForEvent(int m, int d, int dow) { // 1125 called with Month, Day within month and day of the week (0 = Sunday) 1126 1127 event 1128 = false; // assume neither 1129 static or floating 1130 eventindex = -1; // 1131 initial index to eventstrings 1132 1133 // Static event check 1134 1135 1136 for (int i = 0; i < eventnumber; i++) { // 1137 then check the static events 1138 if ((setarray[setmonth] == eventmonth[i]) 1139 && (setarray[setday] == eventday[i])) 1140 { event = true; // 1141 set if match on month and day 1142 eventindex++; // 1143 found one! 1144 eventstrings[eventindex] = eventdescription[i]; // 1145 store pointer to static event description 1146 } 1147 } 1148 1149 // Floating 1150 event check 1151 1152 floatstring = "none"; // 1153 initialize string 1154 1155 if ((dow == thursday) && (m == november) && (d >= 1156 22) && (d <= 28)) { // Thanksgiving 1157 floatstring = 1158 "Thanksgiving"; 1159 } 1160 else if ((dow == sunday) && (m == may) && (d >= 8) 1161 && (d <= 14)) { // Mother's Day 1162 floatstring = "Mother's 1163 Day"; 1164 } 1165 else if ((dow == sunday) && (m == june) && (d >= 15) && (d <= 1166 21)) { //Father's Day 1167 floatstring = "Father's Day"; 1168 1169 } 1170 else if ((dow == monday) && (m == january) && (d >= 15) && (d <= 21)) { 1171 //MLK Day 1172 floatstring = "Martin Luther King Day"; 1173 } 1174 1175 else if ((dow == monday) && (m == february) && (d >= 15) && (d <= 21)) { //President's 1176 Day 1177 floatstring = "President's Day!"; 1178 } 1179 else if ((dow == monday) 1180 && (m == september) && (d <= 7) ) { //Labor Day 1181 floatstring 1182 = "Labor Day"; 1183 } 1184 else if ((dow == monday) && (m == october) && (d >= 1185 8) && (d <= 14) ) { //Indigenous People's Day 1186 floatstring 1187 = "Indigenous People's Day"; 1188 } 1189 else if ((dow == monday) && (m == may) 1190 && (d + 7 > 31) ) { //Memorial Day 1191 floatstring = "Memorial 1192 Day"; 1193 } 1194 else if ((dow == sunday) && (m == march) && (d >= 8) && (d <= 1195 14)) { // DST begins 1196 floatstring = "DST Begins"; 1197 } 1198 1199 else if ((dow == sunday) && (m == november) && (d <= 7) ) { //DST 1200 ends 1201 floatstring = "DST Ends"; 1202 } 1203 1204 if (floatstring != "none" 1205 ) { // did we load anything? 1206 event 1207 = true; // if so, then 1208 we have one 1209 eventindex++; // 1210 so load it into event display queue 1211 eventstrings[eventindex] = floatstring.c_str(); 1212 // store pointer to static event description 1213 } 1214 1215} 1216 // end of floatingevent 1217 1218void LEDBrightness() { 1219 int LEDvalue; 1220 LEDvalue 1221 = analogRead(LEDpin); // Read LDR value 1222 (may need to play with values) 1223 DDTs("LED value",LEDvalue); 1224 LEDvalue 1225 = map(LEDvalue, 0, 1023, 0, MAX_INTENSITY); //map to valid value for 1226 brightness (max intensity is 15 btw) 1227 if (LEDvalue <= 11) { 1228 mx.control(MD_MAX72XX::INTENSITY, 1229 minbright);} 1230 else if (LEDvalue > 13 ) { 1231 mx.control(MD_MAX72XX::INTENSITY, 1232 maxbright); } 1233 else 1234 {mx.control(MD_MAX72XX::INTENSITY, midbright); } 1235 1236 DDTl("Mapped LED value", LEDvalue); 1237 1238 1239 1240} //end of LEDbrightness 1241 1242void 1243 Scrollup() { // 1244 used to 'wipe' previous display 1245 for (uint8_t i = 0; i < 8; i++) { 1246 mx.transform(MD_MAX72XX::TSU); 1247 delay(2 * DELAYTIME); 1248 delay(DELAYTIME); 1249 } 1250} // End of Scrollup 1251 1252 1253void 1254 scrollText(char *p) // 1255 copied from library 1256{ 1257 uint8_t charWidth; 1258 uint8_t cBuf[8]; // this 1259 should be ok for all built-in fonts 1260 mx.clear(); 1261 while (*p != '\\0') 1262 1263 { 1264 charWidth = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf); 1265 1266 1267 for (uint8_t i = 0; i <= charWidth; i++) // allow space between characters 1268 1269 {mx.transform(MD_MAX72XX::TSL); 1270 if (i < charWidth) 1271 mx.setColumn(0, 1272 cBuf[i]); 1273 delay(DELAYTIME);} 1274 } 1275} // End of Scroll Text 1276 1277void 1278 printText(char *pMsg, int LOS, bool CenterJustify) // 1279 copied and modified from library 1280// Print the text string to the LED matrix modules 1281 specified. 1282// Message area is padded with blank columns after printing. 1283// 1284 And center justified if third argument is "true" 1285{ 1286 uint8_t modStart = 1287 0; 1288 uint8_t modEnd = MAX_DEVICES - 1; 1289 uint8_t state = 0; 1290 uint8_t 1291 curLen; 1292 uint16_t showLen; 1293 uint8_t cBuf[8]; 1294 int16_t col = 1295 ((modEnd + 1) * COL_SIZE) - 1; 1296 int pixelcount = 0; 1297 int ccounter = LOS; 1298 1299 1300 mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 1301 1302 do 1303 // finite state machine to print the characters in the space available 1304 1305 { switch (state) 1306 { 1307 case 0: // Load the next character from the 1308 font table 1309 // if we reached end of message, reset the message pointer 1310 1311 if (*pMsg == '\\0') 1312 { 1313 showLen = col - (modEnd * 1314 COL_SIZE); // padding characters 1315 state = 2; 1316 break; 1317 1318 } 1319 1320 // retrieve the next character form the font file 1321 1322 1323 showLen = mx.getChar(*pMsg++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf); 1324 1325 if (ccounter > 0) { 1326 pixelcount = (pixelcount + showLen) + CHAR_SPACING; 1327 1328 ccounter--; 1329 } 1330 curLen = 0; 1331 state++; 1332 1333 // !! deliberately fall through to next state to start displaying 1334 1335 1336 case 1: // display the next part of the character 1337 mx.setColumn(col--, 1338 cBuf[curLen++]); 1339 1340 // done with font character, now display the space 1341 between chars 1342 if (curLen == showLen) 1343 { 1344 showLen 1345 = CHAR_SPACING; 1346 state = 2; 1347 } 1348 break; 1349 1350 case 1351 2: // initialize state for displaying empty columns 1352 1353 curLen = 0; 1354 1355 1356 state++; 1357 // fall through 1358 1359 case 3: // display inter-character 1360 spacing or end of message padding (blank columns) 1361 mx.setColumn(col--, 1362 0); 1363 curLen++; 1364 if (curLen == showLen) 1365 state = 1366 0; 1367 break; 1368 1369 default: 1370 col = -1; // this definitely 1371 ends the do loop 1372 } 1373 } while (col >= (modStart * COL_SIZE)); 1374 1375 if 1376 (CenterJustify) { 1377 for (int i = 1; i <= (((MAX_DEVICES * COL_SIZE) - pixelcount) 1378 / 2); i++) { 1379 mx.transform( MD_MAX72XX::TSR); 1380 } 1381 } 1382 mx.control(modStart, 1383 modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON); 1384} 1385void printCenter(String StringtoPrint) 1386 // Loads the print buffer and centers it 1387{ 1388 1389 int LOS = StringtoPrint.length(); // 1390 Get the string's length 1391 for (int i = 0; i < BufferStringLength; i++) { 1392 1393 BufferString[i] = ' '; // clear buffer 1394 } 1395 for (int i = 0; i < LOS; 1396 i++) { 1397 BufferString[i] = StringtoPrint[i]; // transfer 1398 printText(BufferString, 1399 LOS, true); // Print, providing length of 1400 string and "Yes, center" 1401 1402 } 1403} // End of Center and Load 1404 1405void 1406 ShowValue(int myindex, String setdescription) // 1407 Display while in setup mode 1408{ // 1409 shows what item is setting and its value 1410 1411 for (int i = 0; i < BufferStringLength; 1412 i++) {BufferString[i] = ' ';} // clear buffer 1413 setdescription.toCharArray(BufferString, 1414 setdesclength); // move description to output 1415 buffer 1416 LoadNumber(setarray[setupindex]); 1417 BufferString[setdesclength-1] 1418 = ' '; 1419 for (int i = 0; i <setdesclength; i++) {BufferString[i + setdesclength] 1420 = TDigits[i];} 1421 if (myindex != setyear) { // 1422 only the year is 4 digits, else 2 1423 BufferString[4] = ' '; 1424 1425 BufferString[5] = ' '; 1426 if (BufferString[6] == '0') {BufferString[6] = 1427 ' ';} // and suppress leading 0 for 2 digit numbers 1428 too 1429 } 1430 BufferString[8] = '\\0'; // 1431 and terminate 1432 printText(BufferString, 7, false); 1433 1434 1435} // End of Show 1436 Value 1437 1438void LoadNumber(int numtoload) { // 1439 Converts number to four digit Ascii array 1440 int tempnum = numtoload; 1441 for 1442 (int i = 3; i >= 0; i--) { 1443 TDigits[i] = (tempnum % 10) + DecToAscii;; 1444 1445 tempnum = tempnum / 10; 1446 } 1447} // end of LoadNumber 1448 1449void QueueSound(int 1450 SoundFile) { // place a sound to be played 1451 into sequence 1452 1453 if ((SoundQueuePtr == SizeQueue) || (SoundQueueCtr <= 0)) 1454 { 1455 SoundQueuePtr = -1; // Dont overflow the queue 1456 } 1457 SoundQueuePtr++; 1458 // Increment pointer 1459 SoundQueue[SoundQueuePtr] 1460 = SoundFile; // and store the sound chosen 1461 SoundQueueCtr++; 1462 // and increment # sounds in queue 1463} 1464 // end of Queue Sound File 1465 1466void PlaySound() { // 1467 Plays appropriate Sound file 1468 if (SoundQueueCtr > 0) { // 1469 if nothing in the queue, just return 1470 if (digitalRead(SoundBusyPin) == LOW) 1471 { //or if sound card busy, just return 1472 return; 1473 } 1474 //until idle 1475 if (SoundPlayPtr 1476 == SizeQueue) { 1477 SoundPlayPtr = -1; // Dont go past the queue 1478 } 1479 1480 SoundPlayPtr++; // Increment 1481 pointer 1482 digitalWrite(FirstSoundPin + SoundQueue[SoundPlayPtr], LOW); //Play 1483 the sound 1484 delay(fxset); // 1485 hold to start the sound 1486 digitalWrite(FirstSoundPin + SoundQueue[SoundPlayPtr], 1487 HIGH); //Turn off the sound 1488 delay(fxset); // 1489 Ensure its set 1490 SoundQueueCtr--; // 1491 and decrement sounds yet to be played 1492 if (SoundQueueCtr <= 0) { 1493 SoundPlayPtr 1494 = -1; 1495 }; // reset play pointer when queue is empty 1496 1497 } 1498 1499} // end of PlaySound 1500/* 1501 void PlaySoundUART() // 1502 uncomment for FX sound board UART use 1503 1504 // sfx.playTrack(name); } 1505 1506 { 1507 Serial.print("\ 1508Playing track \\""); Serial.print(name); Serial.print("\\""); 1509 1510 if (! sfx.playTrack(name) ) { 1511 Serial.println("Failed to play track?"); 1512 1513 } 1514 } 1515*/ 1516 1517 1518#ifdef showoffcode 1519 1520void ShowOff() { // 1521 Played at startup -- just the MX Panel Test Graphics 1522 QueueSound(SoundShowOff); 1523 // play Game of Thones theme as sound 1524 PlaySound(); 1525 1526 scrollText("Showing Off"); 1527 rows(); 1528 columns(); 1529 cross(); 1530 checkboard(); 1531 1532 bullseye(); 1533 bounce(); 1534 stripe(); 1535 stripe(); 1536 transformation1(); 1537 1538 transformation2(); 1539 bullseye(); 1540 spiral(); 1541 delay(2000); 1542 DisplayIndex 1543 = DisplayTime; // force display of time after 1544 showing off display 1545} // 1546 end of Show Off 1547 1548void rows() // 1549 these routines are all 1550// Demonstrates the use of setRow() // 1551 from the MX library 1552{mx.clear(); 1553 for (uint8_t row = 0; row < ROW_SIZE; row++) 1554 1555 { 1556 mx.setRow(row, 0xff); 1557 delay(2 * DELAYTIME); 1558 mx.setRow(row, 1559 0x00); 1560 } 1561} 1562 1563void checkboard() 1564// nested rectangles spanning the 1565 entire display 1566{ 1567 uint8_t chkCols[][2] = { { 0x55, 0xaa }, { 0x33, 0xcc }, 1568 { 0x0f, 0xf0 }, { 0xff, 0x00 } }; 1569 mx.clear(); 1570 for (uint8_t pattern = 0; 1571 pattern < sizeof(chkCols) / sizeof(chkCols[0]); pattern++) 1572 { 1573 uint8_t 1574 col = 0; 1575 uint8_t idx = 0; 1576 uint8_t rep = 1 << pattern; 1577 1578 while 1579 (col < mx.getColumnCount()) 1580 { 1581 for (uint8_t r = 0; r < rep; r++) 1582 1583 mx.setColumn(col++, chkCols[pattern][idx]); // use odd/even column masks 1584 1585 idx++; 1586 if (idx > 1) idx = 0; 1587 } 1588 delay(10 * DELAYTIME); 1589 1590 } 1591} // end of Checkboard 1592 1593void columns() 1594// Demonstrates 1595 the use of setColumn() 1596{ 1597 1598 mx.clear(); 1599 1600 for (uint8_t col = 0; 1601 col < mx.getColumnCount(); col++) 1602 { 1603 mx.setColumn(col, 0xff); 1604 delay(DELAYTIME 1605 / MAX_DEVICES); 1606 mx.setColumn(col, 0x00); 1607 } 1608} 1609 1610void cross() 1611// 1612 Combination of setRow() and setColumn() with user controlled 1613// display updates 1614 to ensure concurrent changes. 1615{ 1616 1617 mx.clear(); 1618 mx.control(MD_MAX72XX::UPDATE, 1619 MD_MAX72XX::OFF); 1620 1621 // diagonally down the display R to L 1622 for (uint8_t 1623 i = 0; i < ROW_SIZE; i++) 1624 { 1625 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1626 1627 { 1628 mx.setColumn(j, i, 0xff); 1629 mx.setRow(j, i, 0xff); 1630 } 1631 1632 mx.update(); 1633 delay(DELAYTIME); 1634 for (uint8_t j = 0; j < MAX_DEVICES; 1635 j++) 1636 { 1637 mx.setColumn(j, i, 0x00); 1638 mx.setRow(j, i, 0x00); 1639 1640 } 1641 } 1642 1643 // moving up the display on the R 1644 for (int8_t i = ROW_SIZE 1645 - 1; i >= 0; i--) 1646 { 1647 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1648 { 1649 1650 mx.setColumn(j, i, 0xff); 1651 mx.setRow(j, ROW_SIZE - 1, 0xff); 1652 } 1653 1654 mx.update(); 1655 delay(DELAYTIME); 1656 for (uint8_t j = 0; j < MAX_DEVICES; 1657 j++) 1658 { 1659 mx.setColumn(j, i, 0x00); 1660 mx.setRow(j, ROW_SIZE 1661 - 1, 0x00); 1662 } 1663 } 1664 1665 // diagonally up the display L to R 1666 for 1667 (uint8_t i = 0; i < ROW_SIZE; i++) 1668 { 1669 for (uint8_t j = 0; j < MAX_DEVICES; 1670 j++) 1671 { 1672 mx.setColumn(j, i, 0xff); 1673 mx.setRow(j, ROW_SIZE 1674 - 1 - i, 0xff); 1675 } 1676 mx.update(); 1677 delay(DELAYTIME); 1678 for 1679 (uint8_t j = 0; j < MAX_DEVICES; j++) 1680 { 1681 mx.setColumn(j, i, 0x00); 1682 1683 mx.setRow(j, ROW_SIZE - 1 - i, 0x00); 1684 } 1685 } 1686 mx.control(MD_MAX72XX::UPDATE, 1687 MD_MAX72XX::ON); 1688} 1689 1690void bullseye() 1691// Demonstrate the use of buffer 1692 based repeated patterns 1693// across all devices. 1694{ 1695 1696 mx.clear(); 1697 1698 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 1699 1700 for (uint8_t n = 0; 1701 n < 3; n++) 1702 { 1703 byte b = 0xff; 1704 int i = 0; 1705 1706 while (b 1707 != 0x00) 1708 { 1709 for (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1710 { 1711 1712 mx.setRow(j, i, b); 1713 mx.setColumn(j, i, b); 1714 mx.setRow(j, 1715 ROW_SIZE - 1 - i, b); 1716 mx.setColumn(j, COL_SIZE - 1 - i, b); 1717 } 1718 1719 mx.update(); 1720 delay(3 * DELAYTIME); 1721 for (uint8_t j = 0; j 1722 < MAX_DEVICES + 1; j++) 1723 { 1724 mx.setRow(j, i, 0); 1725 mx.setColumn(j, 1726 i, 0); 1727 mx.setRow(j, ROW_SIZE - 1 - i, 0); 1728 mx.setColumn(j, 1729 COL_SIZE - 1 - i, 0); 1730 } 1731 1732 bitClear(b, i); 1733 bitClear(b, 1734 7 - i); 1735 i++; 1736 } 1737 1738 while (b != 0xff) 1739 { 1740 for 1741 (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1742 { 1743 mx.setRow(j, i, 1744 b); 1745 mx.setColumn(j, i, b); 1746 mx.setRow(j, ROW_SIZE - 1 - i, 1747 b); 1748 mx.setColumn(j, COL_SIZE - 1 - i, b); 1749 } 1750 mx.update(); 1751 1752 delay(3 * DELAYTIME); 1753 for (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1754 1755 { 1756 mx.setRow(j, i, 0); 1757 mx.setColumn(j, i, 0); 1758 mx.setRow(j, 1759 ROW_SIZE - 1 - i, 0); 1760 mx.setColumn(j, COL_SIZE - 1 - i, 0); 1761 } 1762 1763 1764 i--; 1765 bitSet(b, i); 1766 bitSet(b, 7 - i); 1767 } 1768 } 1769 1770 1771 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON); 1772} 1773 1774void spiral() 1775// 1776 setPoint() used to draw a spiral across the whole display 1777{ 1778 1779 int rmin 1780 = 0, rmax = ROW_SIZE - 1; 1781 int cmin = 0, cmax = (COL_SIZE * MAX_DEVICES) - 1782 1; 1783 1784 mx.clear(); 1785 while ((rmax > rmin) && (cmax > cmin)) 1786 { 1787 // 1788 do row 1789 for (int i = cmin; i <= cmax; i++) 1790 { 1791 mx.setPoint(rmin, 1792 i, true); 1793 delay(DELAYTIME / MAX_DEVICES); 1794 } 1795 rmin++; 1796 1797 1798 // do column 1799 for (uint8_t i = rmin; i <= rmax; i++) 1800 { 1801 mx.setPoint(i, 1802 cmax, true); 1803 delay(DELAYTIME / MAX_DEVICES); 1804 } 1805 cmax--; 1806 1807 1808 // do row 1809 for (int i = cmax; i >= cmin; i--) 1810 { 1811 mx.setPoint(rmax, 1812 i, true); 1813 delay(DELAYTIME / MAX_DEVICES); 1814 } 1815 rmax--; 1816 1817 1818 // do column 1819 for (uint8_t i = rmax; i >= rmin; i--) 1820 { 1821 mx.setPoint(i, 1822 cmin, true); 1823 delay(DELAYTIME / MAX_DEVICES); 1824 } 1825 cmin++; 1826 1827 } 1828} 1829 1830void bounce() 1831// Animation of a bouncing ball 1832{ 1833 const 1834 int minC = 0; 1835 const int maxC = mx.getColumnCount() - 1; 1836 const int minR 1837 = 0; 1838 const int maxR = ROW_SIZE - 1; 1839 1840 int nCounter = 0; 1841 1842 int 1843 r = 0, c = 2; 1844 int8_t dR = 1, dC = 1; // delta row and column 1845 1846 1847 1848 mx.clear(); 1849 1850 while (nCounter++ < 200) 1851 { 1852 mx.setPoint(r, c, 1853 false); 1854 r += dR; 1855 c += dC; 1856 mx.setPoint(r, c, true); 1857 delay(DELAYTIME 1858 / 2); 1859 1860 if ((r == minR) || (r == maxR)) 1861 dR = -dR; 1862 if ((c 1863 == minC) || (c == maxC)) 1864 dC = -dC; 1865 } 1866} 1867void stripe() 1868// Demonstrates 1869 animation of a diagonal stripe moving across the display 1870// with points plotted 1871 outside the display region ignored. 1872{ 1873 const uint16_t maxCol = MAX_DEVICES*ROW_SIZE; 1874 1875 const uint8_t stripeWidth = 10; 1876 1877 mx.clear(); 1878 1879 for (uint16_t col=0; 1880 col<maxCol + ROW_SIZE + stripeWidth; col++) 1881 { 1882 for (uint8_t row=0; row 1883 < ROW_SIZE; row++) 1884 { 1885 mx.setPoint(row, col-row, true); 1886 mx.setPoint(row, 1887 col-row - stripeWidth, false); 1888 } 1889 delay(DELAYTIME); 1890 } 1891} 1892 1893void 1894 transformation1() 1895// Demonstrates the use of transform() to move bitmaps on the 1896 display 1897// In this case a user defined bitmap is created and animated. 1898{ 1899 1900 uint8_t arrow[COL_SIZE] = 1901 { 1902 0b00001000, 1903 0b00011100, 1904 0b00111110, 1905 1906 0b01111111, 1907 0b00011100, 1908 0b00011100, 1909 0b00111110, 1910 0b00000000 1911 1912 }; 1913 1914 MD_MAX72XX::transformType_t t[] = 1915 { 1916 MD_MAX72XX::TSL, 1917 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1918 MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1919 MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1920 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1921 MD_MAX72XX::TSL, 1922 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1923 1924 MD_MAX72XX::TFLR, 1925 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1926 MD_MAX72XX::TSR, 1927 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1928 1929 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1930 MD_MAX72XX::TSR, 1931 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1932 MD_MAX72XX::TRC, 1933 MD_MAX72XX::TSD, 1934 MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, 1935 MD_MAX72XX::TSD, MD_MAX72XX::TSD, 1936 MD_MAX72XX::TSD, MD_MAX72XX::TSD, 1937 MD_MAX72XX::TFUD, 1938 MD_MAX72XX::TSU, 1939 MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, 1940 MD_MAX72XX::TSU, MD_MAX72XX::TSU, 1941 MD_MAX72XX::TSU, MD_MAX72XX::TSU, 1942 MD_MAX72XX::TINV, 1943 MD_MAX72XX::TRC, 1944 MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, 1945 MD_MAX72XX::TINV 1946 }; 1947 1948 1949 // transformation 1950 1951 mx.clear(); 1952 1953 // use the arrow bitmap 1954 1955 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 1956 for (uint8_t j=0; j<mx.getDeviceCount(); 1957 j++) 1958 mx.setBuffer(((j+1)*COL_SIZE)-1, COL_SIZE, arrow); 1959 mx.control(MD_MAX72XX::UPDATE, 1960 MD_MAX72XX::ON); 1961 delay(DELAYTIME); 1962 1963 // run through the transformations 1964 1965 mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::ON); 1966 for (uint8_t i=0; i<(sizeof(t)/sizeof(t[0])); 1967 i++) 1968 { 1969 mx.transform(t[i]); 1970 delay(DELAYTIME*4); 1971 } 1972 mx.control(MD_MAX72XX::WRAPAROUND, 1973 MD_MAX72XX::OFF); 1974} 1975 1976void transformation2() 1977// Demonstrates the use 1978 of transform() to move bitmaps on the display 1979// In this case font characters 1980 are loaded into the display for animation. 1981{ 1982 MD_MAX72XX::transformType_t 1983 t[] = 1984 { 1985 MD_MAX72XX::TINV, 1986 MD_MAX72XX::TRC, MD_MAX72XX::TRC, 1987 MD_MAX72XX::TRC, MD_MAX72XX::TRC, 1988 MD_MAX72XX::TINV, 1989 MD_MAX72XX::TSL, 1990 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1991 MD_MAX72XX::TSR, 1992 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1993 MD_MAX72XX::TSR, 1994 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1995 MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1996 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1997 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1998 1999 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 2000 MD_MAX72XX::TSD, MD_MAX72XX::TSU, 2001 MD_MAX72XX::TSD, MD_MAX72XX::TSU, 2002 MD_MAX72XX::TFLR, MD_MAX72XX::TFLR, MD_MAX72XX::TFUD, 2003 MD_MAX72XX::TFUD 2004 };} 2005#endif //showoffcode// 2006
Updated code for clock
arduino
Added some more events
1 2 3 4/* 5 Clock project using two MX7219 matrix displays and the AdaFruit FX Soundboard 6 Provides date, time, temp, humidity and event notifications in rotating order 7 Also can chime in multiple ways, including Westminster chimes 8 Chimes are provided by Adafruit FX Soundboard in GPIO mode 9 There are some conditional options: 10 Davids_Clock changes some of the events and notifications 11 Extra_Display uses a small Adafruit 1306 OLED to continuously show date and time while the main display 12 rolls through its iterations 13 DDT includes a couple of small debugging (get it?) routines and opens serial terminal 14 15*/ 16 17 18 19 20// Code to set up the clock 21// Pushbutton 1 is the toggler , cycle between year, month, day, hours, minutes, seconds 22// Pushbutton 2 is the increment up one 23// Pushbutton 3 is the decrement down one 24 25// Chime setup for toggle switch 26// Center = No chimes 27// Up = Westminster hours + quarterly 28// Down = Simple Bell (hours and 1/2 hour) 29 30// Comment out next line to leave out the little show 31 32#define showoffcode // include "show off" graphics and music for Easter Egg 33 34//#define Davids_Clock // if this is david's clock slightly different announcements 35 36#define Extra_Display // Enables constant date and time in OLED display so never have to wait 37 38#define DDT // simple debug tools (print string, print string and value, same with NL) 39 40 41// Clock "ID's" for temperature adjustment 42// Define only one of these! 43 44//#define Clock_1 // First wine box clock (mine) 45//#define Clock_2 // 2nd wine box clock (For David) 46#define Clock_3 // Acrylic long matrix clock (Mercer Island) 47 48 49// include the libraries for LCD Display, DHT-11 Temperature/humidity sensor and DS3231 RTC and 50// include libraries for MX7219 mult-unit matrix display 51#include "DHT.h" 52#include <Wire.h> 53#include "RTClib.h" 54#include <MD_MAX72xx.h> 55 56// uncomment next two lines to use UART for SoundBoard rather than GPIO 57//#include <Adafruit_Soundboard.h> 58//#include <SoftwareSerial.h> 59 60#ifdef Extra_Display 61#include <Adafruit_GFX.h> // for OLED need graphics and 62#include <Adafruit_SSD1306.h> // the specific driver 63#endif 64 65 66// Set up output functions 67 68#define DHTPIN 9 //Temp Humidity sensor on pin 9 69#define DHTTYPE DHT11 // DHT 11 because the sensor is that type 70 71// Initialize DHT sensor for normal 16mhz Arduino 72DHT dht(DHTPIN, DHTTYPE); 73 74// Initialize for Adafruit DS3231 RTC real time clock 75RTC_DS3231 rtc; 76 77#ifdef Extra_Display // used to include a small OLED date/time display 78// Initialize the Small OLED display 79#define SCREEN_WIDTH 128 // OLED display width, in pixels 80#define SCREEN_HEIGHT 64 // OLED display height, in pixels 81 82// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) 83//#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) 84#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) 85Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); 86#endif Extra_Display 87 88 89// uncomment next set of lines to use UART for SoundBoard 90/* 91 // Choose any two pins that can be used with SoftwareSerial to RX & TX for UART SoundBoard 92 //#define SFX_TX 5 93 //#define SFX_RX 6 94 // Connect to the RST pin on the Sound Board 95 #define SFX_RST 4 96 // You can also monitor the ACT pin for when audio is playing! 97 // we'll be using software serial 98 //SoftwareSerial ss = SoftwareSerial(SFX_TX, SFX_RX); 99 // pass the software serial to Adafruit_soundboard, the second 100 // argument is the debug port (not used really) and the third 101 // arg is the reset pin 102 //Adafruit_Soundboard sfx = Adafruit_Soundboard(&ss, NULL, SFX_RST); 103 // can also try hardware serial with 104 // Adafruit_Soundboard sfx = Adafruit_Soundboard(&Serial1, NULL, SFX_RST); 105*/ 106 107// Define the number of devices we have in the chain and the hardware interface 108// NOTE: These pin numbers will probably not work with your hardware and may 109// need to be adapted 110#define HARDWARE_TYPE MD_MAX72XX::FC16_HW // NOTE: This parameter differs by vendor 111#define MAX_DEVICES 8 // 2 x 4 matrices per unit 112 113//Pins for Arduino Uno 114//#define CLK_PIN 13 // or SCK (this is for the UNO, different for the Mega 115//#define DATA_PIN 11 // or MOSI 116//#define CS_PIN 10 // or SS 117 118 119//Pins for Arduino Mega 120#define CLK_PIN 52 // or SCK 13 121#define DATA_PIN 51 // or MOSI 11 122#define CS_PIN 53 // or SS 10 123 124 125// SPI hardware interface 126MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); 127 128// We always wait a bit between updates of the display 129#define DELAYTIME 100 // in milliseconds 130 131// Text parameters 132#define CHAR_SPACING 1 // pixels between characters 133//const int CHAR_PIXELS = 6; // Pixels taken by each character (including trailing space) 134//const int MAX_CHARS = (MAX_DEVICES*COL_SIZE)/ CHAR_PIXELS; // Maximum characters at once (happens to be 10 btw) 135//const int LEFT_OVER = (MAX_DEVICES*COL_SIZE)- (CHAR_PIXELS*MAX_CHARS); //Since its not 'even' additional pad from front on printText 136const int BufferStringLength = 31; 137char BufferString [BufferStringLength]; //used to construct printouts 138#define DecToAscii 48 // convert number to ascii (add as a constant) 139char DegreeSign = '~'; // for display of 'degrees' after temperature 140int TDigits[4] = {0, 0, 0, 0}; // used to convert four digits to four chacacters 141#define TDOnes 3 // positions in arrays and templates 142#define TDTens 2 143#define TDHundreds 1 144#define TDThousands 0 145#define sunday 0 // used for events, floating events and holidays 146#define monday 1 // just for readability 147#define tuesday 2 148#define wednesday 3 149#define thursday 4 150#define friday 5 151#define saturday 6 152#define january 1 153#define february 2 154#define march 3 155#define april 4 156#define may 5 157#define june 6 158#define july 7 159#define august 8 160#define september 9 161#define october 10 162#define november 11 163#define december 12 164 165//Template Strings and pointers 166 167const int LOTS = 13; // Length of TimeString (without terminator) 168char TimeString[LOTS + 1 ] = {' ', ' ', '1', '2', ':', '3', '1', ':', '4', '5', ' ', 'P', 'M', '\\0'}; 169char DateString[ ] = {'1', '2', '/', '3', '1', '/', '2', '0', '1', '9', '\\0'}; 170char TempString[ ] = {'T', 'e', 'm', 'p', ' ', '7', '2', '.','0', DegreeSign,'F', '\\0'}; 171char HumidString[ ] = {'H', 'u', 'm', ' ', '2', '5', '.', '0', '%', '\\0'}; 172const int THptr = 2; // Pointers within the strings 173const int TMptr = 5; // for loading values 174const int TSptr = 8; 175const int TAMPMptr = 11; 176const int DMptr = 0; 177const int DDptr = 3; 178const int DYptr = 6; 179const int TEMPptr = 5; 180const int HUMIDptr = 4; 181 182// Differentiated Displays 183 184const int DisplayTime = 0; 185const int DisplayDate = 2; 186const int DisplayDOW = 1; 187const int DisplayTemp = 3; 188const int DisplayHumid = 4; 189const int DisplayEvent = 5; 190const int DisplayEventRepeat = 2; //times to repeat the scrolling 'event' display 191const int DisplaySize = 6; // Nunber of different displays 192int DisplayIndex = DisplayTime; // display we are on at the time 193const int DisplayDelayArray[DisplaySize] = {100, 50, 30, 30, 30, 20}; // multiplier for each event 194const int DisplayDelay = 100; // milliseconds to leave each display * its multiplier 195unsigned long DisplayTimer; // used to time each matrix display 196 197 198 199char daysOfTheWeek[7][12 ] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 200 201 202 #ifndef Davids_Clock 203 204const int eventnumber = 50; // number of events and remember: No strings longer than 30 characters! 205 206int eventmonth [eventnumber] = {june, april, november, february, july, december, november, june, december, june, december, january, 207 september, october, march, february, february, july,december, february, december, january, january, february, 208 march,april,april,april,april,may,may,may,may,june,june,june,july,july,october, september, may, april, 209 march,february,march,october,march,november,august,october 210 }; 211int eventday [eventnumber] = {11, 1, 23, 12, 4, 3, 12, 29, 25, 16, 31, 1, 3, 31, 17, 14, 2, 14, 30,12,21,5,18,18,6,7,12,15,24,1,5,20,30,14,14,21, 212 22,24,29,28,18,26,14,3,27,12,30,5,5,4}; 213 214char* eventdescription [eventnumber] = 215{ "Dana's Anniversary", "April Fool's Day", "Joan's Birthday", "Sydney's Birthday", "July 4th!", "Dana's Birthday", 216 "David's Birthday", "Our Anniversary", "Merry Christmas", "Leah's Birthday", "New Year's Eve", "New Year's Day", 217 "Forrest's Birthday", "Happy Halloween", "Saint Patrick's Day", "Valentine's Day", "Groundhog Day", "Bastille Day", "Linsey's Birthday", 218 "Irwin's Birthday", "Winter Solstice", "National Bird Day", "National Winnie the Pooh Day", "National Drink Wine Day","National Oreo Day", 219 "National Beer Day","Grilled Cheese Day", "Tax Day","National DNA Day", "May Day", "Cinco de Mayo", "World Bee Day", "World MS Day", 220 "National Bourbon Day", "Flag Day", "Summer Solstice","National Hot Dog Day", "National Tequila Day","National Cat Day", "National Drink Beer Day", 221 "National Whisky Day", "Nat'l Audubon Day", "National Pi Day", "Nat'l Women Physicians Day", "National Paella Day", "National Gumbo Day", 222 "National Doctors Day", "National Doughnut Day", "National Oyster Day", "National Taco Day" 223}; 224#endif 225#ifdef Davids_Clock 226const int eventnumber = 43; // number of events and remember: No strings longer than 30 characters! 227 228int eventmonth [eventnumber] = {june, april, november, february, july, december, november, june, december, june, december, january, 229 september, october, march, february, february, july,december, february, december, 230 march,april,april,april,may,may,may,june,june,june,july,july,september, 231 march,february,march,october,march,november,october,august 232 }; 233int eventday [eventnumber] = {11, 1, 23, 12, 4, 3, 12, 29, 25, 16, 31, 1, 3, 31, 17, 14, 2, 14, 30,12,21,18,6,7,12,15,1,5,20,14,14,21, 234 22,24,28,14,3,27,12,30,5,4,4}; 235 236char* eventdescription [eventnumber] = 237{ "Dana's Anniversary", "April Fool's Day", "Mom's Birthday", "Sydney's Birthday", "July 4th!", "Dana's Birthday", 238 "My Birthday", "Mom & Dad's Anniversary", "Merry Christmas", "Leah's Birthday", "New Year's Eve", "New Year's Day", 239 "Forrest's Birthday", "Happy Halloween", "Saint Patrick's Day", "Valentine's Day", "Groundhog Day", "Bastille Day", "Linsey's Birthday", 240 "Dad's Birthday", "Winter Solstice", "National Drink Wine Day","National Oreo Day", 241 "National Beer Day","Grilled Cheese Day", "Tax Day", "May Day", "Cinco de Mayo", "World Bee Day", 242 "National Bourbon Day", "Flag Day", "Summer Solstice","National Hot Dog Day", "National Tequila Day","National Drink Beer Day", 243 "National Pi Day", "Nat'l Women Physicians Day", "National Paella Day", "National Gumbo Day", "National Doctors Day", "National Doughnut Day", 244 "National Taco Day", "Nat'l Champagne Day" 245}; 246#endif 247 248 249bool event; // logic flag "on" = event found 250int eventindex; // and the event we found 251const int maxevents = 3; // maximum of three events (real and floating combined) 252char* eventstrings[maxevents] ; // used to store displayed events 253String floatstring = " "; // used for floating events (e.g., Thanksgiving) 254 255#define pb1pin 2 // Pin assignments for reset, increment and decrement 256#define pb2pin 3 257#define pb3pin 4 258 259#define showoffbuttonpin 7 // invoke showing off the matrix display 260 261#define DoWestminster 5 262#define DoHoursOnly 6 263#define silent 0 // no chiming at all 264#define hoursonly 1 // no prelude, just chime number of hours and half hour single chime 265#define westminster 2 // hours + Westminster prelude per quarter 266int ChimeValue = silent; // default to silent 267 268 269const int LEDpin = A0; // Pin assignment for analog reading LDR for LED brightness 270const int minbright = 0; // MAX_BRIGHT for this module is 15 271const int midbright = 2; // but these values "seem" to work 272const int maxbright = 4; 273 274 275 276 277int setupindex = 0; // first thing to set if required 278bool insetupmode = false; // and assume RTC is set, OK, etc., and no 'set' required 279bool setinsetup = false; // flag set to true at interrupt level to go back into setup mode 280 281// date time array for setting, reading, displaying 282 283#define setsize 6 // size of the setting array 284#define setyear 0 // index name for each element 285#define setmonth 1 286#define setday 2 287#define sethour 3 288#define setminute 4 289#define setsecond 5 290 291int setarray [setsize] = {2019, 1, 1, 1, 1, 0}; // set year, month, day, hour, minutes, seconds 292int lowlimit [setsize] = {2019, 1, 1, 0, 1, 0}; // lower limit for each 293int highlimit [setsize] = {2080, 12, 31, 23, 59, 59}; //high limit for each 294const int setdesclength = 4; // maximum length of 'set' descriptor 295char setdesc [setsize] [setdesclength] = {"Yr ", "Mon", "Day", "Hr ", "Min", "Sec"}; 296 297 298#define cqtr0 1 // Chime the hour 299#define cqtr1 2 // Chime the quarter hour 300#define cqtr2 3 // Chime the half hour 301#define cqtr3 4 // Chime the 3/4 hour 302 303// Definitions for the Sound Board 304#define SoundTruncatedSingle 0 // Truncated Single Westminster 305#define SoundQ1 1 // First Quarter 306#define SoundQ2 2 // Second Quarter 307#define SoundQ3 3 // Third 308#define SoundQ4 4 // Fourth (before hour chime) 309#define SoundTrailingSingle 5 // Finish Westminster string of chimes with longer sound tail 310#define SoundTruncatedBell 6 // Simple Bell 311#define SoundTrailingBell 7 // Final Bell (like single, has longer 'tail') 312#define SoundStartup 8 // startup sound 313#define SoundShowOff 9 // Play during show off of matrix 314#define FirstSoundPin 30 // first pin to use for soundboard (0-10 available on soundboard); 315#define SizeSoundPin 10 // number of pins used (must be consecutive) 316#define fxset 150 // Time soundboard must be held LOW to register (documentation says 125 ms) 317#define SoundBusyPin 8 // Soundboard pin that goes LOW when board is active 318 319const int SizeQueue = 15; // Assume Q4+12 bells is the maximum that'll be in the queue at any point 320int SoundQueue[SizeQueue]; // Circular Queue for waiting sounds 321int SoundQueuePtr = -1; //pointer for Queue fill Position 322int SoundPlayPtr = -1; //pointer for Queue play Position 323int SoundQueueCtr = 0; // number of items in the queue 324 325int setstrike = -1; // Chime/strike flag 326byte alreadychimed = false ; // Used to keep from chiming multiple times during the "hot" second 327const int BounceDelay = 250; // Not really 'bounce', its a change of state detection 328 329int i; // generic index variable 330 331int dayoftheweek; // stored day of the week (0-6, 0 = Sunday) 332 333int phours; // for print conversion of military time 334 335float temperaturef; // farenheit temperature back 336int temperature; // integer version of temperature for matrix 337float temperaturec; // centrigade temperature back (not used) 338 339float humidityf; // and humidity 340int humidity ; // and same as temp 341 342// The DHT sensors are cheap and inaccurate so these are 'custom' adjustments 343 344#ifdef Clock_1 // first wine box clock 345float tempadjust = -2.0; // temperature adjustment for sensor (I found it didn't read right against 'comps') 346float humidadjust = +8.0; // corresponding humidity adjustment 347#endif 348 349#ifdef Clock_2 // second wine box clock for David 350float tempadjust = -0.6; // temperature adjustment for sensor 351float humidadjust = +8.0; 352#endif 353 354#ifdef Clock_3 // clear clock 355float tempadjust = 0.0; 356float humidadjust = +8.0; 357#endif 358 359 360#ifdef DDT // debugging tools 361void DDTl(String st, int vt) { // Print descriptor and value and new line 362 DDTs(st, vt); 363 Serial.println(" "); 364} 365void DDTs(String st, int vt) { // Print descriptor and value 366 Serial.print(" "); 367 Serial.print(st); 368 Serial.print(" "); 369 Serial.print(vt); 370} 371void DDTt(String st) { // Print descriptor and value and new line 372 Serial.println(st); 373} 374#endif //DDT// 375 376 377void setup() 378// put your setup code here, to run once: 379 380{ 381 Wire.begin(); // initialize I2C interface 382 dht.begin(); // initialize the temp/humidity sensor 383 mx.begin(); // and MX7219 display 384 #ifdef DDT 385 Serial.begin (9600); //Terminal monitor printing for debugging 386 #endif 387 388 // softwareserial at 9600 baud (uncomment this line and next for UART control of sound board 389 // ss.begin(9600); 390 391#ifdef OLED_Display 392// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally 393 if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x64 394 scrollText("Small OLED display startup failed"); 395 delay(2000);} else //and wait 396 { display.clearDisplay(); // give a little startup msg 397 display.setTextSize(2); // Normal 1:1 pixel scale 398 display.setTextColor(SSD1306_WHITE); // Draw white text 399 display.setCursor(0,0); // Start at top-left corner 400 display.println("Hello"); 401 display.setTextSize(2); 402 display.println("Starting"); 403 display.setTextSize(3); // Draw 2X-scale text 404 display.setTextColor(SSD1306_WHITE); 405 display.print(" UP! "); 406 display.display(); 407 delay(1500); 408 } 409#endif OLED_Display 410 411 pinMode(pb1pin, INPUT_PULLUP); // The three pushbuttons - reset 412 pinMode(pb2pin, INPUT_PULLUP); // increment 413 pinMode(pb3pin, INPUT_PULLUP); // decrement 414 415 pinMode (DoWestminster, INPUT_PULLUP); // When pulled 'low' we want Westminster chimes 416 pinMode (DoHoursOnly , INPUT_PULLUP); // When pulled 'low' we want hours and 1/2 bell (neither is 'silent') 417 418 #ifdef showoffcode 419 pinMode(showoffbuttonpin, INPUT_PULLUP) ; // if show off matrix is there, initialize pin 420 #endif //showoffcode// 421 422 for (i = FirstSoundPin; i < FirstSoundPin + SizeSoundPin; i++) { // pins for sound board 423 pinMode(i, OUTPUT); // each an output 424 digitalWrite(i, HIGH); // and initialize high (off) 425 } 426 427 // set up interupt for PB1 // if PB1 is pushed, it'll pick up on next release from Matrix display 428 attachInterrupt(digitalPinToInterrupt(pb1pin), SetToSetup, FALLING); // and re-enter setup mode (after the end of current display) 429 430 QueueSound(SoundStartup); // play boot up sound 431 PlaySound(); 432 433 if (! rtc.begin()) { // check that clock is there 434 scrollText("Couldn't find RTC"); // clock missing is a fatal error 435 while (1); 436 } 437 438 if (rtc.lostPower()) { // if power lost force a setup, else load 'current' values and 439 scrollText("RTC lost power!"); 440 delay(1000); 441 scrollText("Replace battery?"); 442 delay(1000); 443 scrollText("Setup Mode: "); 444 setupindex = setyear - 1; // setup differently (becuase it will increment) 445 insetupmode = true; 446 for (i = 0; i < setsize; i++) { 447 setarray[i] = lowlimit[i]; 448 } 449 } else // else reload from RTC 450 { DateTime (setarray[setyear], setarray[setmonth], setarray[setday], setarray[sethour], setarray[setminute], setarray[setsecond]) = rtc.now(); 451 insetupmode = false; // not in setup mode, and 452 setinsetup = false; //no interrupt 453 } 454 455 // Two alternative modes of setting date and time (for debugging, just un-comment): 456 // This line sets the RTC to the date & time this sketch was compiled 457 // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 458 // This line sets the RTC with an explicit date & time, for example to set 459 // January 21, 2014 at 3am you would call: 460 // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 461 LEDBrightness(); // Do an initial check for room brightness 462} // end of setup 463 464void loop() { // Main code divided into setup mode and non-setup mode 465 466 while (insetupmode) { // code for setting time, date set, etc. 467 468 // Read the increment button 469 470 if (digitalRead(pb2pin) == LOW) { 471 setarray[setupindex]++; // read increment of current item 472 delay(BounceDelay); 473 if (setarray[setupindex] > highlimit[setupindex]) { 474 setarray[setupindex] = lowlimit[setupindex]; 475 } 476 ShowValue(setupindex, setdesc[setupindex]); // and display description and value 477 } 478 479 // Read the decrement Button 480 if (digitalRead(pb3pin) == LOW) { 481 setarray[setupindex]--; // read decrement of value 482 delay(BounceDelay); 483 if (setarray[setupindex] < lowlimit[setupindex]) { 484 setarray[setupindex] = highlimit[setupindex]; 485 } 486 ShowValue(setupindex, setdesc[setupindex]); // and display description and value 487 } 488 489 // Read for another increment of index 490 491 if (digitalRead(pb1pin) == LOW) { // Rolling through Chime, Year, Month, Day, Hour, Minutes, Seconds 492 setupindex++ ; // increment index 493 delay(BounceDelay); 494 if (setupindex < setsize) { 495 ShowValue(setupindex, setdesc[setupindex]); // show description and value if in bounds 496 } 497 if (setupindex >= setsize) { // and finally exiting setup mode after setting chime, date and time 498 rtc.adjust(DateTime(setarray[setyear], setarray[setmonth], setarray[setday], setarray[sethour], setarray[setminute], setarray[setsecond])); 499 insetupmode = false; 500 DisplayIndex = DisplayTime; 501 } //exit setup mode when done 502 } 503 504 } // End of "While" for setup 505 506 // Begin regular loop for date, time, temp humidity and event display 507 508 while (!insetupmode) { 509 510 GetTempandHumid(); // read temperature and humidity from sensor 511 512 ChimeValue = ReadChimeSetting(); // read SPDT Center off switch for silent, westminster or hours only (and 1/2) 513 514 GetTheDate(); // load date array from RTC for a chime/bell check 515 516 CheckForChime(); // Check for a chime event between displays 517 518 CheckForEvent(setarray[setmonth], setarray[setday], dayoftheweek); // check for static and floating events 519 520 MatrixDisplay(); // Do whatever display is required on the MX7219 521 522 #ifdef OLED_Display // if the little OLED display is used 523 OLED_Update(); // update it 524 #endif Extra display 525 526 LEDBrightness(); // Good place to check for change in room brightness 527 528 // end of display update logic 529 530 // Read a potential request for an entry into setup from PB 1 531 if ((digitalRead(pb1pin) == LOW) || setinsetup) { // to see if we go back to setup mode 532 insetupmode = true; // via a pushbutton or the interrupt 533 setinsetup = false; // clear the interrupt flag 534 setupindex = 0; // re-initialize to 'Year' in setup 535 DisplayIndex = DisplayTime; // and go back to time display when exit setup 536 scrollText("Setup Mode: "); 537 delay(2000); 538 ShowValue(setupindex, setdesc[setupindex]); // show the first setup item (Year) 539 delay(BounceDelay); 540 } 541 #ifdef showoffcode 542 if (digitalRead(showoffbuttonpin) == LOW) {ShowOff();} // check for want to show off matrix 543 #endif //showoffcode// 544 545 } // end of not in setup 546} // end of sketch 547 548void MatrixDisplay() { // Main display routine for display sequences 549 550 Scrollup(); // Clear last display 551 if (DisplayIndex >= DisplaySize) { 552 DisplayIndex = DisplayTime; // reset if at the end 553 } 554 DisplayTimer = DisplayDelayArray[DisplayIndex] * DisplayDelay; // set individual display time 555 556 switch (DisplayIndex) { // and do next display 557 558 case DisplayTime: // Dislay the time 559 do // time is different in that there's a constant 560 { // update of time during display and also play chime, bell etc. 561 GetTheDate(); // Get Current Time 562 #ifdef OLED_Display // If the OLED is there, 563 OLED_Update(); 564 #endif OLED_Display 565 CheckForChime(); // Check for a chime event 566 LoadNumber(phours); // Load the 4 digit character array from number 567 TimeString[THptr] = TDigits[TDTens]; // left digit of the two digit hour 568 TimeString[THptr + 1] = TDigits[TDOnes]; // rightmost digit 569 if (TimeString[THptr] == '0') { 570 TimeString[THptr] = ' '; // eliminate leading zero 571 } 572 LoadNumber(setarray[setminute]); // do same for minutes 573 TimeString[TMptr] = TDigits[TDTens]; // except no need to do space for zero 574 TimeString[TMptr + 1] = TDigits[TDOnes]; 575 LoadNumber(setarray[setsecond]); // seconds then 576 TimeString[TSptr] = TDigits[TDTens]; 577 TimeString[TSptr + 1] = TDigits[TDOnes]; 578 if (setarray[sethour] < 12) // and AM vs PM 579 { 580 TimeString[TAMPMptr] = 'A'; 581 } 582 else 583 { 584 TimeString[TAMPMptr] = 'P'; 585 } 586 printText(TimeString, LOTS, false); // Keep position (no centering) because time keeps updating during display and chimes 587 PlaySound(); // Play any chimes or bells 588 if (SoundQueueCtr == 0) { 589 DisplayTimer = DisplayTimer - DisplayDelay; // if no sound, use display delay logic 590 delay(DisplayDelay); 591 } 592 } while ((DisplayTimer > 0) || (SoundQueueCtr > 0)); // leave this display when no sound or no delay left 593 DisplayIndex++ ; // then move on to next display item 594 break; 595 596 case DisplayDate: // Month, Day and Year Display 597 LoadNumber(setarray[setmonth]); 598 DateString[DMptr] = TDigits[TDTens]; 599 if (DateString[DMptr] == '0') { 600 DateString[DMptr] = ' '; 601 } 602 DateString[DMptr + 1] = TDigits[TDOnes]; 603 LoadNumber(setarray[setday]); 604 DateString[DDptr] = TDigits[TDTens]; 605 DateString[DDptr + 1] = TDigits[TDOnes]; 606 LoadNumber(setarray[setyear]); 607 for (int i = 0; i < 4; i++) { 608 DateString[DYptr + i] = TDigits[i]; 609 } 610 printCenter(DateString); 611 CommonDelay(DisplayTimer); 612 DisplayIndex++ ; 613 break; 614 615 case DisplayDOW: // Just display the day of week string 616 printCenter(daysOfTheWeek[dayoftheweek]); 617 CommonDelay(DisplayTimer); 618 DisplayIndex++ ; 619 break; 620 621 case DisplayTemp: // Temperature display 622 LoadNumber(temperature); 623 TempString[TEMPptr] = TDigits[TDHundreds]; 624 TempString[TEMPptr + 1] = TDigits[TDTens]; 625 TempString[TEMPptr + 3] = TDigits[TDOnes]; 626 printCenter(TempString); 627 CommonDelay(DisplayTimer); 628 DisplayIndex++ ; 629 break; 630 631 case DisplayHumid: // Humidity display 632 LoadNumber(humidity); 633 HumidString[HUMIDptr] = TDigits[TDHundreds]; 634 HumidString[HUMIDptr + 1] = TDigits[TDTens]; 635 HumidString[HUMIDptr + 3] = TDigits[TDOnes]; 636 printCenter(HumidString); 637 CommonDelay(DisplayTimer); 638 DisplayIndex++ ; 639 break; 640 641 case DisplayEvent: // Event Display 642 if (event) { // "Real" events repeat 3 times 643 if (eventindex > 0 ) { // for case where there is more than one event 644 while (eventindex >= 0) 645 {scrollText(eventstrings[eventindex]); // scroll each of them once 646 if (eventindex > 0) { 647 delay(DisplayDelay * 6); 648 printCenter("and"); 649 delay(DisplayDelay * 6);} 650 eventindex--; // and decrement 651 delay(DisplayDelay * 2); 652 } 653 } 654 else { // case of only one event -- repeat it for readability 655 for (int i = 1; i <= DisplayEventRepeat; i++) { // scroll either static or floating event 656 scrollText(eventstrings[eventindex]); // the index is 0 (greater than zero if multiple events) 657 } 658 delay(DisplayDelay * 2); 659 } 660 } // end of "if event" logic 661 if (!event){ // Scroll Default message only once 662 #ifndef Davids_Clock 663 if (setarray[sethour] >= 6 && setarray[sethour] <= 11) { 664 scrollText("Good Morning ");} 665 else if (setarray[sethour] >= 12 && setarray[sethour] <= 16) { 666 scrollText("Good Afternoon");} 667 else if (setarray[sethour] >= 17 && setarray[sethour] <= 21) { 668 scrollText("Good Evening");} else{scrollText("Good Night"); } 669 #endif 670 #ifdef Davids_Clock 671 if (setarray[sethour] >= 6 && setarray[sethour] <= 11) { 672 scrollText("Good Morning, David");} 673 else if (setarray[sethour] >= 12 && setarray[sethour] <= 16) { 674 scrollText("Good Afternoon, David");} 675 else if (setarray[sethour] >= 17 && setarray[sethour] <= 21) { 676 scrollText("Good Evening, David");} else{scrollText("Good Night, David"); } 677 #endif 678 } // end of "if not event" above 679 CommonDelay(DisplayTimer); 680 DisplayIndex++ ; 681 break; 682 683 default: 684 scrollText("Should never get here"); 685 while (1); 686 687 } // End of Switch 688 689} // End of MatrixDisplay 690 691void GetTheDate() { // Read RTC into array 692 DateTime now = rtc.now(); 693 setarray[setyear] = now.year(); 694 setarray[setmonth] = now.month(); 695 setarray[setday] = now.day(); 696 setarray[sethour] = now.hour(); 697 setarray[setminute] = now.minute(); 698 setarray[setsecond] = now.second(); 699 dayoftheweek = now.dayOfTheWeek(); 700 if (setarray[sethour] <= 12) // convert military time to am pm 701 { 702 phours = setarray[sethour]; 703 } 704 else 705 {phours = setarray[sethour] - 12;} 706 if (phours <= 0) { phours = 12; } // don't print 0 for midnite, print "12" 707 708} // End of Get The Date 709 710void GetTempandHumid(){ // Temperature and humidity update 711 712 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) 713 humidityf = dht.readHumidity()+humidadjust; // read humidity and adjust for any error 714 715 // Read temperature as Fahrenheit 716 temperaturef = (dht.readTemperature(true)) + tempadjust; // read and correct for inaccuracy in sensor 717 718 // Check if any reads failed and exit early (to try again). 719 if (isnan(humidityf) || isnan(temperaturec) || isnan(temperaturef)) { 720 temperaturef = 0; // use 0 as a no-read 721 humidityf = 0; // error indication 722 } 723 temperature = temperaturef * 10.0; // get read for matrix printout 724 humidity = humidityf * 10.0; 725} // end of Temperature and Humidity update 726 727void SetToSetup() { // interrupt level back to setup 728 if ((!insetupmode) && (!setinsetup)) { // skip if we are already in Setup mode or have seen the interrupt 729 setinsetup = true; // Go back into setup at next loop 730 DisplayTimer = 0; 731 } // and zero the timer to speed that up if you can 732} // SetToSetup 733 734void CommonDelay(long int MyDelay) { // Common delay routine 735 DisplayTimer = MyDelay; 736 do { 737 DisplayTimer = DisplayTimer - DisplayDelay; 738 delay(DisplayDelay); 739 GetTheDate(); // load date array from RTC for a chime/bell check 740 CheckForChime(); // if a chime happens, setup to end delay 741 } while ((DisplayTimer > 0) && (!setinsetup) && (SoundQueueCtr <= 0)); // repeat while still time and no interrupt and no sound waiting 742 if (SoundQueueCtr > 0){DisplayIndex = DisplayTime-1;} // if leaving due to chime, go directly to time 743} // End of CommonDelay 744 745 746int ReadChimeSetting() { 747 int returnvalue = silent; // Assume 'silent' (Center position) 748 if (digitalRead(DoWestminster) == LOW) { 749 returnvalue = westminster; 750 } else if (digitalRead(DoHoursOnly) == LOW) { 751 returnvalue = hoursonly; 752 } 753 return returnvalue; 754} 755 756// Routine to deal with combinations of chime type, time of day and the current hour 757// called parameters are chime type (e.g., Westminster), Strike type (hour, qtr, half, 3/4) and the hour in military time 758// Note for delays and print cycles: You need to call this at least once during the 'golden' minute (0,15,30,45) 759 760void CheckForChime() { // Logic for chiming 761 762 setstrike = -1; // initialize 'strike' flag to "no strike" 763 764 if (ChimeValue != silent) // if silenced due to setting silent, skip the whole thing 765 { 766 if (setarray[setminute] == 0) { // Look for 'on the hour' 767 setstrike = cqtr0; 768 } else if (setarray[setminute] == 15 ) { // Look for on the quarter hour 769 setstrike = cqtr1; 770 } else if (setarray[setminute] == 30 ) { // Look for on the 1/2 hour 771 setstrike = cqtr2; 772 } 773 else if (setarray[setminute] == 45 ) { // Look for on the three-quarter hour 774 setstrike = cqtr3; 775 } 776 else { 777 alreadychimed = false; // none of the above, reset ability to chime 778 } 779 780 if (setstrike > 0 && !alreadychimed ) { 781 chime(ChimeValue, setstrike, setarray[sethour]); // call chiming with 'type of chime'; 0,15,30,45 ; and # hours 782 DisplayIndex = DisplayTime; // force display of time while chiming 783 alreadychimed = true; // we will be here multiple times but only chime once 784 } 785 } // end of logic for chiming 786} // end of CheckForChime 787 788void chime (int chimetype, int strikeflag, int chour) { 789 790 int chour1; // am pm variable\\ 791 792 if (chour <= 12) { 793 chour1 = chour; // convert military time to am pm 794 } else { 795 chour1 = chour - 12; 796 } 797 798 799 if (chour1 <= 0) { 800 chour1 = 12; // don't chime 0 for midnite, chime 12 801 } 802 if (chimetype == hoursonly && strikeflag == cqtr2) { 803 QueueSound(SoundTrailingBell); // 1/2 hour only, do single 'ding' 804 } 805 else if ( chimetype == hoursonly && strikeflag == cqtr0) { 806 for (int i = 1; i < chour1; i++) { 807 QueueSound(SoundTruncatedBell); // Ding once less than hours 808 } 809 QueueSound(SoundTrailingBell); 810 } // and follow by trailing bell as last 'ding' (if used) 811 else if (((chimetype == westminster) ) && strikeflag == cqtr1) { 812 QueueSound(SoundQ1); // First Quarter 813 } 814 else if (((chimetype == westminster) ) && strikeflag == cqtr2) { 815 QueueSound(SoundQ2); // Second Quarter 816 } 817 else if (((chimetype == westminster)) && strikeflag == cqtr3) { 818 QueueSound(SoundQ3); // Third Quarter 819 } 820 else if (((chimetype == westminster)) && strikeflag == cqtr0) { 821 QueueSound(SoundQ4); 822 for (int i = 1; i < chour1; i++) { 823 QueueSound(SoundTruncatedSingle); // Chime once less than hours 824 } 825 QueueSound(SoundTrailingSingle); 826 } // Chime Westminster final hours 827 828 829} // end of Chime 830 831 832// Routine to check for 'real' (static) events and floating events (e.g., Memorial Day, Thanksgiving, Mother's Day and Fathers Day) 833 834/* Memorial Day is Last Monday in May 835 Thanksgiving is 4th Thursday in November 836 Mother's Day is 2nd Sunday in May 837 Father's Day is 3rd Sunday in June 838 MLK Day is 3rd Monday in February 839 Memorial Day is last Monday in May 840 Labor Day is first Monday in September 841 Daylight Savings Times starts 2nd Sunday in March 842 Daylight Savings Times ends first Sunday in November 843 Indigenous People's Day is second Monday in October (also its Columbus Day) 844 Oktoberfest is 3rd Saturday in September 845 Election Day is first Tuesday in November 846 National Ice Cream Day is 3rd Sunday in July 847 848*/ 849 850void CheckForEvent(int m, int d, int dow) { // called with Month, Day within month and day of the week (0 = Sunday) 851 852 event = false; // assume neither static or floating 853 eventindex = -1; // initial index to eventstrings 854 855 // Static event check 856 857 for (int i = 0; i < eventnumber; i++) { // then check the static events 858 if ((setarray[setmonth] == eventmonth[i]) && (setarray[setday] == eventday[i])) 859 { event = true; // set if match on month and day 860 eventindex++; // found one! 861 eventstrings[eventindex] = eventdescription[i]; // store pointer to static event description 862 } 863 } 864 865 // Floating event check 866 867 floatstring = "none"; // initialize string 868 869 if ((dow == thursday) && (m == november) && (d >= 22) && (d <= 28)) { // Thanksgiving 870 floatstring = "Thanksgiving"; 871 } 872 else if ((dow == sunday) && (m == may) && (d >= 8) && (d <= 14)) { // Mother's Day 873 floatstring = "Mother's Day"; 874 } 875 else if ((dow == sunday) && (m == june) && (d >= 15) && (d <= 21)) { //Father's Day 876 floatstring = "Father's Day"; 877 } 878 else if ((dow == monday) && (m == january) && (d >= 15) && (d <= 21)) { //MLK Day 879 floatstring = "Martin Luther King Day"; 880 } 881 else if ((dow == saturday) && (m == october) && (d >= 15) && (d <= 21)) { //Oktoberfest starts 882 floatstring = "Oktoberfest Begins"; 883 } 884 else if ((dow == sunday) && (m == july) && (d >= 15) && (d <= 21)) { //Oktoberfest starts 885 floatstring = "National Ice Cream Day"; 886 } 887 else if ((dow == monday) && (m == february) && (d >= 15) && (d <= 21)) { //President's Day 888 floatstring = "President's Day!"; 889 } 890 else if ((dow == monday) && (m == september) && (d <= 7) ) { //Labor Day 891 floatstring = "Labor Day"; 892 } 893 else if ((dow == tuesday) && (m == november) && (d <= 7) ) { //Election Day 894 floatstring = "Election Day"; 895 } 896 else if ((dow == monday) && (m == october) && (d >= 8) && (d <= 14) ) { //Indigenous People's Day 897 floatstring = "Indigenous People's Day"; 898 } 899 else if ((dow == monday) && (m == may) && (d + 7 > 31) ) { //Memorial Day 900 floatstring = "Memorial Day"; 901 } 902 else if ((dow == sunday) && (m == march) && (d >= 8) && (d <= 14)) { // DST begins 903 floatstring = "DST Begins"; 904 } 905 else if ((dow == sunday) && (m == november) && (d <= 7) ) { //DST ends 906 floatstring = "DST Ends"; 907 } 908 909 if (floatstring != "none" ) { // did we load anything? 910 event = true; // if so, then we have one 911 eventindex++; // so load it into event display queue 912 eventstrings[eventindex] = floatstring.c_str(); // store pointer to static event description 913 } 914 915} // end of floatingevent 916 917void LEDBrightness() { 918 int LEDvalue; 919 LEDvalue = analogRead(LEDpin); // Read LDR value (may need to play with values) 920 DDTl("LEDvalue",LEDvalue); 921 //DDTs("LED value",LEDvalue); 922 // LEDvalue = map(LEDvalue, 0, 1023, 0, MAX_INTENSITY); //map to valid value for brightness (max intensity is 15 btw) 923 // if (LEDvalue <= 12) { 924 // i = minbright;} 925 // else if (LEDvalue > 13 ) { 926 // i=maxbright; } 927 // else {i = midbright;} 928 if (LEDvalue >=950) {i=maxbright;} 929 else if (LEDvalue >=700) {i=midbright;} 930 else {i=minbright;} 931 932 mx.control(MD_MAX72XX::INTENSITY, i); 933 // DDTl("Mapped LED value", i); 934 935 936 937} //end of LEDbrightness 938 939void Scrollup() { // used to 'wipe' previous display 940 for (uint8_t i = 0; i < 8; i++) { 941 mx.transform(MD_MAX72XX::TSU); delay(2 * DELAYTIME); 942 delay(DELAYTIME); 943 } 944} // End of Scrollup 945 946#ifdef OLED_Display 947 948void OLED_Update(){ 949 display.clearDisplay(); 950 display.setTextSize(2); // Normal 1:1 pixel scale 951 display.setTextColor(SSD1306_WHITE); // Draw white text 952 display.setCursor(0,0); // Start at top-left corner 953 display.println(" Date/Time"); // header line 954 display.print(setarray[setmonth]); // use mm/dd/yyyy 955 display.print("/"); 956 display.print(setarray[setday]); 957 display.print("/"); 958 display.println(setarray[setyear]); 959 display.setTextSize(3); // Draw 3X-scale text so time is somewhat readable 960 if (setarray[sethour] <=12) // convert military time to am pm 961 {phours = setarray[sethour];} 962 else 963 {phours = setarray[sethour]-12;} 964 if (phours <= 0){phours = 12;} // don't print 0 for midnite, print "12" 965 printtwo(phours," "); // print a standard hh:mm am/pm time on the oled 966 display.print(":"); 967 printtwo(setarray[setminute],"0"); 968 if (setarray[sethour] < 12) 969 {display.print("am");} 970 else 971 {display.print("pm");} 972 display.display(); // update display 973 974} // end of OLED display 975 976void printtwo(int value, String fillchar){ // print two always and use fill to make it so 977 if (value <10) {display.print(fillchar);} // blank space for hours, 0 for minutes, seconds 978 display.print(value); 979 } 980#endif 981 982void scrollText(char *p) // copied from library 983{ 984 uint8_t charWidth; 985 uint8_t cBuf[8]; // this should be ok for all built-in fonts 986 mx.clear(); 987 while (*p != '\\0') 988 { 989 charWidth = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf); 990 991 for (uint8_t i = 0; i <= charWidth; i++) // allow space between characters 992 {mx.transform(MD_MAX72XX::TSL); 993 if (i < charWidth) 994 mx.setColumn(0, cBuf[i]); 995 delay(DELAYTIME);} 996 } 997} // End of Scroll Text 998 999void printText(char *pMsg, int LOS, bool CenterJustify) // copied and modified from library 1000// Print the text string to the LED matrix modules specified. 1001// Message area is padded with blank columns after printing. 1002// And center justified if third argument is "true" 1003{ 1004 uint8_t modStart = 0; 1005 uint8_t modEnd = MAX_DEVICES - 1; 1006 uint8_t state = 0; 1007 uint8_t curLen; 1008 uint16_t showLen; 1009 uint8_t cBuf[8]; 1010 int16_t col = ((modEnd + 1) * COL_SIZE) - 1; 1011 int pixelcount = 0; 1012 int ccounter = LOS; 1013 1014 mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 1015 1016 do // finite state machine to print the characters in the space available 1017 { switch (state) 1018 { 1019 case 0: // Load the next character from the font table 1020 // if we reached end of message, reset the message pointer 1021 if (*pMsg == '\\0') 1022 { 1023 showLen = col - (modEnd * COL_SIZE); // padding characters 1024 state = 2; 1025 break; 1026 } 1027 1028 // retrieve the next character form the font file 1029 1030 showLen = mx.getChar(*pMsg++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf); 1031 if (ccounter > 0) { 1032 pixelcount = (pixelcount + showLen) + CHAR_SPACING; 1033 ccounter--; 1034 } 1035 curLen = 0; 1036 state++; 1037 // !! deliberately fall through to next state to start displaying 1038 1039 case 1: // display the next part of the character 1040 mx.setColumn(col--, cBuf[curLen++]); 1041 1042 // done with font character, now display the space between chars 1043 if (curLen == showLen) 1044 { 1045 showLen = CHAR_SPACING; 1046 state = 2; 1047 } 1048 break; 1049 1050 case 2: // initialize state for displaying empty columns 1051 1052 curLen = 0; 1053 1054 state++; 1055 // fall through 1056 1057 case 3: // display inter-character spacing or end of message padding (blank columns) 1058 mx.setColumn(col--, 0); 1059 curLen++; 1060 if (curLen == showLen) 1061 state = 0; 1062 break; 1063 1064 default: 1065 col = -1; // this definitely ends the do loop 1066 } 1067 } while (col >= (modStart * COL_SIZE)); 1068 1069 if (CenterJustify) { 1070 for (int i = 1; i <= (((MAX_DEVICES * COL_SIZE) - pixelcount) / 2); i++) { 1071 mx.transform( MD_MAX72XX::TSR); 1072 } 1073 } 1074 mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON); 1075} 1076void printCenter(String StringtoPrint) // Loads the print buffer and centers it 1077{ 1078 int LOS = StringtoPrint.length(); // Get the string's length 1079 for (int i = 0; i < BufferStringLength; i++) { 1080 BufferString[i] = ' '; // clear buffer 1081 } 1082 for (int i = 0; i < LOS; i++) { 1083 BufferString[i] = StringtoPrint[i]; // transfer 1084 printText(BufferString, LOS, true); // Print, providing length of string and "Yes, center" 1085 1086 } 1087} // End of Center and Load 1088 1089void ShowValue(int myindex, String setdescription) // Display while in setup mode 1090{ // shows what item is setting and its value 1091 1092 for (int i = 0; i < BufferStringLength; i++) {BufferString[i] = ' ';} // clear buffer 1093 setdescription.toCharArray(BufferString, setdesclength); // move description to output buffer 1094 LoadNumber(setarray[setupindex]); 1095 BufferString[setdesclength-1] = ' '; 1096 for (int i = 0; i <setdesclength; i++) {BufferString[i + setdesclength] = TDigits[i];} 1097 if (myindex != setyear) { // only the year is 4 digits, else 2 1098 BufferString[4] = ' '; 1099 BufferString[5] = ' '; 1100 if (BufferString[6] == '0') {BufferString[6] = ' ';} // and suppress leading 0 for 2 digit numbers too 1101 } 1102 BufferString[8] = '\\0'; // and terminate 1103 printText(BufferString, 7, false); 1104 1105 1106} // End of Show Value 1107 1108void LoadNumber(int numtoload) { // Converts number to four digit Ascii array 1109 int tempnum = numtoload; 1110 for (int i = 3; i >= 0; i--) { 1111 TDigits[i] = (tempnum % 10) + DecToAscii;; 1112 tempnum = tempnum / 10; 1113 } 1114} // end of LoadNumber 1115 1116void QueueSound(int SoundFile) { // place a sound to be played into sequence 1117 1118 if ((SoundQueuePtr == SizeQueue) || (SoundQueueCtr <= 0)) { 1119 SoundQueuePtr = -1; // Dont overflow the queue 1120 } 1121 SoundQueuePtr++; // Increment pointer 1122 SoundQueue[SoundQueuePtr] = SoundFile; // and store the sound chosen 1123 SoundQueueCtr++; // and increment # sounds in queue 1124} // end of Queue Sound File 1125 1126void PlaySound() { // Plays appropriate Sound file 1127 if (SoundQueueCtr > 0) { // if nothing in the queue, just return 1128 if (digitalRead(SoundBusyPin) == LOW) { //or if sound card busy, just return 1129 return; 1130 } //until idle 1131 if (SoundPlayPtr == SizeQueue) { 1132 SoundPlayPtr = -1; // Dont go past the queue 1133 } 1134 SoundPlayPtr++; // Increment pointer 1135 digitalWrite(FirstSoundPin + SoundQueue[SoundPlayPtr], LOW); //Play the sound 1136 delay(fxset); // hold to start the sound 1137 digitalWrite(FirstSoundPin + SoundQueue[SoundPlayPtr], HIGH); //Turn off the sound 1138 delay(fxset); // Ensure its set 1139 SoundQueueCtr--; // and decrement sounds yet to be played 1140 if (SoundQueueCtr <= 0) { 1141 SoundPlayPtr = -1; 1142 }; // reset play pointer when queue is empty 1143 } 1144 1145} // end of PlaySound 1146/* 1147 void PlaySoundUART() // uncomment for FX sound board UART use 1148 1149 // sfx.playTrack(name); } 1150 { 1151 Serial.print("\ 1152Playing track \\""); Serial.print(name); Serial.print("\\""); 1153 if (! sfx.playTrack(name) ) { 1154 Serial.println("Failed to play track?"); 1155 } 1156 } 1157*/ 1158 1159 1160#ifdef showoffcode 1161 1162void ShowOff() { // Played at startup -- just the MX Panel Test Graphics 1163 QueueSound(SoundShowOff); // play Game of Thones theme as sound 1164 PlaySound(); 1165 scrollText("Showing Off"); 1166 rows(); 1167 columns(); 1168 cross(); 1169 checkboard(); 1170 bullseye(); 1171 bounce(); 1172 stripe(); 1173 stripe(); 1174 transformation1(); 1175 transformation2(); 1176 bullseye(); 1177 spiral(); 1178 delay(2000); 1179 DisplayIndex = DisplayTime; // force display of time after showing off display 1180} // end of Show Off 1181 1182void rows() // these routines are all 1183// Demonstrates the use of setRow() // from the MX library 1184{mx.clear(); 1185 for (uint8_t row = 0; row < ROW_SIZE; row++) 1186 { 1187 mx.setRow(row, 0xff); 1188 delay(2 * DELAYTIME); 1189 mx.setRow(row, 0x00); 1190 } 1191} 1192 1193void checkboard() 1194// nested rectangles spanning the entire display 1195{ 1196 uint8_t chkCols[][2] = { { 0x55, 0xaa }, { 0x33, 0xcc }, { 0x0f, 0xf0 }, { 0xff, 0x00 } }; 1197 mx.clear(); 1198 for (uint8_t pattern = 0; pattern < sizeof(chkCols) / sizeof(chkCols[0]); pattern++) 1199 { 1200 uint8_t col = 0; 1201 uint8_t idx = 0; 1202 uint8_t rep = 1 << pattern; 1203 1204 while (col < mx.getColumnCount()) 1205 { 1206 for (uint8_t r = 0; r < rep; r++) 1207 mx.setColumn(col++, chkCols[pattern][idx]); // use odd/even column masks 1208 idx++; 1209 if (idx > 1) idx = 0; 1210 } 1211 delay(10 * DELAYTIME); 1212 } 1213} // end of Checkboard 1214 1215void columns() 1216// Demonstrates the use of setColumn() 1217{ 1218 1219 mx.clear(); 1220 1221 for (uint8_t col = 0; col < mx.getColumnCount(); col++) 1222 { 1223 mx.setColumn(col, 0xff); 1224 delay(DELAYTIME / MAX_DEVICES); 1225 mx.setColumn(col, 0x00); 1226 } 1227} 1228 1229void cross() 1230// Combination of setRow() and setColumn() with user controlled 1231// display updates to ensure concurrent changes. 1232{ 1233 1234 mx.clear(); 1235 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 1236 1237 // diagonally down the display R to L 1238 for (uint8_t i = 0; i < ROW_SIZE; i++) 1239 { 1240 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1241 { 1242 mx.setColumn(j, i, 0xff); 1243 mx.setRow(j, i, 0xff); 1244 } 1245 mx.update(); 1246 delay(DELAYTIME); 1247 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1248 { 1249 mx.setColumn(j, i, 0x00); 1250 mx.setRow(j, i, 0x00); 1251 } 1252 } 1253 1254 // moving up the display on the R 1255 for (int8_t i = ROW_SIZE - 1; i >= 0; i--) 1256 { 1257 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1258 { 1259 mx.setColumn(j, i, 0xff); 1260 mx.setRow(j, ROW_SIZE - 1, 0xff); 1261 } 1262 mx.update(); 1263 delay(DELAYTIME); 1264 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1265 { 1266 mx.setColumn(j, i, 0x00); 1267 mx.setRow(j, ROW_SIZE - 1, 0x00); 1268 } 1269 } 1270 1271 // diagonally up the display L to R 1272 for (uint8_t i = 0; i < ROW_SIZE; i++) 1273 { 1274 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1275 { 1276 mx.setColumn(j, i, 0xff); 1277 mx.setRow(j, ROW_SIZE - 1 - i, 0xff); 1278 } 1279 mx.update(); 1280 delay(DELAYTIME); 1281 for (uint8_t j = 0; j < MAX_DEVICES; j++) 1282 { 1283 mx.setColumn(j, i, 0x00); 1284 mx.setRow(j, ROW_SIZE - 1 - i, 0x00); 1285 } 1286 } 1287 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON); 1288} 1289 1290void bullseye() 1291// Demonstrate the use of buffer based repeated patterns 1292// across all devices. 1293{ 1294 1295 mx.clear(); 1296 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 1297 1298 for (uint8_t n = 0; n < 3; n++) 1299 { 1300 byte b = 0xff; 1301 int i = 0; 1302 1303 while (b != 0x00) 1304 { 1305 for (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1306 { 1307 mx.setRow(j, i, b); 1308 mx.setColumn(j, i, b); 1309 mx.setRow(j, ROW_SIZE - 1 - i, b); 1310 mx.setColumn(j, COL_SIZE - 1 - i, b); 1311 } 1312 mx.update(); 1313 delay(3 * DELAYTIME); 1314 for (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1315 { 1316 mx.setRow(j, i, 0); 1317 mx.setColumn(j, i, 0); 1318 mx.setRow(j, ROW_SIZE - 1 - i, 0); 1319 mx.setColumn(j, COL_SIZE - 1 - i, 0); 1320 } 1321 1322 bitClear(b, i); 1323 bitClear(b, 7 - i); 1324 i++; 1325 } 1326 1327 while (b != 0xff) 1328 { 1329 for (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1330 { 1331 mx.setRow(j, i, b); 1332 mx.setColumn(j, i, b); 1333 mx.setRow(j, ROW_SIZE - 1 - i, b); 1334 mx.setColumn(j, COL_SIZE - 1 - i, b); 1335 } 1336 mx.update(); 1337 delay(3 * DELAYTIME); 1338 for (uint8_t j = 0; j < MAX_DEVICES + 1; j++) 1339 { 1340 mx.setRow(j, i, 0); 1341 mx.setColumn(j, i, 0); 1342 mx.setRow(j, ROW_SIZE - 1 - i, 0); 1343 mx.setColumn(j, COL_SIZE - 1 - i, 0); 1344 } 1345 1346 i--; 1347 bitSet(b, i); 1348 bitSet(b, 7 - i); 1349 } 1350 } 1351 1352 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON); 1353} 1354 1355void spiral() 1356// setPoint() used to draw a spiral across the whole display 1357{ 1358 1359 int rmin = 0, rmax = ROW_SIZE - 1; 1360 int cmin = 0, cmax = (COL_SIZE * MAX_DEVICES) - 1; 1361 1362 mx.clear(); 1363 while ((rmax > rmin) && (cmax > cmin)) 1364 { 1365 // do row 1366 for (int i = cmin; i <= cmax; i++) 1367 { 1368 mx.setPoint(rmin, i, true); 1369 delay(DELAYTIME / MAX_DEVICES); 1370 } 1371 rmin++; 1372 1373 // do column 1374 for (uint8_t i = rmin; i <= rmax; i++) 1375 { 1376 mx.setPoint(i, cmax, true); 1377 delay(DELAYTIME / MAX_DEVICES); 1378 } 1379 cmax--; 1380 1381 // do row 1382 for (int i = cmax; i >= cmin; i--) 1383 { 1384 mx.setPoint(rmax, i, true); 1385 delay(DELAYTIME / MAX_DEVICES); 1386 } 1387 rmax--; 1388 1389 // do column 1390 for (uint8_t i = rmax; i >= rmin; i--) 1391 { 1392 mx.setPoint(i, cmin, true); 1393 delay(DELAYTIME / MAX_DEVICES); 1394 } 1395 cmin++; 1396 } 1397} 1398 1399void bounce() 1400// Animation of a bouncing ball 1401{ 1402 const int minC = 0; 1403 const int maxC = mx.getColumnCount() - 1; 1404 const int minR = 0; 1405 const int maxR = ROW_SIZE - 1; 1406 1407 int nCounter = 0; 1408 1409 int r = 0, c = 2; 1410 int8_t dR = 1, dC = 1; // delta row and column 1411 1412 1413 mx.clear(); 1414 1415 while (nCounter++ < 200) 1416 { 1417 mx.setPoint(r, c, false); 1418 r += dR; 1419 c += dC; 1420 mx.setPoint(r, c, true); 1421 delay(DELAYTIME / 2); 1422 1423 if ((r == minR) || (r == maxR)) 1424 dR = -dR; 1425 if ((c == minC) || (c == maxC)) 1426 dC = -dC; 1427 } 1428} 1429void stripe() 1430// Demonstrates animation of a diagonal stripe moving across the display 1431// with points plotted outside the display region ignored. 1432{ 1433 const uint16_t maxCol = MAX_DEVICES*ROW_SIZE; 1434 const uint8_t stripeWidth = 10; 1435 1436 mx.clear(); 1437 1438 for (uint16_t col=0; col<maxCol + ROW_SIZE + stripeWidth; col++) 1439 { 1440 for (uint8_t row=0; row < ROW_SIZE; row++) 1441 { 1442 mx.setPoint(row, col-row, true); 1443 mx.setPoint(row, col-row - stripeWidth, false); 1444 } 1445 delay(DELAYTIME); 1446 } 1447} 1448 1449void transformation1() 1450// Demonstrates the use of transform() to move bitmaps on the display 1451// In this case a user defined bitmap is created and animated. 1452{ 1453 uint8_t arrow[COL_SIZE] = 1454 { 1455 0b00001000, 1456 0b00011100, 1457 0b00111110, 1458 0b01111111, 1459 0b00011100, 1460 0b00011100, 1461 0b00111110, 1462 0b00000000 1463 }; 1464 1465 MD_MAX72XX::transformType_t t[] = 1466 { 1467 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1468 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1469 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1470 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1471 MD_MAX72XX::TFLR, 1472 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1473 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1474 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1475 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1476 MD_MAX72XX::TRC, 1477 MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, 1478 MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, 1479 MD_MAX72XX::TFUD, 1480 MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, 1481 MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, 1482 MD_MAX72XX::TINV, 1483 MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, 1484 MD_MAX72XX::TINV 1485 }; 1486 1487 // transformation 1488 1489 mx.clear(); 1490 1491 // use the arrow bitmap 1492 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); 1493 for (uint8_t j=0; j<mx.getDeviceCount(); j++) 1494 mx.setBuffer(((j+1)*COL_SIZE)-1, COL_SIZE, arrow); 1495 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON); 1496 delay(DELAYTIME); 1497 1498 // run through the transformations 1499 mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::ON); 1500 for (uint8_t i=0; i<(sizeof(t)/sizeof(t[0])); i++) 1501 { 1502 mx.transform(t[i]); 1503 delay(DELAYTIME*4); 1504 } 1505 mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::OFF); 1506} 1507 1508void transformation2() 1509// Demonstrates the use of transform() to move bitmaps on the display 1510// In this case font characters are loaded into the display for animation. 1511{ 1512 MD_MAX72XX::transformType_t t[] = 1513 { 1514 MD_MAX72XX::TINV, 1515 MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, 1516 MD_MAX72XX::TINV, 1517 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1518 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1519 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1520 MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, 1521 MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, 1522 MD_MAX72XX::TSD, MD_MAX72XX::TSU, MD_MAX72XX::TSD, MD_MAX72XX::TSU, 1523 MD_MAX72XX::TFLR, MD_MAX72XX::TFLR, MD_MAX72XX::TFUD, MD_MAX72XX::TFUD 1524 };} 1525#endif //showoffcode// 1526
Downloadable files
Updated code for automatic DST begin and end
I mistakenly thought that the DS3231 RTC module 'knew' about DST transitions. Doesn't. So I've added code to make that transition to/from DST automatic
Updated code for automatic DST begin and end
Clock sounds
The ten sounds used to make up the startup sound, Westminster Chimes, bells and Game of Thrones music
Clock sounds
Matrix Clock Connections
Schematic substitute
Matrix Clock Connections
Matrix Clock Connections
Schematic substitute
Matrix Clock Connections
Updated code for automatic DST begin and end
I mistakenly thought that the DS3231 RTC module 'knew' about DST transitions. Doesn't. So I've added code to make that transition to/from DST automatic
Updated code for automatic DST begin and end
Clock sounds
The ten sounds used to make up the startup sound, Westminster Chimes, bells and Game of Thrones music
Clock sounds
Comments
Only logged in users can leave comments
Anonymous user
2 years ago
What a great project. Mine is working fine thank you :-) I have managed to change the temperature display to Celcius. Can anyone tell me how to reverse the order of the month and date to show dd/mm/yyyy? Thanks for your help Steve
spudnut1
2 years ago
It actually should be pretty easy. I haven't tested it but you should be able to just change const int DMptr = 0; const int DDptr = 3; to be const int DMptr = 3; const int DDptr = 0;
spudnut1
2 years ago
You should be able to use the mini (I didn't know they existed). You could either just do westminster or just bell or lose the startup and demo/showoff mode sounds. Then you can rejigger the file names and pin hookups to match
novax1
2 years ago
Hello it did not make the automatic time change of time. This can be configured to work, with the Spanish time Thank you
novax1
2 years ago
Hello. I want to apologize because I did not understand in the See-Through Matrix Clock Connections that all pins 0,1,2,3,4,5,6,7, of fx sound had to be connected to the Arduino mega. in my case 30,31,32,33,34,35,36,37. now everything works perfectly. thank you and excuse me. great job
novax1
2 years ago
Thank you for your quick response and sorry for the inconvenience. this already exceeds me. Thank you
spudnut1
2 years ago
Great news! I’m so glad to hear! Enjoy! Irwin Goverman Mobile: (206)930-2108 Irwin.goverman@gmail.com Sent via iPad
spudnut1
2 years ago
Might be easier to just order the full size sound board!
spudnut1
2 years ago
I have newer versions of the code that I can post soon. Did it fix when you unplugged it and started it again? Irwin L. Goverman (206)930-2108 mobile Sent from my iPhone
Anonymous user
2 years ago
Anyone try this project using a ESP32 instead? I was thinking of the ESP32 for the WIFI abilities to connect to the NTP servers and maybe a weather feeder.
spudnut1
2 years ago
Yes... the only issue is whether you have enough GPIO pins. I just built a similar NEOPIXEL clock that uses an ESP8266 and scrolling clocks that use the ESP8266 as a co-processor for internet access to news, weather, time etc.
Anonymous user
2 years ago
Can we run this project on Proteus And can u send me Wiring diagram with all pin configuration And much more And also can I do this project with now 4 8*8 Dot matrix Max7219
novax1
2 years ago
Can anyone tell me how to reverse the order of the month and date to show dd/mm/yyyy? thank
spudnut1
2 years ago
It actually should be pretty easy. I haven't tested it but you should be able to just change const int DMptr = 0; const int DDptr = 3; to be const int DMptr = 3; const int DDptr = 0;
novax1
2 years ago
Thank you very much it works before it looks like this 2/5/2021, now shown 05/2/2021
novax1
2 years ago
Hello, I really like your work. There is an option to show the temperature in degrees.
spudnut1
2 years ago
I am not sure if there’s a question in your comment…. The clock does show temperature in degrees. I am about to post a new version that also does internet time, news and weather…
spudnut1
2 years ago
What kind of problems are you having with the sounds? Are you using the FX Soundboard with speaker outputs? (There's another version that does not have the amplifier. Each sound is a number Tnn.OGG file -- they are triggered by a corresponding "low" on the associated sound pin
spudnut1
2 years ago
Next debugging step would be to check the sound board connections and use a simple jumper to test that each sound plays correctly when 'asked to'. It sounds like they may not be right. Playing one less per hour might mean the last 'trailing' (its longer) sound may be missing somehow
spudnut1
2 years ago
Have you checked the chime/bell/silent switch? It’s a SPDT toggle. The center goes to ground a d the two outer connections switch between Westminster and simple bell. Irwin Goverman Mobile: (206)930-2108 Irwin.goverman@gmail.com Sent via iPad
novax1
2 years ago
e tested the sound module individually and they reproduce all sounds. but when I connect the sound module, so that it works with your code, hours go by and it doesn't play anything.
novax1
2 years ago
because when it's 5 o'clock you hear 4 simple bells that happens at all times, always one less. The SPDT is connected as you indicate but it only works in a simple bell position, when changing position the switch the Westminster does not activate. Thank you
novax1
2 years ago
Sorry but I'm a clumsy do not connect the SPDT. Now it works. just Chime the hour. these nothing, Chime the quarter hour Chime the half hour Chime the 3/4 hour sorry for the inconvenience
spudnut1
2 years ago
No problem -- its a complex clock and if that is the biggest (or only) mistake you made (especially since I'm too dumb to figure out Fritzing!) you did great! I have a newer version of the same clock that uses multiple displays, reaches out to the internet for news, weather and the time setting. I will post it soon.
novax1
2 years ago
I have the fx mini module it only has 0 to 7, act. then you show in the instructions connect Pins 0-9 connected to Pins 30-39 on Arduino Mega. I have 0 connected to pin 30 and 7 to pin 39 ?? I choose like that. because I can't get one less tone every hour. I would like to please be able to correct this thanks. I like your great work. regards
novax1
2 years ago
Thanks for answering and for your help. the audio card is an Adafruit FX Soundboard mini with a separate amplifier. I'll check what you tell me.
novax1
2 years ago
eproved and they all sound but with the clock it continues giving a tone less
spudnut1
2 years ago
So, still not what you want, right? You want 5/02/2021, I think. If still not right, let me know and I will fix it for you.
spudnut1
2 years ago
Oh, sorry I read your reply wrong..... I think it IS right. But let me know
spudnut1
2 years ago
More thoughts -- have you tried to play the individual OGG files on your computer just to see if they came across correctly (and that I uploaded them right!). I'm happy to email them otherwise.
novax1
2 years ago
Greetings. I'm trying to reproduce the sounds as programmed but I can't. I am using Adafruit Soundboard with amplifier. can you help me thanks
novax1
2 years ago
this is the one that shows before the correction 2/5/2021 ... 2 is the month 5 the day Should I show this I think it's possible? 05/02/2021 I still don't understand why I have to translate from English to Spanish. Excuse me. thanks
Anonymous user
2 years ago
HERE I NEED YOUR HELP IN SPDT SWITCH CONNECTION WHICH U HAVE WROTE CENTER TO GND AND OTHER TERMINALS TO MEGA 5 AND 6 THIS CONNECTION WILL SHORT VCC AND GND SHOW JUSTIFY ANSWER
spudnut1
2 years ago
No it does not short it. Pins 5 and 6 are not VCC.... They are Pullup connections to digital pins. All the switches (pushbutton and 'toggle') connect a digital pin to ground (not VCC to ground) and that's how they work. Pulled up to 'HIGH' and 'LOW' indicates that switch or pushbutton is 'on'. Does that help?
Anonymous user
2 years ago
NEED YOUR HELP BUDDIE GOT SOME ISSUE HERE [invalid conversion from 'const char*' to 'char*' [-fpermissive] ] AND ALSO UPLOAD THE WHOLE CKT WIRING DIAGRAM PIC AND CAN WE MAKE THIS WHOLE CKT USING ARDUINO NANO WAITING FOR YOUR RESPONSE REPLY AS FAST AS U CAN
Anonymous user
2 years ago
Looking forward for your updates
spudnut1
2 years ago
I have had the same problem. I think redoing the logic around the date event strings would fix it.
Anonymous user
2 years ago
Hi, Very nice project! I have something similar and I have a request if you know... How can I do it in that way on void loop, after clock scroll, the next scroll will be the same clock software, but that for another time (UTC to say); and next scroll back on the first ?!
spudnut1
2 years ago
You can figure out an offset, load a 2nd set of date/time array members and just insert the second scroll into the Case statement
Anonymous user
2 years ago
I've checked and re-check my wiring and code but the output on the display is in a vertical orientation instead of horizontal. Has anybody else had this and is there a cure for it?
spudnut1
4 years ago
You should be able to use the mini (I didn't know they existed). You could either just do westminster or just bell or lose the startup and demo/showoff mode sounds. Then you can rejigger the file names and pin hookups to match
spudnut1
2 years ago
I have newer versions of the code that I can post soon. Did it fix when you unplugged it and started it again? Irwin L. Goverman (206)930-2108 mobile Sent from my iPhone
spudnut1
2 years ago
Might be easier to just order the full size sound board!
spudnut1
2 years ago
Great news! I’m so glad to hear! Enjoy! Irwin Goverman Mobile: (206)930-2108 Irwin.goverman@gmail.com Sent via iPad
novax1
2 years ago
Hello it did not make the automatic time change of time. This can be configured to work, with the Spanish time Thank you
novax1
2 years ago
Hello. I want to apologize because I did not understand in the See-Through Matrix Clock Connections that all pins 0,1,2,3,4,5,6,7, of fx sound had to be connected to the Arduino mega. in my case 30,31,32,33,34,35,36,37. now everything works perfectly. thank you and excuse me. great job
novax1
2 years ago
Thank you for your quick response and sorry for the inconvenience. this already exceeds me. Thank you
spudnut1
4 years ago
No problem -- its a complex clock and if that is the biggest (or only) mistake you made (especially since I'm too dumb to figure out Fritzing!) you did great! I have a newer version of the same clock that uses multiple displays, reaches out to the internet for news, weather and the time setting. I will post it soon.
novax1
2 years ago
I have the fx mini module it only has 0 to 7, act. then you show in the instructions connect Pins 0-9 connected to Pins 30-39 on Arduino Mega. I have 0 connected to pin 30 and 7 to pin 39 ?? I choose like that. because I can't get one less tone every hour. I would like to please be able to correct this thanks. I like your great work. regards
novax1
2 years ago
eproved and they all sound but with the clock it continues giving a tone less
novax1
2 years ago
Thanks for answering and for your help. the audio card is an Adafruit FX Soundboard mini with a separate amplifier. I'll check what you tell me.
spudnut1
4 years ago
What kind of problems are you having with the sounds? Are you using the FX Soundboard with speaker outputs? (There's another version that does not have the amplifier. Each sound is a number Tnn.OGG file -- they are triggered by a corresponding "low" on the associated sound pin
novax1
2 years ago
because when it's 5 o'clock you hear 4 simple bells that happens at all times, always one less. The SPDT is connected as you indicate but it only works in a simple bell position, when changing position the switch the Westminster does not activate. Thank you
novax1
2 years ago
Sorry but I'm a clumsy do not connect the SPDT. Now it works. just Chime the hour. these nothing, Chime the quarter hour Chime the half hour Chime the 3/4 hour sorry for the inconvenience
novax1
2 years ago
e tested the sound module individually and they reproduce all sounds. but when I connect the sound module, so that it works with your code, hours go by and it doesn't play anything.
spudnut1
2 years ago
Next debugging step would be to check the sound board connections and use a simple jumper to test that each sound plays correctly when 'asked to'. It sounds like they may not be right. Playing one less per hour might mean the last 'trailing' (its longer) sound may be missing somehow
spudnut1
2 years ago
Have you checked the chime/bell/silent switch? It’s a SPDT toggle. The center goes to ground a d the two outer connections switch between Westminster and simple bell. Irwin Goverman Mobile: (206)930-2108 Irwin.goverman@gmail.com Sent via iPad
spudnut1
4 years ago
Oh, sorry I read your reply wrong..... I think it IS right. But let me know
novax1
2 years ago
this is the one that shows before the correction 2/5/2021 ... 2 is the month 5 the day Should I show this I think it's possible? 05/02/2021 I still don't understand why I have to translate from English to Spanish. Excuse me. thanks
novax1
2 years ago
Greetings. I'm trying to reproduce the sounds as programmed but I can't. I am using Adafruit Soundboard with amplifier. can you help me thanks
spudnut1
2 years ago
More thoughts -- have you tried to play the individual OGG files on your computer just to see if they came across correctly (and that I uploaded them right!). I'm happy to email them otherwise.
spudnut1
4 years ago
So, still not what you want, right? You want 5/02/2021, I think. If still not right, let me know and I will fix it for you.
novax1
4 years ago
Can anyone tell me how to reverse the order of the month and date to show dd/mm/yyyy? thank
novax1
2 years ago
Thank you very much it works before it looks like this 2/5/2021, now shown 05/2/2021
spudnut1
2 years ago
It actually should be pretty easy. I haven't tested it but you should be able to just change const int DMptr = 0; const int DDptr = 3; to be const int DMptr = 3; const int DDptr = 0;
novax1
4 years ago
Hello, I really like your work. There is an option to show the temperature in degrees.
spudnut1
2 years ago
I am not sure if there’s a question in your comment…. The clock does show temperature in degrees. I am about to post a new version that also does internet time, news and weather…
Anonymous user
4 years ago
NEED YOUR HELP BUDDIE GOT SOME ISSUE HERE [invalid conversion from 'const char*' to 'char*' [-fpermissive] ] AND ALSO UPLOAD THE WHOLE CKT WIRING DIAGRAM PIC AND CAN WE MAKE THIS WHOLE CKT USING ARDUINO NANO WAITING FOR YOUR RESPONSE REPLY AS FAST AS U CAN
spudnut1
2 years ago
I have had the same problem. I think redoing the logic around the date event strings would fix it.
Anonymous user
2 years ago
Looking forward for your updates
Anonymous user
4 years ago
Anyone try this project using a ESP32 instead? I was thinking of the ESP32 for the WIFI abilities to connect to the NTP servers and maybe a weather feeder.
spudnut1
2 years ago
Yes... the only issue is whether you have enough GPIO pins. I just built a similar NEOPIXEL clock that uses an ESP8266 and scrolling clocks that use the ESP8266 as a co-processor for internet access to news, weather, time etc.
Anonymous user
5 years ago
HERE I NEED YOUR HELP IN SPDT SWITCH CONNECTION WHICH U HAVE WROTE CENTER TO GND AND OTHER TERMINALS TO MEGA 5 AND 6 THIS CONNECTION WILL SHORT VCC AND GND SHOW JUSTIFY ANSWER
spudnut1
2 years ago
No it does not short it. Pins 5 and 6 are not VCC.... They are Pullup connections to digital pins. All the switches (pushbutton and 'toggle') connect a digital pin to ground (not VCC to ground) and that's how they work. Pulled up to 'HIGH' and 'LOW' indicates that switch or pushbutton is 'on'. Does that help?
Anonymous user
5 years ago
Can we run this project on Proteus And can u send me Wiring diagram with all pin configuration And much more And also can I do this project with now 4 8*8 Dot matrix Max7219
Anonymous user
5 years ago
What a great project. Mine is working fine thank you :-) I have managed to change the temperature display to Celcius. Can anyone tell me how to reverse the order of the month and date to show dd/mm/yyyy? Thanks for your help Steve
spudnut1
2 years ago
It actually should be pretty easy. I haven't tested it but you should be able to just change const int DMptr = 0; const int DDptr = 3; to be const int DMptr = 3; const int DDptr = 0;
Anonymous user
5 years ago
How can I change the temperature to Celsius?
Anonymous user
2 years ago
Hi You just need to remove the 'true' between the brackets as shown in the code below // Read temperature as Celsius (the default) float t = dht.readTemperature(); // Read temperature as Fahrenheit (isFahrenheit = true) float f = dht.readTemperature(true); Cheers Steve
dbjurstr_3
5 years ago
I've checked and re-check my wiring and code but the output on the display is in a vertical orientation instead of horizontal. Has anybody else had this and is there a cure for it?
Anonymous user
5 years ago
Hi, Very nice project! I have something similar and I have a request if you know... How can I do it in that way on void loop, after clock scroll, the next scroll will be the same clock software, but that for another time (UTC to say); and next scroll back on the first ?!
spudnut1
2 years ago
You can figure out an offset, load a 2nd set of date/time array members and just insert the second scroll into the Case statement
spudnut1
3 Followers
•9 Projects
15
83
tbbucsfan1976
2 years ago
I made this clock for my shop, I live in south Texas and temperatures get above 100' or more, how do I add a third digit (Ex. 109.5 ' F) to the temperature display on the Matrix display ? Thanks, tbbucsfan1976