Skip to content

Commit 077d357

Browse files
committed
Standardize on "signal" for alarm/timer sound, using tone() and fn-specific pitches from EEPROM. Begin to check signalType for future support of signal or radio relays.
1 parent 3a32545 commit 077d357

File tree

2 files changed

+42
-35
lines changed

2 files changed

+42
-35
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ _In these instructions, **Select** is the main pushbutton, and **Adjust** can be
4141
| | **Alarms and sounds** |
4242
| 7. Alarm days | 0 = every day<br/>1 = work week only (per settings below)<br/>2 = weekend only |
4343
| 8. Alarm snooze | 0–60 minutes. 0 disables snooze. |
44-
| 9. Alarm tone pitch | _Not yet implemented._<br/>[Note number on a piano keyboard](https://en.wikipedia.org/wiki/Piano_key_frequencies), from 49 (A4) to 88 (C8). Some are louder than others. |
44+
| 9. Alarm tone pitch | [Note number on a piano keyboard](https://en.wikipedia.org/wiki/Piano_key_frequencies), from 49 (A4) to 88 (C8). Some are louder than others! |
4545
| 10. Timer interval mode | What happens when the timer reaches 0.<br/>0 = stop and sound continuously<br/>1 = restart and sound a single tone (interval timer) |
46-
| 11. Timer tone pitch | _Not yet implemented._<br/>Set the same way as the alarm tone pitch, above. |
46+
| 11. Timer tone pitch | Set the same way as the alarm tone pitch, above. |
4747
| 12. Hourly strike | _Not yet implemented._<br/>0 = off<br/>1 = double tone<br/>2 = pips<br/>3 = strike the hour<br/>4 = ship's bell<br/>(Clocks without radio/timer control only. Will not sound during day-off or night-off.) |
48-
| 13. Hourly strike pitch | _Not yet implemented._<br/>Set the same way as the alarm tone pitch, above. |
48+
| 13. Hourly strike pitch | Set the same way as the alarm tone pitch, above. |
4949
| | **Night-off and day-off** |
5050
| 14. Night-off | To save tube life and/or preserve your sleep, dim or shut off tubes nightly when you're not around or sleeping.<br/>0 = none (tubes fully on at night)<br/>1 = dim tubes at night<br/>2 = shut off tubes at night<br/>When off, you can press **Select** to illuminate the tubes briefly. |
5151
| 15. Night starts at | Time of day. |

sixtube_lm/sixtube_lm.ino

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
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

7170
const 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

8385
const 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)
161163
word 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
165168
word snoozeRemain = 0; //snooze timeout counter, seconds
166169
word timerInitial = 0; //timer original setting, seconds - up to 18 hours (64,800 seconds - fits just inside a word)
167170
word 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
289292
void 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

Comments
 (0)