Ako nekom treba evo prilagodjenog primjera za dekodiranje DCF signala.Primjer je prilagodje s Proton+ PIC Basic compilera na PICBASIC compiler i Easypic 5 plocu s mikrokontrolerom PIC16F876A i kristalom od 4Mhz.
Code: Select all
;V-2
;Compile with Crownhill Proton+ PIC Basic compiler.
;Receives DCF77 data from a standard DCF module and shows date/time on a LCD.
;It is important that the DCF77 reception is optimal.
;For DCF77 info, schematic diagram and control: www.picbasic.nl
; PIC16F628A: +--v--+
; Pulse for gong E1 <[ ]> One pulse per second
; Pulse for gong E2 <[ ]> Daylight saving, high when it's summer
; Volume level gong <[ ]< Connect LDR to +5V, 1M potmeter to GND
; [ ]< 12:00 (AM/PM) or 24:00 notation
; GND [ ] +5V
; DCF77 module signal >[ ]> DB7 LCD
; Normaly open, for test to GND >[ ]> 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)
Define OSC 4
DEFINE LCD_DREG PORTB
DEFINE LCD_DBIT 0
DEFINE LCD_RSREG PORTB
DEFINE LCD_RSBIT 4
DEFINE LCD_EREG PORTB
DEFINE LCD_EBIT 5
DEFINE LCD_BITS 4
DEFINE LCD_LINES 2
DEFINE LCD_COMMANDUS 2000
DEFINE LCD_DATAUS 50
ADCON1= 7
SYMBOL CharType = 42 ;Maximal ZNAK ZVIJEZDICE
SYMBOL LCD_Char = 16 ;Minimal 16: Number of characters of each line (dependence on LCD device)
SYMBOL MaxFindTime = 65 ;Minimal 65: (Sec) Time to find the startsequence (second 00)
SYMBOL PulseLength = 740 ;Minimal 500! Maximal 750: (mSec)
SYMBOL PulseLengthX= PulseLength / 10
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 OFFF = 0
SYMBOL ONN = 1
SYMBOL TRUE = 1
SYMBOL UIT = 1 ;Reversed OFF
;Port aliases
SYMBOL DaylightSav = PORTA.0 ;High when it's summer
SYMBOL SecondPulse = PORTA.1 ;Pulses every second a half second
SYMBOL Gong1 = PORTA.2 ;Pulses high every whole hour, to steer the gong
SYMBOL Gong2 = PORTA.3 ;Pulses high every whole and half hour, to steer the gong
SYMBOL Volume = PORTA.4 ;Changing between output (GND) and input (3-state) for regulate the volume level from the gong
SYMBOL AM_PM = PORTC.6 ;Connect for 24 hours mode to +5V, for 12 hours AM/PM notation to GND
SYMBOL LDR = PORTC.7 ;When it's dark (LDR sensor), sounds the gong softly
SYMBOL DCF_Signal = PORTC.0 ;Input for the DCF77 module (receiver) signal (i.e. Conrad BN641138)
SYMBOL Test = PORTC.1 ;Input leave normaly open, for adjusting LDR, make low BEFORE startup the PIC, for adjusting gong, make low AFTER startup the PIC
; 76543210
TRISA = %11100000
TRISB = %00000000
TRISC = %11111111
'PORTB_PULLUPS ON ;Pull-up for DCF77 receiver and Test button
PORTB.7=0
;WORD
SignalCheck var WORD
Teller var WORD ;Teller = Counter
;BYTE
BitNumber var BYTE
CursorPos var BYTE ;Cursor x-position on LCD
Day var BYTE
GeneralCounter var BYTE
Hour var BYTE
HourDCF var BYTE
HourLCD var BYTE
Minute var BYTE
MinuteDCF var BYTE
Month var BYTE
ReceiveByte var BYTE
Second var BYTE
WeekDay var BYTE
Year var BYTE
BD1 var BYTE ;Byte Dummy 1
MINUTE_OLD VAR BYTE
MINUTE_NEW VAR BYTE
HOUR_LCD_OLD VAR BYTE
YEAR_OLD VAR BYTE
DAY_OLD VAR BYTE
MONTH_OLD VAR BYTE
FLAG VAR BYTE
;BIT
Initialize var BIT ;TRUE when initializing
ParityBit var BIT
ParityError var BIT
ReceiveBit var BIT
Signal var BIT ;TRUE when signal is found
ID1 var BIT ;Bit Dummy 1
PORTA = 0
PORTB = 0
CLEAR
pause 200 ;LCD stabilize
FLAG=0
LCDOut $fe,1
LCDOut $fe,$80, "www.picbasic.nl"
pause 3000
LCDOut $fe,1
LCDOut $fe,$80, "DCF16UKD V-2" ;Version number
pause 2000
LCDOut $fe,1
LCDOut $fe,$80, "Adjust LDR"
WHILE Test = AAN ;If Test = LOW when startup the PIC, the LDR can adjust with the indication from the Daylightsave LED
IF LDR = ONN THEN
DaylightSav = TRUE
ELSE
DaylightSav = FALSE
ENDIF
WEND
LCDOut $fe,1
LCDOut $fe,$80, "Search signal"
Initialize = TRUE
LOW Volume ;When startup the PIC, the gong volume is loud
GOTO MainLoop ;Jump over the subroutines
;SUBROUTINES
ReceiveBitNumber: ;Fill the receivebyte with the requested amount of bits in BCD mode
ReceiveByte=0
FOR BD1 = 0 TO BitNumber - 1
GOSUB ReceiveOneBit
IF ReceiveBit = 1 THEN ReceiveByte.0(BD1)=1
NEXT BD1
ReceiveByte = ((ReceiveByte >> 4) * 10) + (ReceiveByte & 15) ;BCD (Binary-Coded Decimal) to byte conversion
RETURN
ReceiveOneBit: ;Receive a bit and store it in ReceiveBit
Teller =0
WHILE DCF_Signal = AAN
PAUSE 1
Teller=TELLER+1
IF Teller > 3000 THEN ReceiveError
WEND
PAUSE 155 ;135 - 175msec
ReceiveBit = DCF_Signal
IF Initialize = TRUE THEN
CursorPos = (Second * LCD_Char) / 58 ;Calculate where the cursor position must be (dependence on waittime and LCD device)
LCDOut $fe,$C0+CursorPos, CharType ;Make time bar actual
ELSE
LCDOut $fe,$80+6, DEC2 Second ;Print the seconds on LCD
ParityBit = ParityBit + ReceiveBit ;Bit, thus 0+0=0 / 0+1=1 / 1+1=0 / 1+0=1 On the end you can see if it is even or uneven
ENDIF
Second=SECOND+1 ;Because we are in this routine every second, we can use it to count seconds
SecondPulse = ONN ;Outputsignal second pulse
PAUSE 500
SecondPulse = 0
PAUSE PulseLength - 500
RETURN
;MAINPROGRAM
MainLoop:
GeneralCounter =0
Second = 00 ;Start with first second
Signal = FALSE
WHILE Signal = FALSE ;Wait while DCF_Signal is high
Teller =0
WHILE DCF_Signal = UIT
Teller =TELLER+1
PAUSE 1
IF Teller > StartUpTime THEN ReceiveError ;Startup time for the DCF77 receiver by power-on
WEND
Teller=0
WHILE DCF_Signal = AAN ;Start counting time between pulses
Teller=TELLER+1
PAUSE 10
IF Initialize = FALSE THEN
SELECT CASE Teller
CASE 85 - PulseLengthX ;85 = (1000mSec - 155mSec) / 10
LCDOut $FE,$80+6, "59";xx:xx:59, Print the missing second on LCD'PRVI RED
CASE 25
SecondPulse = ONN
CASE 75
SecondPulse = 0
CASE 250
GOTO ReceiveError ;Signal doesn't change within time
END SELECT
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
GeneralCounter =GENERALCOUNTER+1
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 * LCD_Char) / MaxFindTime ;Calculate where the cursor position must be (dependence from first waittime and LCD type)
LCDOut $fe,1
LCDOut $fe,$80, "Found signal "
' LCDOut $fe,$C0, CursorPos , CharType ;Put block characters on LCD while waiting for initialize signal
ENDIF
WEND
IF Initialize = TRUE THEN
LCDOut $fe,1
LCDOut $fe,1,"Initialize..."
LCDOut $fe,$C0, REP "_" \ LCD_Char ;Draw the waiting time bar length
ELSE
CursorPos = LCD_Char - 9 ;X-position from time on LCD
IF ParityError = TRUE THEN ;Tijd not 100%, the PIC self calculates the time now for actualising
IF Minute < 59 THEN
Minute=MINUTE+1
ELSE
Minute = 00 ;\
IF Hour < 23 THEN ;-Time is synchronized, in spite of parityerror
Hour =HOUR+1 ;/
ELSE
Hour = 00 ;Actualising the date have no sense, when an error occured then it isn't gonna changed
ENDIF
ENDIF
ELSE ;No error, put the normal DCF time on LCD
Minute = MinuteDCF
Hour = HourDCF
ENDIF
HourLCD = Hour ;The hour which comes on LCD is equal to the DCF hour
LCDOut $fe,$80 , DEC HourLCD, ":", DEC2 Minute, ":00" ;Put actual time on LCD every minute
IF Minute = 00 OR Minute = 30 OR Test = AAN THEN GongSignal ;Every whole and half hour a gong signal (and every minute if Test is enabled)
ENDIF
IF Signal = TRUE THEN ;Startbit succesfull received, start filling data
GOSUB ReceiveOneBit ;0: Bit 0 (reserved (DCF77 protocol))
Further:
;When the gong sounds, bit 0 is ignored, after a gong, it goes further here
FOR BD1 = 1 TO 14 ;1...14: first 15 bits are reserved (info see www.picbasic.nl --> DCF77 info)
GOSUB ReceiveOneBit
NEXT
ParityBit=0 ;If ParityError is set, then ParityBit is also mutated, thus reset
ParityError=0 ;Reset PariteitsError (Leave these 2 resets on this place, because when a parityerror happens during initializing)
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 = ONN ;Summer
ELSE
DaylightSav = 0 ;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 (7 bits)
GOSUB ReceiveBitNumber
MinuteDCF = ReceiveByte
GOSUB ReceiveOneBit ;28: Parity bit 1, minutes
IF ParityBit = ONN THEN ParityError = TRUE
BitNumber = 6 ;29...34: Receive Hour (6 bits)
GOSUB ReceiveBitNumber
HourDCF = ReceiveByte
GOSUB ReceiveOneBit ;35: Parity bit 2, hours
IF ParityBit = ONN THEN ParityError = TRUE
BitNumber = 6 ;36...41: Receive Day (6 bits)
GOSUB ReceiveBitNumber
Day = ReceiveByte
BitNumber = 3 ;42...44: Receive WeekDay (3 bits)
GOSUB ReceiveBitNumber
WeekDay = ReceiveByte
BitNumber = 5 ;45...49: Receive Month (5 bits)
GOSUB ReceiveBitNumber
Month = ReceiveByte
BitNumber = 8 ;50...57: Receive Year (8 bits)
GOSUB ReceiveBitNumber
Year = ReceiveByte
GOSUB ReceiveOneBit ;58: Parity bit 3, date
IF ParityBit = ONN THEN ParityError = TRUE
IF Initialize = TRUE THEN
IF ParityError = FALSE THEN ;If there is NO parityerror, then we are...
Initialize = FALSE ;...ready with initializing (If there IS a parityerror while initializing, then initialize again)
ENDIF
LCDOut $fe,1
ENDIF
IF ParityError = FALSE THEN;Only actualise the date when there is no parity error
LCDOut $fe,$C0, " " ;Erase the whole 2nd line
SELECT CASE WeekDay
CASE 1
LCDOut $FE,$80+10, "Mon"
CASE 2
LCDOut $FE,$80+10,"Tue"
CASE 3
LCDOut $FE,$80+10, "Wed"
CASE 4
LCDOut $FE,$80+10,"Thu"
CASE 5
LCDOut $FE,$80+10, "Fry"
CASE 6
LCDOut $FE,$80+10,"Sat"
CASE 7
LCDOut $FE,$80+10,"Sun"
END SELECT
LCDOut $fe,$C0, DEC Day, " "
SELECT CASE Month
CASE 1
LCDOut $FE,$C0+3, "January"
CASE 2
LCDOut $FE,$C0+3, "February"
CASE 3
LCDOut $FE,$C0+3, "March"
CASE 4
LCDOut $FE,$C0+3, "April"
CASE 5
LCDOut $FE,$C0+3, "May"
CASE 6
LCDOut $FE,$C0+3, "June"
CASE 7
LCDOut $FE,$C0+3, "July"
CASE 8
LCDOut $FE,$C0+3, "August"
CASE 9
LCDOut $FE,$C0+3, "SeptembR"
CASE 10
LCDOut $FE,$C0+3, "October"
CASE 11
LCDOut $FE,$C0+3, "November"
CASE 12
LCDOut $FE,$C0+3, "December"
END SELECT
LCDOut $FE,$C0+12, "20", DEC2 Year
ENDIF
ELSE ;Else 'Signal' = FALSE, we have no signal found
GOTO ReceiveError
ENDIF
'*********************ovu tu je za usporedbu dva uzastopna ocitanja vremena i ako se poklapaju onda se podaci salju preko serout naredbe na drugi PIC
FLAG=FLAG+1
IF FLAG=1 THEN
YEAR_OLD=YEAR
MONTH_OLD =MONTH
DAY_OLD=DAY
HOUR_LCD_OLD=HOURLCD
ENDIF
IF FLAG=2 THEN gosub ISPIS
IF FLAG=3 THEN FLAG =0
'**************************************************************************************************************************************************************
GOTO MainLoop
GongSignal:
IF LDR = ONn THEN ;If there is daylight or the shadedlamps are switched on, then...
LOW Volume ;...Volumepin low = Volume from gong louder...
ELSE ;...else (is it dark in the living-room)...
INPUT Volume ;...Volumepin 3-state = Volume from gong softly
ENDIF
PAUSE 155
IF Minute = 00 OR Test = AAN THEN Gong1 = ONn ;On the whole hours (and with Test) follows a 3-tone signal
Gong2 = ONn ;On the half hours only a 2-tone signal
SecondPulse = ONn ;Ondertussen gaat ook de seconde puls gewoon door
PAUSE 500
Gong1 = OFFF
Gong2 = OFFF
SecondPulse = OFFF
PAUSE 330 ;985 - 500 - 155
Second =SECOND+1
GOTO Further ;Go further with receiving the DCF bits from bit 15 (we omit bits 0...14)
ReceiveError:
LCDOut $FE,1
LCDOut $FE,$80, "No signal" ;Startbit not found or no signal?
REPEAT
CLEAR ;Erase all RAM
ID1 = DCF_Signal
WHILE DCF_Signal = ID1 ;Wait for signal changing
SignalCheck=SIGNALCHECK+1
PAUSE 1
WEND
ID1 = ID1 ^ 1
WHILE DCF_Signal = ID1 ;Wait for signal changing
SignalCheck=SIGNALCHECK+1
PAUSE 1
WEND
UNTIL SignalCheck < 990
Initialize = TRUE ;Initialize again after the error
GOTO MainLoop
ISPIS: 'rutina za slanje tocnog vremena na master PIC kontroler za korekciju RTC kola
IF YEAR_OLD=YEAR AND MONTH_OLD=MONTH AND DAY_OLD=DAY AND HOUR_LCD_OLD=HOURLCD THEN toggle PORTB.7
FLAG=0
RETURN