.nolist .include "2313def.inc" ;ggf. anpassen .list .DEF DividentHHigh= R13 ;hier steht später das Ergebnis .DEF DividentHigh= R14 ;hier steht später das Ergebnis, R14 .DEF DividentMH = R15 ;hier steht später das Ergebnis, R15 .DEF DividentML = R16 ;hier steht später das Ergebnis, R16 .DEF DividentMLL = R17 .DEF DividentLow = R18 ;hier steht später das Ergebnis, R18 .DEF DividentLLow = R19 ;hier steht später das Ergebnis, R19 .DEF DivisorHHigh = R20 ;bleibt unverändert .DEF DivisorHigh = R21 ;bleibt unverändert .DEF DivisorMH = R22 ;bleibt unverändert .DEF DivisorML = R23 ;bleibt unverändert .DEF DivisorMLL = R24 ;bleibt unverändert .DEF DivisorLow = R25 ;bleibt unverändert .DEF DivisorLLow = R26 ;bleibt unverändert .DEF RestHHigh = R4 .DEF RestHigh = R5 .DEF RestMH = R6 .DEF RestML = R7 .DEF RestMLL = R8 .DEF RestLow = R9 .DEF RestLLow = R10 .DEF Schleife = R31 ; Achtung, Z-Register wird beeinflusst oder nimmt Einfluss .def over_low = r1 .def over_high = r2 ; r3....r15 werden zur Darstellung der dreizehn Dezimalzahlen verwendet .def temp1 = r16 .def temp2 = r17 .def temp3 = r18 .def zaehler = r19 .def zaehler2 = r20 .def zaehler3 = r21 .def Mittel5 = r19 .def rmp = r19 ; wird für Bin2ToDigit gebraucht .def rBin1HH = r29 .def rBin1H = r28 ; wird für Bin5ToBCD13 gebraucht .def rBin1MH = r27 .def rBin1ML = r26 .def rBin1L = r25 ; wird für Bin5ToBCD13 gebraucht .def rBin2HH = r24 .def rBin2H = r23 ; wird für Bin5ToBCD13 gebraucht .def rBin2MH = r22 ; wird für Bin5ToBCD13 gebraucht .def rBin2ML = r21 .def rBin2L = r20 ;--------------------------------------------------------' ;Interrupttabelle: rjmp Initial ; nach RESET zum Hauptprogramm reti ; Externer Interrupt 0 nicht verwendet reti ; Externer Interrupt 1 nicht verwendet reti reti rjmp Timer1 ;Timer0 Überlauf-Int. Initial: ldi temp1, RAMEND ;Stackpointer initialisieren out SPL, temp1 ldi temp1,0b10000000 ; Interrupt bei T/C1-Überlauf Bit7 -> TC1 out TIMSK,temp1 ldi temp1, 0b00000000 ; PortD als Eingang out DDRD, temp1 ldi temp1, 0 out PORTB, temp1 ldi temp1, 0b11111101 ; Port B = Ausgang für's LCD, an PB1 Pull-ups aus lassen out DDRB, temp1 ; so bleibt der Zähleingang hochohmig!! ; rcall lcd_init ;Display initialisieren !!!!!!!!!!!!!!!!!!!! ; rcall lcd_clear ;Display löschen ;_________________________________ _schleife: ldi rBin1HH, 0 ldi rBin1H, 0 ; ldi rBin1L, 0 ; clr temp1 ; Nullen der Zählerregister out TCNT1H, temp1 ; Beim Schreiben immer zuerst das high-Byte schreiben! out TCNT1L, temp1 ; Dann erst das low-Byte. clr over_low ; Zählvariablen nullen, die die Überläufe des Timers1 mit 16-Bit Breite erfassen clr over_high ; rcall clear ; R3 bis R15 auf 0 setzen ; ldi temp2, 0 ; Das Zählregister für die Anzahl der Periodenmessungen auch auf 0 setzen. Oder clear macht das. ;hier wird die Erfassung der Signalflanken geändert, damit bei mehr als einer Periodendauer der Zähler nicht unterbricht. sei flop: ; hier die Abfragerei des Portpins PortD PD5 machen und den Zählerstand in vier Registern bereitstellen. sbic PinD,5 ; warten, bis der Pin zum ersten Mal Low ist rjmp flop _flap: sbis PinD,5 ; warten auf die steigende Flanke (Beginn der Meßzeit, Zähler starten) rjmp _flap ldi temp1, 1 ; 1 bedeutet für T/C1 den internen Quarztakt direkt verwenden. out TCCR1B,temp1 ; TOR ÖFFNEN für T/C1. Abfrage des Überlaufs durch Interrupt! flup: sbic PinD,5 ; warten, bis der Pin wieder Low ist (fallende Flanke). rjmp flup _flup: sbis PinD,5 ; warten auf die steigende Flanke (Ende der Meßzeit, Zähler anhalten) rjmp _flup inc temp2 ; Zählvariable um eins erhöhen ; cpi temp2, 10 ; 10 Durchläufe --> der konstante Divisor muß mit diesem Faktor erweitert werden. 0x 04 8C 27 39 50 00 = 10^13 / 2 durch 1 000 000 = 50,00 000 braucht 48-Bit-Division, gleiches Ergebnis, aber nur über 10 Perioden gemittelt ; cpi temp2, 100 ; 100 Durchläufe --> der konstante Divisor muß mit diesem Faktor erweitert werden. 0x 2D 79 88 3D 20 00 = 10^14 / 2 durch 10 000 000 = 50,00 000 braucht 48-Bit-Division, gleiches Ergebnis, mit 6 Nachkommastellen ; cpi temp2, 128 ; 128 Durchläufe --> der konstante Divisor muß mit diesem Faktor erweitert werden. 0x 3A 35 29 44 00 00 = 6,4+10^13 durch 12 800 000 = 50,00 000 braucht 48-Bit-Division, gleiches Ergebnis, aber mit längerer Mittelung ;neu in Version 12: der konstante Divisor für 56-Bit-Division und 6 Nachkommastellen: ; cpi temp2, 10 ; 10 Durchläufe --> der konstante Divisor muß mit diesem Faktor erweitert werden. 0x 00 2D 79 88 3D 20 00 = 10^14 / 2 durch 1 000 000 = 50,00 000 braucht 56-Bit-Division, jetzt Ergebnis mit 6 Nachkommastellen, aber nur über 10 Perioden gemittelt cpi temp2, 100 ; 100 Durchläufe --> der konstante Divisor muß mit diesem Faktor erweitert werden. 0x 01 C6 BF 52 63 40 00 = 10^15 / 2 durch 10 000 000 = 50,000 000 braucht 56-Bit-Division, jetzt Ergebnis mit 6 Nachkommastellen ; cpi temp2, 128 ; 128 Durchläufe --> der konstante Divisor muß mit diesem Faktor erweitert werden. 0x 02 46 13 9C A8 00 00 = 6,4+10^14 durch 12 800 000 = 50,000 000 braucht 56-Bit-Division, jetzt Ergebnis mit 6 Nachkommastellen breq loop ; bei Gleichstand springe heraus rjmp flup ; springe zurück an den Anfang der Schleife loop: ldi temp1, 0 ; out TCCR1B,temp1 ; TOR SCHLIEßEN für T/C1. cli ;********************************************** ; ab hier den Zählerstand verarbeiten und auf dem Display anzeigen ; in Divident steht hinterher das Ergebnis ldi DivisorHHigh, 0x00 ldi DivisorHigh, 0x00 ldi DivisorMH, 0x00 mov DivisorML, over_high ; Zählerstand unteres Byte lesen mov DivisorMLL, over_low ; Zählerstand unteres Byte lesen in DivisorLLow, TCNT1L ; Zählerstand unteres Byte zuerst lesen, siehe Dabla Seite 15: $2C ($4C) TCNT1L Timer/Counter 1 Low Byte in DivisorLow, TCNT1H ; Zählerstand oberes Byte danach lesen, siehe Dabla Seite 15: $2D ($4D) TCNT1H Timer/Counter 1 High Byte ; rcall div56 ; Division 56 Bit: 1000000000000 = 10 hoch XX durch Zählerstand rechnen ;Übergabe der Werte von DIV56 an Bin5ToBcd13 ;Achtung! R16 ist doppelt belegt: DividentML = R16 und temp1 = R16 ; DividentHigh; oberste Stelle wird nicht berücksichtigt mov rBin1HH, DividentMH ; erste Stelle, die durch Bin5ToBcd13 umgewandelt wird, Eingabe ist nur 5 Bytes breit mov rBin1H, DividentML ; R16 ist doppelt belegt: DividentML = R16 und temp1 = R16 mov rBin1MH, DividentMLL mov rBin1ML, DividentLow mov rBin1L, DividentLLow ldi ZH,0 ldi ZL,0x03 ;Die BCD-Zahlen beginnend bei Register drei eintragen ; rcall Bin5ToBcd13 ;Umwandeln der 56-Bit Binärzahl in dreizehn Stellen BCD ;und noch die Ausgabe ans LCD... rjmp _schleife ;wieder von Anfang an, neuer Durchlauf ;_____________________________________ Timer1: push temp3 push temp2 ; Variblen der Interruptroutine werden auf Stack gesichert push temp1 ; Inhalt des Registers auf Stack sichern in temp1,SREG ; Statusregister sichern push temp1 ; dito ;um die Überläufe des T/C1 zu zählen (zählt die Frequenz am externen Eingang) clr temp2 ldi temp1, 0x01 ; nur Register+Register löst Carry-Flag aus! add over_low, temp1 ; Überläufe des T/C1 mit weiteren zwei Bytes hochzählen adc over_high, temp2; carry addieren plus genulltes Register pop temp1 ; Statusregister vom Stack holen out SREG, temp1 ; dito pop temp1 ; Inhalt des Registers vom Stack holen pop temp2 pop temp3 reti ;______________________________________ Hallo Allerseits, ich habe hier mit dem AT90S2313 einen reziproken Frequenzzähler zur Messung der 50 Hz der Netzfrequenz aufgebaut und programmiert. Der Brumm wird vom Trafo über Kondensator und Schmitt-Trigger aus zwei Tansistoren bereit gestellt und dem 16-Bit Timer1 gegeben. Die Überläufe werde in zwei weiteren Registern aufzummiert. Das vollständige Programm zeigt mir den Messwert, also die aufsummierten Zählpulse während einer Messung sowie den reziproken Wert an, also eine passende große Zahl dividiert durch den Messwert ergibt ungefähr 50,000 Hz mit Nachkommastellen. Quarzfrequenz ist 5 MHz. Ich habe die Wahl, ob nur eine Periode, zehn Perioden oder 100 Perioden zur Messung heran gezogen werden, indem einfach die Flankenerkennung die Perioden mitzählt bis zur gewünschten Anzahl. Nun habe ich die Ausgabe verglichen mit den zwei, drei im Internet verfügbaren online-Anzeigen, die allesamt drei Nachkommastellen bieten und untereinander ziemlich genau überein stimmen. https://www.netzfrequenz.info/ (zwei Sekunden Intervall) https://www.netzfrequenzmessung.de/ (eine Sekunde Intervall) https://50hz.ewelt.net mit STM32 (tendentiell immer geringerer Wert als die anderen beiden, 4 Nachkommastellen) Es zeigt sich, daß mein Programm in etwa das gleiche anzeigt, jedoch immer etwas mehr, nämlich in der dritten Nachkommastelle etwa 3 zu viel, gestern 5 zu viel . Das bedeutet, daß der Messwert zu klein sein muß. Wo könnte ich denn beim Zählen der vorbei kommenden Flanken einen Fehler gemacht haben? Klar ist, die Befehle für Sprung und Abfrage brauchen immer ein, zwei Takte, um zu reagieren. Könnte es sein, daß bei 100 Perioden 100 Flanken zu wenig unter kommen? Vielleicht blickt diesbezüglich jemand durch und kann behilflich sein. Danke im Voraus. mit freundlichem Gruß