'**************************************************************** '* Name : Klok_V2_release * '* Author : Lucas Volwater * '* Notice : Copyright (c) 2011 Lucas Volwater * '* : All Rights Reserved * '* Date : 07-05-2011 * '* Version : 2.0 * '* Notes : Xantus Nixieklok software. Multiplexen nu met * '* Timer interrupt, UI en wekgeluid aangespast. * '**************************************************************** ' Meer info? http://www.circuitsonline.net/forum/view/61376/1#795926 ' Beknopte gebruiksaanwijzing: ' Button 1 om buizen aan/uit te doen ' button 2 om van weergavemodus te wisselen. UU:MM, MM:SS, wektijd UU:MM, Temperatuur. ' Button 2, dan 1 om de wekker aan/uit te doen. ' Button 1 dan 2 om instellingen te wijzigen, afhankelijk van de huidige weergave. ' Bij tijdweergave de tijdinstellingen, bij wektijdweergave de wektijd. ' Bij temperatuurweergave de tijd waarop de buizen vanzelf uit gaan, en het gebruik van de DOT tussen uren en minuten. ' (0 = uit, 1 = aan, 2 = knipperen) ' De buizen gaan vanzelf aan op wektijd, of bij het indrukken van een van de knoppen, en vanzelf uit op de ingestelde tijd. ' Als de wekker afloopt is het indrukken van een willekeurige knop genoeg om dit te stoppen. ' Features: ' Klok: UU:MM of MM:SS ' Thermometer ' wekker ' Alle instellingen (tijd, wektijd, wekker loopt af ja/nee?, buizen uit tijd) blijven behouden bij stroomuitval ' Tijd loopt door bij stroomuitval. DEVICE 16F628A XTAL = 4 ' Internal osc. = 4 MHz ALL_DIGITAL = ON ' geen analoge comperators nodig CONFIG BOREN_ON, CP_OFF, DATA_CP_OFF, PWRTE_ON, WDT_OFF, LVP_OFF, MCLRE_OFF, INTRC_OSC_NOCLKOUT ON_HARDWARE_INTERRUPT GOTO muxdebuizen DECLARE SDA_PIN PORTA.3 ; I2C voor DS1307 RTC DECLARE SCL_PIN PORTA.4 ' [Symbols] SYMBOL BUTTON1 PORTA.0 SYMBOL BUTTON2 PORTA.2 SYMBOL BUZZER PORTA.1 SYMBOL HV PORTA.7 SYMBOL CLK_OUT PORTB.0 ; klok van schijfregisters SYMBOL DATA1 PORTB.1 ; deze wordt niet gebruikt (secondenprint) SYMBOL DATA2 PORTB.2 ; minuten SYMBOL DATA3 PORTB.3 ; uren SYMBOL MULT1 PORTB.4 SYMBOL MULT2 PORTB.5 SYMBOL MULT3 PORTB.6 SYMBOL MULT4 PORTB.7 SYMBOL LT MULT2 ' Linkerbuis SYMBOL RT MULT4 ' Rechterbuis SYMBOL DOT MULT3 ' dots SYMBOL ALRM MULT1 ' alarm dot SYMBOL T0IF 2 ' [VARS] DIM twaalfvierentwintig AS BIT DIM wekkeractief AS BIT DIM wekkerlooptaf AS BIT DIM graden AS BYTE DIM tiengraden AS BYTE DIM minutenbuis AS BYTE DIM tienminutenbuis AS BYTE DIM urenbuis AS BYTE DIM tienurenbuis AS BYTE DIM linksrechts AS BYTE DIM modus AS BYTE DIM klok00h AS BYTE DIM klok01h AS BYTE DIM klok02h AS BYTE DIM tienuren AS BYTE DIM uren AS BYTE DIM tienminuten AS BYTE DIM minuten AS BYTE DIM tienseconden AS BYTE DIM seconden AS BYTE DIM wektienuren AS BYTE DIM wekuren AS BYTE DIM wektienminuten AS BYTE DIM wekminuten AS BYTE DIM temperatuur AS BYTE DIM halvegraad AS BYTE DIM wekkeropslaan AS BYTE DIM buisuittienuur AS BYTE DIM buisuituur AS BYTE DIM buisuitminuten AS BYTE DIM buisuittienminuten AS BYTE DIM dotuse AS BYTE CLEAR ' alle variabelen op 0 innitten '[INIT] TRISA = %01111101 TRISB = %00000000 HV = 1 ' buizen aan bij powerup BUZZER = 0 ' buzzer uit bij powerup INTCON = 0b10100000 ' Global Interrupt Enable, Timer 0 interrupt enable OPTION_REG = 0b11010100 ' Timer 0 klokken uit instructieklok ' timer 0 krijgt prescaler (ipv WDT) ' prescaler is 32. 'Timer0 zal nu 120x per seconde overflowen. Buizen dus muxen aan 60Hz (om en om). BUSOUT %10010000, [$EE] ; start temperatuursensor conversie BUSIN %11010001, $0008, [wektienuren] ; opgeslagen wektijd ophalen BUSIN %11010001, $0009, [wekuren] BUSIN %11010001, $000A, [wektienminuten] BUSIN %11010001, $000B, [wekminuten] BUSIN %11010000, $000D, [wekkeropslaan] ; en of de wekker uberhaupt actief is wekkeractief = wekkeropslaan.1 ; en misschien zelfs afloopt wekkerlooptaf = wekkeropslaan.0 ALRM=wekkeractief ; alarm indicator geeft aan of wekker actief is. BUSIN %11010001, $000E, [buisuituur] ; Ophalen wanneer de buizen uit moeten BUSIN %11010001, $000F, [buisuittienuur] BUSIN %11010001, $0010, [buisuittienminuten] BUSIN %11010001, $0011, [buisuitminuten] ' default buizen uit om 12:11 ' voor geval er niks zinnigs in het ' NVram van de RTC staat: IF buisuitminuten > 9 THEN buisuitminuten = 1 IF buisuittienminuten > 5 THEN buisuittienminuten = 1 IF buisuituur > 9 THEN buisuituur = 2 ELSE IF buisuittienuur = 2 AND buisuituur > 3 THEN buisuituur = 2 END IF IF buisuittienuur > 2 THEN buisuittienuur = 1 ' als er deels iets zinnigs in het geheugen staat kan het ook defaulten naar 12:34 bijvoorbeeld, als de minuten ' toevallig op 34 staan maar de uren zijn onzinnig. Maar bovenstaand stukje zorgt er in ieder geval voor dat het een ' mogelijke tijd wordt, dus niks boven 23:59. (om te voorkomen dat buisuittienuren = 3 en je helemaal moet doorbladeren tot 255 + 1 = 0) ' Defaulten naar 00:00 kan niet: de klok start op 00:00, waardoor de buizen dan gelijk uit gaan. ' (En blijven, want secondes lopen nog niet. Je kunt de buizen dus niet eens aandoen, want het is altijd buisuittijd. Zie main: onderaan.) ' soortgelijk voor de wektijd IF wekminuten > 9 THEN wekminuten = 5 ' default 08:15 IF wektienminuten > 5 THEN wektienminuten = 1 IF wekuren > 9 THEN wekuren = 8 ELSE IF wektienuren = 2 AND wekuren > 3 THEN wekuren = 0 END IF IF wektienuren > 2 THEN wektienuren = 0 BUSIN %11010001, $000C, [dotuse] ' ophalen hoe het scheidingsteken gebruikt wordt SELECT dotuse CASE 0 ' uit DOT = 0 CASE 1 ' aan DOT = 1 CASE 2 ' knipperen dotuse = 2 CASE ELSE ' catch-all: aan (default) dotuse = 1 BUSOUT %11010001, $000C, [dotuse] ' defaultwaarde opslaan (indien nodig) ENDSELECT GOTO main ' spring over ISR heen '[ISR] muxdebuizen: ' ISR INT_SUB_START INTCON.T0IF = 0 ' interruptvlag strijken INC linksrechts ' tellertje. Wordt gebruikt om ' om en om linker/rechterbuis te sturen ' (bit 0), om de DOT zonodig te laten knipperen, ' en om wekker niet constant te laten piepen. IF linksrechts.0 = 1 THEN RT = 0 ' data voor linkerbuizen inklokken CLK_OUT = 0 DATA2 = minutenbuis.3 DATA3 = tienurenbuis.3 CLK_OUT = 1 CLK_OUT = 0 DATA2 = minutenbuis.2 DATA3 = tienurenbuis.2 CLK_OUT = 1 CLK_OUT = 0 DATA2 = minutenbuis.1 DATA3 = tienurenbuis.1 CLK_OUT = 1 CLK_OUT = 0 DATA2 = minutenbuis.0 DATA3 = tienurenbuis.0 CLK_OUT = 1 LT = 1 ' daarna linkerbuizen aan ' (linkerbuizen van beide printjes: ' A- : A- ) ELSE ' zelfde voor rechterbuizen. ' eerst de linkerbuizen uit. LT = 0 ' dan de data inklokken CLK_OUT = 0 DATA2 = tienminutenbuis.3 DATA3 = urenbuis.3 CLK_OUT = 1 CLK_OUT = 0 DATA2 = tienminutenbuis.2 DATA3 = urenbuis.2 CLK_OUT = 1 CLK_OUT = 0 DATA2 = tienminutenbuis.1 DATA3 = urenbuis.1 CLK_OUT = 1 CLK_OUT = 0 DATA2 = tienminutenbuis.0 DATA3 = urenbuis.0 CLK_OUT = 1 RT = 1 ' en de rechterbuizen aan: ' -A : -A ' doordat dit alles 120x per seconde (60x per seconde per buis) gedaan wordt zie je geen geknipper. ' eventueel kan het nog sneller door de timerinstellingen aan te passen. END IF CONTEXT RESTORE INT_SUB_END ' [MAIN] main: IF wekkerlooptaf = 0 THEN ' als de wekker niet afloopt: IF BUTTON1 = 0 THEN ' SW1 stelt modus in HV = 1 ' buizen aan BUZZER = 1 ' piep DELAYMS 50 ' debounce BUZZER = 0 ' stop piep WHILE BUTTON1 = 0 IF BUTTON2 = 0 THEN ' SW1+SW2 -> wekker aan/uit wekkeractief = ~wekkeractief ' toggle wekkeractief ALRM = wekkeractief ' verandering direct zichtbaar wekkeropslaan.1 = wekkeractief ' om 'm in de RTC te zetten is een byte nodig DEC modus ' compenseren voor inc modus / terugbladermogelijkheid GOSUB Laatsw2los BUSOUT %11010000, $000D, [wekkeropslaan] ' wekkerstatus opslaan. END IF DELAYMS 50 ' debounce WEND INC modus END IF IF BUTTON2 = 0 THEN ' sw2: Buizen aan/uit BUZZER = 1 ' beep DELAYMS 50 ' debounce BUZZER = 0 ' stop beep WHILE BUTTON2 = 0 DELAYMS 50 IF BUTTON1 = 0 THEN ' sw2+SW1: Instellen van (wek)tijd etc. GOSUB Laatsw1los GOSUB Laatsw1en2los GOSUB instellen HV = 0 ' wordt straks naar 1 getoggled (compenseren voor toggle naar 0) END IF WEND HV = ~HV ' Buizen uit als ze aan zijn END IF ELSE ' als de wekker wel afloopt: IF BUTTON1 = 0 OR BUTTON2 = 0 THEN ' eender welke knop zet de wekker uit wekkerlooptaf = 0 wekkeractief = 0 BUZZER = 0 GOSUB Laatsw1en2los wekkeropslaan.1 = 0 ' wekkeractief = 0, voor opslag als byte wekkeropslaan.0 = 0 ' wekkerlooptaf = 0, voor opslag als byte BUSOUT %11010000, $000D, [wekkeropslaan] ' wekkerstatus opslaan in NVram van RTC. ELSE ' als er geen knop is ingedrukt: ' wektoon opwekken: IF linksrechts.7 = 1 THEN ' eens per 2 seconden BUZZER = linksrechts.5 ' elke 0,5 seconde buzzer aan, dan 0,5s uit ELSE ' in de volgende 2 seocnden BUZZER = 0 ' constant uit. END IF END IF END IF GOSUB kloklees ' tijd uitlezen uit RTC. ' Dit moet buiten de moduskeuze (en dus ook als de tijd niet wordt weergegeven), omdat anders de wekker niet ' afloopt als de tijd niet wordt weergegeven. SELECT modus CASE 0 ' tijd UU:MM tienurenbuis = tienuren urenbuis = uren tienminutenbuis = tienminuten minutenbuis = minuten CASE 1 ' Tijd MM:SS tienurenbuis = tienminuten urenbuis = minuten tienminutenbuis = tienseconden minutenbuis = seconden CASE 2 ' Wektijd tienurenbuis = wektienuren urenbuis = wekuren tienminutenbuis = wektienminuten minutenbuis = wekminuten CASE 3 ' temperatuur GOSUB leestempsensor urenbuis = 0 tienurenbuis = 0 ' Eigenlijk wil ik geen leading zero's, maar overange blanking geeft ghosting. tienminutenbuis = tiengraden minutenbuis = graden CASE ELSE ' indien modus buiten range modus = 0 ' weer naar 0 ENDSELECT ALRM = wekkeractief ' zorgen dat wekkerindicatie klopt. DOT = dotuse.0 ' dot aan/uit afhankelijk status dotuse IF dotuse = 2 THEN ' of knipperen DOT = linksrechts.6 ' net iets trager dan 1x per seconde END IF IF wektienuren = tienuren AND wekuren = uren AND wektienminuten = tienminuten AND wekminuten = minuten AND seconden = 0 AND tienseconden = 0 THEN ' op wektijd dus ' (seconden ook controleren omdat anders de buizen niet uitkunnen tijdens deze minuut.) HV = 1 ' buizen aan IF wekkeractief = 1 THEN ' en indien gewenst: wekkerlooptaf = 1 ' wekker laten aflopen wekkeropslaan.0 = 1 ' wekkerlooptaf voor opslag als byte gemapt op bit 0 BUSOUT %11010000, $000D, [wekkeropslaan] ' wekkerstatus opslaan in NVram van RTC. END IF END IF IF tienuren = buisuittienuur AND uren = buisuituur AND tienminuten = buisuittienminuten AND minuten = buisuitminuten AND seconden = 0 AND tienseconden = 0 THEN ' seconden ook controleren omdat anders de buizen niet meer aankunnen binnen dezelfde minuut. HV = 0 ' buizen uit op de gewenste tijd END IF GOTO main END ' [subroutines] Laatsw1los: BUZZER = 1 DELAYMS 50 BUZZER = 0 WHILE BUTTON1=0 DELAYMS 50 WEND RETURN Laatsw2los: BUZZER = 1 DELAYMS 50 BUZZER = 0 WHILE BUTTON2=0 DELAYMS 50 WEND RETURN Laatsw1en2los: WHILE BUTTON2=0 OR BUTTON1 = 0 DELAYMS 50 WEND RETURN kloklees: BUSIN %11010001, $0000, [klok00h] ; lees seconden + osc en. BUSIN %11010001, [klok01h] ; lees minuten BUSIN %11010001, [klok02h] ; lees uren en uurinstellingen ' BUSIN %11010001, [weekdag] ; lees dag-van-de-week ' BUSIN %11010001, [klok04h] ; lees dag-van-de-maand ' BUSIN %11010001, [klok05h] ; lees maand ' BUSIN %11010001, [klok06h] ; lees jaar ' [gelezen waardes omzetten] tienseconden.2 = klok00h.6 tienseconden.1 = klok00h.5 tienseconden.0 = klok00h.4 seconden.3 = klok00h.3 seconden.2 = klok00h.2 seconden.1 = klok00h.1 seconden.0 = klok00h.0 tienminuten.2 = klok01h.6 tienminuten.1 = klok01h.5 tienminuten.0 = klok01h.4 minuten.3 = klok01h.3 minuten.2 = klok01h.2 minuten.1 = klok01h.1 minuten.0 = klok01h.0 twaalfvierentwintig = klok02h.6 tienuren.1 = klok02h.5 tienuren.0 = klok02h.4 uren.3 = klok02h.3 uren.2 = klok02h.2 uren.1 = klok02h.1 uren.0 = klok02h.0 ' tienjaar.3 = klok04h.7 ' eventueel uit te breiden ' tienjaar.2 = klok04h.6 ' tienjaar.1 = klok04h.5 ' tienjaar.0 = klok04h.4 ' jaar.3 = klok04h.3 ' jaar.2 = klok04h.2 ' jaar.1 = klok04h.1 ' jaar.0 = klok04h.0 ' [/gelezen waardes omzetten] RETURN leestempsensor: ' DS1621 op adres 000 BUSIN %10010000, $AA, [temperatuur, halvegraad] ; temperatuur inlezen tiengraden = temperatuur / 10 ' tientallen graden = temperatuur - tienminutenbuis * 10 ' eenheden BUSOUT %10010000, [$EE] ; start nieuwe conversie ' halve graden gebruik ik niet. RETURN instellen: HV=1 ' buizen moeten aan om te zien wat er ingesteld wordt IF modus = 0 OR modus = 1 THEN ' als tijd werd weergegeven: tijd instellen settime_minutes: ' tijd instellen, minuten tienurenbuis = tienuren ' zorgen dat weergave ook klopt. urenbuis = uren tienminutenbuis = tienminuten minutenbuis = minuten IF BUTTON2 = 0 THEN INC minuten IF minuten = 10 THEN INC tienminuten minuten = 0 ENDIF IF tienminuten = 6 THEN tienminuten = 0 ENDIF GOSUB Laatsw2los ENDIF IF BUTTON1 = 0 THEN GOSUB Laatsw1los GOTO settime_hours ENDIF GOTO settime_minutes settime_hours: ' tijd instellen, uren tienurenbuis = tienuren urenbuis = uren tienminutenbuis = tienminuten minutenbuis = minuten IF BUTTON2 = 0 THEN INC uren IF uren = 10 THEN INC tienuren uren = 0 ENDIF IF tienuren = 2 AND uren = 4 THEN tienuren = 0 uren = 0 ENDIF GOSUB Laatsw2los ENDIF IF BUTTON1 = 0 THEN GOSUB Laatsw1los GOTO wegschrijven_tijd ENDIF GOTO settime_hours wegschrijven_tijd: twaalfvierentwintig = 0 ; altijd 24-uurs modus ' omzetten naar voor de RTC begrijpbaare waardes: klok01h.6 = tienminuten.2 klok01h.5 = tienminuten.1 klok01h.4 = tienminuten.0 klok01h.3 = minuten.3 klok01h.2 = minuten.2 klok01h.1 = minuten.1 klok01h.0 = minuten.0 klok02h.6 = twaalfvierentwintig klok02h.5 = tienuren.1 klok02h.4 = tienuren.0 klok02h.3 = uren.3 klok02h.2 = uren.2 klok02h.1 = uren.1 klok02h.0 = uren.0 INTCON.7 = 0 ; GIE = 0, interrupts disablen ; voor de zekerheid, zodat het wegschrijven niet onderbroken wordt. BUSOUT %11010000, $0000, [0] ; seconden op 0 zetten, oscilator van RTC aan BUSOUT %11010000, $0001, [klok01h] ; minuten BUSOUT %11010000, $0002, [klok02h] ; uren en uurinstellingen INTCON.7 = 1 ; interrupts weer aan ELSEIF modus = 2 THEN ' als wektijd werd weergegeven: wektijdinst_minutes: ' wektijd instellen, minuten tienurenbuis = wektienuren urenbuis = wekuren tienminutenbuis = wektienminuten minutenbuis = wekminuten IF BUTTON2 = 0 THEN INC wekminuten IF wekminuten = 10 THEN INC wektienminuten wekminuten = 0 ENDIF IF wektienminuten = 6 THEN wektienminuten = 0 ENDIF GOSUB Laatsw2los ENDIF IF BUTTON1 = 0 THEN GOSUB Laatsw1los GOTO wektijdinst_hours ENDIF GOTO wektijdinst_minutes wektijdinst_hours: ' en uren tienurenbuis = wektienuren urenbuis = wekuren tienminutenbuis = wektienminuten minutenbuis = wekminuten IF BUTTON2 = 0 THEN INC wekuren IF wekuren = 10 THEN INC wektienuren wekuren = 0 ENDIF IF wektienuren = 2 AND wekuren = 4 THEN wektienuren = 0 wekuren = 0 ENDIF GOSUB Laatsw2los ENDIF IF BUTTON1 = 0 THEN GOSUB Laatsw1los GOTO wegschrijven_wektijd ENDIF GOTO wektijdinst_hours wegschrijven_wektijd: INTCON.7 = 0 ; GIE = 0, interrupts disablen ; wegschrijven niet ondebreken BUSOUT %11010000, $0008, [wektienuren] ; wektijd in general purpase NVram van RTC BUSOUT %11010000, $0009, [wekuren] BUSOUT %11010000, $000A, [wektienminuten] BUSOUT %11010000, $000B, [wekminuten] INTCON.7 = 1 'interrupts weer enablen ELSEIF modus = 3 THEN 'als temperatuur wordt weergegeven ' temperatuur instellen? Nee, kan de klok niet. Buisuittijd instellen! buisuitset_minutes: tienurenbuis = buisuittienuur urenbuis = buisuituur tienminutenbuis = buisuittienminuten minutenbuis = buisuitminuten IF BUTTON2 = 0 THEN INC buisuitminuten IF buisuitminuten = 10 THEN INC buisuittienminuten buisuitminuten = 0 ENDIF IF buisuittienminuten = 6 THEN buisuittienminuten = 0 ENDIF GOSUB Laatsw2los ENDIF IF BUTTON1 = 0 THEN GOSUB Laatsw1los GOTO buisuitset_hours ENDIF GOTO buisuitset_minutes buisuitset_hours: tienurenbuis = buisuittienuur urenbuis = buisuituur tienminutenbuis = buisuittienminuten minutenbuis = buisuitminuten IF BUTTON2 = 0 THEN INC buisuituur IF buisuituur = 10 THEN INC buisuittienuur buisuituur = 0 ENDIF IF buisuittienuur = 2 AND buisuituur = 4 THEN buisuituur = 0 buisuittienuur = 0 ENDIF GOSUB Laatsw2los ENDIF IF BUTTON1 = 0 THEN GOSUB Laatsw1los GOTO wegschrijven_buisuittijd ENDIF GOTO buisuitset_hours wegschrijven_buisuittijd: INTCON.7 = 0 ; GIE = 0, interrupts disablen BUSOUT %11010000, $000E, [buisuituur] BUSOUT %11010000, $000F, [buisuittienuur] BUSOUT %11010000, $0010, [buisuitminuten] BUSOUT %11010000, $0011, [buisuittienminuten] INTCON.7 = 1 ; interrupts weer aan. ' en hier dan ook maar gebruik van het puntje in het midden instellen: setdotuse: tienurenbuis = 0 urenbuis = 0 tienminutenbuis = 0 minutenbuis = dotuse IF BUTTON2 = 0 THEN INC dotuse GOSUB Laatsw2los ENDIF IF dotuse = 3 THEN dotuse = 0 ENDIF IF BUTTON1 = 0 THEN GOSUB Laatsw1los GOTO schrijfdotuseweg END IF GOTO setdotuse schrijfdotuseweg: INTCON.7 = 0 ; GIE = 0, interrupts disablen BUSOUT %11010001, $000C, [dotuse] INTCON.7 = 1 ' GIE = 1, interrupts weer toestaan. ENDIF 'en bij elke andere modus dus direct terugkeren RETURN