; Binäruhr mit 6 Bit bei Sekunden und Minuten, 5 Bit bei Stunden ; LED-Array gemultiplext zwischen RA0 - RA2 und RB0 - RB5 ; RA0 out high-aktiv Sekunden Zeile ; RA1 out high-aktiv Minuten Zeile ; RA2 out high-aktiv Stunden Zeile ; RA4 in - DCF-Signal vom Empfänger (100ms oder 200ms high; 900ms oder 800ms low) ; RA3 in high-aktiv Taster Abfrage (gemultiplext mit RA0 - RA2) ; RB6 in low-aktiv Spannungskontrolle ; RB0 out low-aktiv 2^0 Bit ; RB1 out low-aktiv 2^1 Bit ; RB2 out low-aktiv 2^2 Bit ; RB3 out low-aktiv 2^3 Bit ; RB4 out low-aktiv 2^4 Bit ; RB5 out low-aktiv 2^5 Bit ;************************************************************** #include __CONFIG _PWRTE_ON & _WDT_OFF & _XT_OSC ;************************************************************** ; Variablennamen vergeben Help_w Equ 0x22 ; Hilfsarbeitspeicher Aloops Equ 0x23 ; Zähler für Warteschleife Bloops Equ 0x24 ; Zähler für Warteschleife Bits Equ 0x25 ; Speicherstelle für einzelne Bits T1_Wert Equ 0x26 ; Betätigungszeit Taster1 Messen T2_Wert Equ 0x27 ; Betätigungszeit Taster2 Messen T3_Wert Equ 0x28 ; Betätigungszeit Taster3 Messen DCF_Zeit_L Equ 0x29 ; Zeit die das DCF_Signal Low ist DCF_Zeit_H Equ 0x2a ; Zeit die das DCF_Signal High ist DCF_BitN Equ 0x2b ; Zählt mit, welches Bit vom DCF nun kommt DCF_WertM Equ 0x2c ; Zähler zur Mittelung des DCF-Signals DCF_ok Equ 0x2d ; Stundenwechsel seit dem letzten erfolgreichen DCF-Empfang, 7 Bit gehört nicht zum Zähler Teiler Equ 0x2e ; Teiler für weiteres Herunterteilen des Timers Sekunden Equ 0x2f ; Speicher für die aktuellen Sekunden Minuten Equ 0x30 ; Speicher für die aktuellen Minuten Stunden Equ 0x31 ; Speicher für die aktuellen Stunden Min_dcf_zw Equ 0x32 ; Zwischenspeicher für die empfangenen DCF Minuten Std_dcf_zw Equ 0x33 ; Zwischenspeicher für die empfangenen DCF Stunden Sek_dcf Equ 0x34 ; Speicher für die empfangenen DCF Sekunden Min_dcf Equ 0x35 ; Speicher für die empfangenen DCF Minuten Std_dcf Equ 0x36 ; Speicher für die empfangenen DCF Stunden Help_w1 Equ 0x37 ; Konstanten definieren #define DCF_Bit_L Bits,0 #define DCF_Bit_H Bits,1 #define DCF_Good Bits,2 #define DCF_PortM Bits,3 #define DCF_ON Bits,4 #define Power_Good PORTB,6 #define DCF_Port PORTA,4 #define Sec_Zeile PORTA,0 #define Min_Zeile PORTA,1 #define Std_Zeile PORTA,2 #define T_Input PORTA,3 ;************************************************************** ; Initialisieren ; Ausgänge und 256 Hz-Timer einstellen bsf STATUS,RP0 ; auf Bank 1 umschalten movlw B'10000010' movwf OPTION_REG ; internen Takt zählen, Vorteiler zum Timer0, 8:1 movlw B'11111000' movwf TRISA ; PortA RA0-RA2 output, RA3,RA4 input movlw B'11000000' movwf TRISB ; PortB RB0-RB5 output, RB6 input bcf STATUS,RP0 ; auf Bank 0 zurückschalten clrf TMR0 ; (((2097152Hz : 4 ): 8 ): 256 = 256 Hz) ; Variablen setzen clrf T1_Wert clrf T2_Wert clrf T3_Wert clrf Sekunden clrf Minuten clrf Stunden clrf Bits clrf Teiler clrf DCF_WertM bsf DCF_WertM,3 clrf Min_dcf_zw clrf Std_dcf_zw clrf Min_dcf clrf Std_dcf clrf Sek_dcf clrf DCF_Zeit_L clrf DCF_Zeit_H clrf DCF_BitN clrf DCF_ok bsf DCF_ON ;************************************************************** goto all_on ;************************************************************** ; Tabelle für die Bitwertigkeit der empfangenen Bits (dcf) table movwf Help_w1 ; Den Wert des Aufrufs zwischenspeichern andlw B'11111000' ; Und Vergleichen, nur Werte zwischen 0 und 7 kommen durch btfss STATUS,Z retlw d'0' ; Wert über 7 => Zurück mit Wert 0 movfw Help_w1 addwf PCL,1 ; Die Wertigkeiten der Bits anspringen retlw d'0' ; 20 28 retlw D'1' ; 21 29 retlw D'2' ; 22 30 retlw D'4' ; 23 31 retlw D'8' ; 24 32 retlw D'10' ; 25 33 retlw D'20' ; 26 34 retlw D'40' ; 27 ;************************************************************** ; Alle LEDs kurz Aufblitzen lassen all_on bsf Sec_Zeile bsf Min_Zeile bsf Std_Zeile ; Alle Zeilen an clrf PORTB ; Alle LEDs an movlw D'250' ; 25 ms Pause call wait bcf Sec_Zeile bcf Min_Zeile bcf Std_Zeile ; Alle Zeilen aus ;************************************************************** ; Anzeige Hauptschleife anzeige ; Sekunden Anzeigen, Taster 1 abfragen comf Sekunden,0 ; Sekunden laden und negieren btfss DCF_ok,7 ; Wenn DCF_ok,7 = 0, dann LEDs auslassen movlw B'11111111' movwf PORTB ; Sekunden in PORTB schreiben bsf Sec_Zeile ; Sekunden an movlw D'3' ; 0.3 ms Pause call wait clrz btfsc T_Input incf T1_Wert,1 ; Wenn Taster 1 gedrückt, dann erhöhen btfsc STATUS,Z ; Wenn Taster 1 lange genug gedrückt(Überlauf; 256 Durchläufe; 1,14s), dann zum einstellmod goto einstellmod btfss T_Input clrf T1_Wert ; Wenn Taster 1 nicht gedrückt, dann Zähler löschen clrf PORTB bcf Sec_Zeile ; Sekunden aus movlw D'12' ; 1.2 ms Pause call wait ; Minuten Anzeigen comf Minuten,0 ; Minuten laden und negieren btfss DCF_ok,7 ; Wenn DCF_ok,7 = 0, dann LEDs auslassen movlw B'11111111' movwf PORTB ; Minuten in PORTB schreiben bsf Min_Zeile ; Minuten an movlw D'3' ; 0.3 ms Pause call wait clrf PORTB bcf Min_Zeile ; Minuten aus movlw D'12' ; 1.2 ms Pause call wait ; Stunden Anzeigen comf Stunden,0 ; Stunden laden und negieren btfss DCF_ok,7 ; Wenn DCF_ok,7 = 0, dann LEDs auslassen movlw B'11111111' movwf PORTB ; Stunden in PORTB schreiben bsf Std_Zeile ; Stunden an movlw D'3' ; 0.3 ms Pause call wait clrf PORTB bcf Std_Zeile ; Stunden aus movlw D'12' ; 1.2 ms Pause call wait goto anzeige ; Wiederholen ;********************************************************** ; Schleife wird 256 mal pro Sekunde ausgeführt zaehler ; Diese Schleife nur ausführen, wenn noch mindestens 0.5 ms gewartet werden soll movlw D'5' subwf Aloops,0 btfss STATUS,C return ; Wenn Aloops größer als 5, dann nicht zurück movlw D'3' subwf Aloops,1 ; Die Zeit, die die Schleifen etwa brauchen werden (ca 0.3ms) von der Wartevariable abziehen bcf INTCON,T0IF ; Interruptbit wieder löschen um das nächste Interrupt zu bemerken ; Tiefpass mit nachgeschaltetem Schmitt-Trigger btfsc DCF_Port incf DCF_WertM,1 ; Wenn DCF-Port 1, dann Mittelwert hochzählen btfss DCF_Port decf DCF_WertM,1 ; Wenn DCF-Port 0, dann Mittelwert runterzählen btfsc DCF_WertM,7 ; Wenn DCF_WertM,7 = 1, dann Wert größer 128, negativer Überlauf bcf DCF_PortM ; DCF_PortM auf 0 btfsc DCF_WertM,7 incf DCF_WertM,1 ; Wert wieder in den gewünschten Bereich zurückbringen btfsc DCF_WertM,3 ; Wenn DCF_WertM,3 = 1, dann Wert auf 8 gestiegen, Grenze bsf DCF_PortM ; DCF_PortM auf 1 btfsc DCF_WertM,3 decf DCF_WertM,1 ; Wert wieder in den gewünschten Bereich zurückbringen call anzeige_flacker ; Erzeugt Flackern falls letzter erfolgreicher DCF-Empfang zu lange zurückliegt btfss DCF_ON bcf DCF_PortM ; Wenn DCF_ON nicht 1, dann DCF_PortM immer wieder auf 0 => kein DCF-Empfang btfss DCF_ON bsf DCF_ok,7 ; Wenn DCF_ON nicht 1, dann DCF_Bit_OK immer 1, weil im Quarzmodus der Empfang nie zu lang her sein kann call dcf_zeit_fax ; DCF-Signale Auswerten, wenn eine gültige Zeit in Speicher, dann ist Sek_dcf größer 0 incf Teiler,1 ; Teiler um 1 erhöhen btfss STATUS,Z return ; Wenn Teiler noch nicht überläuft, dann zurück call zaehler_normal ; Sonst die Zähler bedienen call zaehler_dcf return ;********************************************************** ; Stellt die Anzeige für 8/256 aus, um zu signalisieren, dass letzter gültiger Empfang zu lange her anzeige_flacker bsf DCF_ok,7 movlw B'10000000' xorwf DCF_ok,0 btfss STATUS,Z return ; Wenn DCF_ok gleich 128 (nur Bit gesetzt, Zähler aber auf Null), dann flackern und nicht zurück movlw D'245' subwf Teiler,0 btfsc STATUS,C bcf DCF_ok,7 ; Wenn Teiler größer als 245, dann Anzeige aus return ;********************************************************** ; Normaler Zähler, der mit dem Teiler (Quarz und DCF abhängig) die Zeit zählt zaehler_normal incf Sekunden,1 ; Sekunden um 1 erhöhen movlw D'60' xorwf Sekunden,0 btfss STATUS,Z return ; Wenn Sekunden noch nicht 60, dann zurück incf Minuten,1 ; Minuten um 1 erhöhen clrf Sekunden ; Sekunden löschen movlw D'60' xorwf Minuten,0 btfss STATUS,Z return ; Wenn Minuten noch nicht 60, dann zurück incf Stunden,1 ; Stunden um 1 erhöhen clrf Minuten ; Minuten löschen movlw D'24' xorwf Stunden,0 btfsc STATUS,Z clrf Stunden ; Wenn Vergleich 0 ergibt, war Stunden vorher 24 movlw B'01111111' andwf DCF_ok,0 btfss STATUS,Z decf DCF_ok,1 ; Wenn DCF_ok ohne das Bit geleich 0, dann nicht mehr runterzählen, Empfang zu lange her return ;********************************************************** ; Schreibt bei gültigem Empfang zur vollen Minute die neue Zeit in die normalen Variablen zaehler_dcf movf Sek_dcf,1 ; Wenn Sek_dcf gleich 0, dann zurück, weil kein gültiger Empfang vorliegt btfsc STATUS,Z return incf Sek_dcf,1 ; Sek_dcf um 1 erhöhen movlw D'60' xorwf Sek_dcf,0 btfss STATUS,Z return ; Wenn Sek_dcf noch nicht 60, dann zurück movfw Min_dcf ; Min_dcf nach Minuten schreiben movwf Minuten movfw Std_dcf ; Std_dcf nach Stunden schreiben movwf Stunden clrf Sek_dcf ; Sek_dcf löschen clrf Sekunden ; Sekunden löschen movlw D'24' ; Erfolgreicher Empfang, Countdown wieder auf 24 Stunden setzen movwf DCF_ok return ;********************************************************** dcf_zeit_fax ; Liest die Daten aus dem DCF Brief, Aufruf 256 mal die Sekunde ; Wartet auf mindestens 1 Sekunde Pause im DCF um den Anfang zu erkennen btfsc DCF_PortM ; Wenn 1, dann DCF_Zeit_H erhöhen incf DCF_Zeit_H,1 btfsc DCF_PortM ; Wenn 1, dann DCF_Zeit_L löschen clrf DCF_Zeit_L clrz btfss DCF_PortM ; Wenn DCF-Port 0, dann DCF_Zeit_L erhöhen incf DCF_Zeit_L,1 btfsc STATUS,Z ; Wenn DCF_Zeit_L überläuft, dann 1 Sekunde Pause im Signal => neues Fax clrf DCF_BitN btfsc STATUS,Z clrf Min_dcf_zw btfsc STATUS,Z clrf Std_dcf_zw ; Länge der Signale messen um zu entscheiden, ob es korrekt als 1 oder 0 erkannt wurde btfsc DCF_PortM ; Wenn DCF-Port 1, dann zurück return movf DCF_Zeit_H,1 ; Wenn DCF_Zeit_H gleich 0, dann zurück btfsc STATUS,Z return bcf DCF_Bit_L ; Wenn high dann eine 0 bcf DCF_Bit_H ; Wenn high dann eine 1 movlw D'18' subwf DCF_Zeit_H,0 btfsc STATUS,C bsf DCF_Bit_L ; Wenn DCF_Zeit_H größer als 18, dann war Signal länger als 0,07 Sekunden => lang genug für eine 0 movlw D'34' subwf DCF_Zeit_H,0 btfsc STATUS,C bcf DCF_Bit_L ; Wenn DCF_Zeit_H größer als 34, dann war Signal länger als 0,13 Sekunden => zu lang für eine 0 movlw D'44' subwf DCF_Zeit_H,0 btfsc STATUS,C bsf DCF_Bit_H ; Wenn DCF_Zeit_H größer als 44, dann war Signal länger als 0,17 Sekunden => lang genug für eine 1 movlw D'59' subwf DCF_Zeit_H,0 btfsc STATUS,C bcf DCF_Bit_H ; Wenn DCF_Zeit_H größer als 59, dann war Signal länger als 0,23 Sekunden => zu lang für eine 1 bcf DCF_Good ; Mindestens DCF_Bit_H = 1 oder DCF_Bit_L = 1, dann wird DCF_Good gesetzt btfsc DCF_Bit_H bsf DCF_Good btfsc DCF_Bit_L bsf DCF_Good btfss DCF_Good ; Wenn ein Error, dann DCF_BitN auf 0 um neu zu beginnen, verzichte auf return clrf DCF_BitN btfsc DCF_Good ; Wenn ein kein Error... call teiler_dcf_sync clrf DCF_Zeit_H ; DCF_Zeit_H ausgewertet, wieder löschen (erst hier, damit in teiler_dcf_sync vorhanden) ; Die Bits nach Wertigkeit zuordnen movlw D'20' subwf DCF_BitN,0 call table btfss DCF_Bit_H clrw addwf Min_dcf_zw,1 movlw D'28' subwf DCF_BitN,0 call table btfss DCF_Bit_H clrw addwf Std_dcf_zw,1 movlw D'34' ; Zeit empfangen, jetzt prüfen xorwf DCF_BitN,0 btfsc STATUS,Z call dcf_zeit_test ; DCF-Zeit auf Schlüssigkeit prüfen incf DCF_BitN,1 return ;********************************************************** teiler_dcf_sync movfw DCF_Zeit_H ; Teiler_dcf syncronisieren subwf Teiler,0 btfss STATUS,C incf Teiler,1 ; Wenn Teiler_dcf kleiner als DCF_Zeit_H => + 1, incf, weil Carry unbeeinflusst btfsc STATUS,C decf Teiler,1 ; Wenn Teiler_dcf größer als DCF_Zeit_H => - 1, decf, weil Carry unbeeinflusst return ;********************************************************** ; Überprüft die empfangenen Zeiten auf Schlüssigkeit, bei Zeitumstellung Syncronisation mit 1 min Verspätung dcf_zeit_test movlw D'34' ; Sek_dcf auf die 34 Sekunde setzen movwf Sek_dcf incf Min_dcf,1 ; Zählt die Min_dcf hoch um zu gucken ob sie dann mit Min_dcf_zw passen movlw D'60' subwf Min_dcf,0 btfsc STATUS,C clrf Min_dcf btfsc STATUS,C incf Std_dcf,1 ; Wenn die Min_dcf überlaufen, dann auch die Std_dcf_zw +1 movfw Min_dcf xorwf Min_dcf_zw,0 btfss STATUS,Z clrf Sek_dcf ; Wenn die Minuten passen, dann Sek_dcf nicht löschen movlw D'24' ; Vergleicht Std_dcf mit Std_dcf_zw, wenn gleich, dann ok subwf Std_dcf,0 btfsc STATUS,C clrf Std_dcf movfw Std_dcf xorwf Std_dcf_zw,0 btfss STATUS,Z clrf Sek_dcf movfw Min_dcf_zw ; Min_dcf und Std_dcf mit Aktuellem füllen movwf Min_dcf movfw Std_dcf_zw movwf Std_dcf return ;********************************************************** einstellmod movlw B'11111111' movwf PORTB ; Alle Transistoren aus bsf Sec_Zeile ; Nur Sekundenzeile an movlw D'100' ; 10 ms Pause call wait btfsc T_Input goto einstellmod ; Warten bis Taster losgelassen bcf Sec_Zeile ; Jetzt Sekundenzeile aus clrf T1_Wert clrf T2_Wert clrf T3_Wert dcf_test movlw B'11100000' movwf PORTB bsf Sec_Zeile bsf Min_Zeile bsf Std_Zeile btfss DCF_Port bsf PORTB,2 btfss DCF_ON bsf PORTB,1 btfss DCF_ON bsf PORTB,3 call pol_taster btfsc T1_Wert,7 ; Taster 1 nächster Modus goto edit_sek_on btfsc T2_Wert,7 ; Taster 2 DCF off bcf DCF_ON btfsc T3_Wert,7 ; Taster 3 DCF on bsf DCF_ON goto dcf_test edit_sek_on bsf Sec_Zeile bcf Min_Zeile bcf Std_Zeile ; Nur Sekunden an clrf PORTB movlw D'250' ; 25 ms Pause call wait bcf Sec_Zeile ; Sekunden aus edit_sec call pol_taster comf Sekunden,0 ; Sekunden laden und negieren movwf PORTB ; Sekunden in PORTB schreiben bsf Sec_Zeile ; Sekunden an btfsc T1_Wert,7 ; Taster 1 nächster Modus goto edit_min_on btfsc T2_Wert,7 clrf Sekunden btfsc T2_Wert,7 clrf Teiler btfsc T3_Wert,7 clrf Sekunden btfsc T3_Wert,7 clrf Teiler goto edit_sec edit_min_on bcf Sec_Zeile bsf Min_Zeile bcf Std_Zeile ; Nur Minuten an clrf PORTB movlw D'250' ; 25 ms Pause call wait bcf Min_Zeile ; Minuten aus edit_min call pol_taster comf Minuten,0 ; Minuten laden und negieren movwf PORTB ; Minuten in PORTB schreiben bsf Min_Zeile ; Minuten an btfsc T1_Wert,7 ; Taster 1 nächster Modus goto edit_std_on btfsc T2_Wert,7 incf Minuten,1 movlw B'00111100' xorwf Minuten,0 btfsc STATUS,Z clrf Minuten btfsc T3_Wert,7 decf Minuten,1 movlw B'11111111' xorwf Minuten,0 btfsc STATUS,Z movlw B'00111011' btfsc STATUS,Z movwf Minuten ; Wenn -1 (255), dann Minuten auf 59 stellen goto edit_min edit_std_on bcf Sec_Zeile bcf Min_Zeile bsf Std_Zeile ; Nur Stunden an clrf PORTB movlw D'250' ; 25 ms Pause call wait bcf Std_Zeile ; Stunden aus edit_std call pol_taster comf Stunden,0 ; Stunden laden und negieren movwf PORTB ; Stunden in PORTB schreiben bsf Std_Zeile ; Stunden an btfsc T1_Wert,7 ; Taster 1 nächster Modus goto all_on btfsc T2_Wert,7 incf Stunden,1 movlw B'00011000' xorwf Stunden,0 btfsc STATUS,Z clrf Stunden btfsc T3_Wert,7 decf Stunden,1 movlw B'11111111' xorwf Stunden,0 btfsc STATUS,Z movlw B'00010111' btfsc STATUS,Z movwf Stunden ; Wenn -1 (255), dann Stunden auf 23 stellen goto edit_std pol_taster movlw D'3' ; 0.3 ms Pause, die Zeit für die Anzeige call wait bcf Sec_Zeile bcf Min_Zeile bcf Std_Zeile ; Alle Zeilen aus movlw B'11111111' ; Alle LEDs aus movwf PORTB movlw D'3' ; 0.3 ms Pause, damit LEDs sicher aus call wait ; Drücken von Taster 1 Überwachen bsf Sec_Zeile ; Taster 1 an movfw T1_Wert call ask_taster movwf T1_Wert bcf Sec_Zeile ; Taster 1 aus ; Drücken von Taster 2 Überwachen bsf Min_Zeile ; Taster 2 an movfw T2_Wert call ask_taster movwf T2_Wert bcf Min_Zeile ; Taster 2 aus ; Drücken von Taster 3 Überwachen bsf Std_Zeile ; Taster 3 an movfw T3_Wert call ask_taster movwf T3_Wert bcf Std_Zeile ; Taster 3 aus movlw D'3' ; 0.3 ms Pause, damit LEDs sicher aus call wait return ;********************************************************** ask_taster movwf Help_w bcf Help_w,7 ; Den Wert im Hilfsspeicher speichern und das Tasterbit löschen incf Help_w,1 ; Den Wert 1 hochzählen btfsc Help_w,5 bsf Help_w,7 btfss Help_w,6 bcf Help_w,7 ; Wenn Bit 5 (8) und Bit 6 (64, Schnellbit) wahr, dann Taster Bit setzen btfsc Help_w,7 bcf Help_w,5 ; Wurde Tasterbit gesetzt, dann Bit 5 zurücksetzen movlw D'12' call wait ; 1,2 ms Pause damit Tastersignal sicher gewechselt und LED ON/OFF Verhältnis stimmt btfss T_Input bsf Help_w,7 ; Taster nicht mehr gedrückt Tasterbit auch setzen movlw B'01111100' andwf Help_w,0 btfsc STATUS,Z bcf Help_w,7 ; Wenn der Wert noch nicht größer als 3, dann kann Tasterbit nie gesetzt sein movlw B'10000000' btfss T_Input andwf Help_w,1 ; Taster nicht mehr gedrückt Zähler resetten, Tasterbit lassen movfw Help_w return ;********************************************************** ; Ohne Anzeige power_save movlw B'11111111' movwf PORTB movlw B'00000000' movwf PORTA ; Alle Transistoren aus movlw D'5' ; Zeitkonstante setzen, damit Zähler ausgeführt werden kann movwf Aloops btfsc INTCON,T0IF ; Wenn Interuptbit gesetzt ist... call zaehler btfsc Power_Good goto power_save return ;********************************************************** ; Warteschleife wait movwf Aloops ; Zeitkonstante für gewünschte Wartezeit in 0.1 ms await movlw D'5' ; Zeitkonstante für 0.1ms movwf Bloops btfsc INTCON,T0IF ; Wenn Interuptbit gesetzt ist... call zaehler btfsc Power_Good call power_save ; Wenn der Power_Good Pin high wird dann Anzeige aus nop nop bwait nop nop nop nop nop decfsz Bloops, F ; 0.1 ms vorbei? goto bwait ; nein, noch nicht decfsz Aloops, F ; Wunschzeit vorbei? goto await ; nein, noch nicht return ; das Warten hat ein Ende ;********************************************************** end