;******************************************************************** ;* * ;* Title : DCF * ;* Version : 0.9a 2. November 2004 * ;* Author : Uwe Nagel, Parkstr. 46, D-68766 Hockenheim * ;* Assembler : MPASM (c) Microchip * ;* * ;******************************************************************** #define TITEL "-DCF77-Uhr 0.9a-" ;--- Sprache der Wochentage und Monate ; wenn nichts definiert ist: deutsch #define english ;#define hungarian ;--- BAHN definieren, um den Eingang auf PORTB,0 statt auf PORTA,0 zu haben ; für mich, wegen Mutteruhr-Platine ;#define BAHN ;--- alterText definieren, um Datum im Format ; +----------------+ ; |20:03:15 MESZ ##| ; |Di 01.04.2003 ##| ; +----------------+ ; anzuzeigen, sonst ; +----------------+ ; |20:03:15 MESZ ##| ; |Di 01. APR 03 ##| ; +----------------+ ;#define alterText ;--- PE1DCD definieren, für lange Wochentage auf 2x20-Display ; +--------------------+ ; |20:03:15 Téli idő | ; |Csütörtök 12.08.2004| ; +--------------------+ ;#define PE1DCD ;--- CIOVALLADOLID definieren, um Sekundenimpulse und ; Zeitzeichen, wie im Radio, zu erzeugen ;#define CIOVALLADOLID ;--- EICHLER definieren um die beiden Schaltzeiten ( Unterprogramm alarm ) ; zu aktivieren. Es dürfen nicht CIOVALLADOLID und EICHLER gleichzeitig ; aktiv sein, da die gleichen Portleitungen verwendet werden ;#define EICHLER title TITEL __config _XT_OSC & _WDT_ON & _PWRTE_ON & _CP_OFF errorlevel -302 ; keine bank select message radix dec include include "pic16cxy.inc" ;****** Variablen *************************************************** cblock 0x0c save_w ; w und save_STATUS ; STATUS während interrupt flag ; diverse Bits temp tmp1 tmp2 zweihund ; 200 Interupts sind 1 Sek puls_zeit ; misst Pulsdauer ;*** diese Zeit wird angezeigt dispSec, dispMin, dispStd, dispTag, dispMon, dispJahr, dispWtag, dispStat ;*** hier kommt die gerade empfangene Zeit rein dcfMin, dcfStd, dcfTag, dcfMon, dcfJahr, dcfWtag, dcfStat ;*** zum Vergleich, die letzte Minute dcf1Min, dcf1Std, dcf1Tag, dcf1Mon, dcf1Jahr, dcf1Wtag filter endc #ifdef CIOVALLADOLID cblock SekPuls, BeepPuls, beeps endc #endif ;****** bits in flag ************************************************ #define neusync flag,0 #define alt flag,1 #define sekunde flag,2 #define syncd flag,3 #define dcfsign flag,4 #define comm flag,7 lc_data equ tmp1 ; local in lcd_write lcd_init_cnt equ tmp2 ; only used in lcd_init temp_lcd equ tmp2 ; temporary in write_lcd_char, clear_display temp_byte equ tmp2 ; temporary in write_byte ;****** Konstanten ************************************************** #define TICKS 200 ; für 3,2768 MHz Quarz ;******************************************************************** ;* Programmcode ... ;******************************************************************** org 0 goto main ;******************************************************************** ;* interrupt : ;******************************************************************** org 4 interrupt movwf save_w ; W und STATUS sichern swapf STATUS,w movwf save_STATUS bcf STATUS,RP0 ; Wähle register page 0 jnb INTCON,T0IF,end_t0_isr ; ist es timer interrupt ? #ifdef CIOVALLADOLID movf SekPuls,w btfsc STATUS,Z goto EndPuls1 decf SekPuls,f goto noPuls1 EndPuls1 bcf PORTA,1 bcf PORTA,2 noPuls1 movf BeepPuls,w btfsc STATUS,Z goto EndPuls2 decf BeepPuls,f goto noPuls2 EndPuls2 bcf PORTA,3 noPuls2 #endif ; increment filter if port=1 and filter if less than 8 ; decrement filter if port=0 and filter if greater than 0 #ifdef BAHN btfss PORTB,0 #else btfss PORTA,0 #endif goto port_is_0 port_is_1 incf filter,f btfsc filter,3 ; <8 ? port_is_0 decf filter,f btfsc filter,7 clrf filter ; set dcfsign if filter becomes 6 ; clear dcfsign if filter becomes 1 ; 0 1 2 3 4 5 6 7 6 5 4 3 2 1 0 ; 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 movf filter,w xorlw 6 btfsc STATUS,Z bsf dcfsign xorlw 6^1 btfsc STATUS,Z bcf dcfsign jb alt,NoPos jnb dcfsign,NoPos ;** positive Flanke... bsf alt clrf puls_zeit jnb neusync,NoNeg clrf dispSec movf dcfMin,w movwf dispMin movf dcfStd,w movwf dispStd movf dcfTag,w movwf dispTag movf dcfWtag,w movwf dispWtag movf dcfMon,w movwf dispMon movf dcfJahr,w movwf dispJahr movf dcfStat,w movwf dispStat movlw TICKS ; 218 für NTSC Quartz sonst 200 movwf zweihund bcf neusync bsf sekunde goto end_t0_isr NoPos: jnb alt,NoNeg jb dcfsign,NoNeg ;** fallende Flanke bcf alt movf puls_zeit,w addlw -30 call shiftDCF NoNeg: decfsz zweihund,f goto TimeOut ;** Sekunde abgelaufen movlw TICKS movwf zweihund call tick bsf sekunde TimeOut: incfsz puls_zeit,f ; 1,28 s keine steigende Flanke ? goto end_t0_isr call sec59 end_t0_isr bcf INTCON,T0IF ; lösche timer interrupt flag swapf save_STATUS,w movwf STATUS swapf save_w,f swapf save_w,w retfie ;****** táblák **************************************************** lcd_string_table addwf PCL,f lcd_init_table retlw 0x02 | 0x80 ; switch to 4 bit mode retlw 0x28 | 0x80 ; better do it twice retlw 0x28 | 0x80 ; init for 2x16 Display retlw 0x0c | 0x80 ; Display on, Cursor off, no blinking retlw 0x06 | 0x80 ; increment cursor, no display shift retlw 0x01 | 0x80 ; Clear Display, Cursor home dt TITEL ; Einschaltmeldung #ifndef PE1DCD ; Antennajel definiálás retlw 0x40 | 0x80 ; Pointer CG-Ram retlw b'00000000';0x00 retlw b'00000000';0x00 retlw b'00000000';0x00 retlw b'00000011';0x03 retlw b'00000100';0x04 retlw b'00000001';0x01 retlw b'00000000';0x00 retlw b'00000000';0x00 retlw b'00000000';0x00 retlw b'00000000';0x00 retlw b'00000000';0x00 retlw b'00011000';0x18 retlw b'00000100';0x04 retlw b'00000010';0x02 retlw b'00010001';0x11 retlw b'00001001';0x09 retlw b'00000110';0x06 bal also retlw b'00000001';0x01 retlw b'00000101';0x05 retlw b'00000100';0x04 retlw b'00001110';0x0e retlw b'00001110';0x0e retlw b'00011111';0x1f retlw b'00011111';0x1f retlw b'00001001';0x09 jobb also retlw b'00000001';0x01 retlw b'00000010';0x02 retlw b'00000000';0x00 retlw b'00000000';0x00 retlw b'00000000';0x00 retlw b'00000000';0x00 retlw b'00000000';0x00 #endif retlw 0xff ; Ende der Tabelle ifdef PE1DCD ifdef hungarian ;------------- lcd_mesz_table dt "Nyári idő ",0xff lcd_mez_table dt "Téli idő ",0xff else lcd_mesz_table dt "Summertime",0xff lcd_mez_table dt "Wintertime",0xff endif else ;PE1DCD-nek az else ifdef hungarian lcd_mesz_table dt "Nyár ",0xff lcd_mez_table dt "Téli ",0xff else lcd_mesz_table dt "CEST ",0xff lcd_mez_table dt "CET ",0xff endif endif ; PE1DCD wtag_table ifdef PE1DCD ifdef hungarian dt "---------",0xff dt "Hétfő ",0xff dt "Kedd ",0xff dt "Szerda ",0xff dt "Csütörtök",0xff dt "Péntek ",0xff dt "Szombat ",0xff dt "Vasárnap ",0xff else dt "---------",0xff dt "Monday ",0xff dt "Tuesday ",0xff dt "Wednesday",0xff dt "Thursday ",0xff dt "Friday ",0xff dt "Saturday ",0xff dt "Sunday ",0xff endif ;hung else ;pe addwf PCL,f ifdef hungarian dt "--HéKeSzCsPéSzVa" ; magyar else dt "--MoTuWeThFrSaSu" ; englisch endif endif ;PE1DCD month_table addwf PCL,f ifdef hungarian dt "---JanFebMarAprMajJunJulAugSzeOktNovDec" else dt "---JanFebMarAprMayJunJulAugSepOctNovDec" endif ;****** Főprogram *********************************************** main bsf STATUS,RP0 ; select Register-Page 1 movlf 0x03,OPTION_REG ; TMR0 internal clock/16 = 200Hz @ 3,2768MHz Quarz movlf 0x03,TRISA ; PORTA4-PORTA2 output; PORTA1 und 0 input #ifdef BAHN movlf 0x01,TRISB ; PORTB7..1 output, PORTB,0 input #else movlf 0x00,TRISB ; PORTB7..0 output #endif bcf STATUS,RP0 ; select Register-Page 0 clrf PORTA clrf PORTB clrf flag clrf puls_zeit movlf TICKS,zweihund clrf dispSec clrf dispMin clrf dispStd clrf dispWtag clrf dispJahr movlw 1 movwf dispMon movwf dispTag #ifdef CIOVALLADOLID clrf SekPuls clrf BeepPuls clrf beeps #endif movlf 0xa0,INTCON ; Enable TMR0-Int ;------ Display initke ------ call lcd_init ; init LC-Display hallo: clrwdt btfss sekunde goto hallo movlw 0x01 ; Clear Display call write_lcd_comm ;------ mainloop: clrwdt btfss sekunde goto mainloop bcf sekunde call showtime call special goto mainloop special #ifdef EICHLER ;****** Idő*** *********************************************** movf dispSec,w skpz return ; nur zu beginn einer Minute testen movf dispWtag,w andlw 0x06 xorlw 0x06 skpnz ; an Tagen 6 und 7 ist Wochenende return movf dispStd,w xorlw 0x09 skpz ; alle Schaltzeiten in der neunten Stunde return movf dispMin,w skpnz bsf PORTA,2 ; um 9:00 Uhr PORTA,2 an xorlw 0x15 skpnz bsf PORTA,3 ; um 9:15 Uhr PORTA,3 an xorlw 0x15 ^ 0x30 skpz return bcf PORTA,2 ; um 9:30 Uhr PORTA,2 aus bcf PORTA,3 ; und PORTA,3 aus return #else #ifdef CIOVALLADOLID ;****** Impulsausgabe *********************************************** special movlw 60 movwf SekPuls bsf PORTA,1 ; jede Sekunde 300ms Puls an PORTA,1 movf dispSec,w xorlw 0x02 skpnz bcf PORTA,4 ; PTT ab 2. Sekunde aus, egal welche Minute movf dispSec,w iorwf dispMin,w iorwf dispStd,w skpnz bsf PORTA,2 ; um 0:00:00 300ms Puls auf PORTA,28 movf dispMin,w xorlw 0x29 ; in 29. jz Beep1 xorlw 0x29^0x59 ; und 59. Minute jnz CIO_1 Beep1 movf dispSec,w ; ab Sekunde 53 PTT an xorlw 0x53 skpnz bsf PORTA,4 movf dispSec,w xorlw 0x55 ; und ab der 55. Sekunde jnz CIO_1 movlw 6 ; 6 mal piepsen movwf beeps CIO_1 movf beeps,w jz EndCIO movlw 100 ; der letzte 500ms decfsz beeps,f movlw 20 ; die anderen 100ms movwf BeepPuls bsf PORTA,3 EndCIO return #else return #endif #endif ;****** neue Sekunde anzeigen *************************************** showtime: #ifdef PE1DCD ; 01234567890123456789 ; +--------------------+ ; |20:03:15 Téli idő | ; |Csütörtök 12.08.2004| ; +--------------------+ ;-- 1. sor ;Óra movlw 0x80 call write_lcd_comm movf dispStd,w call write_byte movlw ':' call write_lcd_data movf dispMin,w call write_byte movlw ':' call write_lcd_data movf dispSec,w call write_byte movlw ' ' call write_lcd_data ;Idő számítás movlw lcd_mez_table-lcd_init_table btfsc dispStat,4 movlw lcd_mesz_table-lcd_init_table call lcd_string movlw ' ' call write_lcd_data ;-- 2. sor ; Napok movlw 0xc0 call write_lcd_comm rlf dispWtag,w ; 1..7 *2 movwf temp rlf temp,w ; *4 andlw 0xfc addwf dispWtag,w ; *5 movwf temp clrc rlf temp,w ; *10 addlw wtag_table-lcd_init_table call lcd_string movlw ' ' call write_lcd_data movf dispTag,w call write_byte movlw '.' call write_lcd_data #ifdef alterText movf dispMon,w call write_byte movlw '.' call write_lcd_data movlw 0x20 call write_byte #else movlw ' ' call write_lcd_data movf dispMon,w call write_month movlw ' ' call write_lcd_data #endif movf dispJahr,w call write_byte movlw ' ' call write_lcd_data return #else ; 0123456789abcdef ; wenn alterText definiert ist ; +----------------+ ; |20:03:15 MESZ ##| ; |Di 01.04.2003 ##| ; +----------------+ ; sonst ; +----------------+ ; |20:03:15 MESZ ##| ; |Di 01. APR 03 ##| ; +----------------+ ;-- 1. Zeile movlw 0x80 call write_lcd_comm movf dispStd,w call write_byte movlw ':' call write_lcd_data movf dispMin,w call write_byte movlw ':' call write_lcd_data movf dispSec,w call write_byte movlw ' ' call write_lcd_data movlw lcd_mez_table-lcd_init_table btfsc dispStat,4 movlw lcd_mesz_table-lcd_init_table call lcd_string btfsc syncd ; Antennensymbol movlw 0x00 btfss syncd movlw ' ' call write_lcd_data btfsc syncd movlw 0x01 btfss syncd movlw ' ' call write_lcd_data ;-- 2. Zeile movlw 0xc0 call write_lcd_comm movf dispWtag,w call write_wtag movlw ' ' call write_lcd_data movf dispTag,w call write_byte movlw '.' call write_lcd_data #ifdef alterText movf dispMon,w call write_byte movlw '.' call write_lcd_data movlw 0x20 call write_byte #else movlw ' ' call write_lcd_data movf dispMon,w call write_month movlw ' ' call write_lcd_data #endif movf dispJahr,w call write_byte movlw ' ' call write_lcd_data btfsc syncd ; Antennensymbol movlw 0x02 btfss syncd movlw ' ' call write_lcd_data btfsc syncd movlw 0x03 btfss syncd movlw ' ' call write_lcd_data return #endif ;******************************************************************** shiftDCF: rrf dcfJahr,f rrf dcfMon,f rrf dcfTag,f rrf dcfStd,f rrf dcfMin,f rrf dcfStat,f return ;******************************************************************** ;55555555 54444444 44433333 33333222 22222221 11111111 ;87654321 09876543 21098765 43210987 65432109 87654321 Sekunde ;PJJJJJJJ JMMMMMWW WTTTTTTP SSSSSSPm mmmmmm1a ooaR0000 DCF-Bits ; ;JJJJJJJJ 000MMMMM 00tttttt 00ssssss 0mmmmmmm 1aooaR00 00000www ; Jahr Monat Tag Stunde Minute STATUS Wtag ;******************************************************************** ; jetzt werden die empfangenen Bits erstmal umsortiert ; sec59: rlf dcfMon,w rlf dcfJahr,f ; =Jahr rlf dcfTag,w rlf dcfMon,w andlw 0x07 movwf dcfWtag ; =Wochentag Mo..So = 1..7 rrf dcfMon,f rrf dcfMon,f movlw 0x1f andwf dcfMon,f ; =Monat rrf dcfTag,f movlw 0x3f andwf dcfTag,f ; =Tag rrf dcfStd,w rrf dcfMin,f rrf dcfStat,f rrf dcfMin,f rrf dcfStat,f ; =STATUS movlw 0x7f andwf dcfMin,f ; =Minute rrf dcfStd,f rrf dcfStd,f movlw 0x3f andwf dcfStd,f ; =Stunde movlw dcf1Min movwf FSR call tickMin ; letzte Zeit weiterrechnen movf dcfMin,w ; und mit gerade empfangener xorwf dcf1Min,w ; Zeit vergleichen skpz goto ungleich movf dcfStd,w xorwf dcf1Std,w skpz goto ungleich movf dcfTag,w xorwf dcf1Tag,w skpz goto ungleich movf dcfMon,w xorwf dcf1Mon,w skpz goto ungleich movf dcfJahr,w xorwf dcf1Jahr,w skpz goto ungleich ;*** zwei aufeinanderfolgende Zeiten haben zueinander gepasst ;*** die aktuelle Zeit bei nächster Sekunde ins Display kopieren bsf syncd bsf neusync return ungleich: ;*** zwei aufeinanderfolgende Zeiten haben nicht eine Minute unterschied ;*** merken wir die gerade empfangene Zeit für die nächste Minute movf dcfMin,w movwf dcf1Min movf dcfStd,w movwf dcf1Std movf dcfTag,w movwf dcf1Tag movf dcfMon,w movwf dcf1Mon movf dcfJahr,w movwf dcf1Jahr bcf syncd return ;------ hier wird die Zeit weitergezählt tick: movlw dispSec movwf FSR call IncDec ; Sekunde movlw 0x60 xorwf INDF,w skpz return clrf INDF ; Sekunde=0 incf FSR,f ; ->Minute tickMin: call IncDec ; Minute movlw 0x60 xorwf INDF,w skpz return clrf INDF ; Minute=0 incf FSR,f ; -> Stunde call IncDec ; Stunde movlw 0x24 xorwf INDF,w skpz return clrf INDF ; Stunde=0 incf FSR,f tickTag: call IncDec ; Tag incf FSR,f ; ->Monat incf FSR,f ; ->Jahr incf FSR,f ; ->WTag incf INDF,f movlw 1 btfsc INDF,3 movwf INDF decf FSR,f ; ->Jahr decf FSR,f ; ->Monat movlw 8 subwf INDF,w movf INDF,w skpnc addlw -7 andlw 0x01 addlw 0x31 movwf temp movf INDF,w xorlw 2 ; Februar ? skpz goto nofeb movlw 0x30 movwf temp incf FSR,f ; ->Jahr movf INDF,w ; Jahr decf FSR,f ; ->Monat andlw 0x13 skpnz goto nofeb xorlw 0x12 skpnz goto nofeb movlw 0x29 movwf temp nofeb: decf FSR,f ; -> Tag movf temp,w xorwf INDF,w skpz return movlw 1 movwf INDF ; Tag=1 incf FSR,f ; -> Monat call IncDec movf INDF,w xorlw 0x13 skpz return movlw 1 movwf INDF ; Monat=1 incf FSR,f ; -> Jahr call IncDec return IncDec: incf INDF,f ; Zähler erhöhen movlw 6 addwf INDF,w ; +6 (Dez.-korrektur) --> Ergebnis vorerst in w btfsc STATUS,DC ; Überlauf im Low-Nibble? movwf INDF ; ja, Korr. Ergebn. zurück ;******************************************************************** ;************* LCD-Routinen ***************************************** ;******************************************************************** ;* Display is in 4 bit mode. Datalines connected to PORTB4..7 ;* PORTB3 = Register Select PORTB2 = Read not Write PORTB1 = Enable ;******************************************************************** LCEN equ 1 LCRW equ 2 LCRS equ 3 tst_lcd_busy movlf (1<