Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : Project: Precision Outback Dot Clock
Author | Message | ||||
DuinoMiteMegaAn Senior Member Joined: 17/11/2011 Location: AustraliaPosts: 231 |
Project --> The Precision Outback Dot Clock This is one special precision time piece. Perfect for those out in the bush with no PC, GPS, RF WWV signals and devices. All you need is a 5 VDC USB power source. The clock uses the Maxim-IC +-5 ppm I2C TCXO DS3231M real time clock with a 3 V lithium battery backup (CR2032). (~ 2.5 min/yr). Due to very special MMBasic algorithms, this clock can run for 8-10 years without human intervention even with semi-annual daylight savings time changes! It displays civilian time with AM/PM, day of week, month, day, year, daily sunrise time, daily sunset time, ambient light, ambient humidity RH% and ambient temperature in degrees F. The MaxiMite aka PIC32 CGMMStick1 powers the custom made multicolor, "dot" LED display and sensor board. All the GPIO signals on the CGMMStick1 were completely used up in this application. Outback Dot Clock operation and design Q & A Why did you use five minute intervals for this Outback Dot Clock? There is limited GPIO on the CGMMStick MaxiMite for this application. There is only 20 GPIO and I needed ALL 20 GPIO for this Outback Dot Clock. Using five minute intervals is still a great way of telling time. You will never be late because the time is rounded up to the nearest five minute interval. Note: If I had to indicate all the minutes, I would need, at least, 60 GPIO plus extra discrete drivers and the power current draw plus cost would increase dramatically. How can you tell the clock small hand (hour) from the big hand (minute)? I flash the small hand (hour) yellow LEDs at a high rate and keep the yellow LEDs on for the big hand (minutes) steady. How can you tell the time with only 5 minute intervals? I round up the time in 5 minute intervals. The multi-color LED pattern on the clock face makes it very easy to tell the time. The time is very precise (+- 1or 2 minutes/yr) but the readout is in 5 minute intervals. This automatic clock can run for 10 years WITHOUT setting the time, even for daylight savings time and be only 10 minutes off! It can operate in extreme temperature conditions and still be precise. That's why I called it the "Outback Dot Clock". Its made for an extreme remote location that has no PC,GPS or WWV radio signal. How can you tell the the "pending time" changed before the hour? Time half past the hour is shown "as is" and the time before the hour (30 minutes before the hour) - the hour hand is incremented by one hour. Time read before the hour like 5:45 PM is always read 15 minutes before 6. What happens if both the small and large clock hands point to the same 5 minutes interval? Showing only one hand segment means both the minute and hour hands are overlapping. How can you tell PM from AM? There is a separate red LED around 4 o'clock to indicate PM. (AM is off) What is the current draw of the LEDs? The special low power high brightness LEDs (Kingbright) "dot" draws only 1 ma. each ( ~ 36 ma. total all on) The erase/write cycle on the PIC32 is 1000 cycles. How do you prevent exceeding this value? All application files are stored on the CGMMStick1 SD card. How can you display years and day of the month on the clock face? Since the clock face shows 1 through 12 and decimal numbers are 0-9 then its only a matter of flashing a multi-sequence segment pattern on the clock face. What are the three switches used for? (Two tac switch and one reset switch) Each switch press will create the following LED flash sequence response: Tac switch #1 button press ... Day of week 1-7 Sunday = 1 Month 1-12 Day of month 1-31 Year 0-99 Tac switch #2 button press ... Temperature (ambient) degrees F. Humidity (RH%) 0-100% Light (ambient) 0-10 <------ 0-10 intensity 0=dark 1-10 light Reset switch #3 press... On power on reset, program restart or reset switch closure will restart the Outback Dot Clock and will show the daily sunrise time (within 5 minutes) and sunset time (within 5 minutes) These calculated times are MMBasic computed using the latitude and longitude location of the Outback Dot Clock plus GMT hour offset. Software and hardware are now done. Now on to the Outback Dot Clock packaging design. Very crude photos of the clock below ... 2012-03-03_001719_Outback_Dot_Clock.pdf Better photos 2012-03-03_005336_Better_Photos_Outback_Dot_Clock.pdf |
||||
Geoffg Guru Joined: 06/06/2011 Location: AustraliaPosts: 3194 |
That is so neat. What I like is that it just runs with no complications, just one glance and you can tell the time. And it will run for so long. On top of that you get sunrise/sunset. The calculations for that would have taken a heap of work. Geoff Geoff Graham - http://geoffg.net |
||||
DuinoMiteMegaAn Senior Member Joined: 17/11/2011 Location: AustraliaPosts: 231 |
On top of that you get sunrise/sunset. The calculations for that would have taken a heap of work.
Board member TassyJim's algorithm was the most accurate and precise. The credit goes to him! Link: http://www.thebackshed.com/forum/forum_posts.asp?TID=4434&KW =sunrise+sunset BTW Geoff having no line numbers and defined subroutines helped alot in this project! Here is my beta code for this Outback Dot Clock ... Check out the sunrise sunset algorithm at the bottom - awesome! '--------- Main_R1.bas --------------------
'Project: Outback Dot Clock Rev. 1.0b 'Author: Hacker - DuinoMiteMegaAndy 'Date: 2/3/2012 'App. Version: Rev. 1.0b 'MMBasic Firmware: 3.1 MaxiMite CGStick 'Platform: Win XP/SP3 ' 'Bugs: DO NOT run I2C at 400 KHZ! Gives unknown line feeds in terminal programs. ' '----------Code Begin-------------- ' '------ ' MAIN '------ OPTION BASE 0 'Spring Forward and Fall Back Dates for time change at 02:00 AM. 'DST data date format matches PIC32 Date$: Month/Day/Year xxxx DATA "11-3-2012","4-11-2012","10-3-2013","11-3-2013","9-3-2014" DATA "2-11-2014", "8-3-2015","1-11-2015","13-3-2016","6-11-2016" DATA "12-3-2017","5-11-2017","11-3-2018","4-11-2018","10-3-2019" DATA "3-11-2019" DIM DSTDate$(16) 'Read data into zero base array FOR I=0 TO 15 ' 8 years of DST dates READ DSTDate$(I) NEXT I 'initalize dat files OPEN "B:LOCKOUT.dat" FOR OUTPUT AS #8:? #8, "FALSE":CLOSE #8 ' <-------------<<<<<<<< DIM RTC_SECS, RTC_MINS, RTC_HRS, RTC_DOW, RTC_MON, RTC_DAY, RTC_YR DIM MINS_SEG, HRS_SEG, DC_MID_HR, DC_CIV_HRS DIM RTC_BUFF(6) DS3231M_ADDRESS = 104 ' 0x68 RTC_SECS = 0: RTC_MINS = 0: RTC_HRS = 0: RTC_DOW = 1: RTC_MON = 1: RTC_DAY = 1: RTC_YR = 12 ' setup GPIO SET_GPIO ZERO_SEGMENTS ? "PIC32 Time = ", TIME$ ? "PIC32 Date = ", DATE$ RESET_CLOCK 3 '=========================================================== ==================== ' Sunrise time ' SR_SS_Cal PRINT "Sunrise time = "; PRINT SR_Hr$;":";SR_Mn$ RTC_HRS = val(SR_Hr$) RTC_MINS = val(SR_Mn$) ' display am/pm status red LED PM = ON DISP_DOT_CLK_PM_AM_STATUS RTC_HRS ' re-calculate hours and minutes so the time display is in even increments of 5 mins MINS_SEG = 0: DC_MID_HR = 0: DC_CIV_HRS = 0: HR_FLS_SPD = 0 CONV_RTC_MT_MINS_TO_CLK_SEGS RTC_MINS,MINS_SEG,DC_MID_HR 'convert to min seg 1-12 CONV_RTC_HRS_MT_TO_CIVILIAN RTC_HRS,DC_CIV_HRS 'convert to hours seg numbers 1-12 'mid hour time adjustment IF (DC_MID_HR = 1) THEN DC_CIV_HRS = DC_CIV_HRS + 1: IF (DC_CIV_HRS > 12) THEN DC_CIV_HRS = 1 DISP_DOT_CLK_HR_SEG DC_CIV_HRS DISP_DOT_CLK_MIN_SEG MINS_SEG PAUSE 5000 ZERO_SEGMENTS '=========================================================== ==================== RESET_CLOCK 3 ' Sunset time ' SR_SS_Cal PRINT "Sunset time = "; PRINT SS_Hr$;":";SS_Mn$ RTC_HRS = val(SS_Hr$) RTC_MINS = val(SS_Mn$) ' display am/pm status red LED PM = ON DISP_DOT_CLK_PM_AM_STATUS RTC_HRS ' re-calculate hours and minutes so the time display is in even increments of 5 mins MINS_SEG = 0: DC_MID_HR = 0: DC_CIV_HRS = 0: HR_FLS_SPD = 0 CONV_RTC_MT_MINS_TO_CLK_SEGS RTC_MINS,MINS_SEG,DC_MID_HR 'convert to min seg 1-12 CONV_RTC_HRS_MT_TO_CIVILIAN RTC_HRS,DC_CIV_HRS 'convert to hours seg numbers 1-12 'mid hour time adjustment IF (DC_MID_HR = 1) THEN DC_CIV_HRS = DC_CIV_HRS + 1: IF (DC_CIV_HRS > 12) THEN DC_CIV_HRS = 1 DISP_DOT_CLK_HR_SEG DC_CIV_HRS DISP_DOT_CLK_MIN_SEG MINS_SEG PAUSE 5000 ZERO_SEGMENTS '=========================================================== ==================== 'read and print analog sensors PRT_TEMP PRT_HUM PRT_LIGHT toggle = 1 timer = 0 START: IF (timer > 1001) THEN ' Read DS3231M I2C RTC @ 1 second updates I2Caddr = DS3231M_ADDRESS I2CEN 100,100 ' Enable I2C 400 Khz 100 ms timeout I2CRCV I2Caddr, 0, 7, RTC_BUFF(0), 1, 0 '? "0=ok 1=nack 2=timeout "; MM.I2C I2CDIS timer = 0 Pin(0) = toggle toggle = not(toggle) ENDIF ' convert RTC "hex" buffer to RTC "DEC" variables PROCESS_RTC_BUFFER DST_TIME_OK = 0 DST_DATE_OK = 0 IF ((RTC_HRS = 1) AND (RTC_MINS = 59)) THEN DST_TIME_OK = 1 ' 1:59 am ELSE DST_TIME_OK = 0 ENDIF IF ( DST_TIME_OK = 1) THEN CHECK_DST_DATE DST_DATE_OK IF ( DST_DATE_OK = 1) THEN PROCESS_DST ' display am/pm status red LED PM = ON DISP_DOT_CLK_PM_AM_STATUS RTC_HRS '? "rtc hrs = ", RTC_HRS ' re-calculate hours and minutes so the time display is in even increments of 5 mins MINS_SEG = 0: DC_MID_HR = 0: DC_CIV_HRS = 0: HR_FLS_SPD = 0 CONV_RTC_MT_MINS_TO_CLK_SEGS RTC_MINS,MINS_SEG,DC_MID_HR 'convert to min seg 1-12 '? "mins segs =", mins_seg '? "mid hr =", dc_mid_hr CONV_RTC_HRS_MT_TO_CIVILIAN RTC_HRS,DC_CIV_HRS 'convert to hours seg numbers 1-12 '? "civian hrs", dc_civ_hrs 'mid hour time adjustment IF (DC_MID_HR = 1) THEN DC_CIV_HRS = DC_CIV_HRS + 1: IF (DC_CIV_HRS > 12) THEN DC_CIV_HRS = 1 '? "MID HRS = ", DC_CIV_HRS DISP_DOT_CLK_MIN_SEG MINS_SEG DISP_DOT_CLK_HR_SEG DC_CIV_HRS ZERO_SEGMENTS 'Tac switch #1 Display sensor values IF (PIN(1) = 0) THEN RESET_CLOCK 3: DISPLAY_DC_TEMP: RESET_CLOCK 3: DISPLAY_DC_HUM: RESET_CLOCK 3: DISPLAY_DC_LIGHT 'Tac switch #2 Display DOW, Month, Day, Year IF (PIN(7) = 0) THEN RESET_CLOCK 3: DISPLAY_DOW: RESET_CLOCK 3: DISPLAY_MONTH: RESET_CLOCK 3: DISPLAY_DAY: RESET_CLOCK 3: DISPLAY_YEAR GOTO START ' loop forever ' --------------------------------- ' Subroutines ' --------------------------------- SUB ZERO_SEGMENTS Pin(8) = 0 ' 1 o'clock Pin(9) = 0 ' 2 o'clock Pin(10) = 0 ' 3 o'clock Pin(14) = 1 ' 4 o'clock Pin(15) = 1 ' 5 o'clock Pin(16) = 1 ' 6 o'clock Pin(17) = 1 ' 7 o'clock Pin(18) = 1 ' 8 o'clock Pin(19) = 1 ' 9 o'clock Pin(20) = 1 ' 10 o'clock Pin(11) = 1 ' 11 o'clock Pin(5) = 0 ' 12 o'clock Pin(6) = 0 ' pm/am END SUB SUB PRT_TEMP DIM AVG,IDX, x For idx=1 to 75: avg = avg + Pin(2): Next idx: avg = avg/75 x = (((((avg * 1000) - 500) / 10) * 1.8) + 32) + 3.5 '3.5 is cal offset IF ((x <= 40) OR (x >= 95)) THEN ZERO_SEGMENTS: ? "Temperature Out Of Range!": FOR i = 1 TO 10: PIN(6) = 1: PAUSE 250: PIN(6) = 0: PAUSE 250: NEXT I: ZERO_SEGMENTS ? "Ambient Temperature F. = ", x END SUB SUB DISPLAY_DC_TEMP local AVG,IDX, x, D1,D2, N$, I For idx=1 to 75: avg = avg + Pin(2): Next idx: avg = avg/75 x = (((((avg * 1000) - 500) / 10) * 1.8) + 32) + 3.5 '3.5 is cal offset IF ((x <= 40) OR (x >= 95)) THEN ZERO_SEGMENTS: FOR i = 1 TO 10: PIN(6) = 1: PAUSE 250: PIN(6) = 0: PAUSE 250: NEXT I: ZERO_SEGMENTS: END SUB N$ = str$(abs(CINT(x))) D2 = Val(LEFT$(N$,1)) D1 = Val(RIGHT$(N$,1)) IF D1 = 0 THEN D1 = 1 ' CANNOT SHOW ZERO ZERO_SEGMENTS PAUSE 2000 For I = 1 to 3 DISP_DOT_CLK_MIN_SEG(D2) Pin(6) = 1 Pause 1000 ZERO_SEGMENTS Next I DISP_DOT_CLK_MIN_SEG(D2) DISP_DOT_CLK_MIN_SEG(D1) pause 2000 ZERO_SEGMENTS END SUB SUB PRT_LIGHT local AVG,IDX,x avg = 0: For idx=1 to 75: avg = avg + Pin(3): Next idx: avg = avg/75 x = avg x = (x * 3.03) x = abs(CINT(x)) IF x > 10 THEN x = 10 ? "Light Voltage [DK=0 LT=10] = ", x END SUB SUB DISPLAY_DC_LIGHT local AVG,IDX,x avg = 0: For idx=1 to 75: avg = avg + Pin(3): Next idx: avg = avg/75 x = avg x = (x * 3.03) x = abs(CINT(x)) IF x > 10 THEN x = 10 ZERO_SEGMENTS PAUSE 2000 '? "dc light = ", x DISP_DOT_CLK_MIN_SEG(x) Pin(6) = 1 Pause 2000 ZERO_SEGMENTS END SUB SUB PRT_HUM LOCAL AVG,IDX,x,i avg = 0: For idx=1 to 75: avg = avg + Pin(4): Next idx: avg = avg/75 x = (-23.82075472 + (47.64627406 * avg)) + 3.0 '(using 3.3 volts supply) 3 is cal offset IF ((x <= 25) OR (x >= 55)) THEN ZERO_SEGMENTS: ? "Humidity Out Of Range!": FOR i = 1 TO 10: PIN(6) = 1: PAUSE 250: PIN(6) = 0: PAUSE 250: NEXT I: ZERO_SEGMENTS ? "Humidity RH% = ", x END SUB SUB DISPLAY_DC_HUM LOCAL AVG,IDX,x,i,D1,D2, N$ avg = 0: For idx=1 to 75: avg = avg + Pin(4): Next idx: avg = avg/75 x = (-23.82075472 + (47.64627406 * avg)) + 3.0 '(using 3.3 volts supply) 3 is cal offset IF ((x <= 25) OR (x >= 55)) THEN ZERO_SEGMENTS: ? "Humidity Out Of Range!": FOR i = 1 TO 10: PIN(6) = 1: PAUSE 250: PIN(6) = 0: PAUSE 250: NEXT I: ZERO_SEGMENTS: END SUB N$ = str$(abs(CINT(x))) D2 = Val(LEFT$(N$,1)) D1 = Val(RIGHT$(N$,1)) IF D1 = 0 THEN D1 = 1 ' CANNOT SHOW ZERO ZERO_SEGMENTS PAUSE 2000 For I = 1 to 3 DISP_DOT_CLK_MIN_SEG(D2) Pin(6) = 1 Pause 1000 ZERO_SEGMENTS Next I DISP_DOT_CLK_MIN_SEG(D2) DISP_DOT_CLK_MIN_SEG(D1) PAUSE 2000 ZERO_SEGMENTS END SUB SUB DISPLAY_DOW ZERO_SEGMENTS PAUSE 2000 DISP_DOT_CLK_MIN_SEG(RTC_DOW) Pin(6) = 1 Pause 2000 ZERO_SEGMENTS END SUB SUB DISPLAY_MONTH ZERO_SEGMENTS PAUSE 2000 DISP_DOT_CLK_MIN_SEG(RTC_MON) Pin(6) = 1 Pause 2000 ZERO_SEGMENTS END SUB SUB DISPLAY_DAY LOCAL D1,D2, N$ N$ = str$(RTC_DAY) D2 = Val(LEFT$(N$,1)) D1 = Val(RIGHT$(N$,1)) ZERO_SEGMENTS PAUSE 2000 For I = 1 to 3 DISP_DOT_CLK_MIN_SEG(D2) Pin(6) = 1 Pause 1000 ZERO_SEGMENTS Next I DISP_DOT_CLK_MIN_SEG(D2) DISP_DOT_CLK_MIN_SEG(D1) PAUSE 2000 ZERO_SEGMENTS END SUB SUB DISPLAY_YEAR LOCAL D1,D2, N$ N$ = str$(RTC_YR) D2 = Val(LEFT$(N$,1)) D1 = Val(RIGHT$(N$,1)) ZERO_SEGMENTS PAUSE 2000 For I = 1 to 3 DISP_DOT_CLK_MIN_SEG(D2) Pin(6) = 1 Pause 1000 ZERO_SEGMENTS Next I DISP_DOT_CLK_MIN_SEG(D2) DISP_DOT_CLK_MIN_SEG(D1) PAUSE 2000 ZERO_SEGMENTS END SUB SUB SET_GPIO 'setpin 1,7, TAC 'tac sw1 4.7k pullup/330 ohm pulldown <------ H/L interrupt setpin 1,2 ' tac sw1 4.7k pullup/330 ohm pulldown setpin 2,1 ' tempF MCP9700 setpin 3,1 ' light AMBI 0-3.3V 0=dark 3.3= high light sensor setpin 4,1 ' RH% HIH-5030 sensor setpin 5,8 ' clock seg. 12 with 5V OC ext trans driv setpin 6,8 ' pm/am - normal 3V output 'setpin 7,7, TAC tac sw2 4.7k pullup/300 ohm pulldown <------ H/L interrupt setpin 7,2 ' tac sw2 4.7k pullup/300 ohm pulldown setpin 8,8 ' clock seg. 1 with 5V OC ext trans driv setpin 9,8 ' clock seg. 2 with 5V OC ext trans driv setpin 10,8 ' clock seg. 3 with 5V OC ext trans driv setpin 11,9 ' clock seg. 11 with on chip 5V OC trans driv 'setpin 12,8 <-- I2C SDA -- for ref only 'setpin 13,8 <-- I2C SCL -- for ref only setpin 14,9 ' clock seg. 4 with on chip 5V OC trans driv setpin 15,9 ' clock seg. 5 with on chip 5V OC trans driv setpin 16,9 ' clock seg. 6 with on chip 5V OC trans driv setpin 17,9 ' clock seg. 7 with on chip 5V OC trans driv setpin 18,9 ' clock seg. 8 with on chip 5V OC trans driv setpin 19,9 ' clock seg. 9 with on chip 5V OC trans driv setpin 20,9 ' clock seg. 10 with on chip 5V OC trans driv END SUB SUB RESET_CLOCK(dcrep) local TD TD = 50 FOR I = 1 TO dcrep STEP 1 Pin(8) = 1 ' 1 o'clock PAUSE TD Pin(8) = 0 ' 1 o'clock PAUSE TD Pin(9) = 1 ' 2 o'clock PAUSE TD Pin(9) = 0 ' 2 o'clock PAUSE TD Pin(10) = 1 ' 3 o'clock PAUSE TD Pin(10) = 0 ' 3 o'clock PAUSE TD Pin(14) = 0 ' 4 o'clock PAUSE TD Pin(14) = 1 ' 4 o'clock PAUSE TD Pin(15) = 0 ' 5 o'clock PAUSE TD Pin(15) = 1 ' 5 o'clock PAUSE TD Pin(16) = 0 ' 6 o'clock PAUSE TD Pin(16) = 1 ' 6 o'clock PAUSE TD Pin(17) = 0 ' 7 o'clock PAUSE TD Pin(17) = 1 ' 7 o'clock PAUSE TD Pin(18) = 0 ' 8 o'clock PAUSE TD Pin(18) = 1 ' 8 o'clock PAUSE TD Pin(19) = 0 ' 9 o'clock PAUSE TD Pin(19) = 1 ' 9 o'clock PAUSE TD Pin(20) = 0 ' 10 o'clock PAUSE TD Pin(20) = 1 ' 10 o'clock PAUSE TD Pin(11) = 0 ' 11 o'clock PAUSE TD Pin(11) = 1 ' 11 o'clock PAUSE TD Pin(5) = 1 ' 12 o'clock PAUSE TD Pin(5) = 0 ' 12 o'clock PAUSE TD Pin(6) = 1 ' pm/am PAUSE TD Pin(6) = 0 ' pm/am PAUSE 2 * TD NEXT I END SUB SUB CONV_RTC_MT_MINS_TO_CLK_SEGS(MT_MINS,SEGS,MID_HR) ' for min hand range 0-59 IF ((MT_MINS >=1) AND (MT_MINS <=4)) THEN MID_HR = 0: SEGS = 1: RETURN IF (MT_MINS = 5) THEN MID_HR = 0: SEGS = 1: RETURN IF ((MT_MINS >=6) AND (MT_MINS <=9)) THEN MID_HR = 0: SEGS = 2: RETURN IF (MT_MINS = 10) THEN MID_HR = 0: SEGS = 2: RETURN IF ((MT_MINS >=11) AND (MT_MINS <=14)) THEN MID_HR = 0: SEGS = 3: RETURN IF (MT_MINS = 15) THEN MID_HR = 0: SEGS = 3: RETURN IF ((MT_MINS >=16) AND (MT_MINS <=19)) THEN MID_HR = 0: SEGS = 4: RETURN IF (MT_MINS = 20) THEN MID_HR = 0: SEGS = 4: RETURN IF ((MT_MINS >=21) AND (MT_MINS <=24)) THEN MID_HR = 0: SEGS = 5: RETURN IF (MT_MINS = 25) THEN MID_HR = 0: SEGS = 5: RETURN IF ((MT_MINS >=26) AND (MT_MINS <=29)) THEN MID_HR = 0: SEGS = 6: RETURN IF (MT_MINS = 30) THEN MID_HR = 0: SEGS = 6: RETURN ' change 1 to 0 IF ((MT_MINS >=31) AND (MT_MINS <=34)) THEN MID_HR = 1: SEGS = 7: RETURN IF (MT_MINS = 35) THEN MID_HR = 1: SEGS = 7: RETURN IF ((MT_MINS >=36) AND (MT_MINS <=39)) THEN MID_HR = 1: SEGS = 8: RETURN IF (MT_MINS = 40) THEN MID_HR = 1: SEGS = 8: RETURN IF ((MT_MINS >=41) AND (MT_MINS <=44)) THEN MID_HR = 1: SEGS = 9: RETURN IF (MT_MINS = 45) THEN MID_HR = 1: SEGS = 9: RETURN IF ((MT_MINS >=46) AND (MT_MINS <=49)) THEN MID_HR = 1: SEGS = 10: RETURN IF (MT_MINS = 50) THEN MID_HR = 1: SEGS = 10: RETURN IF ((MT_MINS >=51) AND (MT_MINS <=54)) THEN MID_HR = 1: SEGS = 11: RETURN IF (MT_MINS = 55) THEN MID_HR = 1: SEGS = 11: RETURN IF ((MT_MINS >=56) AND (MT_MINS <=59)) THEN MID_HR = 1: SEGS = 12: RETURN IF (MT_MINS > 59) THEN RETURN ' added IF (MT_MINS = 0) THEN MID_HR = 0: SEGS = 12: RETURN IF (MT_MINS < 1) THEN MID_HR = 0: SEGS = 12: RETURN 'added END SUB SUB CONV_RTC_HRS_MT_TO_CIVILIAN(MT_HRS,CIV_HRS) IF ((MT_HRS >= 13) AND (MT_HRS <= 23)) THEN CIV_HRS = (MT_HRS - 12): RETURN IF ((MT_HRS >= 0) AND (MT_HRS <= 12)) THEN CIV_HRS = MT_HRS: RETURN END SUB SUB DISP_DOT_CLK_PM_AM_STATUS(MT_HRS) ' between 13:xx to 24:xx - military time 0-23 hrs 'Turn on dot clock red PM/AM status LED IF ((MT_HRS >= 12) AND (MT_HRS <= 23)) THEN Pin(6)= 1 ELSE 'Turn off dot clock red PM/AM status to indicate AM Pin(6) = 0 ENDIF END SUB SUB DISP_DOT_CLK_MIN_SEG(MIN_HAND) ' do not flash IF (MIN_HAND = 1) THEN Pin(8) = 1: RETURN ' 1 o'clock IF (MIN_HAND = 2) THEN Pin(9) = 1: RETURN ' 2 o'clock IF (MIN_HAND = 3) THEN Pin(10) = 1: RETURN ' 3 o'clock IF (MIN_HAND = 4) THEN Pin(14) = 0: RETURN ' 4 o'clock IF (MIN_HAND = 5) THEN Pin(15) = 0: RETURN ' 5 o'clock IF (MIN_HAND = 6) THEN Pin(16) = 0: RETURN ' 6 o'clock IF (MIN_HAND = 7) THEN Pin(17) = 0: RETURN ' 7 o'clock IF (MIN_HAND = 8) THEN Pin(18) = 0: RETURN ' 8 o'clock IF (MIN_HAND = 9) THEN Pin(19) = 0: RETURN ' 9 o'clock IF (MIN_HAND = 10) THEN Pin(20) = 0: RETURN ' 10 o'clock IF (MIN_HAND = 11) THEN Pin(11) = 0: RETURN ' 11 o'clock IF (MIN_HAND = 12) THEN Pin(5) = 1: RETURN ' 12 o'clock END SUB SUB DISP_DOT_CLK_HR_SEG(HR_HAND) IF (HR_HAND = 0) THEN FLASHX1(5): RETURN IF (HR_HAND = 1) THEN FLASHX1(8): RETURN IF (HR_HAND = 2) THEN FLASHX1(9): RETURN IF (HR_HAND = 3) THEN FLASHX1(10): RETURN IF (HR_HAND = 4) THEN FLASHX2(14): RETURN IF (HR_HAND = 5) THEN FLASHX2(15): RETURN IF (HR_HAND = 6) THEN FLASHX2(16): RETURN IF (HR_HAND = 7) THEN FLASHX2(17): RETURN IF (HR_HAND = 8) THEN FLASHX2(18): RETURN IF (HR_HAND = 9) THEN FLASHX2(19): RETURN IF (HR_HAND = 10) THEN FLASHX2(20): RETURN IF (HR_HAND = 11) THEN FLASHX2(11): RETURN IF (HR_HAND = 12) THEN FLASHX1(5) : RETURN END SUB SUB FLASHX1(pf1) FOR i=1 TO 10 Pin(pf1) = 1 PAUSE 50 Pin(pf1) = 0 PAUSE 50 NEXT i RETURN END SUB SUB FLASHX2(pf2) FOR i=1 TO 10 Pin(pf2) = 0 PAUSE 50 Pin(pf2) = 1 PAUSE 50 NEXT i RETURN END SUB SUB PROCESS_RTC_BUFFER BCDTEMP = RTC_Buff(0) 'secs (00-59) Decimal = FIX(BCDTemp / 16) * 10: Decimal = Decimal + (BCDTEMP AND &hF) RTC_SECS = decimal '? "rtc secs = ", RTC_SECS BCDTEMP = RTC_Buff(1) ' mins (00-59) Decimal = FIX(BCDTemp / 16) * 10: Decimal = Decimal + (BCDTEMP AND &hF) RTC_MINS = decimal '? "rtc mins = ", RTC_MINS BCDTEMP = RTC_Buff(2) ' hours (00-23) --> In military time! Decimal = FIX(BCDTemp / 16) * 10: Decimal = Decimal + (BCDTEMP AND &hF) RTC_HRS = decimal '? "rtc hrs = ", RTC_HRS BCDTEMP = RTC_Buff(3) ' dow - day of week (1-7) Sunday = 1 Decimal = FIX(BCDTemp / 16) * 10: Decimal = Decimal + (BCDTEMP AND &hF) RTC_DOW = decimal '? "rtc dow = ", RTC_DOW BCDTEMP = RTC_Buff(4) ' date --> day of month (01-31) Decimal = FIX(BCDTemp / 16) * 10: Decimal = Decimal + (BCDTEMP AND &hF) RTC_DAY = decimal '? "rtc day = ", RTC_DAY BCDTEMP = RTC_Buff(5) ' month - (01-12) Decimal = FIX(BCDTemp / 16) * 10: Decimal = Decimal + (BCDTEMP AND &hF) RTC_MON = decimal '? "rtc month = ", RTC_MON BCDTEMP = RTC_Buff(6) ' year - (00-99) Needs + 2000 Decimal = FIX(BCDTemp / 16) * 10: Decimal = Decimal + (BCDTEMP AND &hF) 'decimal = decimal + 2000 ' adjust year + 2000 RTC_YR = decimal '? "rtc year = ", RTC_YR END SUB SUB CHECK_DST_DATE(date_ok) Local key$ FOR I=0 TO 15 ' 8 years of DST dates IF DATE$ = DSTDate$(I) THEN GOTO DST_FOUND NEXT I '? "DST Key Not Found!" OPEN "B:LOCKOUT.dat" FOR INPUT AS #8:INPUT #8, key$ :CLOSE #8 '<------<<<<<<<<<<<<& lt; 'reset dst lockout when the date changes from the "dst day" IF (key$ = "TRUE") THEN OPEN "B:LOCKOUT.dat" FOR OUTPUT AS #8:? #8, "FALSE":CLOSE #8 ' <-------<<<<< date_ok = 0: END SUB DST_FOUND: date_ok = 1 END SUB SUB PROCESS_DST Local key$ OPEN "B:LOCKOUT.dat" FOR INPUT AS #8:INPUT #8, key$ :CLOSE #8 ' <---------<<<<<<<< 'stop multiple dst updates in one day IF (key$ = "TRUE") THEN END SUB 'read CGStick RTC tempdec = VAL(LEFT$(TIME$, 2)) hours_dec = tempdec hex = FIX(tempdec / 10) * 16: hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10 hours = hex tempdec = VAL(MID$(TIME$, 4, 2)) hex = FIX(tempdec / 10) * 16: hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10 minutes = hex tempdec = VAL(RIGHT$(TIME$, 2)) hex = FIX(tempdec / 10) * 16: hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10 seconds = hex tempdec = VAL(LEFT$(DATE$, 2)) DOW_DAY = tempdec hex = FIX(tempdec / 10) * 16: hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10 day = hex tempdec = VAL(MID$(DATE$, 4, 2)) month_dec = tempdec hex = FIX(tempdec / 10) * 16: hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10 month = hex tempdec = (VAL(RIGHT$(DATE$, 4)) - 2000) DOW_Year = tempdec hex = FIX(tempdec / 10) * 16: hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10 year = hex ' a = (14 - dow_month) / 12 a = FIX(a) y = dow_year - a y = FIX(y) m = dow_month + (12 * a) - 2 m = FIX(m) d = ((dow_day + y) + FIX(y / 4) - FIX(y / 100) + FIX(y / 400) + FIX((31 * m) / 12)) DOW = d MOD 7 DOW = DOW + 1 ' offset for DS3231/DS1307 RTC --> Sun(1)Mon(2)Tue(3)Wed(4)Thu(5)Fri(6)Sat(7) tempdec = DOW ' DOW dec hex = FIX(tempdec / 10) * 16: hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10 IF month_dec = 3 THEN GOTO ADD1 'Spring forward +1 hr IF month_dec = 11 THEN GOTO SUB1 'Fall back -1 hr '? "ABORT ---> DST Month Error!" ' check your DST array above! END SUB ' ADD1: IF hours_dec = 23 THEN hours_dec = 0: hex = FIX(tempdec / 10) * 16: hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10: GOTO DST_UPDATE ' ADD +1 to military time IF hours_dec >= 0 AND hours_dec < 23 THEN hours_dec = hours_dec + 1:hex = FIX(tempdec / 10) * 16:hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10: GOTO DST_UPDATE ' ADD +1 to military time '? "error add1" END SUB SUB1: IF hours_dec >= 1 AND hours_dec <= 23 THEN hours_dec = hours_dec - 1:hex = FIX(tempdec / 10) * 16:hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10: GOTO DST_UPDATE ' SUBTRACT -1 to military time IF hours_dec = 0 THEN hours_dec = 23: hex = FIX(tempdec / 10) * 16:hex = hex OR ((tempdec / 10) - (FIX(tempdec / 10))) * 10: GOTO DST_UPDATE 'SUBTRACT -1 to military time '? "error sub1" END SUB DST_UPDATE: rtcwday= hex ' Write DST adjusted Time to DS3231 RTC i2caddr = DS3231M_ADDRESS I2CEN 100,100 ' Enable I2C 400 Khz 100 ms timeout I2CSEND i2caddr, 0, 8, &h0, seconds, minutes, hours_dec, rtcwday, day, month, year '? "0=ok 1=nack 2=timeout"; MM.I2C I2CDIS ' ? "DST has updated the DS3231 RTC!" OPEN "B:DST.dat" FOR APPEND AS #9: ? #9,"RTC_DST_UPDATED":? #9,DATE$:? #9,TIME$:? #9,"<------>":CLOSE #9 OPEN "B:LOCKOUT.dat" FOR OUTPUT AS #8:? #8, "TRUE":CLOSE #8 '<--------<<<<<<<<<< END SUB '=========== ' ISRs - DISABLED '=========== 'Tac switch #1 'TAC: IF (PIN(1) = 0) THEN 'Tac switch #2 'IF (PIN(7) = 0) THEN 'IRETURN '=========================================================== =================== ' Sunrise-Sunset Calculation (SEE CREDITS BELOW) ' SUB SR_SS_Cal DIM A(2), D(2) SR_SS_Lockout = 0 ' SR_SS_CONSTANTS 'Location - Columbus,Ohio USA 39 59' North 82 59' West 'Enter north latitudes positive, west longitudes negative 'INPUT "Lat-deg="; B5 B5 = 40 ' in dec <--------- Location Lat in dec. 'INPUT "Long-deg="; L5 L5 = -82.88 'in dec <------- Location Long in dec. 'INPUT "Time zone-hrs="; H H = 5 ' EDT Eastern standard daylight savings time <--- Location time zone EDT OR EST L5 = L5 / 360: Z0 = H / 24 SR_SS_CALENDAR T = (J - 2451545) + F TT = T / 36525 + 1 ' TT = centuries ' from 1900.0 SR_SS_TIME_ZONE T = T + Z0 ' Get Sun's Position SR_SS_FUN_ARGS A(1) = A5: D(1) = D5 T = T + 1 SR_SS_FUN_ARGS A(2) = A5: D(2) = D5 IF A(2) < A(1) THEN A(2) = A(2) + P2 Z1 = DR * 90.833 ' Zenith dist. S = SIN(B5 * DR): C = COS(B5 * DR) Z = COS(Z1): M8 = 0: W8 = 0 A0 = A(1): D0 = D(1) DA = A(2) - A(1): DD = D(2) - D(1) ' FOR C0 = 0 TO 23 P = (C0 + 1) / 24 A2 = A(1) + P * DA: D2 = D(1) + P * DD SR_SS_COMPUTE A0 = A2: D0 = D2: V0 = V2 NEXT ' SR_SS_PRINT_MESSAGE 'INPUT "Hit CR To Continue "; Query$ ERASE A ' FOR RE-ENTRY ERASE D ' FOR RE-ENTRY 'END END SUB ' ' SUB SR_SS_CONSTANTS ' Constants P1 = 3.14159265 P2 = 2 * P1 DR = P1 / 180 K1 = 15 * DR * 1.0027379 S$ = "Sunset at " R$ = "Sunrise at " M1$ = "No sunrise this date" M2$ = "No sunset this date" M3$ = "Sun down all day" M4$ = "Sun up all day" END SUB SUB SR_SS_CALENDAR ' Calendar --> JD 'INPUT "Year= "; Y Y = VAL(RIGHT$(DATE$, 4)) ' <----- From PIC32 RTC YYYY 'INPUT "Month= "; M M = VAL(MID$(DATE$, 4, 2))' <----- From PIC32 RTC 'INPUT "Day= "; D D = VAL(LEFT$(DATE$, 2)) ' <------ From PIC32 RTC G = 1: IF Y < 1583 THEN G = 0 D1 = INT(D): F = D - D1 - .5 J =0 -INT(7 * (INT((M + 9) / 12) + Y) / 4) IF G = 0 THEN GOTO SR_SS_LABEL_1 S = SGN(M - 9): A = ABS(M - 9) J3 = INT(Y + S * INT(A / 7)) J3 =0 -INT((INT(J3 / 100) + 1) * 3 / 4) SR_SS_LABEL_1: J = J + INT(275 * M / 9) + D1 + G * J3 J = J + 1721027 + 2 * G + 367 * Y IF F >= 0 THEN END SUB F = F + 1: J = J - 1 END SUB SUB SR_SS_TIME_ZONE ' LST at 0h zone time T0 = T / 36525 S = 24110.5 + 8640184.812999999 * T0 S = S + 86636.6 * Z0 + 86400 * L5 S = S / 86400: S = S - INT(S) T0 = S * 360 * DR END SUB SUB SR_SS_FUN_ARGS ' Fundamental arguments ' (Van Flandern & ' Pulkkinen, 1979) L = .779072 + .00273790931 * T G = .993126 + .0027377785 * T L = L - INT(L): G = G - INT(G) L = L * P2: G = G * P2 V = .39785 * SIN(L) V = V - .01 * SIN(L - G) V = V + .00333 * SIN(L + G) V = V - .00021 * TT * SIN(L) U = 1 - .03349 * COS(G) U = U - .00014 * COS(2 * L) U = U + .00008 * COS(L) W = -.0001 - .04129 * SIN(2 * L) W = W + .03211 * SIN(G) W = W + .00104 * SIN(2 * L - G) W = W - .00035 * SIN(2 * L + G) W = W - .00008 * TT * SIN(G) ' ' Compute Sun's RA and Dec S = W / SQR(U - V * V) A5 = L + ATN(S / SQR(1 - S * S)) S = V / SQR(U): D5 = ATN(S / SQR(1 - S * S)) R5 = 1.00021 * SQR(U) END SUB SUB SR_SS_COMPUTE ' Test an hour for an event L0 = T0 + C0 * K1: L2 = L0 + K1 H0 = L0 - A0: H2 = L2 - A2 H1 = (H2 + H0) / 2 ' Hour angle, D1 = (D2 + D0) / 2 ' declination, ' at half hour IF C0 > 0 THEN GOTO SR_SS_LABEL_3 V0 = S * SIN(D0) + C * COS(D0) * COS(H0) - Z SR_SS_LABEL_3: V2 = S * SIN(D2) + C * COS(D2) * COS(H2) - Z IF SGN(V0) = SGN(V2) THEN END SUB V1 = S * SIN(D1) + C * COS(D1) * COS(H1) - Z A = 2 * V2 - 4 * V1 + 2 * V0: B = 4 * V1 - 3 * V0 - V2 D = B * B - 4 * A * V0: IF D < 0 THEN END SUB D = SQR(D) 'IF V0 < 0 AND V2 > 0 THEN PRINT R$; IF V0 < 0 AND V2 > 0 THEN M8 = 1 'IF V0 > 0 AND V2 < 0 THEN PRINT S$; IF V0 > 0 AND V2 < 0 THEN W8 = 1 E = (0-B + D) / (2 * A) IF E > 1 OR E < 0 THEN E = (0-B - D) / (2 * A) T3 = C0 + E + 1 / 120 ' Round off H3 = INT(T3): M3 = INT((T3 - H3) * 60) Hr$=str$(H3):Hr$=right$("0"+Hr$,2):Mn$=str$(M3):Mn$=right$(" 0"+Mn$,2) ' '============================= IF ( SR_SS_Lockout = 1) THEN GOTO SR_SS_LABEL_4 'PRINT Hr$;":";Mn$; SR_Hr$ = Hr$ '? "SR HRS = ", SR_Hr$ SR_Mn$ = Mn$ '? "SR Mins = ", SR_Mn$ SR_SS_Lockout = 1 ELSE 'SR_SS_LABEL_4: PRINT Hr$;":";Mn$; SR_SS_LABEL_4: SS_Hr$ = Hr$ '? "SS HRS = ", SS_Hr$ SS_Mn$ = Mn$ '? "SS Mins = ", SS_Mn$ SR_SS_Lockout = 0 ENDIF '============================== H7 = H0 + E * (H2 - H0) N7 =0 -COS(D1) * SIN(H7) D7 = C * SIN(D1) - S * COS(D1) * COS(H7) AZ = ATN(N7 / D7) / DR IF D7 < 0 THEN AZ = AZ + 180 IF AZ < 0 THEN AZ = AZ + 360 IF AZ > 360 THEN AZ = AZ - 360 'PRINT ", azimuth "; 'PRINT AZ END SUB SUB SR_SS_PRINT_MESSAGE ' Special-message routine IF M8 = 0 AND W8 = 0 THEN SR_SS_LABEL_5 IF M8 = 0 THEN PRINT M1$ IF W8 = 0 THEN PRINT M2$ END SUB SR_SS_LABEL_5: IF V2 < 0 THEN PRINT M3$ IF V2 > 0 THEN PRINT M4$ END SUB ' Credits: The Back Shed forum board member TassyJim ("spot on the minute") and ... ' This program by Roger W. Sinnott calculates the times of sunrise ' and sunset on any date, accurate to the minute within several ' centuries of the present. It correctly describes what happens in the ' arctic and antarctic regions, where the Sun may not rise or set on ' a given date. Enter north latitudes positive, west longitudes ' negative. For the time zone, enter the number of hours west of ' Greenwich (e.g., 5 for EST, 4 for EDT). The calculation is ' discussed in Sky & Telescope for August 1994, page 84. B:\> memory 24kB (81%) Program memory used <---------- 5kB (38%) Variable memory used 8kB (23%) General memory used 29kB Free on the heap Enjoy |
||||
centrex Guru Joined: 13/11/2011 Location: AustraliaPosts: 320 |
hi Duino-Andy Just wondering where you got the 8pin rtc from as all my searching of suppliers I only come up with the 16pin version. Any reason for using the 8pin version as it appears to have a lower spec than the 16pin version. Regards Cliff Cliff |
||||
DuinoMiteMegaAn Senior Member Joined: 17/11/2011 Location: AustraliaPosts: 231 |
Just wondering where you got the 8pin rtc from as all my searching of suppliers I only come up with the 16pin version
Both Mouser and Digikey carry this DS3231M. I bought mine from Digikey # DS3231MZ+-ND (plus dash ND) Having a 8 pin SOIC is alot easier for board layout and hand soldering. At 0.432 seconds per day works out to be 158 seconds per year or 158/60 - 2.68 minutes. I can live with that on the dot clock since it reads out every 5 minutes. On my Outback Dot Clock sensor board, I also added a place to install the
-+ 2 ppm ChronoDot for better accuracy. The ChronoDot cost $16 which is fairly expensive. |
||||
DuinoMiteMegaAn Senior Member Joined: 17/11/2011 Location: AustraliaPosts: 231 |
@ Centrex - Preliminary attached Outback Dot Clock schematic. Note: The PCB house we went to was very expensive and this PCB design used their software for the prototype printed circuit board. The silkscreen and soldermask are required for this design. 2012-03-04_234052_Outback_Dot_Clock_Schematic_R1.pdf Enjoy |
||||
centrex Guru Joined: 13/11/2011 Location: AustraliaPosts: 320 |
Hi I may be missing something but where are the daylight saving times for? According to the NSW Gov site dst starts on the 1st Sunday in October and finishes on the 1st Sunday in April. I cannot see any of these dates in the data file of the clock. As I said I may be missing something but I need pointing in the right direction. Thanks Cliff Cliff |
||||
DuinoMiteMegaAn Senior Member Joined: 17/11/2011 Location: AustraliaPosts: 231 |
The reason why you don't see Australian DST dates is because I am an American Please search the internet for your projected 8 years of DST dates and install yours in the data table. An American is not equal to a fine Australian. <-----<<<<<< '------ ' MAIN '------ OPTION BASE 0 'Spring Forward and Fall Back Dates for time change at 02:00 AM. 'DST data date format matches PIC32 Date$: Day-Month-Year yyyy is 10 chars in Length! <------<<<<<<<<<<<< DATA "11-03-2012","04-11-2012","10-03-2013","11-03-2013","09-03-2 014" DATA "02-11-2014","08-03-2015","01-11-2015","13-03-2016","06-11-2 016" DATA "12-03-2017","05-11-2017","11-03-2018","04-11-2018","10-03-2 019" DATA "03-11-2019" Make sure you have 10 chars to compare! |
||||
centrex Guru Joined: 13/11/2011 Location: AustraliaPosts: 320 |
That explanes it all, the location "Australia" in your profile confused the issue. Thanks Cliff |
||||
DuinoMiteMegaAn Senior Member Joined: 17/11/2011 Location: AustraliaPosts: 231 |
@centrex Also, patch this code snippet with your months of April and October (4 & 10) IF month_dec = 3 THEN GOTO ADD1 'Spring forward +1 hr
IF month_dec = 11 THEN GOTO SUB1 'Fall back -1 hr '? "ABORT ---> DST Month Error!" ' check your DST array above! END SUB |
||||
Print this page |