Skip to content

Commit dc16152

Browse files
committed
Temp option + persistent display + write display to console, for testing ; further (untested) work on LED circuit switching
1 parent 0ae58a8 commit dc16152

File tree

2 files changed

+95
-49
lines changed

2 files changed

+95
-49
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ _Note: Many variations are possible, depending on your clock's hardware; but thi
2222
| **Alarm** | `_7 00 1_` | Shows alarm time (always in 24hr format) and on/off status on 5th tube (1=on, 0=off) and by display brightness (bright=on, dim=off). Use **Adjust** to switch on/off. Hold **Select** to set time (same way as **Time**). When alarm sounds, press **Select** to snooze, or hold for 1sec (followed by a short beep) to silence the alarm for the day. Options menu lets you restrict the alarm to your workweek or weekend only. In a power outage, the alarm will remain set, but it will not sound if power is disconnected at alarm time. |
2323
| **Timer** | `__ __ _0` | A countdown timer, in hours, minutes, and seconds; or `0` when stopped. Can be set to the minute, up to 18 hours. Begins running as soon as you set it, and will continue to run in the background if you change to a different function. To cancel while running, hold **Select**. When timer runs out, press **Select** to silence. If power is lost, the timer will reset to `0`. Can be configured to work as an interval timer in the options menu (10), or as an appliance timer instead ([relay in switched mode](#hardware-configuration)). |
2424
| **Day counter** | `_1 23 __` | Shows the number of days until/since a date you specify. Set the same way as **Date.** |
25-
| **Temperature** | `__ 38 25` | (Disabled by default.) Shows the temperature of the onboard DS3231 chip (e.g. 38.25°C – I think). May not be very useful as it tends to read higher than ambient temperature and its tolerance is low. |
25+
| **Temperature** | `__ 38 25` | Shows the temperature of the onboard DS3231 chip (e.g. 38.25°C – I think). May not be very useful as it tends to read higher than ambient temperature and its tolerance is low. Negative temperatures indicated with leading zeroes. |
2626
| **Tube tester** | `88 88 88` | (Disabled by default.) Cycles through all the digits on all the tubes. |
2727

2828
### Options Menu
@@ -58,6 +58,7 @@ _Note: Many variations are possible, depending on your clock's hardware; but thi
5858
| 23. Work starts at | Time of day. |
5959
| 24. Work ends at | Time of day. |
6060
| 25. LED behavior | 0 = always off<br/>1 = always on<br/>2 = on, but follow day-off and night-off if enabled<br/>3 = off, but on when alarm/timer sounds</br>4 = off, but on with switched relay (if equipped – great for radios!)<br/>(Clocks with LED control only, UNDB v5.x+) |
61+
| 26. Temperature format | 0 = Celsius<br/>1 = Fahrenheit<br/>(Clocks with temperature function enabled only) |
6162

6263
To reset the options menu settings to "factory" defaults, hold **Select** while connecting the clock to power.
6364

sixtube_lm/sixtube_lm.ino

Lines changed: 93 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ const byte fnIsDayCount = 4;
2424
const byte fnIsTemp = 5;
2525
const byte fnIsTubeTester = 6; //cycles all digits on all tubes 1/second, similar to anti-cathode-poisoning cleaner
2626
// functions enabled in this clock, in their display order. Only fnIsTime is required
27-
const byte fnsEnabled[] = {fnIsTime, fnIsDate, fnIsAlarm, fnIsTimer, fnIsDayCount}; //, fnIsTemp, fnIsTubeTester
27+
const byte fnsEnabled[] = {fnIsTime, fnIsDate, fnIsAlarm, fnIsTimer, fnIsDayCount, fnIsTemp}; //, fnIsTemp, fnIsTubeTester
28+
// To control which of these display persistently vs. switch back to Time after a few seconds, search "Temporary-display mode timeout"
2829

2930
// These are the RLB board connections to Arduino analog input pins.
3031
// S1/PL13 = Reset
@@ -58,7 +59,7 @@ const char piezoPin = 10;
5859
const char relayPin = 127;
5960
// If running a v5.0 board with only a piezo output, leave these set to 10 and -1 (disabled) respectively - unless removing the piezo to drive a relay instead, in which case, reverse them.
6061
// If running a v5.x board with both piezo and relay, piezo is 10, relay is X. Extra menu options will appear to let end user decide which functions control which outputs.
61-
// Relay toggles are written to the serial console for testing. To test without relay present, set relayPin to 127.
62+
// To test without relay/load present, set relayPin to 127 to have relay commands written to console instead.
6263
const byte relayMode = 0; //If relay is equipped, what does it do?
6364
// 0 = switched mode: the relay will be switched to control an appliance like a radio or light fixture. If used with timer, it will switch on while timer is running (like a "sleep" function). If used with alarm, it will switch on when alarm trips; specify duration of this in switchDur.
6465
// 1 = pulsed mode: the relay will be pulsed, like the beeper is, to control an intermittent signaling device like a solenoid or indicator lamp. Specify pulse duration in relayPulse.
@@ -76,9 +77,10 @@ const byte enableSoftPowerSwitch = 1; //works with switched relay only
7677
// 0 = no. Use if the connected appliance has its own power switch (independent of this relay circuit) or does not need to be manually switched.
7778

7879
//LED circuit control
79-
const char ledPin = -1;
80+
const char ledPin = 127;
8081
// If running a v5.0 board with constantly powered LEDs, leave this set to -1 (disabled).
8182
// If running a v5.x board, LED control pin is X. An extra menu option will appear to let end user control LEDs.
83+
// To test without LED circuit present, set relayPin to 127 to have LED switch commands written to console instead.
8284

8385
//When display is dim/off, a press will light the tubes for how long?
8486
const byte unoffDur = 10; //sec
@@ -125,7 +127,7 @@ Some are skipped when they wouldn't apply to a given clock's hardware config, se
125127
23 Alarm days
126128
24 Alarm snooze
127129
25 Timer interval mode - skipped when no piezo and relay is switch (start=0)
128-
26 LED circuit behavior
130+
26 LED circuit behavior - skipped when no led pin
129131
27 Night-off
130132
28-29 Night start, mins
131133
30-31 Night end, mins
@@ -140,16 +142,17 @@ Some are skipped when they wouldn't apply to a given clock's hardware config, se
140142
42 Alarm signal, 0=beeper, 1=relay - skipped when no relay (start=0) or no piezo (start=0)
141143
43 Timer signal - skipped when no relay (start=0) or no piezo (start=1)
142144
44 Strike signal - skipped when no pulse relay (start=0) or no piezo (start=1)
145+
45 Temperature format - skipped when fnIsTemp is not in fnsEnabled
143146
*/
144147

145148
//Options menu options' EEPROM locations and default/min/max values.
146149
//Options' numbers may be changed by reordering these arrays (and changing readme accordingly).
147150
//Although these arrays are 0-index, the option number displayed (and listed in readme) is 1-index. (search for "fn-fnOpts+1")
148-
//1-index option number: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
149-
const byte optsLoc[] = {16,17,18,19,20,22,23,24,42,39,43,25,40,21,44,41,27, 28, 30,32,33,34, 35, 37,26};
150-
const word optsDef[] = { 2, 1, 0, 0, 5, 0, 0, 9, 0,61, 0, 0,61, 0, 0,61, 0,1320, 360, 0, 1, 5, 480,1020, 1};
151-
const word optsMin[] = { 1, 1, 0, 0, 0, 0, 0, 0, 0,49, 0, 0,49, 0, 0,49, 0, 0, 0, 0, 0, 0, 0, 0, 0};
152-
const word optsMax[] = { 2, 5, 3, 1,20, 6, 2,60, 1,88, 1, 1,88, 4, 1,88, 2,1439,1439, 2, 6, 6,1439,1439, 4};
151+
//1-index option number: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
152+
const byte optsLoc[] = {16,17,18,19,20,22,23,24,42,39,43,25,40,21,44,41,27, 28, 30,32,33,34, 35, 37,26,45};
153+
const word optsDef[] = { 2, 1, 0, 0, 5, 0, 0, 9, 0,61, 0, 0,61, 0, 0,61, 0,1320, 360, 0, 1, 5, 480,1020, 1, 0};
154+
const word optsMin[] = { 1, 1, 0, 0, 0, 0, 0, 0, 0,49, 0, 0,49, 0, 0,49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
155+
const word optsMax[] = { 2, 5, 3, 1,20, 6, 2,60, 1,88, 1, 1,88, 4, 1,88, 2,1439,1439, 2, 6, 6,1439,1439, 4, 1};
153156

154157
//RTC objects
155158
DS3231 ds3231; //an object to access the ds3231 specifically (temp, etc)
@@ -208,6 +211,7 @@ void setup(){
208211
writeEEPROM(25,0,false); //turn off timer interval mode
209212
}
210213
if(!enableSoftAlarmSwitch) writeEEPROM(2,1,false); //force alarm on if software switch is disabled
214+
//if LED circuit is not switched (v5.0 board), the LED menu setting (eeprom 26) doesn't matter
211215
initOutputs(); //depends on some EEPROM settings
212216
}
213217

@@ -455,8 +459,8 @@ void ctrlEvt(byte ctrl, byte evt){
455459
timerRemain = timerInitial; //set actual timer going
456460
if(relayPin>=0 && relayMode==0 && readEEPROM(43,false)==1) { //if switched relay, and timer signal is set to it
457461
if(relayPin!=127) digitalWrite(relayPin,HIGH);
458-
Serial.print(millis(),DEC); Serial.println(F(" Relay on, timer set"));
459-
if(readEEPROM(26,false)==4) switchLEDs(1); //LEDs following switch relay
462+
else { Serial.print(millis(),DEC); Serial.println(F(" Relay on, timer set")); }
463+
updateLEDs(); //LEDs following switch relay
460464
//TODO will this cancel properly? especially if alarm interrupts?
461465
}
462466
clearSet(); break;
@@ -541,7 +545,15 @@ void fnOptScroll(char dir){
541545
|| ((piezoPin<0 && relayMode==0) && (optLoc==21||optLoc==25)) //no piezo, and relay is switch: no strike or timer interval mode
542546
|| ((relayPin<0 || piezoPin<0) && (optLoc==42||optLoc==43||optLoc==44)) //no relay or no piezo: no alarm/timer/strike signal
543547
|| ((relayMode==0) && (optLoc==44)) //relay is switch: no strike signal
544-
) fnOptScroll(dir);
548+
|| ((ledPin<0) && (optLoc==26)) //no led pin: no led control
549+
) {
550+
fnOptScroll(dir);
551+
}
552+
if(optLoc==45) { //temp not in fnsEnabled: skip temp format option (and calib if we get to it TODO)
553+
bool found = 0;
554+
for(byte fnct=0; fnct<sizeof(fnsEnabled); fnct++) if(fnsEnabled[fnct]==fnIsTemp) found = 1;
555+
if(found==0) fnOptScroll(dir);
556+
}
545557
}
546558

547559
void startSet(word n, word m, word x, byte p){ //Enter set state at page p, and start setting a value
@@ -571,6 +583,7 @@ void doSetHold(){
571583
}
572584
void clearSet(){ //Exit set state
573585
startSet(0,0,0,0);
586+
updateLEDs(); //in case LED setting was changed
574587
checkRTC(true); //force an update to tod and updateDisplay()
575588
}
576589

@@ -630,7 +643,7 @@ void writeEEPROM(int loc, int val, bool isWord){
630643
// if(EEPROM.read(loc)!=val) { Serial.print(val,DEC); } else { Serial.print(F("no change")); }
631644
EEPROM.update(loc,val);
632645
}
633-
Serial.println();
646+
//Serial.println();
634647
}
635648

636649
byte daysInMonth(word y, byte m){
@@ -675,8 +688,8 @@ void checkRTC(bool force){
675688
if(fnSetPg || fn>=fnOpts){
676689
if(pollLast>inputLast+(timeoutSet*1000)) { fnSetPg = 0; fn = fnIsTime; force=true; } //Time out after 2 mins
677690
}
678-
//Temporary-display mode timeout: if we're *not* in a permanent one (time, day counter, tester, or running/signaling timer)
679-
else if(fn!=fnIsTime && fn!=fnIsTubeTester && fn!=fnIsDayCount && !(fn==fnIsTimer && (timerRemain>0 || signalRemain>0))){
691+
//Temporary-display mode timeout: if we're *not* in a permanent one (time, day counter, temp, tester, or running/signaling timer)
692+
else if(fn!=fnIsTime && fn!=fnIsTubeTester && fn!=fnIsDayCount && fn!=fnIsTemp && !(fn==fnIsTimer && (timerRemain>0 || signalRemain>0))){
680693
if(pollLast>inputLast+(timeoutTempFn*1000)) { fnSetPg = 0; fn = fnIsTime; force=true; }
681694
}
682695
//Stop a signal beep if it's time to
@@ -833,15 +846,15 @@ void switchPower(char dir){
833846
if(enableSoftPowerSwitch && relayPin>=0 && relayMode==0) { //if switched relay, and soft switch enabled
834847
//signalStop(); could use this instead of the below to turn the radio off
835848
if(dir==0) dir = !digitalRead(relayPin);
836-
if(relayPin!=127) {
837-
digitalWrite(relayPin,(dir==1?HIGH:LOW));
849+
if(relayPin!=127) digitalWrite(relayPin,(dir==1?HIGH:LOW));
850+
else {
851+
Serial.print(millis(),DEC);
852+
Serial.print(F(" Relay "));
853+
if(dir==0) { Serial.print(F("toggled")); if(relayPin!=127) { Serial.print(digitalRead(relayPin)==HIGH?F(" on"):F(" off")); } }
854+
else Serial.print(dir==1?F("switched on"):F("switched off"));
855+
Serial.println(F(", switchPower"));
838856
}
839-
if(readEEPROM(26,false)==4) switchLEDs(dir); //LEDs following switch relay
840-
Serial.print(millis(),DEC);
841-
Serial.print(F(" Relay "));
842-
if(dir==0) { Serial.print(F("toggled")); if(relayPin!=127) { Serial.print(digitalRead(relayPin)==HIGH?F(" on"):F(" off")); } }
843-
else Serial.print(dir==1?F("switched on"):F("switched off"));
844-
Serial.println(F(", switchPower"));
857+
updateLEDs(); //LEDs following switch relay
845858
}
846859
}
847860

@@ -1001,6 +1014,8 @@ void updateDisplay(){
10011014
break;
10021015
case fnIsTemp: //thermometer
10031016
int temp; temp = ds3231.getTemperature()*100;
1017+
if(readEEPROM(45,false)==1) temp = temp*1.8 + 3200;
1018+
//TODO another option to apply offset
10041019
editDisplay(abs(temp)/100,1,3,(temp<0?true:false),true); //leading zeros if negative
10051020
editDisplay(abs(temp)%100,4,5,true,true);
10061021
break;
@@ -1013,7 +1028,26 @@ void updateDisplay(){
10131028
editDisplay(tod.second(),5,5,true,false);
10141029
default: break;
10151030
}//end switch
1016-
} //end if fn running
1031+
} //end if fn running
1032+
1033+
if(true) { //DEBUG MODE: when display's not working, just write it to the console, with time
1034+
if(tod.hour()<10) Serial.print(F("0"));
1035+
Serial.print(tod.hour(),DEC);
1036+
Serial.print(F(":"));
1037+
if(tod.minute()<10) Serial.print(F("0"));
1038+
Serial.print(tod.minute(),DEC);
1039+
Serial.print(F(":"));
1040+
if(tod.second()<10) Serial.print(F("0"));
1041+
Serial.print(tod.second(),DEC);
1042+
Serial.print(F(" "));
1043+
for(byte i=0; i<displaySize; i++) {
1044+
if(i%2==0 && i!=0) Serial.print(F(" ")); //spacer between units
1045+
if(displayNext[i]>9) Serial.print(F("-")); //blanked tube
1046+
else Serial.print(displayNext[i],DEC);
1047+
}
1048+
Serial.println();
1049+
}
1050+
10171051
} //end updateDisplay()
10181052

10191053
void editDisplay(word n, byte posStart, byte posEnd, bool leadingZeros, bool fade){
@@ -1066,7 +1100,7 @@ void initOutputs() {
10661100
for(byte i=0; i<3; i++) { pinMode(anodes[i],OUTPUT); }
10671101
if(piezoPin>=0) pinMode(piezoPin, OUTPUT);
10681102
if(relayPin>=0 && relayPin!=127) pinMode(relayPin, OUTPUT);
1069-
if(ledPin>=0) pinMode(ledPin, OUTPUT);
1103+
if(ledPin>=0 && ledPin!=127) pinMode(ledPin, OUTPUT);
10701104
updateLEDs(); //set to initial value
10711105
}
10721106

@@ -1178,21 +1212,19 @@ void signalStart(byte sigFn, byte sigDur, word pulseDur){ //make some noise! or
11781212
//piezo or pulsed relay: checkRTC will handle it
11791213
if(getSignalOutput()==1 && relayPin>=0 && relayMode==0) { //switched relay: turn it on now
11801214
if(relayPin!=127) digitalWrite(relayPin,HIGH);
1181-
Serial.print(millis(),DEC); Serial.println(F(" Relay on, signalStart"));
1182-
if(readEEPROM(26,false)==4) switchLEDs(1); //LEDs following switch relay
1215+
else { Serial.print(millis(),DEC); Serial.println(F(" Relay on, signalStart")); }
11831216
}
11841217
}
1185-
if(readEEPROM(26,false)==3) switchLEDs(1); //LEDs following signal
1218+
updateLEDs(); //LEDs following signal or relay
11861219
}
11871220
void signalStop(){ //stop current signal and clear out signal timer if applicable
11881221
signalRemain = 0; snoozeRemain = 0;
11891222
signalPulseStop(); //piezo or pulsed relay: stop now
11901223
if(getSignalOutput()==1 && relayPin>=0 && relayMode==0) { //switched relay: turn it off now
11911224
if(relayPin!=127) digitalWrite(relayPin,LOW);
1192-
Serial.print(millis(),DEC); Serial.println(F(" Relay off, signalStop"));
1193-
if(readEEPROM(26,false)==4) switchLEDs(0); //LEDs following switch relay
1225+
else { Serial.print(millis(),DEC); Serial.println(F(" Relay off, signalStop")); }
11941226
}
1195-
if(readEEPROM(26,false)==3) switchLEDs(0); //LEDs following relay
1227+
updateLEDs(); //LEDs following relay
11961228
}
11971229
//beep start and stop should only be called by signalStart/signalStop and checkRTC
11981230
void signalPulseStart(word pulseDur){
@@ -1202,8 +1234,8 @@ void signalPulseStart(word pulseDur){
12021234
}
12031235
else if(getSignalOutput()==1 && relayPin>=0 && relayMode==1) { //pulsed relay
12041236
if(relayPin!=127) digitalWrite(relayPin,HIGH);
1237+
else { Serial.print(millis(),DEC); Serial.println(F(" Relay on, signalPulseStart")); }
12051238
signalPulseStopTime = millis()+relayPulse; //always use relayPulse in case timing is important for connected device
1206-
Serial.print(millis(),DEC); Serial.println(F(" Relay on, signalPulseStart"));
12071239
}
12081240
}
12091241
void signalPulseStop(){
@@ -1212,8 +1244,8 @@ void signalPulseStop(){
12121244
}
12131245
else if(getSignalOutput()==1 && relayPin>=0 && relayMode==1) { //pulsed relay
12141246
if(relayPin!=127) digitalWrite(relayPin,LOW);
1247+
else { Serial.print(millis(),DEC); Serial.println(F(" Relay off, signalPulseStop")); }
12151248
signalPulseStopTime = 0;
1216-
Serial.print(millis(),DEC); Serial.println(F(" Relay off, signalPulseStart"));
12171249
}
12181250
}
12191251
word getSignalPitch(){ //for current signal: time, timer, or (default) alarm
@@ -1231,19 +1263,32 @@ char getSignalOutput(){ //for current signal: time, timer, or (default) alarm: 0
12311263
}
12321264

12331265
void updateLEDs(){
1234-
//Run whenever something is changed that might affect the LED state
1235-
if(ledPin>=0) switch(readEEPROM(26,false)){
1236-
case 0: //always off
1237-
digitalWrite(ledPin,LOW); break;
1238-
case 1: //always on
1239-
digitalWrite(ledPin,HIGH); break;
1240-
case 2: //on, but follow day-off and night-off
1241-
digitalWrite(ledPin,(displayDim<2?LOW:HIGH)); break;
1242-
case 3: //off, but on when alarm/timer sounds
1243-
digitalWrite(ledPin,(signalRemain && (signalSource==fnIsAlarm || signalSource==fnIsTimer)?HIGH:LOW)); break;
1244-
case 4: //off, but on with switched relay
1245-
if(relayPin>=0 && relayPin<127 && relayMode==0) digitalWrite(ledPin,digitalRead(relayPin)); break;
1246-
//Stopping place: Change all the updateLEDs to not have a polarity, add some more, and hide menu 25 when not equipped, and value 4 when not equipped
1247-
default: break;
1248-
}
1266+
//Run whenever something is changed that might affect the LED state: initial (initOutputs), signal start/stop, relay on/off, setting change
1267+
if(ledPin>=0) {
1268+
switch(readEEPROM(26,false)){
1269+
case 0: //always off
1270+
if(ledPin!=127) digitalWrite(ledPin,LOW);
1271+
else { Serial.println(F("LEDs off always")); }
1272+
break;
1273+
case 1: //always on
1274+
if(ledPin!=127) digitalWrite(ledPin,HIGH);
1275+
else { Serial.println(F("LEDs on always")); }
1276+
break;
1277+
case 2: //on, but follow day-off and night-off
1278+
if(ledPin!=127) digitalWrite(ledPin,(displayDim<2?LOW:HIGH));
1279+
else { Serial.print(displayDim<2?F("LEDs off"):F("LEDs on")); Serial.println(F(" per dim state")); }
1280+
break;
1281+
case 3: //off, but on when alarm/timer sounds
1282+
if(ledPin!=127) digitalWrite(ledPin,(signalRemain && (signalSource==fnIsAlarm || signalSource==fnIsTimer)?HIGH:LOW));
1283+
else { Serial.print(signalRemain && (signalSource==fnIsAlarm || signalSource==fnIsTimer)?F("LEDs on"):F("LEDs off")); Serial.println(F(" per alarm/timer")); }
1284+
break;
1285+
case 4: //off, but on with switched relay
1286+
if(relayPin>=0 && relayMode==0) {
1287+
if(ledPin!=127) digitalWrite(ledPin,digitalRead(relayPin));
1288+
else { Serial.println(F("LEDs follow switched relay")); } //can't actually say in case relayPin is 127
1289+
}
1290+
break;
1291+
default: break;
1292+
} //end switch
1293+
} //if ledPin
12491294
} //end updateLEDs

0 commit comments

Comments
 (0)