; #define Mengenlehreuhr #include __CONFIG 0x3B39 Stunde Equ 0x20 ; aktuelle Stunde Minute Equ 0x21 ; aktuelle Minute Sekunde Equ 0x22 ; aktuelle Sekunde dreiMSL Equ 0x23 ; 3ms-Zaehler (eigtl. 10/3 ms) low-Teil dreiMSH Equ 0x24 ; 3ms-Zaehler (eigtl. 10/3 ms) high-Teil weiterDML Equ 0x25 ; Sollwert fuer 3ms-Zaehler beim Warten low-Teil weiterDMH Equ 0x26 ; Sollwert fuer 3ms-Zaehler beim Warten high-Teil weiterT1L Equ 0x27 ; Sollwert fuer Timer1Zaehler beim Warten low-Teil weiterT1H Equ 0x28 ; Sollwert fuer Timer1Zaehler beim Warten high-Teil tara Equ 0x29 ; zum Tarieren der Zeitkonstante dZFlL Equ 0x2A ; 3ms-Zaehlerstand bei letzter Flanke low-Teil dZFlH Equ 0x2B ; 3ms-Zaehlerstand bei letzter Flanke high-Teil Stati Equ 0x2C ; 0: letzter/aktueller Pegel der DCF77-Empfängers ; 1: Fehler innerhalb der letzten Funkminute ; 2: MEZ/MESZ-Umstellung am Ende der Stunde ; 3: MESZ? ; 4: Schaltsekunde am Ende der Stunde ; 6: letzte Minute kam per Funk ; 7: letzte Stunde kam per Funk tmpL Equ 0x2D ; temporaerer Speicher tmpH Equ 0x2E ; temporaerer Speicher Spalten Equ 0x2F ; zu aktivierende Spalten Zeilen Equ 0x30 ; zu aktivierende Zeile(n) dat0 Equ 0x31 ; Funkdaten, Bit 0..7 dat1 Equ 0x32 ; Funkdaten, Bit 8..15 dat2 Equ 0x33 ; Funkdaten, Bit 16..23 dat3 Equ 0x34 ; Funkdaten, Bit 24..31 dat4 Equ 0x35 ; Funkdaten, Bit 32..39 dat5 Equ 0x36 ; Funkdaten, Bit 40..47 dat6 Equ 0x37 ; Funkdaten, Bit 48..55 dat7 Equ 0x38 ; Funkdaten, Bit 56..58 bzw. 63 GOTO Anfang RETFIE Anfang ; nach den Interrupts BCF STATUS, RP0 BCF STATUS, RP1 ; Bank0 CLRF Stunde ; eigene Variablen initialisieren CLRF Minute CLRF Sekunde MOVLW 0x12 MOVWF Stunde MOVLW 0x34 MOVWF Minute MOVLW 0x56 MOVWF Sekunde CLRF dat0 CLRF dat1 CLRF dat2 CLRF dat3 CLRF dat4 CLRF dat5 CLRF dat6 CLRF dat7 CLRF dreiMSH CLRF dreiMSL MOVLW 0x2C MOVWF weiterDML MOVLW 0x01 MOVWF weiterDMH CLRF weiterT1L CLRF weiterT1H CLRF Stati BSF Stati, 1 MOVLW 0x85 MOVWF tara ; eigentlich 5 1/3 (die 0x80 entspricht einer Null!) CLRF PORTA ; I/O initialisieren CLRF PORTB CLRF PORTC BSF STATUS, RP0 ; Bank 1 MOVLW 0x06 ; Port-A digital MOVWF ADCON1 MOVLW 0x38 ; alles Ausgaenge bis auf A3, A4 und A5 MOVWF TRISA CLRF TRISB ; alles Ausgaenge CLRF TRISC ; alles Ausgaenge BCF PIE1, TMR1IE ; Interrupt für Timer deaktivieren BCF STATUS, RP0 ; Bank 0 MOVLW 0x01 ; Timer1 initialisieren MOVWF T1CON ; MOVLW 0xC0 ; MOVWF INTCON Multiplex #ifdef Mengenlehreuhr MOVF Minute, 0 CALL BCD2Un MOVWF Spalten SWAPF Spalten, 1 MOVF Minute, 0 CALL BCD2Un5H IORWF Spalten, 1 ; anzuzeigende Minutenteile ; BTFSC Stati, 1 ; Funkfehler? ; GOTO SekTaktAnzeigen MOVF Stati, 0 MOVWF tmpL RRF Stati, 0 ANDWF tmpL, 1 ; tmpL<6> = Stati<6> & Stati<7> (Funk korrekt?) BTFSC Stati, 1 BCF tmpL, 6 ; tmpL<6> = Stati<6> & Stati<7> & NOT Stati<1> (Funk korrekt?) RLF PORTA, 0 XORWF tmpL, 1 ; tmpL<6> = (Stati<6> & Stati<7> & NOT Stati<1>) XOR PORTA<5> BTFSC tmpL, 6 ; Funksignal auf Sekunden-LED geben ; BTFSC PORTA, 5 BSF Spalten, 3 GOTO ErsteZeileSetzen SekTaktAnzeigen BTFSC Sekunde, 0 ; Sekunde auf Sekunden-LED geben BSF Spalten, 3 ErsteZeileSetzen #else MOVF Sekunde, 0 ; Sekunde als nächstes anzeigen MOVWF Spalten #endif MOVLW 0x4 MOVWF Zeilen CALL Wait #ifdef Mengenlehreuhr MOVF Minute, 0 CALL BCD2Un5L MOVWF Spalten #else MOVF Minute, 0 MOVWF Spalten ; Minute als nächstes anzeigen #endif MOVLW 0x2 MOVWF Zeilen CALL Wait #ifdef Mengenlehreuhr MOVF Stunde, 0 CALL BCD2Un5L ANDLW 0xF0 MOVWF Spalten MOVF Stunde, 0 CALL BCD2Un IORWF Spalten, 1 #else MOVF Stunde, 0 ANDLW 0x3F MOVWF Spalten ; Stunde als nächstes anzeigen MOVF Stati, 0 MOVWF tmpL RRF Stati, 0 ANDWF tmpL, 1 RLF PORTA, 0 XORWF tmpL, 1 BTFSC tmpL, 6 BSF Spalten, 6 ; Funksignal auf ZusatzLED geben #endif MOVLW 0x1 MOVWF Zeilen CALL Wait GOTO Multiplex ; Unterprogramme Sek ; Sekunde eins weiter stellen BTFSC PORTA, 3 ; Tastendruck? CALL Std BTFSC PORTA, 4 CALL Min INCF Sekunde, 1 MOVLW 0x0F ; 0x0F-Teil von Sekunde anschauen ANDWF Sekunde, 0 SUBLW 0x0A ; = A ? BTFSC STATUS, Z GOTO Sek10 ; neue 10Sek! RETURN ; Sek erfolgreich erhöht Sek10 MOVLW 0x10 ; Sekundenzehner weiter stellen ADDWF Sekunde, 1 MOVLW 0xF0 ; Sekundeneiner löschen ANDWF Sekunde, 1 MOVLW 0x60 ; = 60 ? SUBWF Sekunde, 0 BTFSC STATUS, Z GOTO Min ; neue Minute! RETURN ; erfolgreiche neue 10Sek Min ; Minute eins weiter stellen MOVLW 0x3F ANDWF Stati, 1 ; Funkmin. & Funkstd. zurücksetzen CLRF Sekunde INCF Minute, 1 MOVLW 0x0F ; 0x0F-Teil von Minute anschauen ANDWF Minute, 0 SUBLW 0x0A ; = A ? BTFSC STATUS, Z GOTO Min10 ; neue 10Min! RETURN ; Min erfolgreich erhöht Min10 MOVLW 0x10 ; Minutenzehner weiter stellen ADDWF Minute, 1 MOVLW 0xF0 ; Minuteneiner löschen ANDWF Minute, 1 MOVLW 0x60 ; = 60 ? SUBWF Minute, 0 BTFSC STATUS, Z GOTO Std ; neue Stunde! RETURN ; erfolgreiche neue 10Min Std ; Stunde eins weiter stellen BTFSC Stati, 4 ; Schaltsekunde? INCF Sekunde, 1 BCF Stati, 4 ; und rücksetzen BTFSS Stati, 2 ; ME(S)Z-Umstellung? GOTO keineSZUmstellung BCF Stati, 2 ; rücksetzen MOVLW 0x08 XORWF Stati, 1 ; ME(S)Z-Merker umschalten BTFSC Stati, 3 INCF Stunde, 1 ; etwas rabiat, sollte bei einer Umstellung zwischen ; 2 und 3 Uhr aber funktionieren BTFSS Stati, 3 DECF Stunde, 1 ; dito keineSZUmstellung CLRF Minute INCF Stunde, 1 MOVLW 0x0F ; 0x0F-Teil von Stunde anschauen ANDWF Stunde, 0 SUBLW 0x0A ; = A ? BTFSC STATUS, Z GOTO Std10 ; neue 10Std! MOVLW 0x24 ; = 24 ? SUBWF Stunde, 0 BTFSC STATUS, Z CLRF Stunde ; neuer Tag RETURN ; Std erfolgreich erhöht Std10 MOVLW 0x10 ; Stundenzehner weiter stellen ADDWF Stunde, 1 MOVLW 0xF0 ; Stundeneiner löschen ANDWF Stunde, 1 RETURN ; erfolgreiche neue 10Std Wait MOVF tara, 0 ADDWF weiterT1L, 1 ; + (0x00;tara) BTFSC STATUS, C INCF weiterT1H, 1 MOVLW 0x80 ADDWF weiterT1L, 1 ; + (0x00;0x80) BTFSC STATUS, C INCF weiterT1H, 1 MOVLW 0x0C ; + (0x0C;0x00) ADDWF weiterT1H, 1 ; Solltimerstand setzen (für 300Hz) WLoop MOVF weiterT1H, 0 MOVWF tmpL MOVF TMR1L, 0 SUBWF weiterT1L, 0 BTFSS STATUS, C DECF tmpL, 1 MOVF TMR1H, 0 SUBWF tmpL, 1 BTFSS tmpL, 7 ; weiterT1 - TMR1 >= 0x8000 ("<0"), dann skippen GOTO WLoop MOVLW 0xF8 ANDWF PORTA, 1 MOVF Spalten, 0 MOVWF PORTB MOVF Zeilen, 0 IORWF PORTA, 1 MOVLW 0xFF BTFSS PORTA, 5 MOVLW 0x00 XORWF Stati, 0 ANDLW 0x01 BTFSS STATUS, Z CALL FlankeGefunden INCF dreiMSL, 1 ; 3MS zählen BTFSC STATUS, Z INCF dreiMSH, 1 ; 3*256MS zählen MOVF weiterDMH, 0 ; weiterDM = dreiMS ? SUBWF dreiMSH, 0 BTFSS STATUS, Z RETURN ; nein ! MOVF weiterDML, 0 SUBWF dreiMSL, 0 BTFSS STATUS, Z RETURN ; nein ! ; ja ! CALL setzeWeiterDM ; neue Marke setzen CALL Sek ; neue Sekunde RETURN ; Wait FlankeGefunden MOVF dZFlH, 0 SUBWF dreiMSH, 0 MOVWF tmpH MOVF dZFlL, 0 SUBWF dreiMSL, 0 BTFSS STATUS, C DECF tmpH, 1 MOVWF tmpL ; tmp:= dreiMS - dzFl BTFSS Stati, 0 GOTO warLow BCF Stati, 0 ; war High-Pegel MOVF tmpH, 0 BTFSS STATUS, Z ; tmp >= 0x0100 ? GOTO periodenFehler ; Fehler! MOVF tmpL, 0 SUBLW 0x4B ; tmp > 75? (entspricht 250 ms) BTFSS STATUS, C GOTO periodenFehler ; Fehler! MOVLW 0x0A ; tmp < 10? (entspricht 33 ms) SUBWF tmpL, 0 BTFSS STATUS, C GOTO periodenFehler ; Fehler! MOVLW 0x28 SUBWF tmpL, 0 ; tmp >= 40? (entspricht 133 ms) -> empfangenes Bit RRF dat0, 1 RRF dat1, 1 RRF dat2, 1 RRF dat3, 1 RRF dat4, 1 RRF dat5, 1 RRF dat6, 1 RRF dat7, 1 ; die Pegellänge interessiert bei low nicht RETURN warLow BSF Stati, 0 ; war Low-Pegel MOVF tmpH, 0 BTFSC STATUS, Z ; tmp <= 0x00FF ? (= 0,85 s) GOTO keineNeueFunkMinute SUBLW 0x02 BTFSS STATUS, C ; tmp > 0x02FF ? (= 2,56 s) GOTO periodenFehler ; Fehler! BTFSS tmpH, 1 ; tmp <= 0x01FF ? (= 1,70 s) GOTO keineNeueFunkMinute BTFSS Stati, 1 ; wenn kein Fehler, dann CALL neueFunkMinute CLRF dat0 ; Funk-Werte initialisieren CLRF dat1 CLRF dat2 CLRF dat3 CLRF dat4 CLRF dat5 CLRF dat6 CLRF dat7 BSF dat0, 7 BCF Stati, 1 ; Fehler zurücksetzen keineNeueFunkMinute MOVF dreiMSH, 0 ; Überprüfung, ob neue Sekunde eingeleitet werden muss SUBWF weiterDMH, 0 MOVWF tmpH MOVF dreiMSL, 0 SUBWF weiterDML, 0 BTFSS STATUS, C DECF tmpH, 1 MOVWF tmpL ; tmp := weiterDM - dreiMS MOVF tmpH, 0 BTFSS STATUS, Z ; wenn tmp >= 0x0100 GOTO keineExtraSek ; dann gab's schon 'ne neue Sekunde vom Quarz MOVF tmpL, 0 SUBLW 0x96 BTFSS STATUS, C ; wenn tmp >= 0x0096 (= 150) GOTO keineExtraSek ; dann gab's schon 'ne neue Sekunde vom Quarz BTFSS Stati,1 ; wenn der Funk spinnt, wird nicht an der Zeit gespielt! CALL Sek keineExtraSek BTFSS Stati,1 ; wenn der Funk spinnt, wird nicht an der Zeit gespielt! CALL setzeWeiterDM ; neue Marke setzen GOTO FlankenZeitSpeichern periodenFehler ; wenn die Pegelperiode nicht stimmt, muss ; trotzdem mindestens die Zeitmarke gesetzt werden BSF Stati, 1 FlankenZeitSpeichern MOVF dreiMSL, 0 MOVWF dZFlL MOVF dreiMSH, 0 MOVWF dZFlH RETURN ; FlankeGefunden neueFunkMinute MOVLW 0x10 ; dat7, 5 ist das 0. Bit in Wikipediazählweise XORWF dat7, 0 ANDLW 0x3F BTFSS STATUS, Z ; Anfang nicht korrekt durchgeschoben? RETURN BTFSS dat4, 1 ; 20. Bit sollte immer 1 sein! RETURN BCF Stati, 2 BTFSC dat5, 5 ; 16. Bit (MEZ/MESZ-Umstellung) BSF Stati, 2 MOVLW 0xC0 ANDWF dat5, 0 XORLW 0x40 BTFSC STATUS, Z ; 17. & 18. Bit -> Sommerzeit! BSF Stati, 3 XORLW 0xC0 BTFSC STATUS, Z ; 17. & 18. Bit -> keine Sommerzeit! BCF Stati, 3 ; Im Falle von Fehlern werden diese Bits ignoriert! BCF Stati, 4 BTFSC dat4, 0 ; 19. Bit -> Schaltsekunde am Ende der Stunde? BSF Stati, 4 RRF dat3, 0 MOVWF tmpH RRF dat4, 0 MOVWF tmpL ; (dat3;dat4) eins verschoben merken RRF tmpH, 1 RRF tmpL, 1 ; noch eins verschieben MOVF tmpL, 0 ; -> bit21..bit28 (Minute mit Parität) MOVWF tmpH ; Parität prüfen: RRF tmpH, 1 XORWF tmpH, 1 ; benachbarte Bits XORen MOVF tmpH, 0 RRF tmpH, 1 RRF tmpH, 1 XORWF tmpH, 1 ; Übernächste Nachbarn XORen MOVF tmpH, 0 RRF tmpH, 1 RRF tmpH, 1 RRF tmpH, 1 RRF tmpH, 1 XORWF tmpH, 1 ; üüübernächste Nachbarn XORen BTFSC tmpH, 0 ; gerade Parität! GOTO Funkminutenfehler MOVF tmpL, 0 ANDLW 0x0F SUBLW 0x09 BTFSS STATUS, C ; Minuteneiner >9 ? GOTO Funkminutenfehler MOVF tmpL, 0 ANDLW 0x70 SUBLW 0x50 BTFSS STATUS, C ; Minutenzehner >5 ? GOTO Funkminutenfehler MOVF tmpL, 0 ANDLW 0x7F ; Parität löschen MOVWF Minute ; Minute setzen CLRF Sekunde ; Sekunde auf 0 CALL setzeWeiterDM ; Sekunde auf ,0 BSF Stati, 6 Funkminutenfehler RRF dat2, 0 RRF dat3, 0 MOVWF tmpL ; (dat3;dat4) eins verschoben merken RRF tmpL, 0 ; noch eins verschieben ANDLW 0x7F ; falsche Bits löschen MOVWF tmpL ; -> bit29..bit25 (Stunde mit Parität) MOVWF tmpH ; Parität prüfen: MOVWF tmpH RRF tmpH, 1 XORWF tmpH, 1 ; benachbarte Bits XORen MOVF tmpH, 0 RRF tmpH, 1 RRF tmpH, 1 XORWF tmpH, 1 ; Übernächste Nachbarn XORen MOVF tmpH, 0 RRF tmpH, 1 RRF tmpH, 1 RRF tmpH, 1 RRF tmpH, 1 XORWF tmpH, 1 ; üüübernächste Nachbarn XORen BTFSC tmpH, 0 ; gerade Parität! GOTO Funkstundenfehler MOVF tmpL, 0 ANDLW 0x0F SUBLW 0x09 BTFSS STATUS, C ; Stundeneiner >9 ? GOTO Funkstundenfehler MOVF tmpL, 0 ANDLW 0x30 SUBLW 0x20 BTFSS STATUS, C ; Stundenzehner >2 ? GOTO Funkstundenfehler MOVF tmpL, 0 ANDLW 0x3F SUBLW 0x23 BTFSS STATUS, C ; Stunde >23 ? (ohne Einerüberprüfung!) GOTO Funkstundenfehler MOVF tmpL, 0 ANDLW 0x3F MOVWF Stunde ; Stunde setzen BSF Stati, 7 Funkstundenfehler RETURN ; neueFunkMinute setzeWeiterDM ; setzt weiterDM-Zähler auf nächste 1/300s-Zeit MOVLW 0x01 ADDWF dreiMSH, 0 MOVWF weiterDMH ; high-Teil + 1 MOVLW 0x2C ADDWF dreiMSL, 0 ; low-Teil + 44 BTFSC STATUS, C INCF weiterDMH, 1 ; Übertrag MOVWF weiterDML ; -> /300 RETURN ; setzeWeiterDM #ifdef Mengenlehreuhr BCD2Un5L ; bcd zu unär (5er, low-teil) SUBLW 0x09 SUBLW 0x04 BTFSC STATUS, DC ; 5er an? GOTO BCD2Un5LUng ADDLW 0x05 ANDLW 0xF0 BTFSC STATUS, Z ; =0 ? RETLW 0x00 XORLW 0x10 BTFSC STATUS, Z ; =10 ? RETLW 0xC0 XORLW 0x30 BTFSC STATUS, Z ; =20 ? RETLW 0xF0 XORLW 0x10 BTFSC STATUS, Z ; =30 ? RETLW 0xFC RETLW 0xFF ; >=40 BCD2Un5LUng ; 5er muss gesetzt werden ANDLW 0xF0 BTFSC STATUS, Z ; =5 ? RETLW 0x80 XORLW 0x10 BTFSC STATUS, Z ; =15 ? RETLW 0xE0 XORLW 0x30 BTFSC STATUS, Z ; =25 ? RETLW 0xF8 XORLW 0x10 BTFSC STATUS, Z ; =35 ? RETLW 0xFE RETLW 0xFF ; >=40 BCD2Un5H ; bcd zu unär (5er, high-teil) SUBLW 0x09 SUBLW 0x04 BTFSC STATUS, DC ; 5er an? GOTO BCD2Un5HUng ADDLW 0x05 ANDLW 0xF0 XORLW 0x50 BTFSC STATUS, Z ; =50 ? RETLW 0x06 RETLW 0x00 ; <=40 BCD2Un5HUng ; 5er muss gesetzt werden ANDLW 0xF0 XORLW 0x40 BTFSC STATUS, Z ; =45 ? RETLW 0x04 XORLW 0x10 BTFSC STATUS, Z ; =55 ? RETLW 0x07 RETLW 0x00 ; <=40 BCD2Un ; bcd zu unär (1er) ANDLW 0x0F BTFSC STATUS, Z ; =0 ? RETLW 0x00 XORLW 0x01 BTFSC STATUS, Z ; =1 ? RETLW 0x08 XORLW 0x03 BTFSC STATUS, Z ; =2 ? RETLW 0x0C XORLW 0x01 BTFSC STATUS, Z ; =3 ? RETLW 0x0E XORLW 0x07 BTFSC STATUS, Z ; =4 ? RETLW 0x0F XORLW 0x01 BTFSC STATUS, Z ; =5 ? RETLW 0x00 XORLW 0x03 BTFSC STATUS, Z ; =6 ? RETLW 0x08 XORLW 0x01 BTFSC STATUS, Z ; =7 ? RETLW 0x0C XORLW 0x0F BTFSC STATUS, Z ; =8 ? RETLW 0x0E RETLW 0x0F #endif END