/********************************************************* **Code for the MakerWatch ** **This code shows the time current time on the face of the ** watch and has an alarm that can be turned on and off. **To set the time, push and hold button 3 until the display ** goes black and release the button. Push button 1 and 2 ** in this state to increase and decrease the hours. If ** the time is PM the 4 minute LEDs will light up what ** setting the hour(for both time and alarm, but not while ** displaying the time) ** Push button 3 again and you can now change the minutes. ** **From setting the time, push and hold button 3 until the ** screen goes black again. To turn the alarm on push and ** hold button 1 or 2 until the display goes black. You can ** now change the hour of the alarm by using buttons 1 and 2. ** Push button 3 and you can change the alarm minutes. **To turn off the alarm, push and hold button 1 or 2 again, ** until the screen goes black. **To return to the default state, push and hold button 3 until ** the display goes black. ** **If you wait too long while setting the time or alarm, ** the clock will return to displaying the current time ** (all changes will be saved) ** ** Date: December 26, 2009 ** Jon Hodgins *********************************************************/ //MakerBotWatch .h and .cpp modified from: http://wiki.makerbot.com/makerbot-watch #include "MakerBotWatch.h" MakerBotWatch watch; /********************************** **state machine variables ** **the state machine controls the display and **setting the time and alarm **********************************/ byte buttonEvent = 0;//stores the user input long buttonTimer = millis();//used to tell if the button is being held long buttonHoldTime = 1800;//the mS to hold the button before something happens long timeSetTimeout = 8000;//the mS to wait before the watch resets to default #define noButtonEvent 0 #define buttonEvent1 1 #define buttonEvent1Hold 2 #define buttonEvent2 3 #define buttonEvent2Hold 4 #define buttonEvent3 5 #define buttonEvent3Hold 6 byte state=0;//the current state of the watch //the various states of the watch, each is described in more detatil in stateMachine() #define DEFAULT_STATE 0 #define EXIT_DEFAULT_STATE 1 #define ENTER_SET_TIME_STATE 2 #define SET_HOUR_STATE 3 #define INC_HOUR_STATE 4 #define DEC_HOUR_STATE 5 #define EXIT_HOUR_STATE 6 #define SET_MIN_STATE 7 #define INC_MIN_STATE 8 #define DEC_MIN_STATE 9 #define EXIT_MIN_STATE 10 #define ENTER_SET_AL_STATE 11 #define AL_SET_HOUR_STATE 12 #define AL_INC_HOUR_STATE 13 #define AL_DEC_HOUR_STATE 14 #define AL_EXIT_HOUR_STATE 15 #define AL_SET_MIN_STATE 16 #define AL_INC_MIN_STATE 17 #define AL_DEC_MIN_STATE 18 #define AL_EXIT_MIN_STATE 19 #define ENTER_DEFAULT_STATE 20 /********************************** **clock variables **********************************/ int8_t hours; int8_t minutes; #define AM 0 #define PM 1 long lastClockTime=0, currentClockTime=0, lastTimeUpdated=0;//variables to keep the time going boolean AMPM=0;//indicates if the current time is morning or afternoon, not dispalyed unless setting the time and alarm const long oneMin=60116;//the length of 1 minute in ms(adjusted for clock speed variances, you will also need to adjust) /********************************** **alarm variables **********************************/ int8_t alarmHours; int8_t alarmMinutes; boolean alarmAMPM=0; boolean alarmOn=false;//turns the alarm on or off boolean alarmPlaying=false;//tells the alarm to play the music boolean alarmSounded=true;//stops the alarm from going off more than once for the same time /********************************** **input variables **********************************/ boolean PB1,PB2,PB3;//push button variables boolean blinkVariable=0;//blinks at a regular interval to show when a time is being set byte blinkRate = 500;//the mS the blink is on (and off) /********************************** **music variables **modified from: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1241248988 **********************************/ // defines for the frequency of the notes (.5 x freq of mid C) #define REST 0 // 0 Hz #define GSL 208 //g sharp (lower octave) #define AN 220 //A, 440 Hz #define AS 233 //A sharp, 466 Hz #define BN 247 //B, 493 Hz #define CN 261 //C, 523 Hz #define CS 277 //C sharp, 554 Hz #define DN 294 //D, 588 Hz #define DS 311 //D sharp, 622 Hz #define EN 330 //E, 658 Hz #define FN 349 //F, 698 Hz #define FS 370 //F sharp, 740 Hz #define GN 392 //G, 784 Hz #define GS 415 //G sharp, 830 Hz // defines for the duration of the notes (in ms) #define wh 1024 //whole note #define h 512 //half note #define dq 448 //dotted quarter note #define q 256 //quarter note #define qt 170 //??? #define de 192 //dotted eighth note #define e 128 //eighth note #define et 85 //??? const int numNotes = 17; int songNote[numNotes] = {//the final fantasy battle victory music CN,REST,CN,REST,CN,REST,CN,REST,GSL,REST,AS,REST,CN,REST,AN,CN,REST}; int noteDuration[numNotes] = { q,5 ,q,5 ,q,5 ,dq,5 ,dq ,5 ,dq,5 ,q,e ,q,h ,wh }; /********************************** **code that runs once at startup **********************************/ void setup() { } /********************************** **The main program loop **********************************/ void loop() { clockUpdate();//keep the time current getUserInput();//check for button presses stateMachine();//decide what to do with the input and what to display } /********************************** **Checks the 3 buttons and updates the variable ** buttonEvent with the results **********************************/ void getUserInput(void) { //used to see if a button has been pushed or released, //which resets the holding timer. If the holding timer //eventually exceeds a set time the button is considered held int oldButtonEvent = buttonEvent; //read the buttons PB1 = digitalRead(BUTTON1); PB2 = digitalRead(BUTTON2); PB3 = digitalRead(BUTTON3); //update the output buttonEvent=noButtonEvent; if(!PB1) buttonEvent=buttonEvent1; if(!PB2) buttonEvent=buttonEvent2; if(!PB3) buttonEvent=buttonEvent3; //reset the timer if something changes if(oldButtonEvent != buttonEvent) buttonTimer = millis(); //change the result if the button has been held for a set length of time if(millis()-buttonTimer > buttonHoldTime) { if(!PB1) buttonEvent=buttonEvent1Hold; if(!PB2) buttonEvent=buttonEvent2Hold; if(!PB3) buttonEvent=buttonEvent3Hold; } } /********************************** **This portion of the code decides what to do with the user input and what to show on the display **********************************/ void stateMachine(void) { //if nothing has happened for a while and the clock is not in the default state if(millis()-buttonTimer > timeSetTimeout && state != DEFAULT_STATE) state = DEFAULT_STATE;//put it back in the default state switch(state) { case DEFAULT_STATE: alarm();//check the alarm watch.setTime(hours, minutes);//set the display to show the time watch.showTime();//show the current time if(alarmPlaying==false)//if the alarm is not making noise { if(buttonEvent == buttonEvent3)//if button 3 is pushed state = EXIT_DEFAULT_STATE;//change state to decide what to do } else//if the alarm is making noise { if(buttonEvent != noButtonEvent)//and a button is pushed alarmPlaying=false;//turn off the alarm sound } break; case EXIT_DEFAULT_STATE: watch.setTime(hours, minutes); watch.showTime(); if(buttonEvent == noButtonEvent)//if all buttons are released state = DEFAULT_STATE;//go back to the default state if(buttonEvent == buttonEvent3Hold)//if button 3 is held state = ENTER_SET_TIME_STATE;//set the time break; case ENTER_SET_TIME_STATE: if(buttonEvent == noButtonEvent)//wait for the user to release the button state = SET_HOUR_STATE;//change state to set the hour break; case SET_HOUR_STATE: updateBlink();//update the flashing variable for the display if(blinkVariable==HIGH) { if(AMPM==PM)//turn on the 4 minute LEDs if it is PM watch.setTime(hours, 4); else//otherwise display the minutes watch.setTime(hours, minutes); watch.showTime(); } if(buttonEvent == buttonEvent1)//if button 1 is pushed state = INC_HOUR_STATE;//increase the hour if(buttonEvent == buttonEvent2)//if button 2 is pushed state = DEC_HOUR_STATE;//decrease the hour if(buttonEvent == buttonEvent3)//if button 3 is pushed state = EXIT_HOUR_STATE;//go here to wait for the user and decide what state to go to next break; case INC_HOUR_STATE: watch.setTime(hours, minutes); watch.showTime(); if(buttonEvent == noButtonEvent)//wait for the user to release the button { hours = (hours+1)%12;//increase the hour by one if(hours==0) if(AMPM==PM) AMPM=AM; else AMPM=PM; state = SET_HOUR_STATE;//and return to change the hour again } break; case DEC_HOUR_STATE: watch.setTime(hours, minutes); watch.showTime(); if(buttonEvent == noButtonEvent)//wait for the user to release the button { hours = (hours-1);//decrease the hour by one if(hours < 0) { hours=11; if(AMPM==PM) AMPM=AM; else AMPM=PM; } state = SET_HOUR_STATE;//and return to change the hour again } break; case EXIT_HOUR_STATE: watch.setTime(hours, minutes); watch.showTime(); if(buttonEvent == noButtonEvent)//wait for the user to release the button state = SET_MIN_STATE;//and change state to set the minutes if(buttonEvent == buttonEvent3Hold)//if button 3 is held state = ENTER_SET_AL_STATE;//change state to set the alarm break; case SET_MIN_STATE: updateBlink(); watch.setTime(hours, minutes); if(blinkVariable==HIGH) watch.showTime(); if(buttonEvent == buttonEvent1)//if button 1 is pushed state = INC_MIN_STATE;//increase the minutes if(buttonEvent == buttonEvent2)//if button 2 is pushed state = DEC_MIN_STATE;//decrease the minutes if(buttonEvent == buttonEvent3)//if button 3 is pushed state = EXIT_MIN_STATE;//wait for the user to release in this state and decide what to do break; case INC_MIN_STATE: watch.setTime(hours, minutes); watch.showTime(); if(buttonEvent == noButtonEvent)//when all buttons are released { minutes = (minutes+1)%60;//increase the minutes by one state = SET_MIN_STATE;//and go back to change the minutes again } break; case DEC_MIN_STATE: watch.setTime(hours, minutes); watch.showTime(); if(buttonEvent == noButtonEvent)//when all buttons are released { minutes = (minutes-1);//decrease the minutes by one if(minutes < 0) minutes=59; state = SET_MIN_STATE;//and go back to change the minutes again } break; case EXIT_MIN_STATE: watch.setTime(hours, minutes); watch.showTime(); if(buttonEvent == noButtonEvent)//when the button is released state = SET_HOUR_STATE;//change state to set the hour if(buttonEvent == buttonEvent3Hold)//if the button is held state = ENTER_SET_AL_STATE;//change state to set the alarm break; case ENTER_SET_AL_STATE: if(buttonEvent == noButtonEvent)//when the button is released state = AL_SET_HOUR_STATE;//change state to set the alarm hour break; case AL_SET_HOUR_STATE: updateBlink(); if(alarmOn == true)//if the alarm is turned on { if(blinkVariable==HIGH)//update the display so it blinks { if(AMPM==PM) watch.setTime(alarmHours, 4);//if the time is PM light the 4 minute LEDs to indicate this else watch.setTime(alarmHours, alarmMinutes); watch.showTime(); } if(buttonEvent == buttonEvent1) state = AL_INC_HOUR_STATE;//wait for the user to relese the button in this state if(buttonEvent == buttonEvent2) state = AL_DEC_HOUR_STATE;//wait for the user to relese the button in this state if(buttonEvent == buttonEvent3) state = AL_EXIT_HOUR_STATE;//wait for the user to relese the button or keep holding it to leave setup mode } else//show that the alarm is off { if(buttonEvent == buttonEvent1Hold || buttonEvent == buttonEvent2Hold)//if the user holds button 1 or 2 { if(alarmOn == false) alarmOn = true;//turn the alarm on else alarmOn = false;//turn the alarm off state = ENTER_SET_AL_STATE;//wait for the user to release the button in this state } if(buttonEvent == buttonEvent3Hold) state = ENTER_DEFAULT_STATE;//wait for the user to relese the button or keep holding it to leave setup mode watch.setTime(6, 34);//not ideal, may need to change to make clearer watch.showTime(); } break; case AL_INC_HOUR_STATE: watch.setTime(alarmHours, alarmMinutes); watch.showTime(); if(buttonEvent == noButtonEvent)//wait until all buttons are released { alarmHours = (alarmHours+1)%12;//increase the alarm hour if(alarmHours==0) if(alarmAMPM==PM) alarmAMPM=AM; else alarmAMPM=PM; state = AL_SET_HOUR_STATE;//return to set alarm hour } if(buttonEvent == buttonEvent1Hold || buttonEvent == buttonEvent2Hold)//if the user holds button 1 or 2 { if(alarmOn == false) alarmOn = true;//turn the alarm on else alarmOn = false;//turn the alarm off state = ENTER_SET_AL_STATE;//wait for the user to release the button in this state } break; case AL_DEC_HOUR_STATE: if(buttonEvent == noButtonEvent)//wait until all buttons are released { alarmHours = (alarmHours-1);//decrese the alarm hour if(alarmHours < 0) { alarmHours=11; if(alarmAMPM==PM) alarmAMPM=AM; else alarmAMPM=PM; } state = AL_SET_HOUR_STATE;//return to set alarm hour } if(buttonEvent == buttonEvent1Hold || buttonEvent == buttonEvent2Hold)//if the user holds button 1 or 2 { if(alarmOn == false) alarmOn = true;//turn the alarm on else alarmOn = false;//turn the alarm off state = ENTER_SET_AL_STATE;//wait for the user to release the button in this state } watch.setTime(alarmHours, alarmMinutes); watch.showTime(); break; case AL_EXIT_HOUR_STATE: if(buttonEvent == noButtonEvent)//when all buttons are released state = AL_SET_MIN_STATE;//change state to set the minutes if(buttonEvent == buttonEvent3Hold)//if button 3 is held { state = ENTER_DEFAULT_STATE;//return to the main state } watch.setTime(alarmHours, alarmMinutes); watch.showTime(); break; case AL_SET_MIN_STATE: updateBlink(); watch.setTime(alarmHours, alarmMinutes); if(blinkVariable==HIGH) watch.showTime();//update the display so it blinks if(buttonEvent == buttonEvent1) state = AL_INC_MIN_STATE;//wait for the user to release the button in this state if(buttonEvent == buttonEvent2) state = AL_DEC_MIN_STATE;//wait for the user to release the button in this state if(buttonEvent == buttonEvent3) state = AL_EXIT_MIN_STATE;//wait for the user to release the button in this state break; case AL_INC_MIN_STATE: watch.setTime(alarmHours, alarmMinutes); watch.showTime(); if(buttonEvent == noButtonEvent)//when the button is relesed { alarmMinutes = (alarmMinutes+1)%60;//increase the alarm minutes state = AL_SET_MIN_STATE;//go back to change the minutes again } if(buttonEvent == buttonEvent1Hold || buttonEvent == buttonEvent2Hold)//if the user holds button 1 or 2 state = AL_SET_HOUR_STATE;//return to the main alarm setting state,where the alarm is turned off break; case AL_DEC_MIN_STATE: watch.setTime(alarmHours, alarmMinutes); watch.showTime(); if(buttonEvent == noButtonEvent)//when the button is relesed { alarmMinutes = (alarmMinutes-1);//decrease the alarm minutes if(alarmMinutes < 0) alarmMinutes=59; state = AL_SET_MIN_STATE;//go back to change the minutes again } if(buttonEvent == buttonEvent1Hold || buttonEvent == buttonEvent2Hold)//if the user holds button 1 or 2 state = AL_SET_HOUR_STATE;//return to the main alarm setting state,where the alarm is turned off break; case AL_EXIT_MIN_STATE: watch.setTime(alarmHours, alarmMinutes); watch.showTime(); if(buttonEvent == noButtonEvent)//when no buttons are pressed state = AL_SET_HOUR_STATE;//change state to set the alarm hour if(buttonEvent == buttonEvent3Hold)//if button3 is held state = ENTER_DEFAULT_STATE;//return to the default state break; case ENTER_DEFAULT_STATE: if(buttonEvent == noButtonEvent)//wait until the buttons are released state = DEFAULT_STATE;//and go back to the default state break; default://if something unexpected happens state = DEFAULT_STATE;//go back to the default state (time display) break; } } void updateBlink(void) { if(millis()%blinkRate>=blinkRate/2) blinkVariable=1; else blinkVariable=0; } void clockUpdate() { lastClockTime=currentClockTime;//for when millis wraps around currentClockTime=millis(); if(currentClockTime=lastTimeUpdated)//update the time { lastTimeUpdated+=oneMin;//update the counter minutes=(minutes+1)%60;//get the new time if (minutes==0) { hours=(hours+1)%(12); if(hours==0) if(AMPM==PM) AMPM=AM; else AMPM=PM; } } } void alarm(void) { if(alarmOn == true) { //turn the alarm off if a button is pushed if(alarmPlaying) if(buttonEvent!=noButtonEvent) alarmPlaying=false; //see if the alarm should go off if(alarmHours==hours && alarmMinutes==minutes) if(alarmSounded==false && alarmAMPM==AMPM) { alarmPlaying=true;//turn the alarm on alarmSounded=true;//make sure it only goes off once per minute } if(alarmMinutes!=minutes) alarmSounded=false;//arm the alarm if(alarmPlaying) playTune();//sound the alarm } } void playTune(void) // play a tune . . . { for(int j=0;j0) { toneOut(songNote[j],noteDuration[j]); //delay(et); } else delay(noteDuration[j]); } } void toneOut(int pitch, int duration) // pitch in Hz, duration in ms { int delayPeriod; long cycles, i; delayPeriod = (500000 / pitch) - 7; // calc 1/2 period in us -7 for overhead cycles = ((long)pitch * (long)duration) / 1000; // calc. number of cycles for loop for (i=0; i<= cycles; i++) // play note for duration ms { digitalWrite(SPEAKER, HIGH); delayMicroseconds(delayPeriod); digitalWrite(SPEAKER, LOW); delayMicroseconds(delayPeriod - 1); // - 1 to make up for digitaWrite overhead } }