;V-1 ;Compile with Crownhill Proton+ PIC Basic compiler. ;Receives DCF77 data from a standard DCF module and shows date/time on a 16x2 chars LCD. ;It is important that the DCF77 reception is optimal. ;For DCF77 info, electronic scheme and control: www.picbasic.nl ; PIC16F628A: +--v--+ ; One pulse per second <[ ]> Pulse for gong ; High when it's daylight saving <[ ] ; [ ] ; [ ]> Freq. 10kHz for voltage raising SAB0600 ; GND [ ] +5V ; DCF77 module signal >[ ]> DB7 LCD ; Connect to GND = No gong at half >[ ]> DB6 LCD ; LCD EN <[ ]> DB5 LCD ; LCD RS <[ ]> DB4 LCD ; +-----+ ;Er is ook een Nederlandse versie / There is a Dutch version too ;www.picbasic.nl / Frits Kieftenbelt, Raalte, Netherlands (Frizie) DEVICE = 16F628A CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF ;On-chip RC-oscillator ALL_DIGITAL TRUE ;Normal aliases (constants) SYMBOL CharType = 255 ;Maximal 255: 255 is the ASCII code for a block in the LCD time bar SYMBOL LCD_Char = 16 ;Minimal 16: Number of characters of each line (dependence on LCD device) SYMBOL MaxFindTime = 61 ;Minimal 61: (Sec) Time to find the startsequence SYMBOL PulseLength = 30 ;Maximal 400: (mSec) Pulse length for every second on the outputpin SYMBOL StartUpTime = 45000 ;Maximal 65535: (mSec) 45 seconds startup time for the DCF77 receiver after power-on ;Logical aliases (constants) SYMBOL AAN = 0 ;Reversed ON SYMBOL FALSE = 0 SYMBOL OFF = 0 SYMBOL ON = 1 SYMBOL TRUE = 1 SYMBOL UIT = 1 ;Reversed OFF ;Port aliases SYMBOL Gong = PORTA.1 ;Pulses high every whole hour and half hour, pulse length depence on constant 'PulseLength' (Max 400mSec) SYMBOL SecondPulse = PORTA.2 ;Short pulse every second (Pulse length depence on constant 'PulseLength', max. 400mSec) SYMBOL DaylightSav = PORTA.3 ;High when it's summer (DST) SYMBOL VoltageUp = PORTA.6 ;A 10kHz frequency for charge pump for the SAB0600, which needs a supply from 7...11V SYMBOL DCF_Signal = PORTB.0 ;Input for the DCF77 module (receiver) signal (i.e. Conrad BN641138) SYMBOL GongHalf = PORTB.1 ;Input leave open, gong every half hour / input connect to GND, gong only every whole hour ; 76543210 TRISA = %10110001 TRISB = %11111111 PORTB_PULLUPS ON ;Pull-up for DCF77 receiver ;WORD DIM SignalCheck AS WORD DIM Teller AS WORD ;Teller = Counter ;BYTE DIM BitNumber AS BYTE DIM CursorPos AS BYTE ;Cursor x-position on LCD DIM Day AS BYTE DIM GeneralCounter AS BYTE DIM Hour AS BYTE DIM Minute AS BYTE DIM Month AS BYTE DIM ReceiveByte AS BYTE DIM Second AS BYTE DIM WeekDay AS BYTE DIM Year AS BYTE DIM BD1 AS BYTE ;Byte Dummy 1 ;BIT DIM Initialize AS BIT ;TRUE when initializing DIM ReceiveBit AS BIT DIM Signal AS BIT ;TRUE when signal is found DIM ID1 AS BIT ;Bit Dummy 1 CLEAR DELAYMS 200 ;LCD stabilise CLS PRINT "Search signal" ;Initial screen Initialize = TRUE GOTO MainLoop ;Jump over the subroutines ;SUBROUTINES ReceiveBitNumber: ;Fill the receivebyte with the requested amount of bits in BCD mode CLEAR ReceiveByte FOR BD1 = 0 TO BitNumber - 1 GOSUB ReceiveOneBit IF ReceiveBit = 1 THEN SETBIT ReceiveByte, BD1 NEXT ReceiveByte = ((ReceiveByte >> 4) * 10) + (ReceiveByte & 15) ;BCD (Binary-Coded Decimal) to byte conversion RETURN ReceiveOneBit: ;Receive a bit and store it in ReceiveBit CLEAR Teller WHILE DCF_Signal = AAN DELAYMS 1 INC Teller IF Teller > 3000 THEN ReceiveError WEND DELAYMS 155 ;135 - 175msec ReceiveBit = DCF_Signal IF Initialize = TRUE THEN CursorPos = Second / ((60 / LCD_Char) + 1) ;Calculate where the cursor position must be (dependence on waittime and LCD device) PRINT AT 2, CursorPos , CharType ;Make time bar actual ELSE CursorPos = LCD_Char - 1 ;Calculate the cursor position (dependence on LCD device) PRINT AT 1, 15, DEC2 Second ;Print the seconds on LCD ENDIF INC Second ;Because we are in this routine every second, we can use it to count seconds SecondPulse = ON ;Outputsignal second pulse DELAYMS PulseLength ;(The constant PulseLength may have a value of max.400) SecondPulse = OFF RETURN ;MAINPROGRAM MainLoop: CLEAR GeneralCounter Second = 00 ;Start with first second Signal = FALSE WHILE Signal = FALSE ;Wait while DCF_Signal is high CLEAR Teller WHILE DCF_Signal = UIT INC Teller DELAYMS 1 IF Teller > StartUpTime THEN ReceiveError ;Startup time for the DCF77 receiver by power-on WEND CLEAR Teller WHILE DCF_Signal = AAN ;Start counting time between pulses INC Teller DELAYMS 10 IF Initialize = FALSE THEN SELECT CASE Teller CASE 100 - (PulseLength / 10) PRINT AT 1, 15, "59";xx:xx:59, Print the missing second on LCD SecondPulse = ON CASE 100 SecondPulse = OFF CASE 250 GOTO ReceiveError ;Signal doesn't change within time ENDSELECT ELSE IF Teller > (StartUpTime / 10) THEN ReceiveError ;Startup time for the DCF77 receiver by power-on ENDIF WEND IF GeneralCounter >= MaxFindTime THEN ReceiveError ;If more then 'MaxFindTime' seconds counted then we have a problem INC GeneralCounter IF Teller > 100 THEN Signal = TRUE ;We count per 10mSec, so we need at least 100x10mSec for finding the startsequence IF Initialize = TRUE THEN CursorPos = GeneralCounter / ((MaxFindTime / LCD_Char) + 1) ;Calculate where the cursor position must be (dependence from first waittime and LCD type) PRINT AT 1, 1, "Found signal " PRINT AT 2, CursorPos , CharType ;Put block characters on LCD while waiting for initialize signal ENDIF WEND IF Initialize = TRUE THEN CLS PRINT "Initialize..." PRINT AT 2, 1, REP "_" \ (LCD_Char - 2) ;Draw the waiting time bar length ELSE CursorPos = LCD_Char - 7 ;X-position from time on LCD CURSOR 1, CursorPos IF Hour < 10 THEN PRINT " " ;Clear leading zero (08:00:00 --> 8:00:00) (Null suppression) PRINT DEC Hour, ":", DEC2 Minute, ":00" ;Put actual time on screen every minute IF Minute = 00 THEN GongSignal ;Every whole hour a gong signal IF Minute = 30 AND GongHalf = ON THEN GongSignal ;Also every half hour a gong signal when inputpin GongHalf is high (unconnected) ENDIF IF Signal = TRUE THEN ;Startbit succesfull received, start filling data FOR BD1 = 0 TO 14 ;0...14: first 15 bits are reserved (info see www.picbasic.nl --> DCF77 info) GOSUB ReceiveOneBit NEXT Further: ;When the gong sounds, bits 0 to 14 are ignored, after a gong, it goes further here GOSUB ReceiveOneBit ;15: Which send antenna is used? ; IF ReceiveBit = 0 THEN... ;Signal is sended by the standard antenna, this bit is not used in this program ; IF ReceiveBit = 1 THEN... ;Signal is sended by a reserve antenna, this bit is not used in this program GOSUB ReceiveOneBit ;16: Switch summer/winter next hour? ; IF ReceiveBit = 1 THEN... ;This bit is not used in this program GOSUB ReceiveOneBit ;17: Daylight Savings Time? IF ReceiveBit = 1 THEN DaylightSav = ON ;Summer ELSE DaylightSav = OFF ;Winter ENDIF FOR BD1 = 18 TO 19 ;18...19: Skip bits (Time Zone bit 2 and leap-second bit) GOSUB ReceiveOneBit NEXT GOSUB ReceiveOneBit ;20: Startbit, must always be a 1, not used in this program ; IF ReceiveBit = 0 THEN... ;This bit is not used in this program BitNumber = 7 ;21...27: Receive Minute GOSUB ReceiveBitNumber Minute = ReceiveByte GOSUB ReceiveOneBit ;28: Skip parity bit BitNumber = 6 ;29...34: Receive Hour GOSUB ReceiveBitNumber Hour = ReceiveByte GOSUB ReceiveOneBit ;35: Skip parity bit BitNumber = 6 ;36...41: Receive Day GOSUB ReceiveBitNumber Day = ReceiveByte BitNumber = 3 ;42...44: Receive WeekDay GOSUB ReceiveBitNumber WeekDay = ReceiveByte BitNumber = 5 ;45...49: Receive Month GOSUB ReceiveBitNumber Month = ReceiveByte BitNumber = 8 ;50...57: Receive Year GOSUB ReceiveBitNumber Year = ReceiveByte GOSUB ReceiveOneBit ;58: Skip parity bit IF Initialize = TRUE THEN Initialize = FALSE ;Ready with initializing CLS ENDIF PRINT AT 1, 1, REP " " \ LCD_Char - 8 ;Erase the day on LCD PRINT AT 2, 1, REP " " \ LCD_Char ;Erase the whole 2nd line CURSOR 1, 1 SELECT CASE WeekDay CASE 1: PRINT "Mon" CASE 2: PRINT "Tue" CASE 3: PRINT "Wed" CASE 4: PRINT "Thu" CASE 5: PRINT "Fry" CASE 6: PRINT "Sat" CASE 7: PRINT "Sun" ENDSELECT PRINT AT 2, 1, DEC Day, " " SELECT CASE Month CASE 1: PRINT "January" CASE 2: PRINT "February" CASE 3: PRINT "March" CASE 4: PRINT "April" CASE 5: PRINT "May" CASE 6: PRINT "June" CASE 7: PRINT "July" CASE 8: PRINT "August" CASE 9: PRINT "September" CASE 10: PRINT "October" CASE 11: PRINT "November" CASE 12: PRINT "December" END SELECT PRINT " '", DEC2 Year ELSE ;Else 'Signal' = FALSE, we have no signal found GOTO ReceiveError ENDIF GOTO MainLoop GongSignal: CursorPos = LCD_Char - 1 ;Depending on the LCD-device, calculate the cursorposition for the seconds, during the gong Gong = ON ;Gong pin high FOR Second = 0 TO 14 SOUND VoltageUp, [127, 20] ;The sound IC SAB0600 needs a power supply of 7...11V, we make it here with a frequentie from 10kHz (charge pump) PRINT AT 1, CursorPos, DEC2 Second ;At the same time we're doing this, the seconds counts further SecondPulse = ON ;Still the SecondPulse pulses every second SOUND VoltageUp, [127, PulseLength / 12] Gong = OFF ;Gong pin low SecondPulse = OFF SOUND VoltageUp, [127, 60 - (PulseLength / 12)] NEXT GOTO Further ;Read the DCF77 bits from bit 15 (We omit the DCF77 bits 0...14) ReceiveError: CLS PRINT "No signal" ;Startbit not found or no signal? REPEAT CLEAR ;Erase all RAM ID1 = DCF_Signal WHILE DCF_Signal = ID1 ;Wait for signal changing INC SignalCheck DELAYMS 1 WEND ID1 = ID1 ^ 1 WHILE DCF_Signal = ID1 ;Wait for signal changing INC SignalCheck DELAYMS 1 WEND UNTIL SignalCheck < 990 Initialize = TRUE ;Initialize again after the error GOTO MainLoop