Components and supplies
Adafruit DS3231 RTC
Pushbutton Switch, Momentary
Adafruit LCD 20x4 Backlit with Backpack
Rotary potentiometer (generic)
Adafruit Wave Shield
Arduino UNO
DHT11 Temperature & Humidity Sensor (4 pins)
Adafruit Seven Segment 1.5" LED Red
Project description
Code
Clock Code
arduino
This is the logic for the clock Arduino for time and weather and to control the chiming.
1/* 2 * Clock project using LED, LCD and Wave Shield 3 * Provides date, time, temp, humidity and limited number of event notifications 4 * Also can chime in multiple ways, including Westminster chimes and cuckoo clock 5 * Chimes are provided by Adafruit Wave Shield on serial bus 6 * A second Arduino to run the Wave Shield is used due to memory limitations 7 * and all the global variables and libraries involved in sound, LED, LCD, etc. 8 */ 9 10/* Files on SD Card must match this sketch: 11 * in format SOUNDnn.WAV where nn is two digit sound number 12 * and one file called "STARTUP.WAV" that is played once on SETUP 131 Short 1 (no Westminster) 142 Short 2 153 Short 3 164 Short 4 175 Short 5 186 Short 6 197 Short 7 208 Short 8 219 Short 9 2210 Short 10 2311 Short 11 2412 Short 12 2513 Q1 (Quarter Hour Chimes) 2614 Q2 2715 Q3 2816 Long 1 (Westminster Hours) 2917 Long 2 (with built in Q4) 3018 Long 3 3119 Long 4 3220 Long 5 3321 Long 6 3422 Long 7 3523 Long 8 3624 Long 9 3725 Long 10 3826 Long 11 3927 Long 12 4028 Cuckoo Clock 1 4129 Cuckoo Clock 2 4230 Cuckoo Clock 3 4331 Cuckoo Clock 4 4432 Cuckoo Clock 5 4533 Cuckoo Clock 6 4634 Cuckoo Clock 7 4735 Cuckoo Clock 8 4836 Cuckoo Clock 9 4937 Cuckoo Clock 10 5038 Cuckoo Clock 11 5139 Cuckoo Clock 12 52 53 54 */ 55 56// Code to set up the clock 57// Pushbutton 1 is the toggler , cycle between vhime, year, month, day, hours, minutes, seconds 58// Pushbutton 2 is the increment up one 59// Pushbutton 3 is the decrement down one 60 61// Chime setup 62// 0 = No chimes 63// 1 = Chime for hour and 1/2 hour only 64// 2 = Westminster hours + quarterly 65// 3 = Cuckoo clock (hours and 1/2 hour only like above but different chime 66// 4 = Westminster silenced after 11pm and before 7am 67 68 69// include the libraries for LCD Display, DHT-11 Temperature/humidity sensor and DS3231 RTC and 70// include libraries for bigger seven segment display with backpack 71#include "DHT.h" 72#include <Wire.h> 73#include "RTClib.h" 74#include <LiquidCrystal_I2C.h> 75#include "Adafruit_LEDBackpack.h" 76 77 78// Set up output functions 79 80Adafruit_7segment matrix = Adafruit_7segment(); 81 82LiquidCrystal_I2C lcd(0x27,20,4); // initialize LCD 83 84#define DHTPIN 8 //Temp Humidity sensor on pin 8 85#define DHTTYPE DHT11 // DHT 11 because the sensor is that type 86 87// Initialize DHT sensor for normal 16mhz Arduino 88DHT dht(DHTPIN, DHTTYPE); 89 90// Initialize for Adafruit DS3231 RTC real time clock 91RTC_DS3231 rtc; 92 93 94char daysOfTheWeek[7][12] = {"Sunday ", "Monday ", "Tuesday ", "Wednesday", "Thursday ", "Friday ", "Saturday "}; 95 96// Event arrays 97// Load with month of 'event', day of event and description to be displayed 98 99const int eventnumber = 19; // number of events and remember: No strings longer than 20 characters! 100int eventmonth [eventnumber] = {6,4,11,2,7,12,11,6,12,6,3,12,1,9,10,3,2,2,7}; 101int eventday [eventnumber] = {11,1, 23, 12,4,3,12,29,25,18,17,31,1,3,31,17,14,2,14}; 102char eventdescription [eventnumber] [21] = 103 {"Dana's Anniversary","April Fool's Day", "Joan's Birthday", "Sydney's Birthday", "Happy July 4th!", "Dana's Birthday", 104 "David's Birthday", "Our Anniversary", "Merry Christmas", "Leah's Birthday", "St Patrick's Day", "New Year's Eve", "New Year's Day", 105 "Forrest's Birthday", "Happy Halloween", "Saint Patrick's Day", "Valentine's Day!", "Groundhog Day", "Bastille Day"}; 106 107 108 109const int pb1pin = 10; // Pin assignments for reset, increment and decrement 110const int pb2pin = 11; 111const int pb3pin = 12; 112 113const int potpin = A0; // Pin assignment for analog reading potentiometer for LED brightness 114int potvalue = 15; // Brightness for LED (default to full 0-15) 115 116int setupindex = 0; // first thing to set if required 117bool insetupmode = false; // and assume RTC is set, OK, etc., and no 'set' required 118 119// date time array for setting, reading, displaying 120 121const int setsize = 7; // size of the setting array 122const int setchime = 0; // set chime choice first to help seconds synching 123const int setyear = 1; // index name for each element 124const int setmonth = 2; 125const int setday = 3; 126const int sethour = 4; 127const int setminute = 5; 128const int setsecond = 6; 129 130int setarray [setsize] = {0,2019, 1, 1, 1, 1,0}; // set year, month, day, hour, minutes, seconds and chimes 131int lowlimit [setsize] = {0,2019, 1, 1, 0, 1,0}; // lower limit for each 132int highlimit [setsize] = {4,2050, 12, 31, 23, 59, 59}; //high limit for each 133char setdesc [setsize] [8] = {"Chimes","Year", "Month", "Day", "Hour", "Minutes", "Seconds"}; 134char chimedesc [5] [12] = {"Silent ", "Hours Only ", "Westminster", "Cuckoo ", "Night Quiet"}; 135char shortchimedesc [5] [5] = {"SLNT","HOUR","WSTM", "CUCK", "ANSO"}; // ANSO stands for Automatic Night Silent Option (11:00 to 6:59am silenced) 136const int silent = 0; // no chiming at all 137const int hoursonly = 1; // no prelude, just chime number of hours and half hour single chime 138const int westminster =2; // hours + Westminster prelude per quarter 139const int cuckoo = 3; // Same as hoursonly, but cuckoo clock sounds 140const int ANSO = 4; // Same as westminster, but skip hour from 11:01pm-6:59am (silent then) 141const int cqtr0 = 1; // Chime the hour 142const int cqtr1 = 2; // Chime the quarter hour 143const int cqtr2 = 3; // Chime the half hour 144const int cqtr3 = 4; // Chime the 3/4 hour 145 146 147// The following four 'starts' need to be synchronized with the SD Card files 148// They correspond to first file of each chime type (e.g. cuckoo single is SOUND27.WAV) 149 150const int firstshort = 1; //file position and name of short, single chime 151const int firstquarter = 13; //same for Westminster quarters (1,2,3) 152const int firstwestminster = 16; //same for Westminster 1-12 (including their 4th quarter introductions 153const int firstcuckoo = 28; // finally, where the cuckoo clock sounds start 154 155 156int setstrike = -1; // Chime/strike flag 157byte alreadychimed = false ; // Used to keep from chiming multiple times during the "hot" second 158int displaychiming = 0; // display'chiming' when a signal sent to Wave Shield 159const int BounceDelay = 250; // Not really 'bounce', its a change of state detection 160const int wavechannel = 8; // I2C channel for communicating to Wave Shield 161 162int i; // generic index variable 163bool event; // logic flag "on" = event found 164int eventindex; // and the event we found 165int dayoftheweek; // stored day of the week (0-6, 0 = Sunday) 166 167int phours; // for print conversion of military time 168int oldseconds = -1; // only update display if seconds change (current seconds not equal last time) 169 170float temperaturef; // farenheit temperature back 171float temperaturec; // centrigade temperature back (not used) 172 173float humidity; // and humidity 174 175int LEDTime; // used for converting single time to 4 digit 176float tempadjust = -3.9; // temperature adjustment for sensor (I found it didn't read right against 'comps') 177byte degreesymbol = 223; // LCD output of 'degree' symbol 178int THupdate = -1; // sensor changes too frequently, only update every 15 seconds 179 180 181 182void setup() 183 // put your setup code here, to run once: 184 185{ 186 Wire.begin(); // initialize I2C interface 187 lcd.init(); // initialize LCD 188 lcd.backlight(); 189 dht.begin(); // initialize the temp/humidity sensor 190 matrix.begin(0x70); // initialize LED 191 Serial.begin (9600); //uncomment if needed to debug 192 193 194 pinMode(pb1pin, INPUT_PULLUP); // The three pushbuttons - reset 195 pinMode(pb2pin, INPUT_PULLUP); // increment 196 pinMode(pb3pin, INPUT_PULLUP); // decrement 197 198if (! rtc.begin()) { // check that clock is there 199 lcd.print("Couldn't find RTC"); // clock missing is a fatal error 200 while (1); 201 } 202 203if (rtc.lostPower()) { // if power lost force a setup, else load 'current' values and 204 lcd.print("RTC lost power!"); // only change time on a PB 1 push if its known already 205 insetupmode = true; 206 for (i=0; i<setsize;i++) {setarray[i] = lowlimit[i];} 207 delay(3000);} else 208 {DateTime (setarray[setyear],setarray[setmonth],setarray[setday],setarray[sethour],setarray[setminute],setarray[setsecond]) = rtc.now(); 209 insetupmode = false; 210 } 211 212 // Two alternative modes of setting date and time (for debugging): 213 // This line sets the RTC to the date & time this sketch was compiled 214 // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 215 // This line sets the RTC with an explicit date & time, for example to set 216 // January 21, 2014 at 3am you would call: 217 // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 218 219 setarray[setchime] = westminster; // default chime is Westminster after reboot 220} // end of setup 221 222void loop() { 223 // Main code divided into setup mode and non-setup mode 224 225 226 while (insetupmode){ // Main code for time, date set 227 228 229 LEDBrightness(); // Make sure LED brightness hasn't changed 230 231 // Read the increment button 232 233 if (digitalRead(pb2pin) == LOW) {setarray[setupindex]++; 234 delay(BounceDelay); 235 if (setarray[setupindex] > highlimit[setupindex]) {setarray[setupindex] = lowlimit[setupindex];} 236 } 237 238 239 // Read the decrement Button 240 241 if (digitalRead(pb3pin) == LOW) {setarray[setupindex]--; 242 delay(BounceDelay); 243 if (setarray[setupindex] < lowlimit[setupindex]) {setarray[setupindex] = highlimit[setupindex];} 244 } 245 246 // Display what we are setting up and the value 247 lcd.setCursor(0,0); 248 lcd.print("In Setup Mode: "); 249 lcd.setCursor(0,2); 250 lcd.print(setdesc[setupindex]); // what we are setting up 251 lcd.print(" "); // and current value 252 if (setupindex != setchime) {lcd.print(setarray[setupindex]); 253 lcd.print(" ");} 254 if (setupindex == setchime) {lcd.print(" "); // Treat Chimes diffently 255 i = setarray[setupindex]; // because its not a number, it is 256 lcd.print(chimedesc[i]);} // it is none, hours, all westminster, night silent or cuckoo! 257 258 259 // Read for another increment of index 260 261 if (digitalRead(pb1pin) == LOW){ // Rolling through Chime, Year, Month, Day, Hour, Minutes, Seconds 262 setupindex++ ; 263 clearline(2); 264 delay(BounceDelay); 265 if (setupindex >= setsize) {insetupmode = false; // and finally exiting setup mode after setting chime, date and time 266 rtc.adjust(DateTime(setarray[setyear],setarray[setmonth],setarray[setday],setarray[sethour],setarray[setminute],setarray[setsecond])); 267 lcd.clear(); // clear display from setup stuff 268 THupdate = -1; // and force immediate update of temperature and humidity 269 270 } //exit setup mode when done 271 } 272 273 } // End of "While" for setup 274 275 // Begin regular loop for date, time, temp humidity and event display 276 277 while (!insetupmode){ 278 279 280 // and onto date, time, etc. 281 282 DateTime now = rtc.now(); 283 setarray[setyear] = now.year(); 284 setarray[setmonth] = now.month(); 285 setarray[setday] = now.day(); 286 setarray[sethour] = now.hour(); 287 setarray[setminute] = now.minute(); 288 oldseconds = setarray[setsecond]; // store old seconds 289 setarray[setsecond] = now.second(); 290 dayoftheweek = now.dayOfTheWeek(); 291 292// Update display once a second, but not more frequently 293 294 if (oldseconds != setarray[setsecond]) 295 296 { // start display code 297 298// At start of new day, clear the event & date lines because may have become shorter 299 if (setarray[sethour] == 0 && setarray[setminute] == 0 && setarray[setsecond] == 0){ 300 clearline(3); // clear the event line 301 clearline(1);} // clear the date line 302 303// Temperature and humidity update 304 305 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) 306 humidity = dht.readHumidity(); 307 308 // Read temperature as Fahrenheit 309 temperaturef = (dht.readTemperature(true))+ tempadjust; // read and correct for inaccuracy in sensor 310 311 // Check if any reads failed and exit early (to try again). 312 if (isnan(humidity) || isnan(temperaturec) || isnan(temperaturef)) { 313 temperaturef = 0; // use 0 as a no-read 314 humidity = 0; // error indication 315 } 316 317 // (note: line 1 is the second row, since counting begins with 0) 318 319 // only update temp and humidity display every 15 seconds to eliminate flicker 320 321 if (THupdate <= 0) 322 { 323 lcd.setCursor(0, 2); 324 325 // Print Temperature Farenheit 326 lcd.print(temperaturef,1); 327 // lcd.setCursor(4,2); 328 lcd.print((char)degreesymbol); // print degree symbol 329 lcd.print("F "); // farenheit 330 331 // Print Humidity 332 lcd.print(humidity,1); 333 lcd.print("%H"); 334 THupdate = 15; // after print, reset the counter 335 } else --THupdate; // if no print of temp and hum, decrement 336 337 // Print chime condition 338 339 lcd.setCursor(16,2); 340 i = setarray[setchime]; 341 lcd.print(shortchimedesc[i]); 342 343 344 lcd.setCursor(4, 0); // position for date, time, etc. 345 346 if (setarray[sethour] <=12) // convert military time to am pm 347 {phours = setarray[sethour]; 348 } 349 else 350 {phours = setarray[sethour]-12;} 351 352 if (phours <= 0){phours = 12;} // don't print 0 for midnite, print "12" 353 354 printtwo(phours," "); 355 lcd.print(":"); 356 printtwo(setarray[setminute],"0"); 357 lcd.print(":"); 358 printtwo(setarray[setsecond],"0"); 359 if (setarray[sethour] < 12) 360 {lcd.print(" AM ");} 361 else 362 {lcd.print(" PM ");} 363 364 // Now update the LED Time 365 366 LEDBrightness(); // Make sure brightness hasn't changed 367 LEDTime = (phours*100) + setarray[setminute] ; // hours and minutes (shifting hours 2 segments left) 368 matrix.print(LEDTime, DEC); // print to LED 369 // matrix.drawColon((setarray[setsecond] ==((setarray[setsecond]/2)*2))); // blink only on even seconds 370 matrix.drawColon(setarray[setsecond]%2); // blink only on even seconds 371 matrix.writeDisplay(); // and push out the LED print 372 373 374 // Now update the LCD date and event lines too 375 lcd.setCursor(0, 1); 376 // lcd.print(monthsOfTheYear[now.month()-1]); // took up too much space on the LCD 377 lcd.print(setarray[setmonth]); // so went with mm/dd/yyyy 378 lcd.print("/"); 379 lcd.print(setarray[setday], DEC); 380 lcd.print("/"); 381 lcd.print(setarray[setyear], DEC); 382 lcd.print(" "); 383 lcd.print(daysOfTheWeek[dayoftheweek]); 384 385 386 lcd.setCursor(0,3); // Last line of display is Event or greeting` 387 388 event = floatingevent(setarray[setmonth], setarray[setday], dayoftheweek); // return true if already have an event, false if not 389 390 if (event == false) { // if no special (non-static) event 391 for (int i = 0; i < eventnumber; i++){ // then check the statics 392 393 if ((setarray[setmonth] == eventmonth[i]) && (setarray[setday] == eventday[i])) { 394 event = true; // set if match on month and day 395 eventindex = i; 396 }} 397 398 if (event == true) { // if so, use it, else generic msg 399 lcd.print( eventdescription[eventindex]);} 400 else 401 if (setarray[sethour] >= 6 && setarray[sethour] <= 11){lcd.print("Good Morning! ");} else 402 if (setarray[sethour] >= 12 && setarray[sethour] <= 16){lcd.print("Good Afternoon! ");} else 403 if (setarray[sethour] >= 17 && setarray[sethour] <= 21){lcd.print("Good Evening! ");} else 404 {lcd.print("Good Night! ");} 405 406 407 } 408 } // end of display update logic 409 410 // Logic for chiming 411 setstrike = -1; // initialize 'strike' flag to "no strike" 412 413 if ((setarray[setchime] != silent) && !((setarray[setchime] == ANSO) && ((setarray[sethour] == 23 && setarray[setminute] > 0) || (setarray[sethour] >= 0 && setarray[sethour] < 7)))) // if silenced due to setting silent 414 { // or ANSO and 11pm-6:59am then skip this 415 if (setarray[setminute] == 0 && setarray[setsecond] == 0){ // Look for 'on the hour' 416 setstrike = cqtr0; 417 } else 418 if (setarray[setminute] == 15 && setarray[setsecond] == 0) { // Look for on the quarter hour 419 setstrike = cqtr1; 420 } else 421 if (setarray[setminute] == 30 && setarray[setsecond] == 0){ // Look for on the 1/2 hour 422 setstrike = cqtr2;} 423 else 424 if (setarray[setminute] == 45 && setarray[setsecond] == 0){ // Look for on the three-quarter hour 425 setstrike = cqtr3;} 426 else {alreadychimed = false;} // none of the above, reset ability to chime 427 428 if (setstrike >0 && !alreadychimed ) { 429 chime(setarray[setchime], setstrike, setarray[sethour]); // call chiming with 'type of chime'; 0,15,30,45 ; and # hours 430 alreadychimed = true; // we will be here multiple times within a second 431 432 } 433 434 } // end of logic for chiming 435 436 437 // Read a potential request for an entry into setup from PB 1 438 if (digitalRead(pb1pin) == LOW){ // to see if we go back to setup mode 439 insetupmode = true; 440 setupindex = 0; 441 lcd.clear(); 442 delay(BounceDelay); 443 } 444 445 446 } // end of not in setup while 447 } // end of sketch 448 449 void clearline(int line){ // Simply clears the line its called with and 450 lcd.setCursor(0,line); 451 lcd.print(" "); // and then 452 lcd.setCursor(0,line); } // Repositions cursor to start of line 453 454 void printtwo(int value, String fillchar){ // print two always and use fill to make it so 455 if (value <10) {lcd.print(fillchar);} // blank space for hours, 0 for minutes, seconds 456 lcd.print(value); 457 } 458 459 // Routine to deal with combinations of chime type, time of day and the current hour 460 // called parameters are chime type (e.g., Westminster), Strike type (hour, qtr, half, 3/4) and the hour in military time 461 462 void chime (int chimetype, int strikeflag, int chour){ 463 464 int chour1; // am pm variable 465 int callbyte =0; // used to talk to Wave Shield 466 467 if (chour <=12){chour1 = chour;} else {chour1 = chour-12;} // convert military time to am pm 468 469 470 if (chour1 <= 0){chour1 = 12;} // don't chime 0 for midnite, chime 12 471 if (chimetype == hoursonly && strikeflag == cqtr2){callbyte = firstshort;} // 1/2 hour only, do single chime (same as 1pm, short chime) 472 else if ( chimetype == hoursonly && strikeflag == cqtr0) { 473 callbyte = chour1;} // hours only and strike hours 474 else if (((chimetype == westminster) ||(chimetype == ANSO)) && strikeflag == cqtr1) {callbyte = firstquarter;} // First Quarter 475 else if (((chimetype == westminster) ||(chimetype == ANSO)) && strikeflag == cqtr2) {callbyte = firstquarter+1;} // Second Quarter 476 else if (((chimetype == westminster) ||(chimetype == ANSO)) && strikeflag == cqtr3) {callbyte = firstquarter+2;} // Third Quarter 477 else if (((chimetype == westminster) ||(chimetype == ANSO)) && strikeflag == cqtr0) {callbyte = (chour1+firstwestminster-1);} // Strike Westminster hours 478 else if (chimetype == cuckoo && strikeflag == cqtr2){callbyte = firstcuckoo;} // 1/2 hour only, do single cuckoo (same as 1pm, single cuckoo) 479 else if ( chimetype == cuckoo && strikeflag == cqtr0) { callbyte = (chour1+firstcuckoo-1);} // hours only and strike cuckoo hours 480 481 482 Wire.beginTransmission(wavechannel); // finally transmit single byte result to Wave Shield 483 Wire.write(callbyte); // sends one byte 484 Wire.endTransmission(); // stop transmitting 485 486 487 } // end of Chime 488 489 // Routine to look up floating events (Memorial Day, Thanksgiving, Mother's Day and Fathers Day) 490 /* Memorial Day is Last Monday in May 491 * Thanksgiving is 4th Thursday in November 492 * Mother's Day is 2nd Sunday in May 493 * Father's Day is 3rd Sunday in June 494 * MLK Day is 3rd Monday in February 495 * Memorial Day is last Monday in May 496 * Labor Day is first Monday in September 497 * Daylight Savings Times starts 2nd Sunday in March 498 * Daylight Savings Times ends first Sunday in November 499 * 500 */ 501 502 bool floatingevent(int m, int d, int dow){ // called with Month, Day within month and day of the week (0 = Sunday) 503 const int sunday = 0; 504 const int monday = 1; 505 const int thursday = 4; 506 String floatstring = " "; 507 508 if ((dow == thursday) && (m==11) && (d >= 22) && (d <= 28)){ // Thanksgiving 509 floatstring = "Thanksgiving Day!";} 510 else if ((dow == sunday) && (m==5) && (d >= 8) && (d <= 14)){ // Mother's Day 511 floatstring = "Mother's Day!";} 512 else if ((dow == sunday) && (m==6) && (d >= 15) && (d <= 21)){ //Father's Day 513 floatstring = "Father's Day!";} 514 else if ((dow == monday) && (m==1) && (d >= 15) && (d <= 21)){ //MLK Day 515 floatstring = "MLK Day!";} 516 else if ((dow == monday) && (m==2) && (d >= 15) && (d <= 21)){ //President's Day 517 floatstring = "President's Day!";} 518 else if ((dow == monday) && (m==9) && (d <= 7) ){ //Labor Day 519 floatstring = "Labor Day!";} 520 else if ((dow == monday) && (m==5) && (d+7 > 31) ){ //Memorial Day 521 floatstring = "Memorial Day!";} 522 else if ((dow == sunday) && (m==3) && (d >= 8) && (d <= 14)){ // DST begins 523 floatstring = "DST Begins";} 524 else if ((dow == sunday) && (m==11) && (d <= 7) ){ //DST ends 525 floatstring = "DST Ends";} 526 527 if (floatstring == " " ){ return false;} else { 528 lcd.print(floatstring); 529 return true;} 530 531 } // end of floatingevent 532 void LEDBrightness(){ 533 potvalue = analogRead(potpin); // Read potentiometer value 534 potvalue = map(potvalue, 0, 1023, 0, 15); //map to valid value for brightness 535 if (potvalue == 14) {potvalue = potvalue+1;} // round up if not full brightness 536 matrix.setBrightness(potvalue); 537 return; 538 } //end of LEDbrightness 539 540 541 542 543 544
Sound Code
arduino
This program runs on the 2nd Arduino with the Wave Shield. Its pretty simple -- just responds to the I2C 'call' and plays the requested sound file on the SD Card
1// Companion to clock module 2// Plays the appropriate Sound file when called with a single byte 3// on Serial Channel 4// Much of the code here comes from PLAY6 example sketch 5 6 7 8 9// #include <FatReader.h> 10//#include <SdReader.h> 11#include "WaveUtil.h" 12#include "WaveHC.h" 13#include <Wire.h> 14 15 16SdReader card; // This object holds the information for the card 17FatVolume vol; // This holds the information for the partition on the card 18FatReader root; // This holds the information for the filesystem on the card 19FatReader f; // This holds the information for the file we're play 20 21WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time 22 23int soundchannel = 8; //I2C channel to listen to [MUST match with clock sketch] 24char filename[15] = {"SOUND00.WAV"}; // foundational file name SOUNDNN.WAV 25int dectoascii = 48; // convert integer to ascii 26byte z = 0; 27 28/* Byte should be 0-39 for files 29 * Also can chime in multiple ways, including Westminster chimes and cuckoo clock 30 * Chimes are provided by Adafruit Wave Shield on serial bus 31 * Separate Arduino and Shield used due to memory limitations 32 */ 33 34/* Files on SD Card must match this sketch: 35 * in format SOUNDnn.WAV where nn is two digit sound number 36 * and one file called "STARTUP.WAV" that is played once during setup 371 Short 1 (no Westminster) 382 Short 2 393 Short 3 404 Short 4 415 Short 5 426 Short 6 437 Short 7 448 Short 8 459 Short 9 4610 Short 10 4711 Short 11 4812 Short 12 4913 Q1 (Quarter Hour Chimes) 5014 Q2 5115 Q3 5216 Long 1 (Westminster Hours) 5317 Long 2 (with built in Q4) 5418 Long 3 5519 Long 4 5620 Long 5 5721 Long 6 5822 Long 7 5923 Long 8 6024 Long 9 6125 Long 10 6226 Long 11 6327 Long 12 6428 Cuckoo Clock 1 6529 Cuckoo Clock 2 6630 Cuckoo Clock 3 6731 Cuckoo Clock 4 6832 Cuckoo Clock 5 6933 Cuckoo Clock 6 7034 Cuckoo Clock 7 7135 Cuckoo Clock 8 7236 Cuckoo Clock 9 7337 Cuckoo Clock 10 7438 Cuckoo Clock 11 7539 Cuckoo Clock 12 76 77 */ 78 79 80 81 82/* this handy function will return the number of bytes currently free in RAM, great for debugging! 83int freeRam(void) 84{ 85 extern int __bss_end; 86 extern int *__brkval; 87 int free_memory; 88 if((int)__brkval == 0) { 89 free_memory = ((int)&free_memory) - ((int)&__bss_end); 90 } 91 else { 92 free_memory = ((int)&free_memory) - ((int)__brkval); 93 } 94 return free_memory; 95} 96*/ 97void sdErrorCheck(void) 98{ 99 if (!card.errorCode()) return; 100 putstring("\ 101\ SD I/O error: "); 102 Serial.print(card.errorCode(), HEX); 103 putstring(", "); 104 Serial.println(card.errorData(), HEX); 105 while(1); 106} 107 108void setup() { 109 // set up serial port if needed for debugging 110 Serial.begin(9600); 111 112 Wire.begin(soundchannel); // join i2c bus with address defined 113 Wire.onReceive(receiveEvent); // register event 114 115// putstring_nl("Sound Receiver"); 116// delay (1000); 117// putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad 118// Serial.println(freeRam()); // if this is under 150 bytes it may spell trouble! 119 120 // Set the output pins for the DAC control. These pins are defined in the library 121 pinMode(2, OUTPUT); // and actually soldered between Arduino 122 pinMode(3, OUTPUT); // and the WAVE shield 123 pinMode(4, OUTPUT); 124 pinMode(5, OUTPUT); 125 126 127 // if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you 128 if (!card.init()) { //play with 8 MHz spi (default faster!) 129 putstring_nl("Card init. failed!"); // Something went wrong, lets print out why 130 sdErrorCheck(); 131 while(1); // then 'halt' - do nothing! 132 } 133 134 // enable optimize read - some cards may timeout. Disable if you're having problems 135 card.partialBlockRead(true); 136 137// Now we will look for a FAT partition! 138 uint8_t part; 139 for (part = 0; part < 5; part++) { // we have up to 5 slots to look in 140 if (vol.init(card, part)) 141 break; // we found one, lets bail 142 } 143 if (part == 5) { // if we ended up not finding one :( 144 putstring_nl("No valid FAT partition!"); 145 sdErrorCheck(); // Something went wrong, lets print out why 146 while(1); // then 'halt' - do nothing! 147 } 148 149 // Lets tell the user about what we found 150 // putstring("Using partition "); 151// Serial.print(part, DEC); 152// putstring(", type is FAT"); 153 // Serial.println(vol.fatType(),DEC); // FAT16 or FAT32? 154 155 // Try to open the root directory 156 if (!root.openRoot(vol)) { 157 putstring_nl("Can't open root dir!"); // Something went wrong, 158 while(1); // then 'halt' - do nothing! 159 } 160 161 // Whew! We got past the tough parts. 162 putstring_nl("Ready!"); 163 playcomplete("STARTUP.WAV"); // play once to show its working 164 165 166} 167 168void loop() { 169 170 while (z > 0){ // wait for the interrupt 171 172 filename[5] = (z/10) + dectoascii; // create filename from byte sent 173 filename[6] = (z - ((z/10)*10))+ dectoascii; 174// Serial.print(z); 175// Serial.print(" "); 176// Serial.println(filename); 177 playcomplete(filename); // will play to completion 178 z= 0; // and reset flag 179 } 180 } 181 182 183 184 185 186// Plays a full file from beginning to end with no pause. 187void playcomplete(char *name) { 188 // call our helper to find and play this name 189 playfile(name); 190 while (wave.isplaying) { 191 // do nothing while its playing 192 } 193 // now its done playing 194} 195 196void playfile(char *name) { 197 // see if the wave object is currently doing something 198 if (wave.isplaying) {// already playing something, so stop it! 199 wave.stop(); // stop it 200 } 201 // look in the root directory and open the file 202 if (!f.open(root, name)) { 203 putstring("Couldn't open file "); Serial.print(name); return; 204 } 205 // OK read the file and turn it into a wave object 206 if (!wave.create(f)) { 207 putstring_nl("Not a valid WAV"); return; 208 } 209 210 // ok time to play! start playback 211 wave.play(); 212} 213 214 215// function that executes whenever data is received from master 216// this function is registered as an event, see setup() 217 218void receiveEvent() { 219 int x = Wire.read(); // receive byte as an integer 220// Serial.println(x); // print the integer 221 z = x; //make the byte available 222 return ; 223} 224
Clock Code
arduino
This is the logic for the clock Arduino for time and weather and to control the chiming.
1/* 2 * Clock project using LED, LCD and Wave Shield 3 * Provides date, time, temp, humidity and limited number of event notifications 4 * Also can chime in multiple ways, including Westminster chimes and cuckoo clock 5 * Chimes are provided by Adafruit Wave Shield on serial bus 6 * A second Arduino to run the Wave Shield is used due to memory limitations 7 * and all the global variables and libraries involved in sound, LED, LCD, etc. 8 */ 9 10/* Files on SD Card must match this sketch: 11 * in format SOUNDnn.WAV where nn is two digit sound number 12 * and one file called "STARTUP.WAV" that is played once on SETUP 131 Short 1 (no Westminster) 142 Short 2 153 Short 3 164 Short 4 175 Short 5 186 Short 6 197 Short 7 208 Short 8 219 Short 9 2210 Short 10 2311 Short 11 2412 Short 12 2513 Q1 (Quarter Hour Chimes) 2614 Q2 2715 Q3 2816 Long 1 (Westminster Hours) 2917 Long 2 (with built in Q4) 3018 Long 3 3119 Long 4 3220 Long 5 3321 Long 6 3422 Long 7 3523 Long 8 3624 Long 9 3725 Long 10 3826 Long 11 3927 Long 12 4028 Cuckoo Clock 1 4129 Cuckoo Clock 2 4230 Cuckoo Clock 3 4331 Cuckoo Clock 4 4432 Cuckoo Clock 5 4533 Cuckoo Clock 6 4634 Cuckoo Clock 7 4735 Cuckoo Clock 8 4836 Cuckoo Clock 9 4937 Cuckoo Clock 10 5038 Cuckoo Clock 11 5139 Cuckoo Clock 12 52 53 54 */ 55 56// Code to set up the clock 57// Pushbutton 1 is the toggler , cycle between vhime, year, month, day, hours, minutes, seconds 58// Pushbutton 2 is the increment up one 59// Pushbutton 3 is the decrement down one 60 61// Chime setup 62// 0 = No chimes 63// 1 = Chime for hour and 1/2 hour only 64// 2 = Westminster hours + quarterly 65// 3 = Cuckoo clock (hours and 1/2 hour only like above but different chime 66// 4 = Westminster silenced after 11pm and before 7am 67 68 69// include the libraries for LCD Display, DHT-11 Temperature/humidity sensor and DS3231 RTC and 70// include libraries for bigger seven segment display with backpack 71#include "DHT.h" 72#include <Wire.h> 73#include "RTClib.h" 74#include <LiquidCrystal_I2C.h> 75#include "Adafruit_LEDBackpack.h" 76 77 78// Set up output functions 79 80Adafruit_7segment matrix = Adafruit_7segment(); 81 82LiquidCrystal_I2C lcd(0x27,20,4); // initialize LCD 83 84#define DHTPIN 8 //Temp Humidity sensor on pin 8 85#define DHTTYPE DHT11 // DHT 11 because the sensor is that type 86 87// Initialize DHT sensor for normal 16mhz Arduino 88DHT dht(DHTPIN, DHTTYPE); 89 90// Initialize for Adafruit DS3231 RTC real time clock 91RTC_DS3231 rtc; 92 93 94char daysOfTheWeek[7][12] = {"Sunday ", "Monday ", "Tuesday ", "Wednesday", "Thursday ", "Friday ", "Saturday "}; 95 96// Event arrays 97// Load with month of 'event', day of event and description to be displayed 98 99const int eventnumber = 19; // number of events and remember: No strings longer than 20 characters! 100int eventmonth [eventnumber] = {6,4,11,2,7,12,11,6,12,6,3,12,1,9,10,3,2,2,7}; 101int eventday [eventnumber] = {11,1, 23, 12,4,3,12,29,25,18,17,31,1,3,31,17,14,2,14}; 102char eventdescription [eventnumber] [21] = 103 {"Dana's Anniversary","April Fool's Day", "Joan's Birthday", "Sydney's Birthday", "Happy July 4th!", "Dana's Birthday", 104 "David's Birthday", "Our Anniversary", "Merry Christmas", "Leah's Birthday", "St Patrick's Day", "New Year's Eve", "New Year's Day", 105 "Forrest's Birthday", "Happy Halloween", "Saint Patrick's Day", "Valentine's Day!", "Groundhog Day", "Bastille Day"}; 106 107 108 109const int pb1pin = 10; // Pin assignments for reset, increment and decrement 110const int pb2pin = 11; 111const int pb3pin = 12; 112 113const int potpin = A0; // Pin assignment for analog reading potentiometer for LED brightness 114int potvalue = 15; // Brightness for LED (default to full 0-15) 115 116int setupindex = 0; // first thing to set if required 117bool insetupmode = false; // and assume RTC is set, OK, etc., and no 'set' required 118 119// date time array for setting, reading, displaying 120 121const int setsize = 7; // size of the setting array 122const int setchime = 0; // set chime choice first to help seconds synching 123const int setyear = 1; // index name for each element 124const int setmonth = 2; 125const int setday = 3; 126const int sethour = 4; 127const int setminute = 5; 128const int setsecond = 6; 129 130int setarray [setsize] = {0,2019, 1, 1, 1, 1,0}; // set year, month, day, hour, minutes, seconds and chimes 131int lowlimit [setsize] = {0,2019, 1, 1, 0, 1,0}; // lower limit for each 132int highlimit [setsize] = {4,2050, 12, 31, 23, 59, 59}; //high limit for each 133char setdesc [setsize] [8] = {"Chimes","Year", "Month", "Day", "Hour", "Minutes", "Seconds"}; 134char chimedesc [5] [12] = {"Silent ", "Hours Only ", "Westminster", "Cuckoo ", "Night Quiet"}; 135char shortchimedesc [5] [5] = {"SLNT","HOUR","WSTM", "CUCK", "ANSO"}; // ANSO stands for Automatic Night Silent Option (11:00 to 6:59am silenced) 136const int silent = 0; // no chiming at all 137const int hoursonly = 1; // no prelude, just chime number of hours and half hour single chime 138const int westminster =2; // hours + Westminster prelude per quarter 139const int cuckoo = 3; // Same as hoursonly, but cuckoo clock sounds 140const int ANSO = 4; // Same as westminster, but skip hour from 11:01pm-6:59am (silent then) 141const int cqtr0 = 1; // Chime the hour 142const int cqtr1 = 2; // Chime the quarter hour 143const int cqtr2 = 3; // Chime the half hour 144const int cqtr3 = 4; // Chime the 3/4 hour 145 146 147// The following four 'starts' need to be synchronized with the SD Card files 148// They correspond to first file of each chime type (e.g. cuckoo single is SOUND27.WAV) 149 150const int firstshort = 1; //file position and name of short, single chime 151const int firstquarter = 13; //same for Westminster quarters (1,2,3) 152const int firstwestminster = 16; //same for Westminster 1-12 (including their 4th quarter introductions 153const int firstcuckoo = 28; // finally, where the cuckoo clock sounds start 154 155 156int setstrike = -1; // Chime/strike flag 157byte alreadychimed = false ; // Used to keep from chiming multiple times during the "hot" second 158int displaychiming = 0; // display'chiming' when a signal sent to Wave Shield 159const int BounceDelay = 250; // Not really 'bounce', its a change of state detection 160const int wavechannel = 8; // I2C channel for communicating to Wave Shield 161 162int i; // generic index variable 163bool event; // logic flag "on" = event found 164int eventindex; // and the event we found 165int dayoftheweek; // stored day of the week (0-6, 0 = Sunday) 166 167int phours; // for print conversion of military time 168int oldseconds = -1; // only update display if seconds change (current seconds not equal last time) 169 170float temperaturef; // farenheit temperature back 171float temperaturec; // centrigade temperature back (not used) 172 173float humidity; // and humidity 174 175int LEDTime; // used for converting single time to 4 digit 176float tempadjust = -3.9; // temperature adjustment for sensor (I found it didn't read right against 'comps') 177byte degreesymbol = 223; // LCD output of 'degree' symbol 178int THupdate = -1; // sensor changes too frequently, only update every 15 seconds 179 180 181 182void setup() 183 // put your setup code here, to run once: 184 185{ 186 Wire.begin(); // initialize I2C interface 187 lcd.init(); // initialize LCD 188 lcd.backlight(); 189 dht.begin(); // initialize the temp/humidity sensor 190 matrix.begin(0x70); // initialize LED 191 Serial.begin (9600); //uncomment if needed to debug 192 193 194 pinMode(pb1pin, INPUT_PULLUP); // The three pushbuttons - reset 195 pinMode(pb2pin, INPUT_PULLUP); // increment 196 pinMode(pb3pin, INPUT_PULLUP); // decrement 197 198if (! rtc.begin()) { // check that clock is there 199 lcd.print("Couldn't find RTC"); // clock missing is a fatal error 200 while (1); 201 } 202 203if (rtc.lostPower()) { // if power lost force a setup, else load 'current' values and 204 lcd.print("RTC lost power!"); // only change time on a PB 1 push if its known already 205 insetupmode = true; 206 for (i=0; i<setsize;i++) {setarray[i] = lowlimit[i];} 207 delay(3000);} else 208 {DateTime (setarray[setyear],setarray[setmonth],setarray[setday],setarray[sethour],setarray[setminute],setarray[setsecond]) = rtc.now(); 209 insetupmode = false; 210 } 211 212 // Two alternative modes of setting date and time (for debugging): 213 // This line sets the RTC to the date & time this sketch was compiled 214 // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 215 // This line sets the RTC with an explicit date & time, for example to set 216 // January 21, 2014 at 3am you would call: 217 // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 218 219 setarray[setchime] = westminster; // default chime is Westminster after reboot 220} // end of setup 221 222void loop() { 223 // Main code divided into setup mode and non-setup mode 224 225 226 while (insetupmode){ // Main code for time, date set 227 228 229 LEDBrightness(); // Make sure LED brightness hasn't changed 230 231 // Read the increment button 232 233 if (digitalRead(pb2pin) == LOW) {setarray[setupindex]++; 234 delay(BounceDelay); 235 if (setarray[setupindex] > highlimit[setupindex]) {setarray[setupindex] = lowlimit[setupindex];} 236 } 237 238 239 // Read the decrement Button 240 241 if (digitalRead(pb3pin) == LOW) {setarray[setupindex]--; 242 delay(BounceDelay); 243 if (setarray[setupindex] < lowlimit[setupindex]) {setarray[setupindex] = highlimit[setupindex];} 244 } 245 246 // Display what we are setting up and the value 247 lcd.setCursor(0,0); 248 lcd.print("In Setup Mode: "); 249 lcd.setCursor(0,2); 250 lcd.print(setdesc[setupindex]); // what we are setting up 251 lcd.print(" "); // and current value 252 if (setupindex != setchime) {lcd.print(setarray[setupindex]); 253 lcd.print(" ");} 254 if (setupindex == setchime) {lcd.print(" "); // Treat Chimes diffently 255 i = setarray[setupindex]; // because its not a number, it is 256 lcd.print(chimedesc[i]);} // it is none, hours, all westminster, night silent or cuckoo! 257 258 259 // Read for another increment of index 260 261 if (digitalRead(pb1pin) == LOW){ // Rolling through Chime, Year, Month, Day, Hour, Minutes, Seconds 262 setupindex++ ; 263 clearline(2); 264 delay(BounceDelay); 265 if (setupindex >= setsize) {insetupmode = false; // and finally exiting setup mode after setting chime, date and time 266 rtc.adjust(DateTime(setarray[setyear],setarray[setmonth],setarray[setday],setarray[sethour],setarray[setminute],setarray[setsecond])); 267 lcd.clear(); // clear display from setup stuff 268 THupdate = -1; // and force immediate update of temperature and humidity 269 270 } //exit setup mode when done 271 } 272 273 } // End of "While" for setup 274 275 // Begin regular loop for date, time, temp humidity and event display 276 277 while (!insetupmode){ 278 279 280 // and onto date, time, etc. 281 282 DateTime now = rtc.now(); 283 setarray[setyear] = now.year(); 284 setarray[setmonth] = now.month(); 285 setarray[setday] = now.day(); 286 setarray[sethour] = now.hour(); 287 setarray[setminute] = now.minute(); 288 oldseconds = setarray[setsecond]; // store old seconds 289 setarray[setsecond] = now.second(); 290 dayoftheweek = now.dayOfTheWeek(); 291 292// Update display once a second, but not more frequently 293 294 if (oldseconds != setarray[setsecond]) 295 296 { // start display code 297 298// At start of new day, clear the event & date lines because may have become shorter 299 if (setarray[sethour] == 0 && setarray[setminute] == 0 && setarray[setsecond] == 0){ 300 clearline(3); // clear the event line 301 clearline(1);} // clear the date line 302 303// Temperature and humidity update 304 305 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) 306 humidity = dht.readHumidity(); 307 308 // Read temperature as Fahrenheit 309 temperaturef = (dht.readTemperature(true))+ tempadjust; // read and correct for inaccuracy in sensor 310 311 // Check if any reads failed and exit early (to try again). 312 if (isnan(humidity) || isnan(temperaturec) || isnan(temperaturef)) { 313 temperaturef = 0; // use 0 as a no-read 314 humidity = 0; // error indication 315 } 316 317 // (note: line 1 is the second row, since counting begins with 0) 318 319 // only update temp and humidity display every 15 seconds to eliminate flicker 320 321 if (THupdate <= 0) 322 { 323 lcd.setCursor(0, 2); 324 325 // Print Temperature Farenheit 326 lcd.print(temperaturef,1); 327 // lcd.setCursor(4,2); 328 lcd.print((char)degreesymbol); // print degree symbol 329 lcd.print("F "); // farenheit 330 331 // Print Humidity 332 lcd.print(humidity,1); 333 lcd.print("%H"); 334 THupdate = 15; // after print, reset the counter 335 } else --THupdate; // if no print of temp and hum, decrement 336 337 // Print chime condition 338 339 lcd.setCursor(16,2); 340 i = setarray[setchime]; 341 lcd.print(shortchimedesc[i]); 342 343 344 lcd.setCursor(4, 0); // position for date, time, etc. 345 346 if (setarray[sethour] <=12) // convert military time to am pm 347 {phours = setarray[sethour]; 348 } 349 else 350 {phours = setarray[sethour]-12;} 351 352 if (phours <= 0){phours = 12;} // don't print 0 for midnite, print "12" 353 354 printtwo(phours," "); 355 lcd.print(":"); 356 printtwo(setarray[setminute],"0"); 357 lcd.print(":"); 358 printtwo(setarray[setsecond],"0"); 359 if (setarray[sethour] < 12) 360 {lcd.print(" AM ");} 361 else 362 {lcd.print(" PM ");} 363 364 // Now update the LED Time 365 366 LEDBrightness(); // Make sure brightness hasn't changed 367 LEDTime = (phours*100) + setarray[setminute] ; // hours and minutes (shifting hours 2 segments left) 368 matrix.print(LEDTime, DEC); // print to LED 369 // matrix.drawColon((setarray[setsecond] ==((setarray[setsecond]/2)*2))); // blink only on even seconds 370 matrix.drawColon(setarray[setsecond]%2); // blink only on even seconds 371 matrix.writeDisplay(); // and push out the LED print 372 373 374 // Now update the LCD date and event lines too 375 lcd.setCursor(0, 1); 376 // lcd.print(monthsOfTheYear[now.month()-1]); // took up too much space on the LCD 377 lcd.print(setarray[setmonth]); // so went with mm/dd/yyyy 378 lcd.print("/"); 379 lcd.print(setarray[setday], DEC); 380 lcd.print("/"); 381 lcd.print(setarray[setyear], DEC); 382 lcd.print(" "); 383 lcd.print(daysOfTheWeek[dayoftheweek]); 384 385 386 lcd.setCursor(0,3); // Last line of display is Event or greeting` 387 388 event = floatingevent(setarray[setmonth], setarray[setday], dayoftheweek); // return true if already have an event, false if not 389 390 if (event == false) { // if no special (non-static) event 391 for (int i = 0; i < eventnumber; i++){ // then check the statics 392 393 if ((setarray[setmonth] == eventmonth[i]) && (setarray[setday] == eventday[i])) { 394 event = true; // set if match on month and day 395 eventindex = i; 396 }} 397 398 if (event == true) { // if so, use it, else generic msg 399 lcd.print( eventdescription[eventindex]);} 400 else 401 if (setarray[sethour] >= 6 && setarray[sethour] <= 11){lcd.print("Good Morning! ");} else 402 if (setarray[sethour] >= 12 && setarray[sethour] <= 16){lcd.print("Good Afternoon! ");} else 403 if (setarray[sethour] >= 17 && setarray[sethour] <= 21){lcd.print("Good Evening! ");} else 404 {lcd.print("Good Night! ");} 405 406 407 } 408 } // end of display update logic 409 410 // Logic for chiming 411 setstrike = -1; // initialize 'strike' flag to "no strike" 412 413 if ((setarray[setchime] != silent) && !((setarray[setchime] == ANSO) && ((setarray[sethour] == 23 && setarray[setminute] > 0) || (setarray[sethour] >= 0 && setarray[sethour] < 7)))) // if silenced due to setting silent 414 { // or ANSO and 11pm-6:59am then skip this 415 if (setarray[setminute] == 0 && setarray[setsecond] == 0){ // Look for 'on the hour' 416 setstrike = cqtr0; 417 } else 418 if (setarray[setminute] == 15 && setarray[setsecond] == 0) { // Look for on the quarter hour 419 setstrike = cqtr1; 420 } else 421 if (setarray[setminute] == 30 && setarray[setsecond] == 0){ // Look for on the 1/2 hour 422 setstrike = cqtr2;} 423 else 424 if (setarray[setminute] == 45 && setarray[setsecond] == 0){ // Look for on the three-quarter hour 425 setstrike = cqtr3;} 426 else {alreadychimed = false;} // none of the above, reset ability to chime 427 428 if (setstrike >0 && !alreadychimed ) { 429 chime(setarray[setchime], setstrike, setarray[sethour]); // call chiming with 'type of chime'; 0,15,30,45 ; and # hours 430 alreadychimed = true; // we will be here multiple times within a second 431 432 } 433 434 } // end of logic for chiming 435 436 437 // Read a potential request for an entry into setup from PB 1 438 if (digitalRead(pb1pin) == LOW){ // to see if we go back to setup mode 439 insetupmode = true; 440 setupindex = 0; 441 lcd.clear(); 442 delay(BounceDelay); 443 } 444 445 446 } // end of not in setup while 447 } // end of sketch 448 449 void clearline(int line){ // Simply clears the line its called with and 450 lcd.setCursor(0,line); 451 lcd.print(" "); // and then 452 lcd.setCursor(0,line); } // Repositions cursor to start of line 453 454 void printtwo(int value, String fillchar){ // print two always and use fill to make it so 455 if (value <10) {lcd.print(fillchar);} // blank space for hours, 0 for minutes, seconds 456 lcd.print(value); 457 } 458 459 // Routine to deal with combinations of chime type, time of day and the current hour 460 // called parameters are chime type (e.g., Westminster), Strike type (hour, qtr, half, 3/4) and the hour in military time 461 462 void chime (int chimetype, int strikeflag, int chour){ 463 464 int chour1; // am pm variable 465 int callbyte =0; // used to talk to Wave Shield 466 467 if (chour <=12){chour1 = chour;} else {chour1 = chour-12;} // convert military time to am pm 468 469 470 if (chour1 <= 0){chour1 = 12;} // don't chime 0 for midnite, chime 12 471 if (chimetype == hoursonly && strikeflag == cqtr2){callbyte = firstshort;} // 1/2 hour only, do single chime (same as 1pm, short chime) 472 else if ( chimetype == hoursonly && strikeflag == cqtr0) { 473 callbyte = chour1;} // hours only and strike hours 474 else if (((chimetype == westminster) ||(chimetype == ANSO)) && strikeflag == cqtr1) {callbyte = firstquarter;} // First Quarter 475 else if (((chimetype == westminster) ||(chimetype == ANSO)) && strikeflag == cqtr2) {callbyte = firstquarter+1;} // Second Quarter 476 else if (((chimetype == westminster) ||(chimetype == ANSO)) && strikeflag == cqtr3) {callbyte = firstquarter+2;} // Third Quarter 477 else if (((chimetype == westminster) ||(chimetype == ANSO)) && strikeflag == cqtr0) {callbyte = (chour1+firstwestminster-1);} // Strike Westminster hours 478 else if (chimetype == cuckoo && strikeflag == cqtr2){callbyte = firstcuckoo;} // 1/2 hour only, do single cuckoo (same as 1pm, single cuckoo) 479 else if ( chimetype == cuckoo && strikeflag == cqtr0) { callbyte = (chour1+firstcuckoo-1);} // hours only and strike cuckoo hours 480 481 482 Wire.beginTransmission(wavechannel); // finally transmit single byte result to Wave Shield 483 Wire.write(callbyte); // sends one byte 484 Wire.endTransmission(); // stop transmitting 485 486 487 } // end of Chime 488 489 // Routine to look up floating events (Memorial Day, Thanksgiving, Mother's Day and Fathers Day) 490 /* Memorial Day is Last Monday in May 491 * Thanksgiving is 4th Thursday in November 492 * Mother's Day is 2nd Sunday in May 493 * Father's Day is 3rd Sunday in June 494 * MLK Day is 3rd Monday in February 495 * Memorial Day is last Monday in May 496 * Labor Day is first Monday in September 497 * Daylight Savings Times starts 2nd Sunday in March 498 * Daylight Savings Times ends first Sunday in November 499 * 500 */ 501 502 bool floatingevent(int m, int d, int dow){ // called with Month, Day within month and day of the week (0 = Sunday) 503 const int sunday = 0; 504 const int monday = 1; 505 const int thursday = 4; 506 String floatstring = " "; 507 508 if ((dow == thursday) && (m==11) && (d >= 22) && (d <= 28)){ // Thanksgiving 509 floatstring = "Thanksgiving Day!";} 510 else if ((dow == sunday) && (m==5) && (d >= 8) && (d <= 14)){ // Mother's Day 511 floatstring = "Mother's Day!";} 512 else if ((dow == sunday) && (m==6) && (d >= 15) && (d <= 21)){ //Father's Day 513 floatstring = "Father's Day!";} 514 else if ((dow == monday) && (m==1) && (d >= 15) && (d <= 21)){ //MLK Day 515 floatstring = "MLK Day!";} 516 else if ((dow == monday) && (m==2) && (d >= 15) && (d <= 21)){ //President's Day 517 floatstring = "President's Day!";} 518 else if ((dow == monday) && (m==9) && (d <= 7) ){ //Labor Day 519 floatstring = "Labor Day!";} 520 else if ((dow == monday) && (m==5) && (d+7 > 31) ){ //Memorial Day 521 floatstring = "Memorial Day!";} 522 else if ((dow == sunday) && (m==3) && (d >= 8) && (d <= 14)){ // DST begins 523 floatstring = "DST Begins";} 524 else if ((dow == sunday) && (m==11) && (d <= 7) ){ //DST ends 525 floatstring = "DST Ends";} 526 527 if (floatstring == " " ){ return false;} else { 528 lcd.print(floatstring); 529 return true;} 530 531 } // end of floatingevent 532 void LEDBrightness(){ 533 potvalue = analogRead(potpin); // Read potentiometer value 534 potvalue = map(potvalue, 0, 1023, 0, 15); //map to valid value for brightness 535 if (potvalue == 14) {potvalue = potvalue+1;} // round up if not full brightness 536 matrix.setBrightness(potvalue); 537 return; 538 } //end of LEDbrightness 539 540 541 542 543 544
Downloadable files
Component and Arduino Pin Connections
All the connections (except for details on building the Wave Shield)
Component and Arduino Pin Connections
Component and Arduino Pin Connections
All the connections (except for details on building the Wave Shield)
Component and Arduino Pin Connections
Documentation
Acrylic Box
I ordered this as an enclosure after mounting things using L brackets and a base.
Acrylic Box
Acrylic Box
I ordered this as an enclosure after mounting things using L brackets and a base.
Acrylic Box
Comments
Only logged in users can leave comments