diff --git a/README.md b/README.md index 8a0570b..423d1c1 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,8 @@ The calendar cycles through several displays, before returning to the time of da * **The date.** [Several formats](#optionsgeneral) are available. When setting, it will ask for the year, then the month, then the date. * **Day counter.** This will count down to, or up from, a date of your choice, repeating every year. When setting, it will ask for the month, then the date, then the direction (0 = count down, 1 = count up). * TIP: To display the day of the year, set it to count up from December 31. -* **Sunrise/sunset.** These two displays show the previous and next apparent sunrise/sunset times (indicated by `1` or `0` on the seconds tubes – during the day, it shows sunrise then sunset; at night, sunset then sunrise). The times are calculated using the latitude, longitude, UTC offset, and auto DST rule specified in the [options](#optionsgeography), and shown in the same 12h/24h format as the time of day. +* **Sunrise/sunset.** These two displays show the previous and next apparent sunrise/sunset times (indicated by `1` or `0` on the seconds tubes – during the day, it shows sunrise then sunset; at night, sunset then sunrise), in the same 12h/24h format as the time of day. + * Specify your latitude, longitude, and UTC offset in the [options menu](#optionsgeography). (From v1.8.1, sunrise/sunset is not displayed if latitude/longitude are left at 0.) * NOTE: At this writing, the times may be incorrect by a few minutes, depending on [your longitude and time of year](https://docs.google.com/spreadsheets/d/1dYchVCJAuhvosrCdtEeHLT3ZXcLZK8X0UtENItZR32M/edit#gid=0). I believe this to be a rounding error(s) in the [Dusk2Dawn library](https://github.com/dmkishi/Dusk2Dawn) (compared to the [NOAA Solar Calculator](https://www.esrl.noaa.gov/gmd/grad/solcalc/) it’s based on) and plan to investigate. ## Alarm @@ -90,7 +91,7 @@ This feature can count up (chrono) or down (timer), up to 100 hours each way. Wh | 3 | Display date during time? | 0 = never
1 = date instead of seconds
2 = full date each minute at :30 seconds
3 = same as 2, but scrolls in and out | | 4 | Leading zeros | 0 = no
1 = yes | | 5 | Digit fade | 0–20 (in hundredths of a second) | -| 6 | Auto DST | Add 1h for daylight saving time between these dates (at 2am):
0 = off
1 = second Sunday in March to first Sunday in November (US/CA)
2 = last Sunday in March to last Sunday in October (UK/EU)
3 = first Sunday in April to last Sunday in October (MX)
4 = last Sunday in September to first Sunday in April (NZ)
5 = first Sunday in October to first Sunday in April (AU)
6 = third Sunday in October to third Sunday in February (BZ)
If the clock is not powered at the time, it will correct itself when powered up. | +| 6 | Auto DST | Add 1h for daylight saving time between these dates (at 2am):
0 = off
1 = second Sunday in March to first Sunday in November (US/CA)
2 = last Sunday in March to last Sunday in October (UK/EU)
3 = first Sunday in April to last Sunday in October (MX)
4 = last Sunday in September to first Sunday in April (NZ)
5 = first Sunday in October to first Sunday in April (AU)
6 = third Sunday in October to third Sunday in February (BZ)
If the clock is not powered at the time, it will correct itself when powered up.
If you observe DST but your locale’s rules are not represented here, leave this set to 0 and set the clock manually (and the [DST offset](#optionsgeography) if applicable). | | 7 | LED behavior | 0 = always off
1 = always on
2 = on, but follow night/away shutoff if enabled
3 = off, but on when alarm/timer sounds
4 = off, but on with switched relay (if equipped)
(Clocks with LED lighting only) | | 8 | Anti-cathode poisoning | Briefly cycles all digits to prevent [cathode poisoning](http://www.tube-tester.com/sites/nixie/different/cathode%20poisoning/cathode-poisoning.htm)
0 = once a day, either at midnight or when night shutoff starts (if enabled)
1 = at the top of every hour
2 = at the top of every minute
(Will not trigger during night/away shutoff) | | | **Alarm** | | @@ -121,7 +122,7 @@ This feature can count up (chrono) or down (timer), up to 100 hours each way. Wh | | **Geography** | | | 50 | Latitude | Your latitude, in tenths of a degree; negative (south) values are indicated with leading zeroes. (Example: Dallas is at 32.8°N, set as `328`.) | | 51 | Longitude | Your longitude, in tenths of a degree; negative (west) values are indicated with leading zeroes. (Example: Dallas is at 96.7°W, set as `00967`.) | -| 52 | UTC offset | Your time zone’s offset from UTC (non-DST), in hours and minutes; negative (west) values are indicated with leading zeroes. (Example: Dallas is UTC–6, set as `0600`.) | +| 52 | UTC offset | Your time zone’s offset from UTC (non-DST), in hours and minutes; negative (west) values are indicated with leading zeroes. (Example: Dallas is UTC–6, set as `0600`.)
If you observe DST but set the clock manually rather than using the [auto DST feature](#optionsgeneral), you must add an hour to the UTC offset during DST, or the sunrise/sunset times will be an hour early. | To reset the clock to “factory” defaults, hold **Select** while powering up the clock. diff --git a/arduino-nixie/arduino-nixie.ino b/arduino-nixie/arduino-nixie.ino index 7cc9199..1226468 100644 --- a/arduino-nixie/arduino-nixie.ino +++ b/arduino-nixie/arduino-nixie.ino @@ -12,7 +12,7 @@ ////////// Software version ////////// const byte vMajor = 1; const byte vMinor = 8; -const byte vPatch = 0; +const byte vPatch = 1; ////////// Other includes, global consts, and vars ////////// #include //Arduino - GNU LPGL @@ -150,7 +150,7 @@ unsigned long millisAtLastCheck = 0; word unoffRemain = 0; //un-off (briefly turn on tubes during full night/away shutoff) timeout counter, seconds byte displayDim = 2; //dim per display or function: 2=normal, 1=dim, 0=off byte cleanRemain = 0; //anti-cathode-poisoning clean timeout counter, increments at cleanSpeed ms (see loop()). Start at 11 to run at clock startup -byte scrollRemain = 0; //"frames" of scroll – 0=not scrolling, >0=coming in, <0=going out, -128=scroll out at next change +int8_t scrollRemain = 0; //"frames" of scroll – signed byte - 0=not scrolling, >0=coming in, <0=going out, -128=scroll out at next change. byte versionRemain = 3; //display version at start @@ -198,28 +198,9 @@ void setup(){ initOutputs(); //depends on some EEPROM settings } -unsigned long pollCleanLast = 0; //every cleanSpeed ms -unsigned long pollScrollLast = 0; //every scrollSpeed ms void loop(){ - unsigned long now = millis(); - //If we're running a tube cleaning, advance it every cleanSpeed ms. - if(cleanRemain && (unsigned long)(now-pollCleanLast)>=cleanSpeed) { //account for rollover - pollCleanLast=now; - cleanRemain--; - if(cleanRemain<1) calcSun(tod.year(),tod.month(),tod.day()); //take this opportunity to perform a calculation that blanks the display for a bit - updateDisplay(); - } - //If we're scrolling an animation, advance it every scrollSpeed ms. - else if(scrollRemain!=0 && scrollRemain!=-128 && (unsigned long)(now-pollScrollLast)>=scrollSpeed) { - pollScrollLast=now; - if(scrollRemain<0) { - scrollRemain++; updateDisplay(); - } else { - scrollRemain--; updateDisplay(); - if(scrollRemain==0) scrollRemain=-128; - } - } //Every loop cycle, check the RTC and inputs (previously polled, but works fine without and less flicker) + checkEffects(false); //cleaning and scrolling display effects - not handled by checkRTC since they have their own timing checkRTC(false); //if clock has ticked, decrement timer if running, and updateDisplay millisApplyDrift(); checkInputs(); //if inputs have changed, this will do things + updateDisplay as needed @@ -334,6 +315,25 @@ void ctrlEvt(byte ctrl, byte evt){ updateDisplay(); return; } + //If a scroll is waiting to scroll out, cancel it, and let the button event do what it will + if(scrollRemain==-128 && evt==1){ + scrollRemain = 0; + } + //If a scroll is going, fast-forward to end of scroll in/out - see also checkRTC + else if(scrollRemain!=0 && evt==1){ + btnStop(); + if(scrollRemain>0) scrollRemain = 1; + else scrollRemain = -1; + checkEffects(true); + return; + } + //If the version display is going, any press should cancel it, with a display update + if(versionRemain>0 && evt==1){ + versionRemain = 0; + btnStop(); + updateDisplay(); + return; + } //Is it a press for an un-off? unoffRemain = unoffDur; //always do this so continued button presses during an unoff keep it alive @@ -757,10 +757,10 @@ void initEEPROM(bool hard){ btnCur = mainSel; btnStop(); //If a hard init, set the clock if(hard) { - ds3231.setYear(18); + ds3231.setYear(20); ds3231.setMonth(1); ds3231.setDate(1); - ds3231.setDoW(1); //2018-01-01 is Monday. DS3231 will keep count from here + ds3231.setDoW(3); //2020-01-01 is Wednesday. DS3231 will keep count from here ds3231.setHour(0); ds3231.setMinute(0); ds3231.setSecond(0); @@ -774,7 +774,7 @@ void initEEPROM(bool hard){ if(hard) writeEEPROM(7,0,false); //7: Alt function preset //8: TODO functions/pages enabled (bitmask) //9: free - //15: DST on flag (will be set at first RTC check) + if(hard) writeEEPROM(15,0,false); //15: last known DST on flag - clear on hard reset (to match the reset RTC/auto DST/anti-poisoning settings to trigger midnight tubes as a tube test) //then the options menu defaults bool isInt = false; for(byte opt=0; opt=3000) { //3sec per date page + //If a scroll in is going, fast-forward to end - see also ctrlEvt + if(scrollRemain>0) { + scrollRemain = 1; + checkEffects(true); + } //Here we just have to increment the page and decide when to reset. updateDisplay() will do the rendering fnPg++; inputLast+=3000; //but leave inputLastTODMins alone so the subsequent page displays will be based on the same TOD - if(fnPg >= fnDatePages){ fnPg = 0; fn = fnIsTime; } + while(fnPg= fnDatePages){ fnPg = 0; fn = fnIsTime; } // when we run out of pages, go back to time. When the half-minute date is triggered, fnPg is set to 254, so it will be 255 here and be cancelled after just the one page. force=true; } //Temporary-display function timeout: if we're *not* in a permanent one (time, or running/signaling timer) @@ -918,7 +927,7 @@ void checkRTC(bool force){ } //end alarm trigger } //At bottom of minute, see if we should show the date - if(tod.second()==30 && fn==fnIsTime && fnSetPg==0 && unoffRemain==0) { + if(tod.second()==30 && fn==fnIsTime && fnSetPg==0 && unoffRemain==0 && cleanRemain==0 && scrollRemain==0 && versionRemain==0) { if(readEEPROM(18,false)>=2) { fn = fnIsDate; inputLast = now; inputLastTODMins = tod.hour()*60+tod.minute(); fnPg = 254; updateDisplay(); } if(readEEPROM(18,false)==3) { startScroll(); } } @@ -1288,6 +1297,30 @@ byte displayNext[6] = {15,15,15,15,15,15}; //Internal representation of display. byte displayLast[6] = {11,11,11,11,11,11}; //for noticing changes to displayNext and fading the display to it byte scrollDisplay[6] = {15,15,15,15,15,15}; //For animating a value into displayNext from right, and out to left +unsigned long pollCleanLast = 0; //every cleanSpeed ms +unsigned long pollScrollLast = 0; //every scrollSpeed ms +void checkEffects(bool force){ + //control the cleaning/scrolling effects - similar to checkRTC but it has its own timings + unsigned long now = millis(); + //If we're running a tube cleaning, advance it every cleanSpeed ms. + if(cleanRemain && (unsigned long)(now-pollCleanLast)>=cleanSpeed) { //account for rollover + pollCleanLast=now; + cleanRemain--; + if(cleanRemain<1) calcSun(tod.year(),tod.month(),tod.day()); //take this opportunity to perform a calculation that blanks the display for a bit + updateDisplay(); + } + //If we're scrolling an animation, advance it every scrollSpeed ms. + else if(scrollRemain!=0 && scrollRemain!=-128 && ((unsigned long)(now-pollScrollLast)>=scrollSpeed || force)) { + pollScrollLast=now; + if(scrollRemain<0) { + scrollRemain++; updateDisplay(); + } else { + scrollRemain--; updateDisplay(); + if(scrollRemain==0) scrollRemain = -128; + } + } +} + void updateDisplay(){ //Run as needed to update display when the value being shown on it has changed //This formats the new value and puts it in displayNext[] for cycleDisplay() to pick up @@ -1323,7 +1356,7 @@ void updateDisplay(){ */ else if(scrollRemain>0) { //scrolling display: value coming in - these don't use editDisplay as we're going array to array for(byte i=0; i