'**************************************************************** '* Name : UNTITLED.BAS * '* Author : Pieter Verstraete * '* Notice : Copyright (c) 2011 Pieter Verstraete * '* : All Rights Reserved * '* Date : 25/04/2011 * '* Version : 1.0 * '* Notes : * '* : * '**************************************************************** Device 16F628A ;We gebruiken een 16F628A type Config HS_OSC, WDT_OFF, PWRTE_ON, LVP_OFF, BODEN_OFF, MCLRE_OFF ALL_DIGITAL TRUE ;Alle ingangen digitaal XTAL = 16 ;Gebruik een kristal van 20MHz HSERIAL_BAUD = 2400 ;Transmissiesnelheid van de data over de bus HSERIAL_RCSTA = %10010000 ;Bit7:Enable serial port / Bit4:Continu ontvangen HSERIAL_TXSTA = %00000000 ;Bit5:Transmitpin uitgeschakeld (TXEN (Transmit ENable) = 0) ;Logische constanten Symbol HOOG = 1 ;Hoog niveau Symbol LAAG = 0 ;Laag niveau Symbol AAN = 0 ;Omgekeerd ON Symbol FALSE = 0 Symbol offf = 0 Symbol onn = 1 Symbol TRUE = 1 Symbol UIT = 1 ;Omgekeerd OFF ;Normale aliases (constanten) Symbol Baud2400I = 16780 ;2400 Baud Inverted (baudrate voor SEROUT) 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 ;Poortnamen Symbol SerieelIn = PORTB.1 ;Ontvangt via HSERIN data van de bus (B.1 = USART ingang, RX) Symbol SerieelUit = PORTB.2 ;Stuurt via SEROUT data naar de bus (B.2 = USART uitgang, TX) Symbol SecondePuls = PORTA.1 ;Iedere seconde een puls van 0,5 seconde Symbol DCF_Signaal = PORTB.0 ;Ingang voor de DCF77 module (ontvanger) signaal (bv. Conrad BN641138) ;Variabelen declareren ;WORD-ARRAY Dim Buffer[4] As Word ;Ontvangst buffer van de USART (een array) ;WORD Dim OntvangenData As Word ;Bevat de ontvangen 16-bits data vanuit USART Dim SignaalCheck As Word Dim Teller As Word ;BYTE Dim Opdracht As Byte ;Bevat de laatst ontvangen opdrachtcode Dim Waarde As Byte ;Eventueel retour gezonden waarde (zoals gemeten LDR waarde) 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 Dim Dummy As Bit Declare LCD_TYPE ALPHA Declare LCD_INTERFACE = 4 Declare LCD_ENPIN = PORTA.3 Declare LCD_RSPIN = PORTB.3 Declare LCD_DTPIN = PORTB.4 Declare LCD_LINES = 2 ; 76543210 PORTA = %00000001 ;LED voor dit voorbeeld aanzetten (PIC opstart controle) PORTB = %00000000 ;PORTB poorten laag TRISA = %11111111 ;A.0 is uitgang voor de LED (in dit voorbeeld) TRISB = %11111111 ;USART uitgang B.2 moet in rust hoog-ohmig zijn PORTB_PULLUPS On ;PORTB pull-ups geactiveerd voor de toets Clear ;Wis alle RAM geheugen DelayMS 500 ;Stabilisatie signalen en voorbeeld LED opstart tijd Dummy = 0 ON_INTERRUPT GoTo InterruptAfhandeling ;Spring naar label als data is ontvangen door de USART INTCON.7 = 1 ;GIE (Global Interrupt Enable) activeren INTCON.6 = 1 ;PEIE (PEripheral Interrupt Enable) activeren PIE1.5 = 1 ;RCIE (USART ReCeive Interrupt Enable) activeren DelayMS 200 ;LCD stabilisering Cls Print "DCF16NLD V-2" ;Versie nummer DelayMS 2000 Cls Print "Signaal zoeken" Initialiseren = TRUE GoTo HoofdLus ;Spring over subroutine(s) ;SUBROUTINE(S) ZendBus: ;De bus die door het huis loopt RCSTA = %00000000 ;Zet USART uit, anders ontvangt deze zijn eigen verzonden data SerOut SerieelUit, Baud2400I, [Opdracht, Waarde] ;Geinverteerd verzenden (vanwege BC547) RCSTA = %10010000 ;Schakel USART weer in, zodat de PIC weer data kan ontvangen Input SerieelUit ;Maak TX poort (PORTB.2) hoog-ohmig door er een ingang te maken Return 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 = onn ;Uitgangssignaal seconde puls DelayMS 500 SecondePuls = offf DelayMS PulsLengte - 500 Return ;HOOFDPROGRAMMA HoofdLus: Clear Opdracht ;Opdracht (na uitvoering) wissen Clear Waarde ;Idem voor 'Waarde' If Buffer[0] > 0 Then ;Zolang er zich een opdracht in de buffer bevindt, dan... Opdracht = Buffer[0] & 255 ;De laagste 8 bits bevatten de Opdrachtbyte Waarde = Buffer[0] >> 8 ;De hoogste 8 bits bevatten een eventueel meegezonden waarde Buffer[0] = Buffer[1] ;Schuif de waarden die in de buffer zitten 1 verder door Buffer[1] = Buffer[2] Buffer[2] = Buffer[3] Buffer[3] = 0 ;Maak laatste bufferplaats leeg (opdracht en waarde wissen) GoTo OpdrachtUitvoeren ;Voer opdracht uit EndIf ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ;Voorbeeld voor de picbasic.nl site (om te experimenteren, zelf uitbreiden) ;Onderstaand stukje staat dus niet in het programma bij mij thuis ' If Toets = LAAG Then ;Als toets wordt ingedrukt, dan... ' Opdracht = 26 ;Verzendt waarde 26 over de bus ' GoSub ZendBus ' DelayMS 20 ;Antidender voor indrukken van de toets ' While Toets = LAAG : Wend ;Wacht tot toets wordt losgelaten, anders blijft hij zenden ' DelayMS 20 ;Antidender voor loslaten van de toets ' EndIf ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ;Op deze plek staat bij mij de oneindige lus met voorwaarden (zie vorig voorbeeld) ' vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 'Dit is het begin van het programmastuk van de DCF-klok 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 = onn Case 75 SecondePuls = offf 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 UurLCD = Uur Print " " ;Wis deel van 12 uurs notatie (AM/PM) uit bij omschakeling naar 24 uurs notatie 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 CursorPos = LCD_Char - 1 ;Cursor positie alvast instellen voor de seconden EndIf If Signaal = TRUE Then ;Startbit succesvol ontvangen, start met het vullen van data GoSub OntvangEenBit ;0: Bit 0 (gereserveerd (DCF77 protocol) VerderDCF: ;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 zomer/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 = onn Then PariteitsError = TRUE 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 = onn Then PariteitsError = TRUE 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 = onn 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 ;September (9 karakters) past anders niet op 16 karakters LCD Else Print " 20", DEC2 Jaar EndIf EndIf Else ;Else 'Signaal' = FALSE, geen signaal gevonden GoTo ErrorOntvangst EndIf 'Dit is het einde van het programmastuk van de DCF-klok ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GoTo HoofdLus OpdrachtUitvoeren: Select Opdracht ;Deze SELECT lijst bepaalt wat een ontvangen opdracht gaat doen Case 26 ;Als de waarde '26' is ontvangen van de bus, dan... ' LED = ~LED ;... de LED aan of uitzetten (togglen) Case 120 ;Als waarde '120' is ontvangen, dan... ' LED = HOOG ;... de LED aanzetten (poort een HOOG niveau geven) Case 121 ;Als waarde '121' is ontvangen, dan... ' LED = LAAG ;... de LED uitzetten (poort een LAAG niveau geven) End Select GoTo HoofdLus ;Ga weer naar de oneindige hoofdlus InterruptAfhandeling: ;Uitlezen en leegschuiven van buffer gebeurt in hoofdprogramma HSerIn 7, Verder, [OntvangenData] ;Time out staat op 7mSec ingesteld For BD1 = 0 To 3 ;Buffer met plaats voor maximaal 4 WORD arrays (0...3) If Buffer[BD1] = 0 Then ;Bufferplaats nog leeg? Dan... Buffer[BD1] = OntvangenData ;...hierin de ontvangen data plaatsen, en... Break ;...uit de FOR...NEXT lus springen EndIf Next Verder: ;In het geval van een time-out, hier verder gaan Context Restore ;Restore registers, ga terug naar plek waar interrupt ontstond GoTo HoofdLus ;Zekerheid, eigenlijk staat dit er overbodig 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 GongSignaal: DelayMS 155 If Minuut = 00 Or Dummy = AAN Then ;Gong1 = onn ;Op de hele uren (en met test) volgt een 3-tonig signaal SecondePuls = onn DelayMS 500 SecondePuls = offf DelayMS 330 ;985 - 500 - 155 Inc Seconde EndIf GoTo VerderDCF ;Ga verder met het lezen van de DCF77 bits vanaf bit 1 (We slaan de DCF77 bit 0 over)