Skip to content

Commit 807a66d

Browse files
committed
Implements an (untested) EEPROM versioning system for automatic initializations after major changes. But I realized a simpler approach would be to never move established EEPROM locations, so this will be removed by next commit – just keeping for posterity.
1 parent 67eadfb commit 807a66d

File tree

2 files changed

+61
-51
lines changed

2 files changed

+61
-51
lines changed

README.md

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# arduino-nixie
2-
Code for Arduino Nano in [RLB Designs](http://rlb-designs.com/) IN-12/17 clock v5.0
3-
4-
Featuring timekeeping by DS3231 real-time clock and six digits multiplexed 3x2 via two SN74141 driver chips
2+
**A digital clock with perpetual calendar, alarm, countdown timer, and day counter.** Written for the Arduino Nano at the heart of [RLB Designs'](http://rlb-designs.com/) Universal Nixie Driver Board (UNDB) v5.0, featuring a DS3231 thermocompensated battery-backed real-time clock, and driving up to 6 digits multiplexed in pairs via two SN74141 driver chips. Uses AdaEncoder and ooPinChangeInt (for rotary encoders, optional) and NorthernWidget DS3231 libraries.
53

64
**This is an alternate codebase that is very much in progress!**
75

@@ -11,19 +9,18 @@ _In these instructions, **Select** is the main pushbutton, and **Adjust** can be
119

1210
### Clock Functions
1311

14-
* Press **Select** to cycle through the clock's functions.
15-
* Some functions return to Time after a few seconds.
12+
* Press **Select** to cycle through the clock's functions. Some return to Time after a few seconds.
1613
* To set a function, hold **Select** 'til the display flashes; use **Adjust** to set, and **Select** to save.
1714

1815
| Function | Looks like | Notes |
1916
| --- | --- | --- |
20-
| **Time** | `12 34 56` | The time of day. You can choose 12h or 24h format in Options. When setting, it's in 24h format (so you can tell AM from PM) and the seconds will reset to :00 when you save. |
17+
| **Time** | `12 34 56` | The time of day. You can choose 12h or 24h format in Options. When setting, it's in 24h format (so you can tell AM from PM) and the seconds will reset to :00 when you save. The clock keeps time during power outages, and its timekeeping is corrected for temperature changes. |
2118
| **Date** | `_2 _4 _0`<br/>(for&nbsp;Sun&nbsp;2/4) | You can choose month/date or date/month format in the options menu (2). Setting is done in three stages: first year, then month, then date.<br/>Weekdays are: 0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thu, 5=Fri, 6=Sat |
22-
| **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 the beeper. |
23-
| **Day counter** | `_1 23 __` | Shows the number of days until/since a date you specify The target date is set the same way as **Date.** |
19+
| **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 the beeper. If power is lost, the timer will reset to `0`. |
20+
| **Day counter** | `_1 23 __` | Shows the number of days until/since a date you specify. The target date is set the same way as **Date.** |
2421
| **Thermometer** | `__ 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. |
2522
| **Cleaner** | `88 88 88` | Cycles all the digits on all the tubes. A quick and dirty anti-cathode-poisoning mode, until automatic digit cycling is implemented. |
26-
| **Alarm** | `_7 00 1_` | _Not yet implemented. Intended to work like this:_<br/>Shows alarm time and status. Use **Adjust** to switch on/off; status is shown on 5th tube (1=on, 0=off) and by display brightness (bright=on, dim=off). Hold **Select** to set the time the 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. |
23+
| **Alarm** | `_7 00 1_` | _Not yet implemented._<br/>Shows alarm time and status. Use **Adjust** to switch on/off; status is shown on 5th tube (1=on, 0=off) and by display brightness (bright=on, dim=off). Hold **Select** to set the time the 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. |
2724

2825
### Options Menu
2926

@@ -34,27 +31,31 @@ _In these instructions, **Select** is the main pushbutton, and **Adjust** can be
3431

3532
| Option | Settings |
3633
| --- | --- |
34+
| **Timekeeping and display** | |
3735
| 1. Time format | 1 = 12-hour<br/>2 = 24-hour<br/>(time-of-day display only; setting times is always done in 24h) |
3836
| 2. Date format | 1 = month/date<br/>2 = date/month |
3937
| 3. Display date during time? | 0 = never<br/>1 = date instead of seconds<br/>2 = full date (as above) every minute at :30 seconds |
4038
| 4. Leading zero in hour, date, and month? | 0 = no<br/>1 = yes |
41-
| 7. Auto DST | Add 1h for daylight saving time between these dates (at 2am):<br/>0 = off<br/>1 = second Sunday in March to first Sunday in November (US/CA)<br/>2 = last Sunday in March to last Sunday in October (UK/EU)<br/>3 = first Sunday in April to last Sunday in October (MX)<br/>4 = last Sunday in September to first Sunday in April (NZ)<br/>5 = first Sunday in October to first Sunday in April (AU)<br/>6 = third Sunday in October to third Sunday in February (BZ) |
42-
43-
**Setup options not implemented yet**
44-
45-
| Option | Settings |
46-
| --- | --- |
47-
| 5. Transition fade | 0–50 (in hundredths of a second) |
48-
| 6. Digit cycle (prevents [cathode poisoning](http://www.tube-tester.com/sites/nixie/different/cathode%20poisoning/cathode-poisoning.htm)) | 0 = before midnight and/or before day-off<br/>1 = every hour before :01 minute |
49-
| 8. Hourly strike | 0 = off<br/>1 = double beep<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.) |
50-
| 9. Alarm snooze | 0–60 minutes. 0 disables snooze. |
51-
| 10. Alarm days | 0 = every day<br/>1 = workdays only (per options 15/16)<br/>2 = non-workdays only |
52-
| 11. Night-off | To save tube life or preserve your sleep, dim or shut off tubes 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 light the tubes briefly. |
53-
| 12. Night starts at | Time of day |
54-
| 13. Night ends at | Time of day. Set to 0:00 to use the alarm time. |
55-
| 14. Day-off | To save tube life, shut off tubes during the day when you're not around.<br/>0 = none (tubes fully on during day)<br/>1 = clock at work (shut off all day on weekends)<br/>2 = clock at home (shut off on workdays during work hours)<br/>When off, you can press **Select** to light the tubes briefly. |
56-
| 15. First day of work week | 0–6 (Sunday–Saturday) |
57-
| 16. Last day of work week | 0–6 (Sunday–Saturday) |
58-
| 17. Work starts at | Time of day |
59-
| 18. Work ends at | Time of day |
60-
| 19. Fine regulation | Adjusts clock's timekeeping in tenths of a second per week. 500 is "normal." (e.g.: 503 causes clock to run 0.3s faster per week.) |
39+
| 5. Digit fade | _Not yet implemented._<br/>0–50 (in hundredths of a second) |
40+
| 6. Auto DST | Add 1h for daylight saving time between these dates (at 2am):<br/>0 = off<br/>1 = second Sunday in March to first Sunday in November (US/CA)<br/>2 = last Sunday in March to last Sunday in October (UK/EU)<br/>3 = first Sunday in April to last Sunday in October (MX)<br/>4 = last Sunday in September to first Sunday in April (NZ)<br/>5 = first Sunday in October to first Sunday in April (AU)<br/>6 = third Sunday in October to third Sunday in February (BZ) |
41+
| **Alarms and sounds** | |
42+
| 7. Alarm days | _Not yet implemented._<br/>0 = every day<br/>1 = workweek only (per workdays setting below)<br/>2 = weekend only |
43+
| 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. |
45+
| 10. Timer interval mode | _Not yet implemented._<br/>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. |
47+
| 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. |
49+
| **Night-off and day-off** | |
50+
| 14. Night-off | _Not yet implemented._<br/>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 light the tubes briefly. |
51+
| 15. Night starts at | _Not yet implemented._<br/>Time of day. |
52+
| 16. Night ends at | _Not yet implemented._<br/>Time of day. Set to 0:00 to use the alarm time. At this time (whether night-off/alarm is enabled or not), all tubes will briefly cycle through all digits at full brightness to help prevent [cathode poisoning](http://www.tube-tester.com/sites/nixie/different/cathode%20poisoning/cathode-poisoning.htm). |
53+
| 17. Day-off | _Not yet implemented._<br/>To further save tube life, shut off tubes during the day when you're not around.<br/>0 = none (tubes fully on during the day)<br/>1 = clock at work (shut off all day on weekends)<br/>2 = clock at home (shut off during work hours)<br/>When off, you can press **Select** to light the tubes briefly. |
54+
| 18. First day of work week | _Not yet implemented._<br/>0–6 (Sunday–Saturday) |
55+
| 19. Last day of work week | _Not yet implemented._<br/>0–6 (Sunday–Saturday) |
56+
| 20. Work starts at | _Not yet implemented._<br/>Time of day. |
57+
| 21. Work ends at | _Not yet implemented._<br/>Time of day. |
58+
59+
### Factory Reset
60+
61+
To reset the clock to "factory" defaults, hold **Select** while connecting the clock to power.

sixtube_lm/sixtube_lm.ino

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const byte fnIsDayCount = 4;
3535
const byte fnIsTemp = 5;
3636
const byte fnIsCleaner = 6;
3737
// functions enabled in this clock, in their display order. Only fnIsTime is required
38-
const byte fnsEnabled[] = {fnIsTime, fnIsDate, fnIsTimer, fnIsDayCount, fnIsTemp, fnIsCleaner};
38+
const byte fnsEnabled[] = {fnIsTime, fnIsDate, fnIsAlarm, fnIsTimer, fnIsDayCount, fnIsTemp, fnIsCleaner};
3939

4040
// These are the RLB board connections to Arduino analog input pins.
4141
// S1/PL13 = Reset
@@ -90,40 +90,44 @@ const byte velThreshold = 100; //ms
9090
// Recommend ~100 for rotaries. If you want to use this feature with buttons, extend to ~400.
9191

9292

93-
////////// Other global consts and vars used in multiple sections //////////
94-
95-
DS3231 ds3231; //an object to access the ds3231 specifically (temp, etc)
96-
RTClib rtc; //an object to access a snapshot of the ds3231 rtc via now()
97-
DateTime tod; //stores the now() snapshot for several functions to use
98-
byte toddow; //stores the day of week as calculated from tod
93+
////////// EEPROM stuff //////////
9994

100-
//Software version
95+
//Current software version
10196
const byte vMaj = 1;
10297
const byte vMin = 3;
98+
//Earliest software version to use the current EEPROM allocation
99+
//Change this when changing EEPROM allocation, to trigger an intialization
100+
const byte vMajLastEEPROMChange = 1;
101+
const byte vMinLastEEPROMChange = 3;
103102

104-
//EEPROM locations for set values - default values are in initEEPROM()
103+
//EEPROM locations for software version as of last run
104+
//If setup() finds these to be earlier than the above, it triggers an initialization
105+
const byte vMajLoc = 14;
106+
const byte vMinLoc = 15;
107+
108+
//EEPROM locations for values set outside of the options menu - default values in initEEPROM()
105109
const byte alarmTimeLoc = 0; //and 1 (word) in minutes past midnight.
106110
const byte alarmOnLoc = 2; //byte
107111
const byte dayCountYearLoc = 3; //and 4 (word)
108112
const byte dayCountMonthLoc = 5; //byte
109113
const byte dayCountDateLoc = 6; //byte
110114

111-
//EEPROM locations for software version as of last run - to detect software upgrades that need EEPROM initializations
112-
const byte vMajLoc = 14;
113-
const byte vMinLoc = 15;
114-
115115
//EEPROM locations and default values for options menu
116116
//Option numbers are 1-index, so arrays are padded to be 1-index too, for coding convenience. TODO change this
117117
//Most vals (default, min, max) are 1-byte. In case of two-byte (max-min>255), high byte is loc, low byte is loc+1.
118-
//options are offset to loc 16, to reserve 16 bytes of space for other set values per above
119118
// Option number: - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
120119
const byte optsLoc[] = {0,16,17,18,19,20,21,22,23,24, 25,27, 28, 30,32,33,34, 35, 37}; //EEPROM locs
121120
const word optsDef[] = {0, 2, 1, 0, 0, 0, 0, 0, 0, 0,500, 0,1320, 360, 0, 1, 5, 480,1020};
122121
const word optsMin[] = {0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0};
123122
const word optsMax[] = {0, 2, 2, 2, 1,50, 1, 6, 4,60,999, 2,1439,1439, 2, 6, 6,1439,1439};
124123

125124

125+
////////// Other global consts and vars used in multiple sections //////////
126126

127+
DS3231 ds3231; //an object to access the ds3231 specifically (temp, etc)
128+
RTClib rtc; //an object to access a snapshot of the ds3231 rtc via now()
129+
DateTime tod; //stores the now() snapshot for several functions to use
130+
byte toddow; //stores the day of week as calculated from tod
127131

128132
// Hardware inputs and value setting
129133
//AdaEncoder mainRot;
@@ -157,8 +161,15 @@ void setup(){
157161
Wire.begin();
158162
initOutputs();
159163
initInputs();
160-
if(!enableSoftAlarmSwitch) writeEEPROM(alarmOnLoc,1,false); //TODO test and get rid of
164+
//EEPROM initialization on demand or if necessary due to upgrades
161165
if(readInput(mainSel)==LOW) initEEPROM();
166+
else if(readEEPROM(vMajLoc,false)<vMajLastEEPROMChange) initEEPROM(); //at least 1 major version behind
167+
else if(readEEPROM(vMinLoc,false)<vMinLastEEPROMChange) initEEPROM(); //at least 1 minor version behind TODO test this
168+
//Record the current version as the latest version in EEPROM
169+
writeEEPROM(vMajLoc,vMaj,false);
170+
writeEEPROM(vMinLoc,vMin,false);
171+
//If no soft alarm switch, set alarm on
172+
if(!enableSoftAlarmSwitch) writeEEPROM(alarmOnLoc,1,false); //TODO test and get rid of
162173
}
163174

164175
unsigned long pollLast = 0;
@@ -310,9 +321,7 @@ void ctrlEvt(byte ctrl, byte evt){
310321
case fnIsDate: //set year
311322
fnSetValDate[1]=tod.month(), fnSetValDate[2]=tod.day(); startSet(tod.year(),0,9999,1); break;
312323
case fnIsAlarm: //set mins
313-
//DS3231_get_a1(&buff[0], 59); //TODO write a wrapper function for this
314-
//startSet(buff,0,1439,1); //alarm: set mins
315-
break;
324+
startSet(readEEPROM(alarmTimeLoc,true),0,1439,1); break;
316325
case fnIsTimer: //set mins, up to 18 hours (64,800 seconds - fits just inside a word)
317326
if(timerRemain>0) { timerRemain = 0; btnStop(); updateDisplay(); break; } //If the timer is running, zero it out.
318327
startSet(timerInitial/60,0,1080,1); break;
@@ -385,12 +394,12 @@ void ctrlEvt(byte ctrl, byte evt){
385394
default: break;
386395
} break;
387396
case fnIsAlarm:
388-
break;
397+
writeEEPROM(alarmTimeLoc,fnSetVal,true);
398+
clearSet(); break;
389399
case fnIsTimer: //timer
390400
timerInitial = fnSetVal*60; //timerRemain is seconds, but timer is set by minute
391401
timerRemain = timerInitial; //set actual timer going
392-
clearSet();
393-
break;
402+
clearSet(); break;
394403
case fnIsDayCount: //set like date, save in eeprom like finishOpt
395404
switch(fnSetPg){
396405
case 1: //save year, set month
@@ -609,7 +618,7 @@ void checkRTC(bool force){
609618
//at 2am, check for DST change
610619
if(tod.minute()==0 && tod.hour()==2) autoDST();
611620
//check if we should trigger the alarm - TODO weekday limiter
612-
if(tod.hour()*60+tod.minute()==readEEPROM(alarmTimeLoc,true) && readEEPROM(alarmOnLoc,false) && false) {
621+
if(tod.hour()*60+tod.minute()==readEEPROM(alarmTimeLoc,true) && readEEPROM(alarmOnLoc,false)) {
613622
fnSetPg = 0; fn = fnIsTime; soundRemain = alarmDur*60;
614623
}
615624
//checkDigitCycle();

0 commit comments

Comments
 (0)