;V-2 ;Compileren met Crownhill Proton+ PIC Basic compiler. ;Ontvangt DCF77 data van een standaard DCF module en geeft datum/tijd weer op een LCD. ;Het is belangrijk dat de DCF77 ontvangst optimaal is. ;Voor DCF77 info, schema en bediening: www.picbasic.nl ; PIC16F628A: +--v--+ ; Puls voor gong E1 <[ ]> Een puls per seconde ; Puls voor gong E2 <[ ]> Hoog = zomertijd, laag = wintertijd ; Volume niveau gong <[ ]< LDR aan +5V, potmeter van 1M aan GND ; [ ]< 12:00 (AM/PM) of 24:00 notatie ; GND [ ] +5V ; DCF77 module signaal >[ ]> DB7 LCD ;Normaal open laten, voor test aan GND >[ ]> DB6 LCD ; LCD EN <[ ]> DB5 LCD ; LCD RS <[ ]> DB4 LCD ; +-----+ ;There is an English version too / Er is ook een Engelse versie ;www.picbasic.nl / Frits Kieftenbelt, Raalte, Netherlands (Frizie) DEVICE = 16F628A CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF ;Interne RC-oscillator ALL_DIGITAL TRUE ;Normale aliases (constanten) SYMBOL Blokje = 255 ;Maximaal 255: 255 is de ASCII code voor een blokje op de LCD tijdsbalk SYMBOL LCD_Char = 16 ;Minimaal 16: Aantal karakters per regel (afhankelijk van het gebruikte LCD type) SYMBOL MaxVindTijd = 65 ;Minimaal 65: (Sec) Tijd om seconde 00 te vinden SYMBOL OpStartTijd = 45000 ;Maximaal 65535: (mSec) 45 seconden opstart tijd voor de DCF77 module na power-on SYMBOL PulsLengte = 740 ;Minimaal 500! Maximaal 750: (mSec) SYMBOL PulsLengteX = PulsLengte / 10 ;Logische aliases (constanten) SYMBOL AAN = 0 ;Omgekeerd ON SYMBOL FALSE = 0 SYMBOL OFF = 0 SYMBOL ON = 1 SYMBOL TRUE = 1 SYMBOL UIT = 1 ;Omgekeerd OFF ;Poort aliases SYMBOL Zomertijd = PORTA.0 ;Hoog als het zomertijd is (hulp LED bij het afregelen van de LDR) SYMBOL SecondePuls = PORTA.1 ;Iedere seconde een puls van 0,5 seconde SYMBOL Gong1 = PORTA.2 ;Elk heel uur komt hier een puls voor aansturing gong SYMBOL Gong2 = PORTA.3 ;Elk heel en half uur komt hier een puls voor aansturing gong SYMBOL Volume = PORTA.4 ;Wisselt tussen output (GND) en input (hoog-ohmig) om het volume van de gong te regelen SYMBOL AM_PM = PORTA.6 ;In 24 uurs mode met +5V verbinden, voor 12 uurs AM/PM notatie deze poort met GND verbinden SYMBOL LDR = PORTA.7 ;Als het donker is maakt de gong minder geluid dan overdag of met schemerlampen aan SYMBOL DCF_Signaal = PORTB.0 ;Ingang voor de DCF77 module (ontvanger) signaal (bv. Conrad BN641138) SYMBOL Test = PORTB.1 ;Normaal open laten, voor afregelen van LDR laag maken VOOR opstarten PIC, voor afregelen gong laag maken NA opstart PIC ; 76543210 TRISA = %11100000 TRISB = %11111111 PORTB_PULLUPS ON ;Pull-up voor DCF77 ontvanger en AM/PM keuze ingang ;WORD DIM SignaalCheck AS WORD DIM Teller AS WORD ;BYTE DIM AlgemeneTeller AS BYTE DIM BitAantal AS BYTE DIM CursorPos AS BYTE ;Cursor x-positie op de LCD DIM Dag AS BYTE DIM Jaar AS BYTE DIM Maand AS BYTE DIM Minuut AS BYTE DIM MinuutDCF AS BYTE ;Bevat de DCF minuut, is er een pariteitserror, dan wordt Minuut NIET gelijk gemaakt met MinuutDCF, maar alleen met 1 verhoogd DIM OntvangByte AS BYTE DIM Seconde AS BYTE DIM Uur AS BYTE DIM UurDCF AS BYTE ;Bevat het DCF uur, is er een pariteitserror, dan wordt Uur NIET gelijk gemaakt met UurDCF DIM UurLCD AS BYTE ;Normaal gelijk aan Uur, alleen bij AM/PM notatie wijkt hij 's middags af DIM WeekDag AS BYTE DIM BD1 AS BYTE ;Byte Dummy 1 ;BIT DIM Initialiseren AS BIT ;TRUE bij initialiseren DIM OntvangBit AS BIT DIM PariteitsBit AS BIT DIM PariteitsError AS BIT DIM Signaal AS BIT ;TRUE als er een signaal is (gevonden) DIM ID1 AS BIT ;Bit Dummy 1 PORTA = 0 PORTB = 0 CLEAR DELAYMS 200 ;LCD stabilisering CLS PRINT "www.picbasic.nl" DELAYMS 3000 CLS PRINT "DCF16NLD V-2" ;Versie nummer DELAYMS 2000 CLS PRINT "LDR afregelen" WHILE Test = AAN ;Als Test laag is bij opstart van PIC, kan de LDR afgeregeld worden met behulp van de ZomerTijd LED IF LDR = ON THEN ZomerTijd = TRUE ELSE ZomerTijd = FALSE ENDIF WEND CLS PRINT "Signaal zoeken" Initialiseren = TRUE LOW Volume ;Bij opstarten staat volume van gong op hard GOTO HoofdLus ;Spring over de subroutines ;SUBROUTINES OntvangBitAantal: ;Vul het ontvangstbyte met het opgegeven aantal bits in BCD mode CLEAR OntvangByte FOR BD1 = 0 TO BitAantal - 1 GOSUB OntvangEenBit IF OntvangBit = 1 THEN SETBIT OntvangByte, BD1 NEXT OntvangByte = ((OntvangByte >> 4) * 10) + (OntvangByte & 15) ;BCD (Binary-Coded Decimal) naar byte conversie RETURN OntvangEenBit: ;Ontvang een bit en bewaar dit in OntvangBit CLEAR Teller WHILE DCF_Signaal = AAN DELAYMS 1 INC Teller IF Teller > 3000 THEN ErrorOntvangst ;Tegen een eventuele 'hang up' WEND DELAYMS 155 ;135 - 175msec OntvangBit = DCF_Signaal IF Initialiseren = TRUE THEN CursorPos = (Seconde * LCD_Char) / 58 ;Bereken waar de cursor moet staan (afhankelijk van de wachttijd en LCD type) PRINT AT 2, CursorPos, Blokje ;Maak tijdsbalk actueel ELSE PRINT AT 1, CursorPos, DEC2 Seconde ;Zet de seconden op het LCD PariteitsBit = PariteitsBit + OntvangBit ;Bit, dus 0+0=0 / 0+1=1 / 1+1=0 / 1+0=1 ENDIF INC Seconde ;Omdat we toch elke seconde in deze routine zijn, gebruiken we het ook om de seconden te tellen SecondePuls = ON ;Uitgangssignaal seconde puls DELAYMS 500 SecondePuls = OFF DELAYMS PulsLengte - 500 RETURN ;HOOFDPROGRAMMA HoofdLus: CLEAR AlgemeneTeller Seconde = 00 ;Start met de eerste seconde Signaal = FALSE WHILE Signaal = FALSE ;Wacht tot het DCF signaal hoog is CLEAR Teller WHILE DCF_Signaal = UIT INC Teller DELAYMS 1 IF Teller > OpStartTijd THEN ErrorOntvangst ;Opstart tijd voor de DCF77 ontvanger bij power-on WEND CLEAR Teller WHILE DCF_Signaal = AAN ;Meet de tijd tussen de pulsen INC Teller DELAYMS 10 IF Initialiseren = FALSE THEN SELECT CASE Teller CASE 85 - PulsLengteX ;85 = (1000mSec - 155mSec) / 10 PRINT AT 1, CursorPos, "59";xx:xx:59, zet de niet uitgezonden seconde '59' op het LCD CASE 25 SecondePuls = ON CASE 75 SecondePuls = OFF CASE 250 GOTO ErrorOntvangst;Signaal is niet binnen de tijd van niveau veranderd ENDSELECT ELSE IF Teller > (OpStartTijd / 10) THEN ErrorOntvangst ;Opstart tijd voor de DCF77 ontvanger bij power-on ENDIF WEND IF AlgemeneTeller >= MaxVindTijd THEN ErrorOntvangst ;Als er meer dan 'MaxVindTijd' seconden zijn geteld dan hebben we een probleem INC AlgemeneTeller IF Teller > 100 THEN Signaal = TRUE ;We tellen per 10mSec, dus we hebben minstens 100x10mSec nodig om het begin te vinden IF Initialiseren = TRUE THEN CursorPos = (AlgemeneTeller * LCD_Char) / MaxVindTijd ;Bereken waar de cursor moet staan (afhankelijk van de wachttijd en LCD type) PRINT AT 1, 1, "Signaal gevonden" PRINT AT 2, CursorPos , Blokje ;Zet blokjes op het LCD tijdens wachten op het init signaal ENDIF WEND IF Initialiseren = TRUE THEN CLS PRINT "Initialiseren..." PRINT AT 2, 1, REP "_" \ LCD_Char ;Teken een dunne lijn die aangeeft hoe lang de tijdsbalk wordt ELSE CursorPos = LCD_Char - 9 ;X-positie van tijd op het LCD CURSOR 1, CursorPos IF PariteitsError = TRUE THEN ;Tijd onbetrouwbaar, de PIC zorgt nu zelf voor actualisering van de tijd IF Minuut < 59 THEN INC Minuut ELSE Minuut = 00 ;\ IF Uur < 23 THEN ;-Tijd wordt gelijk gezet, ondanks pariteitserror INC Uur ;/ ELSE Uur = 00 ;De datum verhogen heeft geen zin, die wordt bij een error nl. niet gewijzigd ENDIF ENDIF ELSE ;Geen error, dus gewoon de DCF tijd neerzetten Minuut = MinuutDCF Uur = UurDCF ;Het uur wordt alleen geactualiseerd als er geen pariteitserror is ENDIF IF AM_PM = AAN THEN ;...als AM/PM notatie is ingeschakeld dan... SELECT CASE Uur CASE 0 :UurLCD = 12 ;Als het 00:xx uur is dan op LCD weergeven als 12:xx CASE > 12:UurLCD = Uur - 12 ;Als het 13:xx t/m 23:xx is dan op LCD weergeven als 1:xx t/m 11:xx END SELECT ELSE UurLCD = Uur PRINT " " ;Wis deel van 12 uurs notatie (AM/PM) uit bij omschakeling naar 24 uurs notatie ENDIF IF UurLCD < 10 THEN PRINT " " ;Wis de eerste nul (08:00:00 --> 8:00:00) (Nul onderdrukking) PRINT DEC UurLCD, ":", DEC2 Minuut, ":00" ;Zet elke minuut de actuele tijd op het LCD IF AM_PM = AAN THEN ;Als AM/PM notatie is ingeschakeld dan... IF Uur < 12 THEN ;...als het voor de middag is dan... PRINT "am" ;...AM achter de tijd zetten... ELSE ;...anders (is het na de middag)... PRINT "pm" ;...PM achter de tijd zetten ENDIF CursorPos = LCD_Char - 3 ;Cursor positie alvast instellen voor de seconden, 2 meer naar links voor de AM/PM ELSE CursorPos = LCD_Char - 1 ;Cursor positie alvast instellen voor de seconden ENDIF IF Minuut = 00 OR Minuut = 30 OR Test = AAN THEN GongSignaal ;Elk heel en half uur een gong signaal (en elke minuut als Test = AAN) ENDIF IF Signaal = TRUE THEN ;Startbit succesvol ontvangen, start met het vullen van data GOSUB OntvangEenBit ;0: Bit 0 (gereserveerd (DCF77 protocol) Verder: ;Als de gong klinkt, wordt bit 0 genegeerd, na de gong, wordt hier verder gegaan FOR BD1 = 1 TO 14 ;1...14: deze bits zijn gereserveerd (info zie www.picbasic.nl --> DCF77 info) GOSUB OntvangEenBit NEXT CLEAR PariteitsBit ;Als PariteitsError is geset, dan is PariteitsBit ook verminkt (geweest), even resetten CLEAR PariteitsError ;Reset PariteitsError (Deze 2 resets op deze plek laten staan ivm. pariteitserror tijdens initialiseren) GOSUB OntvangEenBit ;15: Welke zend antenne is gebruikt? ; IF OntvangBit = 0 THEN... ;Signaal is verzonden door de standaard antenne, dit bit wordt niet gebruikt in dit programma ; IF OntvangBit = 1 THEN... ;Signaal is verzonden door een reserve antenne, dit bit wordt niet gebruikt in dit programma GOSUB OntvangEenBit ;16: Omschakeling naar summer/winter volgend uur? ; IF OntvangBit = 1 THEN... ;Dit bit wordt niet gebruikt in dit programma GOSUB OntvangEenBit ;17: Zomer- of wintertijd? IF OntvangBit = 1 THEN Zomertijd = TRUE ;Zomer ELSE Zomertijd = FALSE ;Winter ENDIF FOR BD1 = 18 TO 19 ;18...19: Deze bits worden niet gebruikt (Time Zone bit 2 en schrikkel-seconde bit) GOSUB OntvangEenBit NEXT GOSUB OntvangEenBit ;20: Startbit, normaal altijd 1, dit bit wordt niet gebruikt in dit programma ; IF OntvangBit = 0 THEN... ;Dit bit wordt niet gebruikt in dit programma BitAantal = 7 ;21...27: Ontvang minuut (7 bits) GOSUB OntvangBitAantal MinuutDCF = OntvangByte ;Wordt eerst in MinuutDCF opgeslagen, als blijkt dat er geen pariteitserror is, dan wordt het aan Minuut gegeven, bij een error niet GOSUB OntvangEenBit ;28: Pariteitsbit 1, minuten IF PariteitsBit = ON THEN SET PariteitsError BitAantal = 6 ;29...34: Ontvang uur (6 bits) GOSUB OntvangBitAantal UurDCF = OntvangByte ;Wordt eerst in UurDCF opgeslagen, als blijkt dat er geen pariteitserror is, dan wordt het aan Uur gegeven, bij een error niet GOSUB OntvangEenBit ;35: Pariteitsbit 2, uren IF PariteitsBit = ON THEN SET PariteitsError BitAantal = 6 ;36...41: Ontvang dag (6 bits) GOSUB OntvangBitAantal Dag = OntvangByte BitAantal = 3 ;42...44: Ontvang weekdag (3 bits) GOSUB OntvangBitAantal WeekDag = OntvangByte BitAantal = 5 ;45...49: Ontvang maand (5 bits) GOSUB OntvangBitAantal Maand = OntvangByte BitAantal = 8 ;50...57: Ontvang jaar (8 bits) GOSUB OntvangBitAantal Jaar = OntvangByte GOSUB OntvangEenBit ;58: Pariteitsbit 3, datum IF PariteitsBit = ON THEN PariteitsError = TRUE IF Initialiseren = TRUE THEN IF PariteitsError = FALSE THEN ;Als er GEEN pariteitserror is, dan zijn we... Initialiseren = FALSE ;...klaar met initialiseren (Dus opnieuw initialiseren als er WEL een pariteitserror tijdens initialiseren was ENDIF CLS ENDIF IF PariteitsError = FALSE THEN ;Alleen datum actualiseren als er geen error in de ontvangst is ; PRINT AT 1, 1, REP " " \ 9 ;Wis de dag op het LCD (Alleen nodig bij volledige naam van de dag) PRINT AT 2, 1, REP " " \ LCD_Char ;Wis de hele tweede lijn CURSOR 1, 1 SELECT CASE WeekDag CASE 1: PRINT "Ma" CASE 2: PRINT "Di" CASE 3: PRINT "Wo" CASE 4: PRINT "Do" CASE 5: PRINT "Vr" CASE 6: PRINT "Za" CASE 7: PRINT "Zo" ENDSELECT PRINT AT 2, 1, DEC Dag, " " SELECT CASE Maand CASE 1: PRINT "januari" CASE 2: PRINT "februari" CASE 3: PRINT "maart" CASE 4: PRINT "april" CASE 5: PRINT "mei" CASE 6: PRINT "juni" CASE 7: PRINT "juli" CASE 8: PRINT "augustus" CASE 9: PRINT "september" CASE 10: PRINT "oktober" CASE 11: PRINT "november" CASE 12: PRINT "december" END SELECT IF Maand = 9 THEN PRINT " '", DEC2 Jaar ELSE PRINT " 20", DEC2 Jaar ENDIF ENDIF ELSE ;Else 'Signaal' = FALSE, geen signaal gevonden GOTO ErrorOntvangst ENDIF GOTO HoofdLus GongSignaal: IF LDR = ON THEN ;Als het daglicht is of de schemerlampen zijn aan dan... LOW Volume ;...Volumepin laag = Volume van gong harder... ELSE ;...anders (is het donker in huis)... INPUT Volume ;...Volumepin hoog-ohmig (3-state) = Volume van gong zacht ENDIF DELAYMS 155 IF Minuut = 00 OR Test = AAN THEN Gong1 = ON ;Op de hele uren (en met test) volgt een 3-tonig signaal Gong2 = ON ;Op de halve uren alleen een 2-tonig signaal SecondePuls = ON DELAYMS 500 Gong1 = OFF Gong2 = OFF SecondePuls = OFF DELAYMS 330 ;985 - 500 - 155 INC Seconde ; Bij gebruik van onderstaande methode (d.m.v. tijd) het LDR syntax gedeelte uitschakelen ; IF Uur > 5 THEN ;Tussen 0:30 uur en 6:30 uur staat het volume van de gong zachter ; LOW Volume ;Volumepin laag = Volume harder ; ELSE ; INPUT Volume ;Volumepin hoog-ohmig (3-state) = Volume zacht ; ENDIF GOTO Verder ;Ga verder met het lezen van de DCF77 bits vanaf bit 1 (We slaan de DCF77 bit 0 over) ErrorOntvangst: CLS PRINT "Geen signaal" ;Startbit niet gevonden of geen signaal? REPEAT CLEAR ;Wis alle RAM ID1 = DCF_Signaal WHILE DCF_Signaal = ID1 ;Wacht op signaal verandering INC SignaalCheck DELAYMS 1 WEND ID1 = ID1 ^ 1 WHILE DCF_Signaal = ID1 ;Wacht op signaal verandering INC SignaalCheck DELAYMS 1 WEND UNTIL SignaalCheck < 990 Initialiseren = TRUE ;Na een error moet er weer worden geinitialiseerd GOTO HoofdLus ;V-2 t.o.v. V-1: ;Met pariteitscheck ;PulsLengte zo lang mogelijk gemaakt ;SecondePuls duurt nu precies 0,5 sec