33// Originally written by Robin Birtles and Chris Gerekos based on http://arduinix.com/Main/Code/ANX-6Tube-Clock-Crossfade.txt
44// Refactored and expanded by Luke McKenzie (luke@theclockspot.com)
55
6- // TODO: Alarm - display, set, sound, snooze, 24h silence
76// TODO: Timer - display, set, run, sound, silence - make non-volatile?
87// TODO: Cathode anti-poisoning
98// TODO: implement other setup options
@@ -69,16 +68,19 @@ const char mainAdjFn = -1;
6968// const byte altAdjFn = -1;
7069
7170const byte enableSoftAlarmSwitch = 1 ;
72- // 1 = yes. Use if using the integrated beeper or another non-switched device (bell solenoid, etc).
71+ // 1 = yes. Use if using the integrated piezo or another non-switched device (bell solenoid, etc).
7372// 0 = no. Use if the connected alarm device has its own switch (e.g. clock radio function switch).
7473// Alarm will be permanently on in software.
75- const byte alarmRadio = 0 ;
76- // 0 = no. Alarm output is connected to the onboard piezoelectric beeper or similar signal device.
77- // When alarm and timer go off, it will output a beep pattern for alarmDur minutes.
78- // 1 = yes. Alarm output is connected to a relay to switch other equipment (like a radio).
79- // When alarm goes off, output will stay on for alarmDur minutes (120 is common).
74+ const byte signalPin = 10 ;
75+ const byte signalType = 0 ;
76+ // What is the signal pin connected to?
77+ // 0 = Piezo. When alarm and timer go off, it will output a beep pattern with tone() for signalDur minutes.
78+ // 1 = Signal relay TODO. Same as above, but it will simply switch the pin, for e.g. a solenoid.
79+ // 2 = Radio relay TODO.
80+ // When alarm goes off, output will stay on for signalDur minutes (120 is common).
8081// When timer is running, output will stay on until timer runs down.
81- const byte alarmDur = 1 ;
82+ const word signalBeepDur = 500 ; // With signalType 0/1, beeps happen once per second; how long is each beep in ms?
83+ const byte signalDur = 1 ; // When alarm goes off (and timer, with signalType 0/1), how many mins does signal run for?
8284
8385const byte unoffDur = 10 ; // when display is dim/off, a press will light the tubes for this many seconds
8486
@@ -161,7 +163,8 @@ bool fnSetValVel; //whether it supports velocity setting (if max-min > 30)
161163word fnSetValDate[3 ]; // holder for newly set date, so we can set it in 3 stages but set the RTC only once
162164
163165// Volatile running values
164- word soundRemain = 0 ; // alarm/timer sound timeout counter, seconds
166+ word signalRemain = 0 ; // alarm/timer signal timeout counter, seconds
167+ word signalPitch = 440 ; // which pitch to use - set by what started the signal going
165168word snoozeRemain = 0 ; // snooze timeout counter, seconds
166169word timerInitial = 0 ; // timer original setting, seconds - up to 18 hours (64,800 seconds - fits just inside a word)
167170word timerRemain = 0 ; // timer actual counter
@@ -285,29 +288,30 @@ void checkRot(){
285288
286289// //////// Input handling and value setting //////////
287290
288- bool stoppingSound = false ; // Special stuff (snooze canceling) happens right after a press that silences the sound
291+ bool stoppingSignal = false ; // Special stuff (snooze canceling) happens right after a press that silences the signal
289292void ctrlEvt (byte ctrl, byte evt){
290293 // Handle control events (from checkBtn or checkRot), based on current fn and set state.
291294 // evt: 1=press, 2=short hold, 3=long hold, 0=release.
292295 // We only handle press evts for adj ctrls, as that's the only evt encoders generate.
293296 // But we can handle short and long holds and releases for the sel ctrls (always buttons).
294297 // TODO needs alt handling
295298
296- // Before all else, is it a press while the beeper is sounding ? Silence it
297- if (soundRemain >0 && evt==1 ){
298- stoppingSound = true ;
299- soundRemain = 0 ;
300- noTone (10 );
299+ // Before all else, is it a press to stop the signal ? Silence it
300+ if (signalRemain >0 && evt==1 ){
301+ stoppingSignal = true ;
302+ signalRemain = 0 ;
303+ if (signalType== 0 ) noTone (signalPin );
301304 // If we're displaying the clock (as alarm trigger does), start snooze. 0 will have no effect
302305 if (fn==fnIsTime) snoozeRemain = readEEPROM (24 ,false )*60 ;
303306 return ;
304307 }
305308 // After pressing to silence, short hold cancels a snooze; ignore other btn evts
306- if (stoppingSound ){
307- stoppingSound = false ;
309+ if (stoppingSignal ){
310+ stoppingSignal = false ;
308311 if (evt==2 && snoozeRemain>0 ) {
309312 snoozeRemain = 0 ;
310- tone (10 , 3136 , 100 ); // G7
313+ // A short beep at alarm pitch. Use signalBeepDur or 100ms, whichever is smaller
314+ if (signalType==0 ) tone (signalPin, getHz (readEEPROM (39 ,false )), (signalBeepDur<100 ?signalBeepDur:100 ));
311315 }
312316 btnStop ();
313317 return ;
@@ -620,7 +624,7 @@ void checkRTC(bool force){
620624 if (pollLast-inputLast>120000 ) { fnSetPg = 0 ; fn = fnIsTime; force=true ; } // Time out after 2 mins
621625 }
622626 // Temporary-display mode timeout: if we're *not* in a permanent one (time, day counter, or running timer)
623- else if (fn!=fnIsTime && fn!=fnIsCleaner && fn!=fnIsDayCount && !(fn==fnIsTimer && (timerRemain>0 || soundRemain >0 ))){
627+ else if (fn!=fnIsTime && fn!=fnIsCleaner && fn!=fnIsDayCount && !(fn==fnIsTimer && (timerRemain>0 || signalRemain >0 ))){
624628 if (pollLast>inputLast+5000 ) { fnSetPg = 0 ; fn = fnIsTime; force=true ; }
625629 }
626630 }
@@ -642,7 +646,7 @@ void checkRTC(bool force){
642646 if (readEEPROM (23 ,false )==0 || // any day of the week
643647 (readEEPROM (23 ,false )==1 && toddow>=readEEPROM (33 ,false ) && toddow<=readEEPROM (34 ,false )) || // weekday only
644648 (readEEPROM (23 ,false )==2 && toddow<readEEPROM (33 ,false ) && toddow>readEEPROM (34 ,false ))) { // weekend only
645- fnSetPg = 0 ; fn = fnIsTime; soundRemain = alarmDur *60 ;
649+ fnSetPg = 0 ; fn = fnIsTime; signalPitch = getHz ( readEEPROM ( 39 , false )); signalRemain = signalDur *60 ;
646650 } // end toddow check
647651 } // end alarm trigger
648652 // checkDigitCycle();
@@ -657,26 +661,26 @@ void checkRTC(bool force){
657661 if (timerRemain>0 ) {
658662 timerRemain--;
659663 if (timerRemain<=0 ) { // timer has elasped
660- if (readEEPROM (25 ,false )) { // interval timer: sound for 1sec and restart; don't change to timer fn
661- soundRemain = 1 ; timerRemain = timerInitial;
664+ signalPitch = getHz (readEEPROM (40 ,false ));
665+ if (readEEPROM (25 ,false )) { // interval timer: a short signal and restart; don't change to timer fn
666+ signalRemain = 1 ; timerRemain = timerInitial;
662667 } else {
663- fnSetPg = 0 ; fn = fnIsTimer; inputLast = pollLast; soundRemain = alarmDur *60 ;
668+ fnSetPg = 0 ; fn = fnIsTimer; inputLast = pollLast; signalRemain = signalDur *60 ;
664669 }
665670 // TODO radio mode
666671 } // end timer elapsed
667672 }
668- // If beeper has time on it, decrement and sound the beeper for 1/2 second
669- if (soundRemain>0 ) {
670- soundRemain--;
671- // tone(10, 1568, 500); //G6
672- tone (10 , 1760 , 500 ); // A6
673- // tone(10, 1976, 500); //B6
674- // tone(10, 2093, 500); //C7
675- }
676673 // If alarm snooze has time on it, decrement and trigger beeper if we reach zero (and alarm is still on)
677674 if (snoozeRemain>0 ) {
678675 snoozeRemain--;
679- if (snoozeRemain<=0 && readEEPROM (2 ,false )) { fnSetPg = 0 ; fn = fnIsTime; soundRemain = alarmDur*60 ; }
676+ if (snoozeRemain<=0 && readEEPROM (2 ,false )) {
677+ fnSetPg = 0 ; fn = fnIsTime; signalPitch = getHz (readEEPROM (39 ,false )); signalRemain = signalDur*60 ;
678+ }
679+ }
680+ // If signal has time on it, decrement and make a beep
681+ if (signalRemain>0 ) {
682+ signalRemain--;
683+ if (signalType==0 ) tone (signalPin, signalPitch, signalBeepDur);
680684 }
681685 if (unoffRemain>0 ) {
682686 unoffRemain--; // updateDisplay will naturally put it back to off state if applicable
@@ -776,6 +780,9 @@ void updateDisplay(){
776780 if (fnSetVal>=60 ) editDisplay (fnSetVal/60 , 0 , 1 , false ); else blankDisplay (0 ,1 ); // hour only if present, else blank
777781 editDisplay (fnSetVal%60 , 2 , 3 , (fnSetVal>=60 ?true :false )); // leading zero only if hour present
778782 editDisplay (0 ,4 ,5 ,true ); // placeholder seconds
783+ } else if (fnSetValMax==88 ) { // A piezo pitch. Play a short demo beep.
784+ editDisplay (fnSetVal, 0 , 3 , false );
785+ if (signalType==0 ) tone (signalPin, getHz (fnSetVal), (signalBeepDur<100 ?signalBeepDur:100 ));
779786 } else editDisplay (fnSetVal, 0 , 3 , false ); // some other type of value
780787 }
781788 else if (fn >= fnOpts){ // options menu, but not setting a value
0 commit comments