Pfad: Home ==> Mikrobeginner ==> 13. Frequenzzähler, Induktivitätsmessgerät     This page in English (external): Flag EN
ATtiny24

Lektion 13: Frequenzzähler und Induktivitätsmessgerät


Und noch mal was richtig Praktisches: ein Frequenzzähler, mit Umwandlung von 24-Bit- und 40-Bit-Binärzahlen in ihre Dezimalentsprechung. Und obendrein ein praktisches Induktivitätsmessgerät, mit Quadrieren und Dividieren in Assembler.

13.0 Übersicht

  1. Einführung in die Frequenzmessung
  2. Einführung in die Dezimalumwandlung
  3. Digitalsignalmessung mit PCINT
  4. Analogsignalmessung mit Analogvergleicher
  5. Induktivitätsmessung mit PCINT

13.1 Einführung in die Frequenzmessung

13.1.1 Wahl der Torzeit

Die Messung von Frequenzen ist eigentlich trivial: man zählt einfach die Anzahl Sinuskurven des Eingangssignals über eine Sekunde und zeigt diese dann auf der LCD-Anzeige an. Nun ist eine Sekunde etwas lang.Wie wäre es mit 0,5 Sekunden oder gar 0,25 Sekunden?

Das Erkennen von Rechtecksignalen kann man mit dem Eingang INT0 oder, mit dem PCINT0 oder PCINT1, an jedem anderen Eingang vornehmen. Verwendet man INT0, kann man die zu erkennende Flanke (aufwärts, abwärts, beide) vorwählen. Beim PCINT tritt der Interrupt bei beiden Flanken ein, also pro Schwingung zweimal.

Die großartige Aufgabe in Assembler ist dann die Multiplikation der gezählten Impulse mit zwei oder vier. Der C-Programmierer wirft jetzt seine großartige Multiplikationsbibliothek an (und steigt erst mal auf einen größeren AVR-Typ um, weil ihm das Flash dadurch schon arg knapp wird), während der Assemblerkundige mit zweimaligem Links-Shiften und viermaligem Links-Rotieren in ganzen sechs Takten schon fertig ist, also z. B. so:

; Zaehlergebnis ueber 0,25 Sekunden in R3:R2:R1
	lsl R1 ; mal zwei
	rol R2
	rol R3
	lsl R1 ; mal vier
	rol R2
	rol R3

Wieso eigentlich drei Register? Mit denen lässt sich bis 256*256*256-1 = 16.777.215 zählen, also in einer Viertelsekunde bis 66,8 MHz. Also weit oberhalb dessen, was normale Elektronikbastler so an Schwingungen machen und auch weit oberhalb dessen, was so ein AVR normal zählen kann. Der ist mit 1 MHz Takt schon bei unter 100 kHz voll mit Zählen ausgelastet und geht in die Sättigung. Mit der folgenden Zähl-Interrupt-Serviceroutine kriegen wir nämlich folgende Ausführungszeiten:

; Interrupt starten: 4 Takte; Vektorsprung: 2 Takte
CntIsr:
	in R15,SREG ; SREG sichern, +1 = 7
	inc R1 ; Einer aufwaerts zaehlen, +1 = 8
	brne CntIsrRet ; +1/2 = 9/10
	inc R2 ; 256-er aufwaerts
	brne CntIsrRet
	inc R3 ; 65536-er aufwaerts
CntIsrRet: ; Minimum 10 Takte
	out SREG,R15 ; SREG wieder herstellen, +1 = 11
	reti ; +4 = 15

Mit 15 Takten sind bei 1 MHz Systemtakt 15 µs vergangen und bei 1.000.000 / 15 = 66.667 Hz ist es aus mit Zählen. Mit einem Takt von 8 MHz kommen wir immerhin noch bis 533 kHz Zählrate. Verwendet man zum Zählen den eingebauten Timer, indem man statt des Vorteilers den externen Eingang T1 (beim ATtiny24 PA4 am Pin 9) zählen lässt, kommt man etwa auf 250 kHz (1 MHz Takt) oder 2 MHz (8 MHz Takt). Allerdings hängt an diesem Pin in unserer Schaltung schon der Datenport D4 der LCD und wir müssten uns zusätzlich was einfallen lassen, wie wir wechselweise das Messsignal und den LCD-Datenport, lesend und schreibend, an diesen Pin bringen. Mit einem anderen AVR hätten wir dieses Problem möglicherweise nicht.

Wer noch mehr zählen will, taktet den AVR mit 20 MHz (maximal 1,3 MHz Zählrate) oder schaltet einen binären Vorteiler zwischen Messsignal und AVR, allerdings unter Einbußen bei der Auflösung.

Umgekehrt sind bei ganz niedrigen Frequenzen von weniger als 10 Hz (kommt selten vor) entweder längere Torzeiten angebracht. Oder man wechselt die Messmethode: man zählt einfach die Zeit t zwischen zwei Signalen, die Frequenz ist dann 1 / t. Die wären dann z. B. dadurch messbar, indem der Timer bei 1 MHz Takt mit einem Vorteiler von 1 zählt, wie lange es von Schwingung zu Schwingung braucht. Dann kriegt man direkt die Mikrosekunden. Durch Teilen von 1.000.000 durch diese Zahl kriegt man die Frequenz in mHz. Wie man solche großen Zahlen binär teilt (ohne wie der C-Programmierer die ganze riesige Fließkommabibliothek zu bemühen und dann doch auf einen 96-pinnigen ATxmega umzusteigen), kriegen wir etwas später in dieser Lektion.

13.1.2 Analogsignale auswerten

Oft tun uns zu messende Signale nicht den Gefallen, schon als steilflankige Rechteckschwingung mit 5 V Amplitude vorzuliegen. Die Signale von einem Mikrofon, einem Lautsprecher oder aus anderen Quellen sind Sinusse mit irgendeiner Amplitude von 5 mV (dynamisches Mikrofon) bis 2 V (Lautsprecher, 1 Watt an 4 Ohm). Der Elektronikbastler verstärkt jetzt diese Signale so viel, dass da schon ein Rechteck rauskommt und schickt dieses schon steile Signal noch mal durch einen Schmitt-Trigger. Jede Menge externe Elektronik jedenfalls.

Analogvergleicher Nicht so der AVR-Kundige. Der weiß, dass jeder uralte popelige AVR diese ganze Mimik schon an Bord hat und nur darauf harrt, eingeschaltet zu werden. Die Mimik nennt sich Analogvergleicher (Analog Comparator). Sie besteht aus einem Operationsverstärker, dessen positiver Eingang am Pin AIN0 (PA1) und dessen negativer Eingang am Pin AIN1 (PA2) angeschlossen ist. Das Vergleichsergebnis ist im Bit ACO im Analogstatus- und kontrollregister ACSR ablesbar. Ist das Bit ACIE (Bit 3) in diesem Register gesetzt, dann wird bei jedem Wechsel des Bits der Analogvergleicher-Interrupt ausgelöst und die Ausführung verzweigt an dessen Vektor-Adresse (beim ATtiny24 0x000C). Das kann man sich auch zum Frequenzmessen zunutze machen.

Damit ist fast alles schon vorhanden, um Analogsignale niedrigster Amplitude auf Polaritätswechsel hin zu untersuchen: die ausgelösten Interrupts müssen einfach nur gezählt werden. Es sind doppelt so viele wie die Frequenz, weil jeder Sinusdurchgang zweimal die Polarität wechselt. Wir können uns bei einer Messzeit von 250 ms also einmal Linksschieben und zweimal Linksrotieren des Zählergebnisses sparen.

13.1.3 Induktivitäten messen

Induktivitäten sind Spulen. Die Größe der Induktivität wird in Henry (H) angegeben. Ihre Größe lässt sich anhand des (Schein-)Widerstands messen, den sie einer Wechselspannung mit der Frequenz F entgegensetzen. Dieser Scheinwiderstand Z ergibt sich aus der Formel
ZL (Ohm) = 2 * Π * F (Hz) * L (H)

Darin wird der Teil "2 * Π * F" auch als Kreisfrequenz bezeichnet und mit ω abgekürzt.

Nun lässt sich der Widerstand nur etwas aufwändig messen, besonders, da es sich um Wechselspannung handeln muss. Eleganter, und viel einfacher, ist es, die Spule mit einem Kondensator zu einem Schwingkreis zu verschalten. Schwingkreise lassen sich bekanntlich zum Schwingen anregen. Sie schwingen dann auf der Frequenz, bei der der Scheinwiderstand der Spule gleich groß ist wie der des Kondensators. Dessen Scheinwiderstand ist umgekehrt zur Frequenz (je größer die Frequenz, desto kleiner der Widerstand), also
ZC = 1 / (ω * C (Farad))

Die Gleichheit der beiden Scheinwiderstände ZL = ZC zeitigt die Schwingungsgleichung
ZL = ZC oder ω * L = 1 / (ω * C) oder ω2 = 1 / (L * C) oder ω = √(1/(L * C)) oder F = 1 / (2 * Π) * √(1/(L * C))

Regt man den Schwingkreis mit der Spule und einem bekannten Kondensator zum Schwingen an, kann man aus der gemessenen Frequenz mit der Formel
L(H) = 1 / (4 * Π2 * C(F) * F(Hz)2)

direkt die Induktivität ermitteln.

Da der Assemblerprogrammierer solche komplizierten Formeln etwas scheut (der C-Programmierer nicht, der nimmt einfach seine Riesen-Fließkommabibliothek und steigt auf Mega um), müsste sich das mit etwas Intelligenz umformulieren lassen. Da sowohl 4 als auch Π2 als auch C sich nicht ändern, kann man 1 / (4 * Π2 * C) einmal ausrechnen und dann nur durch F2 teilen. Nehmen wir das Ganze noch mit 1.000.000 mal, kriegen wir die Induktivität in µH. Für einen Kondensator von 50 nF resultiert daraus die Zahl 506.605.918.079, oder hexadezimal 75.F4.10.D7.7F, eine 40-bittige Zahl.

Diese ist durch F2 zu teilen. Statt nun wieder die großartige Fließkomma-Bibliothek zu bemühen nimmt der Assemblerprogrammierer die gemessene Frequenz, einfach mit sich selbst mal. Für die Frequenzmessung kommt eine 24-bittige Zahl zum Einsatz (siehe oben), eigentlich liefert die beim Malnehmen ein 48-bittiges Ergebnis. Auf die oberen 8 Bit können wir verzichten.

Divisionsgrenzen Begrenzen wir F2 auf 40 Bits, darf F maximal 741,455 kHz werden, was bei 1 MHz Taktfrequenz ohnehin nicht mehr messbar ist.

Die Untergrenze ergibt sich daraus, dass die Ausgabe von Induktivitäten von über 999 H unnötig ist. Es kommen daher nur Frequenzen von 23 und mehr Hz für die Ausgabe in Frage.

13.1.3.1 Division 8-Bit durch 8-Bit

8-Bit-Division Die einfachste Division geht mit 8 Bits folgendermaßen. Zuerst wird das höchste Bit des Dividenten in den noch leeren Divisionsbereich hineingeschoben. Von diesen 8 Bits wird der Divisor abgezogen. Tritt dabei ein Überlauf auf, wird die Subtraktion wieder zurück genommen und eine Null in das Ergebnisregister geschoben. Trat kein Überlauf auf, wird eine Eins in das Ergebnis geschoben.

Diese Abfolge wird weitere sieben Male wiederholt und die Division ist fertig.
In Assembler sieht das so aus.

;
; Division 8 Bit durch 8 Bit
;
	ldi R16,0xEE ; Dividend
	ldi R17,10 ; Divisor
	ldi R18,8 ; Anzahl Bits
	clr R19 ; Dividend laufend
	clr R20 ; Ergebnis
Shift:
	lsl R16 ; Oberstes Bit Dividend 
	rol R20 ; in laufenden Dividend
	sub R20,R17 ; Divisor abziehen
	brcc Eins ; Carry clear = Eins
	add R20,R17 ; Divisor wieder addieren
	clc ; Ergebnisbit = 0
	rjmp Resultat ; in Ergebnis 
Eins:
	sec ; loesche Ergebnisbit
Resultat:
	rol R19 ; in Ergebnis rollen
	dec R18 ; abwaerts zaehlen
	brne Shift ; noch weiter
	nop ; fertig

Das Studio sagt, dass die Division 92 µs benötigt.

Eigentlich ist binäre Division einfacher als dezimale, da es ja immer nur entweder Abziehen (Eins) oder nicht Abziehen (Null) gibt.

13.1.3.2 Division 16-Bit durch 8-Bit

Bei 16 Bits kommen jeweils zwei Register zum Einsatz, bei denen Überträge mit addiert und subtrahiert werden.

;
; Division 16 Bit durch 8 Bit
;
	ldi R31,High(50000) ; Dividend
	ldi R30,Low(50000)
	ldi R16,75 ; Divisor, LSB
	clr R17 ; MSB
	clr R27 ; Ergebnis, MSB
	clr R26 ; LSB
	clr R18 ; Dividend, aktuell, LSB
	clr R19 ; MSB
	ldi R20,16 ; 16 Bits, Zaehler
Shift:
	lsl R30 ; Dividend links schieben
	rol R31 ; MSB
	rol R18 ; in aktuellen rollen, LSB
	rol R19 ; MSB
	sub R18,R16 ; subtrahiere Divisor, LSB
	sbc R19,R17 ; MSB
	brcc Eins ; kein Carry, schiebe 1
	add R18,R16 ; Carry, subtrahieren rueckgaengig
	adc R19,R17 ; MSB
	clc ; schiebe 0
	rjmp Ergebnis ; in das Ergebnis
Eins:
	sec ; schiebe 1
Ergebnis:
	rol R26
	rol R27
	dec R20
	brne Shift
	nop

Auch das ist nicht gerade riesiger Aufwand. Das Ganze braucht nun 265 µs.

13.1.3.3 Division 40-Bit durch 40-Bit

Nachdem das Prinzip nunmehr verstanden ist, ist die 40-Bit-Division eigentlich kein Problem mehr. Das Dividieren der 40-bittigen Zahl durch eine maximal 40-bittige Zahl (F2) mit einem potenziell 40-bittigen Resultat erfordert aber insgesamt 160 Bits oder 20 Register, weil für den Dividenten 80 Bits gebraucht werden. Bei 20 Registern zum Dividieren bleibt nicht viel für Anderes übrig. Die Lösung für diesen Engpass ist die Verlegung des Dividenten in das SRAM. Mit fünfmaligem

	ld R16,Z ; Z zeigt auf Tabelle im SRAM
	rol R16
	st Z+,R16

wird dann das jeweils höchstwertige Bit des verbleibenden Dividenten in das Carry geschoben und von da aus in den aktuellen Dividenden. Das braucht etwas länger, aber auch das ist kein Riesendrum.

Die folgende Tabelle vollzieht den Ablauf im Programm für eine gemessene Frequenz von 1000 Hz (=0x0003E8, F2 = 1.000.000 = 0x0F4240).
Dez.HexErgebnis hexNach Subtr.SubtrNach RollenRollenSRAM, HexSRAM, Dez
40280000000000000000000000000000000075F410D77F506.605.918.079
392700000000000000000001000000000011EBE821AEFE1.013.211.836.158
382600000000000000000003000000000031D7D0435DFC926.912.044.540
372500000000000000000007000000000071AFA086BBF8754.312.461.304
36240000000000000000000E0000000000E05F410D77F0409.113.294.832
35230000000000000000001D0000000001D1BE821AEFE0818.226.589.664
34220000000000000000003A0000000003A07D0435DFC0536.941.551.552
332100000000000000000075000000000751FA086BBF801.073.883.103.104
3220000000000000000000EB000000000EB1F410D77F001.048.254.578.432
311F000000000000000001D7000000001D71E821AEFE00996.997.529.088
301E000000000000000003AF000000003AF1D0435DFC00894.483.430.400
291D0000000000000000075F0000000075F1A086BBF800689.455.233.024
281C00000000000000000EBE00000000EBE0410D77F000279.398.838.272
271B00000000000000001D7D00000001D7D1821AEFE000558.797.676.544
261A00000000000000003AFA00000003AFA00435DFC00018.083.725.312
2519000000000000000075F4000000075F40086BBF800036.167.450.624
24180000000000000000EBE80000000EBE8010D77F000072.334.901.248
23170000000000000001D7D00000001D7D0021AEFE0000144.669.802.496
22160000000000000003AFA00000003AFA00435DFC0000289.339.604.992
211500000000000000075F4100000075F41186BBF80000578.679.209.984
2014000000000000000EBE82000000EBE8200D77F0000057.846.792.192
1913000000000100000E3AC4100001D7D0401AEFE00000115.693.584.384
1812000000000300000D3348100001C7588035DFC00000231.387.168.768
1711000000000700000B2450100001A669006BBF800000462.774.337.536
1610000000000F0000070661100001648A11D77F000000925.548.675.072
150F000000001E00000E0CC3000000E0CC31AEFE000000751.585.722.368
140E000000003D00000CD746100001C198605DFC000000403.659.816.960
130D000000007B00000A6C4D1000019AE8D1BBF8000000807.319.633.920
120C00000000F7000005965A1000014D89A077F0000000515.127.640.064
110B00000001EE00000B2CB5000000B2CB51EFE00000001.030.255.280.128
100A00000003DD000007172B1000016596B1DFC0000000960.998.932.480
90900000007BA00000E2E57000000E2E571BF80000000822.486.237.184
8080000000F7500000D1A6E100001C5CAE07F00000000545.460.846.592
7070000001EEB00000AF29D100001A34DD1FE000000001.090.921.693.184
6060000003DD7000006A2FB1000015E53B1FC000000001.082.331.758.592
5050000007BAE00000D45F7000000D45F71F8000000001.065.151.889.408
404000000F75D00000B49AF100001A8BEF1F0000000001.030.792.151.040
303000001EEBB000007511F1000016935F1E000000000962.072.674.304
202000003DD7600000EA23F000000EA23F1C000000000824.633.720.832
101000007BAED00000E023F100001D447F18000000000549.755.813.888
0Rdg000007BAEE00000CC23E100001C047E000000000000
Das Ergebnis der Division vor der Rundung, 506.606 µH, stimmt mit der Berechnung überein. Die Berechnung dauert laut Studio 277 µs für die Multiplikation, 2.919 µs für die Division und 487 µs für die Dezimalumwandlung, insgesamt 3.232 µs für alles. Nicht so arg lang für solche Riesenzahlen.

Damit steht der intelligenten Berechnung der Induktivität nichts mehr im Wege.

Home Top Frequenzen Dezimalumwandlung Digital Analog Induktivität


13.2 Einführung in die Dezimalumwandlung (24- und 32-Bit)

Schon in der Lektion 11 mit dem EEPROM-Einschaltzähler hatten wir 8- und 16-Bit-Zahlen von Binär in Dezimalzahlen verwandelt und dabei führende Nullen unterdrückt. Bei den Infrarot-Experimenten haben wir es uns einfach gemacht und die Zahlen aus gutem Grund lieber hexadezimal ausgegeben. Nun haben wir es mit Monsterzahlen von 24 und 32 Bit Länge zu tun. Ich bin mir nicht sicher, was der C-Programmierer jetzt macht, auf jeden Fall ist er auf eine riesige Fließkomma-Bibliothek angewiesen und steigt mindestens auf einen Mega, wenn nicht auf einen Xmega um. Was bloß das Gerücht, Assembler sei schwer zu lernen, aus ansonsten ganz cleveren Menschen machen kann.

Dabei ist die Erweiterung von 16-Bit-Dezimalumwandlung auf 24 oder 32 Bit lange Zahlen eigentlich ganz easy, wenn man das Prinzip mal verstanden hat: wiederholtes Abziehen der Dezimalzahlen, von der größten angefangen immer zehnmal weniger und nacheinander bis herunter zur 10. Entsprechend hatten wir bei 8 Bit mit dezimal 100 angefangen und bei 16 Bit mit dezimal 10.000. Bei 24 Bit (256 hoch 3 minus 1 = 16.777.215) beginnen wir mit 10 Millionen, bei 32 Bit (256 hoch 4 minus 1 = 4.294.967.295) eben einfach mit einer Milliarde. Spätestens bei 40 Bit stoßen wir allerdings auf eine Grenze, die mit den Eigenheiten von Assemblerprogrammen zu tun hat. Die verwalten nämlich Ganzzahlen manchmal als vorzeichenbehaftete 32-Bit-Zahlen und können daher eigentlich nur 31 Bit Länge und keinesfalls 40 Bit. Größere Zahlen muss man in Assembler auf andere Weise handhaben. In dieser Lektion werden wir es mit einer 40-Bit-Zahl zu tun kriegen.

Mehr dazu später, wenn wir es brauchen.

Home Top Frequenzen Dezimalumwandlung Digital Analog Induktivität


13.3 Digitalsignale messen mit PCINT

13.3.1 Aufgabenstellung

In der ersten Aufgabe sind digitale Rechtecksignale zu messen.

13.3.2 Hardware, Aufbau

Digitalsignalmessung Der Hardwareaufwand bei dieser Aufgabe ist Null. Die Signalquelle wird einfach an den Eingang PA3 angeschlossen.

Aufbau Digitalmessung So kann das Ganze aussehen.

Alternativer Aufbau

Wer dieses oder die nächsten Experimente lieber auf kompaktere Weise aufbauen möchte und die vielen Zuleitungen zur LCD fest verdrahtet sehen möchte, kann sich das
Board hier als gedruckte Platine bauen. Alle Programmbeispiele dieser und der nachfolgenden Lektionen laufen darauf ohne Änderungen.

13.3.3 Programm

Das Programm ist im Folgenden gelistet (der Quellcode ist hier).

;
; **************************************
; * Frequenzmessg Digital ATtiny24/LCD *
; * (C)2016 by www.gsc-elektronic.net  *
; **************************************
;
.NOLIST
.INCLUDE "tn24def.inc"
.LIST
;
; ----------- Programmablauf -----------
;
; Misst die Anzahl Pegelwechsel an PA0 mittels
; PCINT ueber eine Viertelsekunde lang, nimmt
; diese mit Zwei mal, wandelt das Ergebnis in
; eine Dezimalzahl um und gibt sie auf der LCD
; aus.
;
; ----------- Hardware -----------------
; Digitaler Frequenzzaehler Eingang an
;   PCINT3/PA3
;
; ----------- Timing -------------------
; Messzeit                 250 ms
; Prozessor-Takt     8.000.000 Hz
; TC1-Prescaler             64
; TC1-Takt             125.000 Hz
; TC1-Takte in 250 ms   31.250
.equ cTc1CmpA = 31249
;
; ----------- Messwertmittelung --------
; Aktueller Messwert        / 2 plus
; Vorheriger Messwert       / 4 plus
; Vorvorheriger Messwert    / 8 plus
; Vorvorvorheriger Messwert / 8 =
; Aktuelle Anzeige          = F
;
; ----------- Ports, Pins --------------
.equ pOut = PORTA ; Ausgabeport
.equ pDir = DDRA ; Richtungsport
.equ bIO = PORTB3 ; Pin-Out Digital
.equ bID = DDA3 ; Pin-Richtung Digital
;
; ----------- Register -----------------
; benutzt: R0, R1 fuer LCD
.def rM0L = R2 ; aktueller Messwert, LSB
.def rM0M = R3 ; dto., MSB
.def rM0H = R4 ; dto., HSB
; frei: R5 .. R14
.def rSreg = R15 ; Statusregister
.def rmp = R16 ; Vielzweckregister
.def rmo   = R17 ; Vielzweckregister
.def rLine = R18 ; LCD-Zeilenzaehler
.def rLese = R19 ; LCD-Register
.def rimp = R20 ; Vielzweck, Interrupts
.def rFlag = R21 ; Flaggen
	.equ bTO = 0 ; Timeout vom Timer
.def rHilf = R22 ; Hilfsregister Dezimal
; frei: R22 .. R25
; benutzt: R27:R26 X ; fuer diverse Zwecke
; frei: R29:R28 Y
; benutzt: R31:R30 Z ; fuer LCD
;
; ----------- SRAM ---------------------
.DSEG
.ORG 0x0060
sM: ; Messwertspeicher, vier Werte:
;  aktuell/2, letzter/4, vorletzter/8,
;    vorvorletzter/8
;  jeweils: L(+0), M(+1), H(+2)
.Byte 12
sMEnd:
;
; ---- Reset- und Int-Vektoren ---------
.CSEG
.ORG 0x0000
	rjmp Start ; Reset-Vektor, Init
	reti ; INT0 External Int 0
	rjmp Pci0Isr ; PCI Request 0
	reti ; PCINT1 PCI Request 1
	reti ; WDT Watchdog Time-out
	reti ; TIM1_CAPT TC1 Capture Event
	rjmp Tc1Isr ; TIM1_COMPA TC1 Compare Match A
	reti ; TIM1_COMPB TC1 Compare Match B
	reti ; TIM1_OVF TC1 Overflow
	reti ; TIM0_COMPA TC0 Compare Match A
	reti ; TIM0_COMPB TC0 Compare Match B
	reti ; TIM0_OVF TC0 Overflow
	reti ; ANA_COMP Analog Comparator
	reti ; ADC ADC Conversion Complete
	reti ; EE_RDY EEPROM Ready
	reti ; USI_STR USI START
	reti ; USI_OVF USI Overflow
;
; ----- Interrupt Service Routinen -----
;
; PCINT Interrupt
;   wird von jedem Pegelwechsel am PCINT3-
;   Eingang ausgeloest
;
; Erhoeht den 24-Bit-Zaehler rM0H:rM0M:rM0L
;
Pci0Isr: ; Impulse am Digitaleingang zaehlen
	in rSreg,SREG ; Status retten
	inc rM0L ; zaehlen
	brne Pci0IsrRet
	inc rM0M ; MSB erhoehen
	brne Pci0IsrRet
	inc rM0H
Pci0IsrRet:
	out SREG,rSreg ; Status herstellen
	reti
;
; TC1 Compare Match A Interrupt
;   wird nach Ablauf jedes CTC-Zyklusses
;   ausgeloest
;
; Ausloesung nach 64 * (31.249 + 1) / 8 =
;   250 ms.
;
; Stoppt den PCINT-Interrupt und setzt
; die bTO-Flagge die die Ergebnisaus-
; gabe ausloest
;
Tc1Isr: ; Timeout Zaehler
	in rSreg,SREG ; Status retten
	ldi rimp,0 ; Zaehlen anhalten
	out GIMSK,rimp ; Int-Disable
	sbr rFlag,1<<bTO ; Timeout-Flagge
	out SREG,rSreg ; Status herstellen
	reti
;
; ----------- Hauptprogramm-Init ------
Start:
	; Stapel einrichten
	ldi rmp,LOW(RAMEND) ; RAM-Ende
	out SPL,rmp ; in Stapelzeiger
	; Auf 8 MHz Takt umstellen
	ldi rmp,1<<CLKPCE ; Change Enable
	out CLKPR,rmp ; in Clock Prescaler
	ldi rmp,0 ; Precaler / 1
	out CLKPR,rmp
	; Port initialisieren
	sbi pOut,bIO ; Eingabepin Pullup
	cbi pDir,bID ; Eingabepin Input
	; LCD-Port-Ausgaenge initiieren
	ldi rmp,(1<<bLcdCRE)|(1<<bLcdCRRS)|(1<<bLcdCRRW)
	out pLcdCR,rmp ; Kontrollport-Ausgaenge
	clr rmp ; Ausgaenge aus
	out pLcdCO,rmp ; an Kontrollport
	ldi rmp,mLcdDRW ; Datenport-Ausgabe, Schreiben
	out pLcdDR,rmp ; auf Richtung Datenausgabeport
	; LCD Init
	rcall LcdInit ; starten LCD
	ldi ZH,High(2*LcdTextOut) ; Z auf Text
	ldi ZL,Low(2*LcdTextOut)
	rcall LcdText ; Gib Text aus
	; Timer Init
	ldi rmp,High(cTc1CmpA) ; Compare auf
	out OCR1AH,rmp ; Messzyklusdauer
	ldi rmp,Low(cTc1CmpA)
	out OCR1AL,rmp
	clr rmp ; TC1 Normal operation
	out TCCR1A,rmp
	ldi rmp,(1<<CS11)|(1<<CS10) ; Presc 64
	out TCCR1B,rmp
	ldi rmp,1<<OCIE1A ; Compare Match Int
	out TIMSK1,rmp
	; PCINT3 aktivieren
	ldi rmp,1<<PCINT3 ; Pin change PA3
	out PCMSK0,rmp ; maskieren
	ldi rmp,1<<PCIE0 ; PCINT0 Interrupt
	out GIMSK,rmp ; in Int-Maske
	; Sleep Mode
	ldi rmp,1<<SE ; Sleep enable
	out MCUCR,rmp ; in Kontrollregister
	; Interrupts enablen
	sei ; Ints zulassen
Schleife:
	sleep ; schlafen legen
	nop ; nach Aufwachen
	sbrc rFlag,bTO ; Timeout-Flagge?
	rcall Auswerten ; gesetzt, Auswerten
	rjmp Schleife
;
; Routine Auswerten der Zaehlergebnisse
;   wird von der bTO-Flagge ausgeloest
;
; Stoppt den Compare-Match-Int von TC1,
; nimmt den Messwert mit zwei Mal, mit-
; telt die aktuelle und die letzten drei
; Messungen (Durchschnitt ueber eine Se-
; kunde), gibt den Durchschnitt dezimal
; auf der LCD aus und startet die naech-
; ste Messung.
;
Auswerten:
	cbr rFlag,1<<bTO ; Flagge ruecksetzen
	clr rmp ; Compare Match Int aus
	out TIMSK1,rmp
	; Messwerte im SRAM verschieben+dividieren
	ldi ZH,High(sMEnd) ; Ziel
	ldi ZL,Low(sMEnd)
	ldi XH,High(sMEnd-3) ; Quelle
	ldi XL,Low(sMEnd-3)
	ld rmp,-X ; vorletzter nach vorvorletzter 
	st -Z,rmp ; kopieren
	ld rmp,-X
	st -Z,rmp
	ld rmp,-X
	st -Z,rmp
	ld rmp,-X ; letzter nach vorletzter+Division
	lsr rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	ld rmp,-X ; neuester nach letzter+Division
	lsr rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	st -Z,rM0H ; neuester ablegen
	st -Z,rM0M
	st -Z,rM0L
	adiw ZL,3 ; Zeiger auf letzten
	ldi rmp,4
	mov R0,rmp ; R0 ist Zaehler
Auswerten1:
	ld rmp,Z+ ; lese LSB
	add rM0L,rmp ; Zu aktuellem Ergebnis addieren
	ld rmp,Z+ ; lese MSB
	adc rM0M,rmp ; addieren mit Uebertrag
	ld rmp,Z+ ; lese HSB
	adc rM0H,rmp ; addieren mit Uebertrag
	dec R0
	brne Auswerten1 ; Weitere Werte addieren
	ldi ZH,1 ; LCD auf Ergebnisposition
	ldi ZL,8
	rcall LcdPos
	rcall DezimalAus ; gib dezimal aus
Neustart:
	clr rM0L ; Zaehler loeschen
	clr rM0M
	clr rM0H
	ldi rmp,1<<PCIE0 ; PCINT0 Interrupt
	out GIMSK,rmp ; in Int-Maske
	clr rmp
	out TCNT1H,rmp ; Zaehler ruecksetzen
	out TCNT1L,rmp
	ldi rmp,1<<OCIE1A ; Compare Match Int
	out TIMSK1,rmp
	ret
;
; 3 Byte-Zahl in rM0H:rM0M:rM0L in dezimal
;   auf der LCD ausgeben
;
; Wird von der Auswerte-Routine aufgerufen
; Verwendet die 24-Bit-Dezimalwert-Tabelle
; bis 9,99 MHz (maximal bis 0x98.96.7F)
; Unterdrueckt fuehrende Nullen und Dezimal-
; trennzeichen
;
DezimalAus:
	ldi ZH,High(2*DezimalTab)
	ldi ZL,Low(2*DezimalTab)
	clt ; Fuehrende Nullen
DezimalAus1:
	lpm XL,Z+ ; lese Dezimalzahl
	lpm XH,Z+
	lpm rHilf,Z+
	clr rmp ; Teilerzaehler
	cp XL,rmp
	brne DezimalAus2
	cp XH,rmp
	brne DezimalAus2
	cp rHilf,rmp
	breq DezimalAusEnd
DezimalAus2:
	sub rM0L,XL ; abziehen
	sbc rM0M,XH
	sbc rM0H,rHilf
	brcs DezimalAus3 ; Ueberlauf
	inc rmp
	rjmp DezimalAus2 ; weiter subtrahieren
DezimalAus3:
	add rM0L,XL ; Ruecknahme Subtraktion
	adc rM0M,XH
	adc rM0H,rHilf
	tst rmp ; Null?
	brne DezimalAus4 ; Nicht Null
	brts DezimalAus5 ; keine Nullen unterdr.
	ldi rmp,' '
	rcall LcdD4Byte
	ldi rmp,' '
	rjmp DezimalAusKomma
DezimalAus4:
	set ; keine fuehrenden Nullen unterdr.
DezimalAus5:
	subi rmp,-'0'
	rcall LcdD4Byte
	ldi rmp,'.'
DezimalAusKomma:
	cpi XL,Byte1(1000000)
	breq DezimalAusKomma1
	cpi XL,Byte1(1000)
	breq DezimalAusKomma1 
	rjmp DezimalAus1
DezimalAusKomma1:
	rcall LcdD4Byte
	rjmp DezimalAus1
DezimalAusEnd:
	ldi rmp,'0' ; letzte Ziffer
	add rmp,rM0L ; addieren
	rjmp LcdD4Byte
;
DezimalTab:
.db Byte1(1000000),Byte2(1000000)
.db Byte3(1000000),Byte1(100000)
.db Byte2(100000),Byte3(100000)
.db Byte1(10000),Byte2(10000)
.db Byte3(10000),Byte1(1000)
.db Byte2(1000),Byte3(1000)
.db Byte1(100),Byte2(100)
.db Byte3(100),Byte1(10)
.db Byte2(10),Byte3(10)
.db 0,0,0,0
;
; LCD Starttext
LcdTextOut:
.db "Frequenzmesser tn24 ",0x0D,0xFF
.db "F(dig)= x,xxx,xxx Hz",0x0D,0xFF
;            8
.db "                    ",0x0D,0xFF
.db "                    ",0xFE,0xFE
;
; LCD-Include
.include "Lcd4Busy.inc"
;
; Ende Quellcode
;

13.3.4 Messbeispiel

Mit einem quarzgetriebenen Signalgenerator liefert die Messung folgendes Ergebnis:

Signalgenerator Messergebnis

Die Übereinstimmung ist nicht berauschend, was an dem recht ungenauen RC-Generator im ATtiny24 liegt. Der ist bei 3 V Betriebsspannung kalibriert. Wer es genauer möchte, kann das Oscillator Calibration Byte verändern. Wie das gemacht wird, steht im Handbuch. Oder kann das Messergebnis per Multiplikation etwas genauer gestalten. Die entsprechenden Grundlagen für die Multiplikation sind alle hier beschrieben.

Home Top Frequenzen Dezimalumwandlung Digital Analog Induktivität


13.4 Analogsignalmessung mit Analogvergleicher

13.4.1 Aufgabe

Die Frequenz von sinusförmigen Wechselspannungen ab 5 mV(eff) sollen gemessen und angezeigt werden.

13.4.2 Hardware und Bauteile

Schaltbild

Schaltbild Analogfrequenzmessung Das ist die nötige Hardware zum Messen. Sie besteht im Wesentlichen aus einem Spannungsteiler, der für eine gewisse Ruhe sorgt, solange kein Signal angeschlossen ist. Die zu messende Wechselspannung wird über einen Kondensator zugeführt.

Bauteile

Elko 1 µF Das ist der 1 µF-Elko, der die Referenzspannung konstant hält. Das längere Bein ist wie immer der Pluspol.

Kondensator 100 nF Das ist eine mögliche Bauform des Folienkondensators von 100 nF.

Widerstand 100 k Das sind die beiden Widerstände von 100 k, aus denen der Spannungsteiler aufgebaut ist. Den 220 Ω hatten wir bereits früher.

Aufbau

Aufbau Analogmessung So oder ähnlich sieht der Aufbau der Schaltung aus. Wer die Anschlussdrähte der Widerstände etwas kürzt und die Schaltung kompakter aufbaut als hier gezeigt, kriegt weniger störende Streusignale in den Eingang.

13.4.3 Programm

Das Programm ist im Folgenden gelistet (hier geht es zum Quellcode). Eine Besonderheit und Unterschied zu allen bisherigen Formulierungen ist noch wichtig: der Betrieb des Analogvergleichers im Interruptmodus ist mit dem Schlafmodus inkompatibel. Manchmal, und unvorhersehbar, setzt im Schlafmodus das Aufwachen nach Interrupts völlig aus, d. h. weder Analogvergleicher- noch Timer-Interrupts wecken die CPU auf. Der Chip versinkt in den Dauerschlaf und die Messungen setzen aus. Nur ein Reset haucht der CPU wieder Leben ein, aber nur für eine gewisse Zeit lang. ATMEL beschreibt diesen Fehler im Handbuch korrekt. Diese Software arbeitet daher nicht im Schlafmodus.

Die Software misst nacheinander sowohl das Analogsignal wie auch das Signal am Digitaleingang. Beide Ereignisse werden von der gleichen Interrupt-Service-Routine gezählt, nur sind nacheinander der PCINT vom Digitaleingang und der Analogvergleicher-Int eingeschaltet. Der Softwareteil zur Mittelung arbeitet daher mit zwei SRAM-Puffern.

;
; *************************************
; * Frequenzmessg Analog ATtiny24/LCD *
; * (C)2016 by www.gsc-elektronic.net *
; *************************************
;
.NOLIST
.INCLUDE "tn24def.inc"
.LIST
;
; ----------- Programmablauf -----------
;
; Nacheinander werden
; a) die Anzahl Pegelwechsel am PCINT3-
;    Eingang,
; b) die Anzahl Pegelwechsel an den Analog-
;    vergleicher-Eingaengen
; ueber 250 ms lang gezaehlt, gemittelt und
; in Hz auf der LCD angezeigt.
;
; ----------- Hardware -----------------
; Analoger Frequenzzaehler am Analog-
;   vergleicher AIN0/PA1 und AIN1/PA2
;
; ----------- Timing -------------------
; Messzeit                 250 ms
; Prozessor-Takt     8.000.000 Hz
; TC1-Prescaler             64
; TC1-Takt             125.000 Hz
; TC1-Takte in 250 ms   31.250
.equ cTc1CmpA = 31249
;
; ----------- Messwertmittelung --------
; Aktueller Messwert        / 2 plus
; Vorheriger Messwert       / 4 plus
; Vorvorheriger Messwert    / 8 plus
; Vorvorvorheriger Messwert / 8 =
; Aktuelle Anzeige          = F
;
; ----------- Ports, Pins --------------
.equ pOut = PORTA ; Ausgabeport
.equ pDir = DDRA ; Richtungsport
.equ bIO = PORTB3 ; Pin-Out Digital
.equ bID = DDA3 ; Pin-Richtung Digital
;
; ----------- Register -----------------
; benutzt: R0, R1 fuer LCD
.def rM0L = R2 ; aktueller Messwert, LSB
.def rM0M = R3 ; dto., MSB
.def rM0H = R4 ; dto., HSB
; frei: R5 .. R14
.def rSreg = R15 ; Statusregister
.def rmp = R16 ; Vielzweckregister
.def rmo   = R17 ; Vielzweckregister
.def rLine = R18 ; LCD-Zeilenzaehler
.def rLese = R19 ; LCD-Register
.def rimp = R20 ; Vielzweck, Interrupts
.def rFlag = R21 ; Flaggen
	.equ bTO = 0 ; Timeout vom Timer
	.equ bAn = 1 ; Analogvergleicher aktiv
.def rHilf = R22 ; Hilfsregister Dezimal
; frei: R22 .. R25
; benutzt: R27:R26 X ; fuer diverse Zwecke
; frei: R29:R28 Y
; benutzt: R31:R30 Z ; fuer LCD
;
; ----------- SRAM ---------------------
.DSEG
.ORG 0x0060
sMD: ; Digitalwerte
.Byte 12
sMDEnd:
sMA: ; Analogwerte
.Byte 12
sMAEnd:
;
; ---- Reset- und Int-Vektoren ---------
.CSEG
.ORG 0x0000
	rjmp Start ; Reset-Vektor, Init
	reti ; INT0 External Int 0
	rjmp CntIsr ; PCI Request 0
	reti ; PCINT1 PCI Request 1
	reti ; WDT Watchdog Time-out
	reti ; TIM1_CAPT TC1 Capture Event
	rjmp Tc1Isr ; TIM1_COMPA TC1 Compare Match A
	reti ; TIM1_COMPB TC1 Compare Match B
	reti ; TIM1_OVF TC1 Overflow
	reti ; TIM0_COMPA TC0 Compare Match A
	reti ; TIM0_COMPB TC0 Compare Match B
	reti ; TIM0_OVF TC0 Overflow
	rjmp CntIsr ; ANA_COMP Analog Comparator
	reti ; ADC ADC Conversion Complete
	reti ; EE_RDY EEPROM Ready
	reti ; USI_STR USI START
	reti ; USI_OVF USI Overflow
;
; ----- Interrupt Service Routinen -----
;
; CntIsr Interrupt
;   wird wechselweise vom PCINT-Interrupt und
;   vom Analogvergleicher-Interrupt bei jedem
;   Pegelwechsel ausgeloest
;
; Zaehlt die Anzahl Pegelwechsel in rM0H:rM0M:rM0L.
;
CntIsr: ; Impulse am Analogvergleicher zaehlen
	in rSreg,SREG ; Status retten
	inc rM0L ; zaehlen
	brne CntIsrRet
	inc rM0M ; MSB erhoehen
	brne CntIsrRet
	inc rM0H
CntIsrRet:
	out SREG,rSreg ; Status herstellen
	reti
;
; TC1 Compare Match A Interrupt
;   wird nach 250 ms vom Compare Match A
;   ausgeloest
;
; Schaltet die Comparator- und PCINT-
;   Interrupts ab und setzt die bTO-Flagge.
;
Tc1Isr: ; Timeout Zaehler
	ldi rimp,0
	out ACSR,rimp ; Disable Int Comparator
	out GIMSK,rimp ; Disable PCInt
	in rSreg,SREG ; Status retten
	sbr rFlag,1<<bTO ; Timeout-Flagge
	out SREG,rSreg ; Status herstellen
	reti
;
; ----------- Hauptprogramm-Init ------
Start:
	; Stapel einrichten
	ldi rmp,LOW(RAMEND) ; RAM-Ende
	out SPL,rmp ; in Stapelzeiger
	; Auf 8 MHz Takt umstellen
	ldi rmp,1<<CLKPCE ; Change Enable
	out CLKPR,rmp ; in Clock Prescaler
	ldi rmp,0 ; Precaler / 1
	out CLKPR,rmp
	; Port initialisieren
	sbi pOut,bIO ; Eingabepin Pullup
	cbi pDir,bID ; Eingabepin Input
	; LCD-Port-Ausgaenge initiieren
	ldi rmp,(1<<bLcdCRE)|(1<<bLcdCRRS)|(1<<bLcdCRRW)
	out pLcdCR,rmp ; Kontrollport-Ausgaenge
	clr rmp ; Ausgaenge aus
	out pLcdCO,rmp ; an Kontrollport
	ldi rmp,mLcdDRW ; Datenport-Ausgabemaske, Schreiben
	out pLcdDR,rmp ; auf Richtungsregister Datenausgabeport
	; LCD Init
	rcall LcdInit ; starten LCD
	ldi ZH,High(2*LcdTextOut) ; Z auf Text
	ldi ZL,Low(2*LcdTextOut)
	rcall LcdText ; Gib Text aus
	ldi rmp,0x0C ; Cursor und Blink aus
	rcall LcdC4Byte
	; Timer Init
	ldi rmp,High(cTc1CmpA) ; Compare auf
	out OCR1AH,rmp ; Messzyklusdauer
	ldi rmp,Low(cTc1CmpA)
	out OCR1AL,rmp
	clr rmp ; TC1 Normal operation
	out TCCR1A,rmp
	ldi rmp,(1<<CS11)|(1<<CS10) ; Presc 64
	out TCCR1B,rmp
	ldi rmp,1<<OCIE1A ; Compare Match Int
	out TIMSK1,rmp
	; Analogvergleicher deaktivieren
	ldi rmp,0 ; Disable Int Comparator
	out ACSR,rmp
	ldi rmp,(1<<ADC2D)|(1<<ADC1D) ; Input Pin disable
	out DIDR0,rmp
	; PCINT3 aktivieren
	ldi rmp,1<<PCINT3 ; Pin change PA3
	out PCMSK0,rmp ; maskieren
	ldi rmp,1<<PCIE0 ; PCINT0 Interrupt
	out GIMSK,rmp ; in Int-Maske
	; Kein Sleep Mode wegen Analogcomparator!
	ldi rmp,0 ; Sleep enable
	out MCUCR,rmp ; in Kontrollregister
	; Interrupts enablen
	sei ; Ints zulassen
Schleife:
	sbrc rFlag,bTO ; Timeout-Flagge?
	rcall Auswerten ; gesetzt, Auswerten
	rjmp Schleife
;
; Rountine Auswerten der Zaehlergebnisse
;   wird von der bTO-Flagge ausgeloest
;
; Berechnet abhaengig von der Flagge bAn fuer
;   PCINT- und Analogvergleicherergebnisse
;   den Durchschnitt aus der aktuellen und
;   den drei letzten Messwerten und gibt ihn
;   dezimal auf der LCD aus.
;
Auswerten:
	cbr rFlag,1<<bTO ; Flagge ruecksetzen
	clr rmp ; Compare Match Int aus
	out TIMSK1,rmp
	; Messwerte im SRAM verschieben/Dividieren
	sbrc rFlag,bAn ; Digitalwerte auswerten?
	rjmp AuswertenAnalog
	ldi ZH,High(sMDEnd) ; Ziel
	ldi ZL,Low(sMDEnd)
	ldi XH,High(sMDEnd-3) ; Quelle
	ldi XL,Low(sMDEnd-3)
	rjmp AuswertenShift
AuswertenAnalog:
	ldi ZH,High(sMAEnd) ; Ziel
	ldi ZL,Low(sMAEnd)
	ldi XH,High(sMAEnd-3) ; Quelle
	ldi XL,Low(sMAEnd-3)
AuswertenShift:
	; Messwerte im SRAM verschieben+dividieren
	ld rmp,-X ; vorletzter nach vorvorletzter 
	st -Z,rmp ; kopieren
	ld rmp,-X
	st -Z,rmp
	ld rmp,-X
	st -Z,rmp
	ld rmp,-X ; letzter nach vorletzter+Division
	lsr rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	ld rmp,-X ; neuester nach letzter+Division
	lsr rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	st -Z,rM0H ; neuester ablegen
	st -Z,rM0M
	st -Z,rM0L
	adiw ZL,3 ; Zeiger auf letzten
	ldi rmp,4
	mov R0,rmp ; R0 ist Zaehler
Auswerten1:
	ld rmp,Z+ ; lese LSB
	add rM0L,rmp ; Zu aktuellem Ergebnis addieren
	ld rmp,Z+ ; lese MSB
	adc rM0M,rmp ; addieren mit Uebertrag
	ld rmp,Z+ ; lese HSB
	adc rM0H,rmp ; addieren mit Uebertrag
	dec R0
	brne Auswerten1 ; Weitere Werte addieren
	ldi ZH,1 ; Digitalergebnis ausgeben
	sbrc rFlag,bAn ; Analogflagge gesetzt?
	ldi ZH,2 ; ja, Analogposition
	ldi ZL,8
	rcall LcdPos
	rcall DezimalAus ; gib dezimal aus
Neustart:
	clr rM0L ; Letzte Dezimale loeschen
	ldi rmp,1<<bAn ; Analog-Flagge umkehren
	eor rFlag,rmp ; Invertiert bAn-Flagge
	sbrc rFlag,bAn ; Analogflagge gesetzt?
	rjmp NeustartAnalog ; ja
	; Digital messen, PCINT3 aktivieren
	ldi rmp,1<<PCINT3 ; Pin change PA3
	out PCMSK0,rmp ; maskieren
	ldi rmp,1<<PCIE0 ; PCINT0 Interrupt
	out GIMSK,rmp ; in Int-Maske
	rjmp Neustart1
NeustartAnalog:
	ldi rmp,1<<ACIE ; Enable Int Comparator
	out ACSR,rmp
Neustart1:
	clr rmp
	out TCNT1H,rmp ; Zaehler ruecksetzen
	out TCNT1L,rmp
	ldi rmp,1<<OCIE1A ; Compare Match Int
	out TIMSK1,rmp
	ret
;
; 3 Byte-Zahl in rM0H:rM0M:rM0L in dezimal
; auf der LCD ausgeben
;   wird von der Auswerten-Routine aufgerufen
;
; Wandelt rM0H:rM0M:rM0L in Dezimalzahl um
; und gibt sie an der aktuellen LCD-Position
; aus, unterdrueckt fuehrende Nullen und De-
; zimaltrennzeichen
; 
DezimalAus:
	ldi ZH,High(2*DezimalTab)
	ldi ZL,Low(2*DezimalTab)
	clt ; Fuehrende Nullen
DezimalAus1:
	lpm XL,Z+ ; lese Dezimalzahl
	lpm XH,Z+
	lpm rHilf,Z+
	clr rmp ; Teilerzaehler
	cp XL,rmp
	brne DezimalAus2
	cp XH,rmp
	brne DezimalAus2
	cp rHilf,rmp
	breq DezimalAusEnd
DezimalAus2:
	sub rM0L,XL ; abziehen
	sbc rM0M,XH
	sbc rM0H,rHilf
	brcs DezimalAus3 ; Ueberlauf
	inc rmp
	rjmp DezimalAus2 ; weiter subtrahieren
DezimalAus3:
	add rM0L,XL ; Ruecknahme Subtraktion
	adc rM0M,XH
	adc rM0H,rHilf
	tst rmp ; Null?
	brne DezimalAus4 ; Nicht Null
	brts DezimalAus5 ; keine Nullen unterdr.
	ldi rmp,' '
	rcall LcdD4Byte
	ldi rmp,' '
	rjmp DezimalAusKomma
DezimalAus4:
	set ; keine fuehrenden Nullen unterdr.
DezimalAus5:
	subi rmp,-'0'
	rcall LcdD4Byte
	ldi rmp,'.'
DezimalAusKomma:
	cpi XL,Byte1(1000000)
	breq DezimalAusKomma1
	cpi XL,Byte1(1000)
	breq DezimalAusKomma1 
	rjmp DezimalAus1
DezimalAusKomma1:
	rcall LcdD4Byte
	rjmp DezimalAus1
DezimalAusEnd:
	ldi rmp,'0' ; letzte Ziffer
	add rmp,rM0L ; addieren
	rjmp LcdD4Byte
;
DezimalTab:
.db Byte1(1000000),Byte2(1000000)
.db Byte3(1000000),Byte1(100000)
.db Byte2(100000),Byte3(100000)
.db Byte1(10000),Byte2(10000)
.db Byte3(10000),Byte1(1000)
.db Byte2(1000),Byte3(1000)
.db Byte1(100),Byte2(100)
.db Byte3(100),Byte1(10)
.db Byte2(10),Byte3(10)
.db 0,0,0,0
;
; LCD Starttext
LcdTextOut:
.db "Frequenzmesser tn24 ",0x0D,0xFF
.db "F(dig)= x.xxx.xxx Hz",0x0D,0xFF
;            8
.db "F(ana)= x.xxx.xxx Hz",0x0D,0xFF
;            8
.db "                    ",0xFE,0xFE
;
; LCD-Include
.include "Lcd4Busy.inc"
;
; Ende Quellcode
;

13.4.4 Messbeispiele

Der analoge Messeingang ist sehr empfindlich, bei höheren Frequenzen reichen 2 mV(eff) für eine stabile Messung aus. Bei niedrigen Frequenzen macht sich der hohe kapazitive Scheinwiderstand des 100 nF-Kondensators etwas bemerkbar, so dass höhere Amplituden erforderlich sind. Bei offenem Eingang machen sich Signale am Digitaleingang störend bemerkbar.

Das gleiche Signal, einmal analog (mit kleiner Amplitude) und gleichzeitig digital eingespeist, zeigt nicht immer das gleiche Ergebnis. Ursache dafür dürfte Übersprechen auf den Analogeingang sein.

Messung Analog 2 Messung Analog 1



Home Top Frequenzen Dezimalumwandlung Digital Analog Induktivität


13.5 Induktivitätsmessung mit PCINT

13.5.1 Aufgabe

Die Induktivität von Spulen ist zu messen. Sie soll einen weiten Messbereich von 1 mH bis über 10 H umfassen.

13.5.2 Hardware und Bauteile

Schaltbild

Schaltbild F-L-Messung Dies ist das komplette Schaltbild zur gleichzeitigen Messung von Digital- und Analogfrequenzen sowie zur Bestimmung der Induktivität. Der induktive Teil ist mit einem CMOS-NAND-Gatter realisiert, das die besten Schwingeigenschaften über den weiten Messbereich aufweist. Die beiden Kondensatoren von 100 nF bilden mit der Induktivität den Schwingkreis, sie sind in Serie geschaltet (wirksame Kapazität 50 nF). Die Rückkopplung ist über 100 k recht niedrig angekoppelt, reicht aber über den gesamten Messbereich gut aus. Das zweite NAND-Gatter dient der Signalauskopplung, zwei weitere Gatter in der Packung sind unbenutzt.

Bauteile

4011 CMOS-Gatter Das ist das Vierfach-NAND. Es eignen sich auch andere invertierende CMOS-Gatter.

Aufbau

Aufbau F-L-Meter Das ist der Aufbau. Die Spule ist mit Krokodilklemmen angekoppelt.

13.5.3 Programm

Das hier ist das Programm (zum Quellcode geht es hier). Es misst nacheinander an allen drei Eingängen und stellt die Messergebnisse auf drei LCD-Zeilen dar. Auf den Schlafmodus wurde wieder verzichtet, weil der Analogvergleicher das Aufwecken blockiert.

;
; *************************************
; * Frequenz- und Induktivitaetsmessg *
; * (C)2016 by www.gsc-elektronic.net *
; *************************************
;
.NOLIST
.INCLUDE "tn24def.inc"
.LIST
;
; ----------- Programmablauf -----------
;
; Misst nacheinander Pegelwechsel
; a) am PCINT3-Eingang,
; b) an den Analogvergleichereingaengen,
; c) am LC-Oszillator
; ueber 250 ms lang, rechnet diese in
; Frequenzen (a, b) oder Induktivitaet (c)
; um und stellt das Ergebnis dezimal auf
; der LCD dar.
;
; ----------- Hardware -----------------
; Digitaler Frequenzzaehler am Input PA3
; und
; Analoger Frequenzzaehler am Analog-
;   vergleicher AIN0/PA1 und AIN1/PA2
; und
; Induktivitaetsmessung aus Frequenz am
;   Input PA0 (4011-LC-Oszillator)
;
; ----------- Timing -------------------
; Messzeit                 250 ms
; Prozessor-Takt     1.000.000 Hz
; TC1-Prescaler             64
; TC1-Takt              15.625 Hz
; TC1-Takte in 250 ms    3.906
.equ cTc1CmpA = 3905
;
; ----------- Messwertmittelung --------
; Aktueller Messwert        / 2 plus
; Vorheriger Messwert       / 4 plus
; Vorvorheriger Messwert    / 8 plus
; Vorvorvorheriger Messwert / 8 =
; Aktuelle Anzeige          = F
;
; ----------- Ports, Pins --------------
.equ pOut = PORTA ; Ausgabeport
.equ pDir = DDRA ; Richtungsport
.equ bIO = PORTB3 ; Pin-Out Digital
.equ bID = DDA3 ; Pin-Richtung Digital
;
; ----------- Register -----------------
; benutzt: R0, R1 fuer LCD
.def rM0L = R2 ; aktueller Messwert, LSB
.def rM0M = R3 ; dto., MSB
.def rM0H = R4 ; dto., HSB
.def rMH0 = R5 ; 5-Byte Hilfsregister
.def rMH1 = R6 ;   fuer Multiplikation
.def rMH2 = R7 ;   und Division
.def rMH3 = R8
.def rMH4 = R9
.def rME0 = R10 ; 5-Byte Ergebnisregister
.def rME1 = R11 ;   fuer Multiplikation
.def rME2 = R12 ;   und Division
.def rME3 = R13
.def rME4 = R14 
; frei: R5 .. R14
.def rSreg = R15 ; Statusregister
.def rmp = R16 ; Vielzweckregister
.def rmo   = R17 ; Vielzweckregister
.def rLine = R18 ; LCD-Zeilenzaehler
.def rLese = R19 ; LCD-Register
.def rimp = R20 ; Vielzweck, Interrupts
.def rFlag = R21 ; Flaggen
	.equ bAn = 0 ; Analogvergleicher aktiv
	.equ bIp = 1 ; Induktivitaetsmessung
	.equ bTO = 2 ; Timeout vom Timer
.def rHilf = R22 ; Hilfsregister Dezimal
; frei: R22 .. R25
; benutzt: R27:R26 X ; fuer diverse Zwecke
; frei: R29:R28 Y
; benutzt: R31:R30 Z ; fuer LCD
;
; ----------- SRAM ---------------------
.DSEG
.ORG 0x0060
sMD: ; Digitalwerte, 4*(HSB:MSB:LSB)
.Byte 12
sMDEnd:
sMA: ; Analogwerte
.Byte 12
sMAEnd:
sMI: ; Induktivitaetswerte
.Byte 12
sMIEnd:
sDividend: ; fuer Division
.Byte 5
sDividendEnde:
;
; ---- Reset- und Int-Vektoren ---------
.CSEG
.ORG 0x0000
	rjmp Start ; Reset-Vektor, Init
	reti ; INT0 External Int 0
	rjmp CntIsr ; PCI Request 0
	reti ; PCINT1 PCI Request 1
	reti ; WDT Watchdog Time-out
	reti ; TIM1_CAPT TC1 Capture Event
	rjmp Tc1Isr ; TIM1_COMPA TC1 Compare Match A
	reti ; TIM1_COMPB TC1 Compare Match B
	reti ; TIM1_OVF TC1 Overflow
	reti ; TIM0_COMPA TC0 Compare Match A
	reti ; TIM0_COMPB TC0 Compare Match B
	reti ; TIM0_OVF TC0 Overflow
	rjmp CntIsr ; ANA_COMP Analog Comparator
	reti ; ADC ADC Conversion Complete
	reti ; EE_RDY EEPROM Ready
	reti ; USI_STR USI START
	reti ; USI_OVF USI Overflow
;
; ----- Interrupt Service Routinen -----
;
; CntIsr wird nacheinander von PCINT- und
;   Analogvergleicher-Interrupts ausgeloest
;
; Zaehlt die Impulse in rM0H:rM0M:rM0L
;
CntIsr: ; Impulse zaehlen
	in rSreg,SREG ; Status retten
	inc rM0L ; zaehlen
	brne CntIsrRet
	inc rM0M ; MSB erhoehen
	brne CntIsrRet
	inc rM0H
CntIsrRet:
	out SREG,rSreg ; Status herstellen
	reti
;
; TC1 Compare Match A Interrupt
;   wird nach 250 ms vom Compare Match aus-
;   geloest
;
; Schaltet Analogvergleicher-, PCINT- und
; TC1-Interrupts aus und setzt die bTO-Flagge.
;
Tc1Isr: ; Timeout Zaehler
	ldi rimp,0
	out ACSR,rimp ; Disable Int Comparator
	out GIMSK,rimp ; Disable PCInt
	out TIMSK1,rimp ; Diable Timer-Int
	in rSreg,SREG ; Status retten
	sbr rFlag,1<<bTO ; Timeout-Flagge
	out SREG,rSreg ; Status herstellen
	reti
;
; ----------- Hauptprogramm-Init ------
Start:
	; Stapel einrichten
	ldi rmp,LOW(RAMEND) ; RAM-Ende
	out SPL,rmp ; in Stapelzeiger
	; Port initialisieren
	sbi pOut,bIO ; Eingabepin Pullup
	cbi pDir,bID ; Eingabepin Input
	; LCD-Port-Ausgaenge initiieren
	ldi rmp,(1<<bLcdCRE)|(1<<bLcdCRRS)|(1<<bLcdCRRW)
	out pLcdCR,rmp ; Kontrollport-Ausgaenge
	clr rmp ; Ausgaenge aus
	out pLcdCO,rmp ; an Kontrollport
	ldi rmp,mLcdDRW ; Datenport-Ausgabemaske, Schreiben
	out pLcdDR,rmp ; auf Richtungsregister Datenausgabeport
	; LCD Init
	rcall LcdInit ; starten LCD
	ldi ZH,High(2*LcdTextOut) ; Z auf Text
	ldi ZL,Low(2*LcdTextOut)
	rcall LcdText ; Gib Text aus
	ldi rmp,0x0C ; Cursor und Blink aus
	rcall LcdC4Byte
	; Timer Init
	ldi rmp,High(cTc1CmpA) ; Compare auf
	out OCR1AH,rmp ; Messzyklusdauer
	ldi rmp,Low(cTc1CmpA)
	out OCR1AL,rmp
	clr rmp ; TC1 Normal operation
	out TCCR1A,rmp
	ldi rmp,(1<<CS11)|(1<<CS10) ; Presc 64
	out TCCR1B,rmp
	ldi rmp,1<<OCIE1A ; Compare Match Int
	out TIMSK1,rmp
	; Analogvergleicher deaktivieren
	ldi rmp,0 ; Disable Int Comparator
	out ACSR,rmp
	ldi rmp,(1<<ADC2D)|(1<<ADC1D) ; Input Pin disable
	out DIDR0,rmp
	; PCINT3 aktivieren
	ldi rmp,1<<PCINT3 ; Pin change PA3
	out PCMSK0,rmp ; maskieren
	ldi rmp,1<<PCIE0 ; PCINT0 Interrupt
	out GIMSK,rmp ; in Int-Maske
	; Sleep Mode, kein Sleep wegen Analogcomparator
	clr rmp ; Sleep mode disable
	out MCUCR,rmp ; in Kontrollregister
	; Interrupts enablen
	sei ; Ints zulassen
Schleife:
	; kein Schlafen wegen Analog-Comparator
	sbrc rFlag,bTO ; Timeout-Flagge?
	rcall Auswerten ; gesetzt, Auswerten
	rjmp Schleife
;
; Routine Auswerten der Zaehlergebnisse
;   wird von gesetzter bTO-Flagge ausge-
;   loest
;
; Wertet Digital-, Analog- und Induktions-
; messwerte aus (Flaggenbits 0 und 1:
; 0 = Digital, 1 = Analog, 2 = Indukt.)
; Mittelt den aktuellen und die drei
; vorherigen Messwert und gibt sie als
; Frequenz in Hz (0 und 1) oder als
; Induktivitaet in uH (2) aus.
;
Auswerten:
	cbr rFlag,1<<bTO ; Flagge ruecksetzen
	clr rmp ; Compare Match Int aus
	out TIMSK1,rmp
	; Messwerte im SRAM verschieben/Dividieren
	cpi rFlag,0x01 ; Induktivitaetswerte?
	breq AuswertenAnalog ; Analog
	brcs AuswertenDigital ; Digital
	; Induktivitaet auswerten
	ldi ZH,High(sMIEnd) ; Ziel
	ldi ZL,Low(sMIEnd)
	ldi XH,High(sMIEnd-3) ; Quelle
	ldi XL,Low(sMIEnd-3)
	rjmp AuswertenShift
AuswertenDigital:
	ldi ZH,High(sMDEnd) ; Ziel
	ldi ZL,Low(sMDEnd)
	ldi XH,High(sMDEnd-3) ; Quelle
	ldi XL,Low(sMDEnd-3)
	rjmp AuswertenShift
AuswertenAnalog:
	ldi ZH,High(sMAEnd) ; Ziel
	ldi ZL,Low(sMAEnd)
	ldi XH,High(sMAEnd-3) ; Quelle
	ldi XL,Low(sMAEnd-3)
AuswertenShift:
	; Messwerte im SRAM verschieben+dividieren
	ld rmp,-X ; vorletzter nach vorvorletzter 
	st -Z,rmp ; kopieren
	ld rmp,-X
	st -Z,rmp
	ld rmp,-X
	st -Z,rmp
	ld rmp,-X ; letzter nach vorletzter+Division
	lsr rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	ld rmp,-X ; neuester nach letzter+Division
	lsr rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	ld rmp,-X
	ror rmp
	st -Z,rmp
	st -Z,rM0H ; neuester ablegen
	st -Z,rM0M
	st -Z,rM0L
	adiw ZL,3 ; Zeiger auf letzten
	ldi rmp,4
	mov R0,rmp ; R0 ist Zaehler
Auswerten1:
	ld rmp,Z+ ; lese LSB
	add rM0L,rmp ; Zu aktuellem Ergebnis addieren
	ld rmp,Z+ ; lese MSB
	adc rM0M,rmp ; addieren mit Uebertrag
	ld rmp,Z+ ; lese HSB
	adc rM0H,rmp ; addieren mit Uebertrag
	dec R0
	brne Auswerten1 ; Weitere Werte addieren
	cpi rFlag,0x02 ; Induktivitaet? 
	brcs Auswerten2
	rcall Indukt ; Induktivitaet ausgeben
	rjmp Neustart
Auswerten2:
	mov ZH,rFlag ; Position Digital/Analog-Ausgabe
	inc ZH
	ldi ZL,8
	rcall LcdPos
;
; 3 Byte-Zahl in rM0H:rM0M:rM0L in dezimal
; auf der LCD ausgeben
;
; Wandelt Zahl bis 9,99 Mio. in Dezimalformat um
; und gib sie auf LCD aus, mit Unterdrueckung
; fuehrender Nullen und Dezimaltrennzeichen
;
Dezimal3Aus:
	ldi ZH,High(2*Dezimal3Tab)
	ldi ZL,Low(2*Dezimal3Tab)
	clt ; Fuehrende Nullen
Dezimal3Aus1:
	lpm XL,Z+ ; lese Dezimalzahl
	lpm XH,Z+
	lpm rHilf,Z+
	clr rmp ; Teilerzaehler
	cp XL,rmp
	brne Dezimal3Aus2
	cp XH,rmp
	brne Dezimal3Aus2
	cp rHilf,rmp
	breq Dezimal3AusEnd
Dezimal3Aus2:
	sub rM0L,XL ; abziehen
	sbc rM0M,XH
	sbc rM0H,rHilf
	brcs Dezimal3Aus3 ; Ueberlauf
	inc rmp
	rjmp Dezimal3Aus2 ; weiter subtrahieren
Dezimal3Aus3:
	add rM0L,XL ; Ruecknahme Subtraktion
	adc rM0M,XH
	adc rM0H,rHilf
	tst rmp ; Null?
	brne Dezimal3Aus4 ; Nicht Null
	brts Dezimal3Aus5 ; keine Nullen unterdr.
	ldi rmp,' '
	rcall LcdD4Byte
	ldi rmp,' '
	rjmp Dezimal3AusKomma
Dezimal3Aus4:
	set ; keine fuehrenden Nullen unterdr.
Dezimal3Aus5:
	subi rmp,-'0'
	rcall LcdD4Byte
	ldi rmp,'.'
Dezimal3AusKomma:
	cpi XL,Byte1(1000000)
	breq Dezimal3AusKomma1
	cpi XL,Byte1(1000)
	breq Dezimal3AusKomma1 
	rjmp Dezimal3Aus1
Dezimal3AusKomma1:
	rcall LcdD4Byte
	rjmp Dezimal3Aus1
Dezimal3AusEnd:
	ldi rmp,'0' ; letzte Ziffer
	add rmp,rM0L ; addieren
	rcall LcdD4Byte
	rjmp Neustart
;
Dezimal3Tab:
.db Byte1(1000000),Byte2(1000000)
.db Byte3(1000000),Byte1(100000)
.db Byte2(100000),Byte3(100000)
.db Byte1(10000),Byte2(10000)
.db Byte3(10000),Byte1(1000)
.db Byte2(1000),Byte3(1000)
.db Byte1(100),Byte2(100)
.db Byte3(100),Byte1(10)
.db Byte2(10),Byte3(10)
.db 0,0,0,0
;
; Routine Indukt
;   wird von Auswerten aufgerufen wenn Mess-
;   zyklus Induktivitaet gemessen hat
; 
; Rechnet Induktivitaet aus und gibt sie aus.
; Prueft, ob Frequenz kleiner 23 oder groe-
; sser 0x0B5050 ist und gibt Fehlermeldung
; aus.
; Multipliziert F mit sich selbst und teilt
; Konstante in Dividendtabelle durch F hoch
; 2. Gibt das 32-Bit-Ergebnis auf der LCD
; aus.
;
Indukt:
	ldi ZH,3
	ldi ZL,6
	rcall LcdPos
	tst rM0M
	brne InduktN2
	tst rM0H
	brne InduktN2
	mov rmp,rM0L ; LSB Frequenz in rmp
	cpi rmp,2 ; Frequenz 0 oder 1?
	brcc InduktN1
	; F = 0 oder 1, Zeile leeren und Null
	ldi XL,10
InduktN0:
	ldi rmp,' '
	rcall LcdD4Byte
	dec XL
	brne InduktN0
	ldi rmp,'0'
	rjmp LcdD4Byte
;
InduktN1: ; F groesser Null
	cpi rmp,23 ; F zwischen 2 und 22?
	brcc InduktN2
	ldi ZH,High(2*Underflow22)
	ldi ZL,Low(2*Underflow22)
	rjmp LcdTextC
Underflow22:
.db "(F < 23 Hz) ",0xFE,0xFF
InduktN2:
	ldi rmp,0x50
	cp rM0L,rmp
	cpc rM0M,rmp
	ldi rmp,0x0B
	cpc rM0H,rmp
	brcs InduktN3
	ldi ZH,High(2*Overflow)
	ldi ZL,Low(2*Overflow)
	rjmp LcdTextC
Overflow:
.db " (F > Max)  ",0xFE,0xFF
InduktN3:
	; rM0H:rM0M:rM0L mit sich selbst multipliz
	mov rMH0,rM0L ; Zahl kopieren
	mov rMH1,rM0M
	mov rMH2,rM0H
	clr rMH3
	clr rMH4
	clr rME0 ; Ergebnis leeren
	clr rME1
	clr rME2
	clr rME3
	clr rME4
Indukt1:
	lsr rM0H ; niedrigstes Bit herausschieben
	ror rM0M
	ror rM0L
	brcc Indukt2
	add rME0,rMH0 ; zum Ergebnis addieren
	adc rME1,rMH1
	adc rME2,rMH2
	adc rME3,rMH3
	adc rME4,rMH4
Indukt2:
	tst rM0L
	brne Indukt3
	tst rM0M
	brne Indukt3
	tst rM0H
	breq Indukt4
Indukt3:
	lsl rMH0 ; mit 2 multiplizieren
	rol rMH1
	rol rMH2
	rol rMH3
	rol rMH4
	rjmp Indukt1
Indukt4:
	; Division, Dividend in SRAM laden
	ldi ZH,High(2*Dividendtabelle)
	ldi ZL,Low(2*Dividendtabelle)
	ldi XH,High(sDividend)
	ldi XL,Low(sDividend)
Indukt5:
	lpm rmp,Z+ ; Dividend aus Tabelle
	st X+,rmp ; in SRAM
	cpi XL,Low(sDividendEnde)
	brcs Indukt5
	; Dividend leeren
	clr rMH0
	clr rMH1
	clr rMH2
	clr rMH3
	clr rMH4
	; Ergebnis leeren
	clr rM0L
	clr rM0M
	clr rM0H
	clr ZL
	clr ZH
	; Dividend in SRAM rechts schieben
	ldi rmp,8*(sDividendEnde-sDividend)+1
	mov R0,rmp
Indukt6:
	; Dividieren
	ldi XH,High(sDividend)
	ldi XL,Low(sDividend)
	ldi rmp,sDividendEnde-sDividend
	mov R1,rmp
	clc ; Carry loeschen
Indukt7:
	ld rmp,X ; Byte aus SRAM laden
	rol rmp ; hoechstes Bit in Carry
	st X+,rmp ; Byte in SRAM speichern
	dec R1
	brne Indukt7
	; Carry in Hilfsregister schieben
	rol rMH0
	rol rMH1
	rol rMH2
	rol rMH3
	rol rMH4
	sub rMH0,rME0 ; Abziehen
	sbc rMH1,rME1
	sbc rMH2,rME2
	sbc rMH3,rME3
	sbc rMH4,rME4
	brcc Indukt8 ; Abziehen korrekt
	add rMH0,rME0 ; wieder addieren
	adc rMH1,rME1
	adc rMH2,rME2
	adc rMH3,rME3
	adc rMH4,rME4
	clc ; Carry clr
	rjmp Indukt9
Indukt8:
	sec ; Carry auf Eins
Indukt9:
	dec R0
	breq Indukt10 ; weiter dividieren
	rol rM0L ; in Ergebnis rollen
	rol rM0M
	rol rM0H
	rol ZL
	rol ZH
	rjmp Indukt6
	; Ergebnis runden
Indukt10:
	ldi rmp,0
	adc rM0L,rmp
	adc rM0M,rmp
	adc rM0H,rmp
	adc ZL,rmp
	adc ZH,rmp
	mov rMH0,ZL
	mov rMH1,ZH
;
; 4 Byte-Zahl in rMH0:rM0H:rM0M:rM0L in dezimal
; auf der LCD ausgeben
;
; Wandelt in dezimal um, unterdrueckt fuehrende
; Nullen und Dezimaltrennzeichen
;
Dezimal4Aus:
	ldi ZH,High(2*Dezimal4Tab)
	ldi ZL,Low(2*Dezimal4Tab)
	clt ; Fuehrende Nullen
Dezimal4Aus1:
	lpm rME0,Z+ ; Lese Dezimalzahl
	lpm rME1,Z+
	lpm rME2,Z+
	lpm rME3,Z+
	clr rmp
	or rmp,rME0 ; Ende der Tabelle?
	or rmp,rME1
	or rmp,rME2
	or rmp,rME3
	breq Dezimal4AusEnd
	clr rmp
Dezimal4Aus2:
	sub rM0L,rME0 ; abziehen
	sbc rM0M,rME1
	sbc rM0H,rME2
	sbc rMH0,rME3
	brcs Dezimal4Aus3
	inc rmp
	rjmp Dezimal4Aus2
Dezimal4Aus3:
	add rM0L,rME0 ; abziehen rueckgaengig
	adc rM0M,rME1
	adc rM0H,rME2
	adc rMH0,rME3
	tst rmp
	brne Dezimal4Aus4
	brts Dezimal4Aus5 
	ldi rmp,' '
	ldi rmp,' '
	rjmp Dezimal4Aus6
Dezimal4Aus4:
	set ; Kein fuehrenden Nullen
Dezimal4Aus5:
	subi rmp,-'0'
	ldi rmp,'.'
Dezimal4Aus6:
	cpi ZL,Low(2*Dezimal4Tab1Mio)
	breq Dezimal4Aus7
	cpi ZL,Low(2*Dezimal4Tab1000)
	brne Dezimal4Aus1
Dezimal4Aus7:
	rjmp Dezimal4Aus1
Dezimal4AusEnd:
	ldi rmp,'0'
	add rmp,rM0L
	rcall LcdD4Byte
	rjmp Neustart
;
Dividendtabelle:
.db 0x7F,0xD7,0x10,0xF4,0x75,0x00
;
Dezimal4Tab:
.dw LWRD(100000000),HWRD(100000000)
.dw LWRD(10000000),HWRD(10000000)
.dw LWRD(1000000),HWRD(1000000)
Dezimal4Tab1Mio:
.dw LWRD(100000),HWRD(100000)
.dw LWRD(10000),HWRD(10000)
.dw LWRD(1000),HWRD(1000)
Dezimal4Tab1000:
.dw LWRD(100),HWRD(100)
.dw LWRD(10),HWRD(10)
.dw 0,0
;
Neustart:
	clr rM0L ; Letztes Ergebnis loeschen
	clr rM0M
	clr rM0H
	inc rFlag ; naechster Messmodus
	cpi rFlag,3
	brcs NeuStart1
	clr rFlag ; erster Messmodus
NeuStart1:
	; rFlag=0:digital, =1:analog, =2:L
	cpi rFlag,0x01
	brcs NeustartDigital
	breq NeustartAnalog
	; Neustart Induktivitaetsmessung
	ldi rmp,1<<PCINT0 ; Pin Change PA0
	rjmp NeuStartPcInt
	; Digital messen, PCINT3 aktivieren
NeuStartDigital:
	ldi rmp,1<<PCINT3 ; Pin change PA3
NeuStartPcInt:
	out PCMSK0,rmp ; maskieren
	ldi rmp,1<<PCIE0 ; PCINT0 Interrupt
	out GIMSK,rmp ; in Int-Maske
	rjmp Neustart2
NeustartAnalog:
	clr rmp
	out GIMSK,rmp
	ldi rmp,1<<ACIE ; Enable Int Comparator
	out ACSR,rmp
Neustart2:
	ldi rmp,1<<TSM ; Prescaler Sync Mode
	out GTCCR,rmp
	ldi rmp,(1<<TSM)|(1<<PSR10) ; Reset Presc1
	out GTCCR,rmp
	clr rmp
	out GTCCR,rmp ; Prescaler Count Mode
	out TCNT1H,rmp ; 16-Bit-Zaehler ruecksetzen
	out TCNT1L,rmp
	ldi rmp,1<<OCIE1A
	out TIMSK1,rmp ; in Timer-Int-Maske
	ret
;
; LCD Starttext
LcdTextOut:
.db "Frequenzmesser tn24 ",0x0D,0xFF
.db "F(dig)= x.xxx.xxx Hz",0x0D,0xFF
;            8
.db "F(ana)= x.xxx.xxx Hz",0x0D,0xFF
;            8
.db "L =   xxx.xxx.xxx ",0xE4,"H",0xFE,0xFE
;          6
; LCD-Include
.include "Lcd4Busy.inc"
;
; Ende Quellcode
;



Home Top Frequenzen Dezimalumwandlung Digital Analog Induktivität


13.5.4 Simulation der Programmausführung

Die Simulation wird wieder mit avr_sim vorgenommen. Alle Aufrufe von LCD-Routinen werden dazu mit ";" auskommentiert und durch Schreiboperationen in das SRAM ersetzt, um die Ergebnisse anschauen zu können. Das Registerpaar Y kann für diese Schreiboperationen verwendet werden.

Nützlich ist es, die 24-Bit-Dezimalumwandlung und die Induktivitätsberechnung zu simulieren.

13.5.4.1 Simulation der 24-Bit-Binär-Dezimal-Umwandlung

Simulieren Binär zu Dezimal von 1234567 Um die Dezimalumwandlung zu erproben, wird die Dezimalzahl 1.234.567 in binärem Format in die Register rM0H:rM0M:rM0L geladen und damit die Umwandlungsroutine aufgerufen.

Wandlungsergebnis Das Umwandlungsergebnis, statt auf die LCD ins SRAM geschrieben, ist korrekt.

Zeitbedarf der Wandlung Die Zeit, die für die Umwandlung benötigt wird, ist deutlich unterhalb von einer Millisekunde. Das stört die parallel ablaufende nächste Frequenzmessung nicht im Geringsten, selbst wenn wir noch die Schreiboperationen zur LCD (ca. 40 µs pro Zeichen) dazu zählen.

13.5.4.2 Simulation der Induktiviätsberechnung

Laden von f=1000 Hz Als Erstes simulieren wir die Induktivitätsberechnung mit einer Frequenz von 1.000 Hz. Dieser Wert wird in die Register R4:R3:R2 geschrieben.

Der berechnete Induktivitätswert in Micro-Henry Das Resultat ist mit 506,606 mH korrekt (wie die obige Beispielrechnung ausweist).

Berechnungszeit bei 1000 Hz 3,6 ms sind vergangen. Die Division dauert halt etwas länger als die Multiplikation, insbsondere wenn man die zu dividierende Zahl mühsam Bit für Bit aus dem SRAM in das Divisionsregister schieben muss.

Induktivität bei 10.000 Hz Das wäre das Ergebnis, wenn der LC-Oszillator 10.000 Hz produziert hätte: 5,6 mH.

Inductivität bei 50 Hz Simulation von 50 Hz Oszillatorfrequenz resultiert in einer Induktivität von 202 H, was eine ziemlich große Spule wäre.

Berechnungszeit bei 50 Hz Der Zeitbedarf bei der Berechnung von 50 Hz ist ein bisschen länger, dauert aber nicht zu lang.

Simulation hilft dabei, komplizierte Berechnungen zu entwickeln und zu überprüfen, ob sie unter allen realistischen Bedingungen korrekt rechnen. Damit können Unterprogramme mit einer klar definierten Aufgabenstellung mit Eingangszahlen (in Registern oder im SRAM) gefüttert werden und es kann ziemlich einfach gecheckt werden, ob sie zu korrekten Resultaten kommen.

13.5.5 Messbeispiele

Bei den beiden folgenden Messungen waren der Digital- und der Analog-Eingang unbeschaltet, die dargestellten Messwerte in Zeile 2 und 3 der LCD sind Einstrahlungen aus den Messobjekten und kapazitive Einstreuungen vom Aufbau.

13.5.5.1 Große Spule

Das ist die Messung mit einer relativ großen Spule.

Spule 3,58H Messung 3,58H

Die Messung stimmt relativ gut mit der auf andere Weise ermittelten Induktivität überein. Wieder ist die angezeigte Induktivität etwas zu groß, die gemessene Frequenz also etwas zu niedrig.

13.5.5.2 Lautsprecherspule

Auch die Lautsprecherspule, die wir in einem anderen Experiment verwendet haben, hat eine Induktivität:

Lautsprecher Messung Lautsprecher

Die Induktivität der Lautsprecherspule ist mit knapp 800 µH doch recht bescheiden.

Home Top Frequenzen Dezimalumwandlung Digital Analog Induktivität


©2016-2018 by http://www.gsc-elektronic.net