Hallo,
über InputCapture Interrupt des Mega8515 (läuft mit 16MHz)will ich
Flankenwechsel erkennen.
Das Hauptprogramm besteht nur aus einer Endlosschleife, in der auf den
Timer1_Capture Interrupt gewartet wird.
In der ersten Ausführung des InputCapture Interrupt wechselt der Port
der LED den Zustand bei jedem Flankenwechsel, egal ob steigend oder
fallend. Das funktioniert auch
Timer1_Capt:
;==== verwendete Register sichern
push r16
;==== Zeitwert einlesen
in r24, ICR1L
in r25, ICR1H
;==== wechseln der Flankenerkennung
switchFlanks:
in r16, TCCR1B
sbrs r16, ICES1
rjmp NextIntIsRisingEdge
NextIntIsFallingEdge:
cbr r16, (1<<ICES1)
out TCCR1B, r16
rjmp switchLED
NextIntIsRisingEdge:
sbr r16, (1<<ICES1)
out TCCR1B, r16
;==== LED umschalten
switchLED:
sbic PIN_LED, 0
rjmp LED_out
LED_on:
sbi PORT_LED, 0
rjmp endTimer1_Capt
LED_out:
cbi PORT_LED, 0
endTimer1_Capt:
;==== verwendete Register wiederherstellen
pop r16
reti
In der zweiten Ausführung soll die LED nur umschalten, wenn der
Interrupt durch eine fallende Flanke ausgelöst wurde. Dazu ersetze ich
"rjmp switch LED" in der ersten Ausführung unter
"NextIntIsFallingEdge" durch "rjmp endTimer1_Capt", so daß bei
einer aktuell gestiegenen Flanke gleich zum Ende des Interrupt
verzweigt wird, ohne die LED umzuschalten.
DAS FUNKTIONIERT ABER NICHT: mit dem Oszi stelle ich am LED-Pin fest,
das dieser unregelmäßig mal bei steigender,
mal bei fallender Flanke wechselt, machmal lässt er Flankenwechsel
einfach aus, ohne die LED umzuschalten....
Im Datenblatt des Mega8515 steht auch, daß für DutyCycleMessungen ICF1
nach jedem Flankenwechsel mit einer 1 beschrieben werden muss. Warum
das gemacht werden muss, verstehe ich sowiso nicht. Aber auch das hat
zu keinem Erfolg geführt.
(nach jedem Flankenwechsel ausgeführt)
ResetICF:
in r16, TIFR
sbr r16, (1<<ICF1)
out TIFR, r16
In einer dritten Ausführung wollte ich dann zuerst mal prüfen, durch
welchen Flankenwechsel der Interrupt ausgelöst wurde und dann, immer
wenn es sich um eine fallende Flanke handelte, die LED umschalten.
Auch das funktionierte nicht und hatte ein ähnlich unregelmäßiges
umschalten der LED zur folge.
Timer1_Capt:
;=== verwendete Register sichern
push r16
;=== prüfen ob Int durch steigende oder fallende Flanke ausgelöst
wurde
in r16, TCCR1B
sbrc r16, ICES1
rjmp switchFlanks ;Abbruch bei steigender Flanke da kein einlesen des
Zeitwerts und kein Umschalten der LED benötigt
;=== Zeitwert einlesen
in r24, ICR1L
in r25, ICR1H
;=== LED umschalten
switchLED:
sbic PIN_LED, 0
rjmp LED_out
LED_on:
sbi PORT_LED, 0
rjmp switchFlanks
LED_out:
cbi PORT_LED, 0
;==== wechseln der Flankenerkennung
switchFlanks:
in r16, TCCR1B
sbrs r16, ICES1
rjmp NextIntIsRisingEdge
NextIntIsFallingEdge:
cbr r16, (1<<ICES1)
out TCCR1B, r16
rjmp endTimer1_Capt
NextIntIsRisingEdge:
sbr r16, (1<<ICES1)
out TCCR1B, r16
endTimer1_Capt:
;==== verwendete Register wiederherstellen
pop r16
reti
Was mache ich denn falsch, oder verstehe ich da grundsätzlich noch
irgendetwas falsch am InputCapture???
Vielen Dank für Eure hilfe und sorry für den langen thread!!!
Puuuhhhhh...
Schwer nachvollziehbar (kann aber an meiner Müdigkeit liegen)...
Hier mal als Beispiel eine funktionierende ICP-ISR, die ein
pulsweitenmoduliertes serielles Datentelegramm am ICP-Pin einliest und
auf bestimmte Daten reagiert. Die Routine ist Teil eines Zündgerätes
für (Klasse 4-) Feuerwerk.
.equ basis1=32 ;Gerät 'B' (erster Schuss von Zünduhr)
.equ basis2=224 ;Gerät 'H' (darauf reagieren alle Zündverteiler)
.equ schuesse=31 ;Anzahl der Schüsse
.equ icps=(1<<icnc1)|(1<<ices1)+3 ;Timer1-ICP steigende Flanke, VT=64
.equ icpf=(1<<icnc1)+3 ;Timer1-ICP fallende Flanke, VT=64
impuls: ;ISR Input-Capture Timer 1 (Datenempfang von Zünduhr)
;Achtung, das Signal ist wegen Optokoppler Low-aktiv!
in srsk,sreg ;SREG sichern
in xl,tccr1b ;aktuelle Flanke ermitteln
cpi xl,icpf ;fallende Flanke? (Impulsbeginn)
brne impuls_steigend ;nein, steigende
impuls_fallend: ;Impulsbeginn (L-aktiv)
ldi xl,icps ;ja, ICP auf steigende
out tccr1b,xl ;Flanke umschalten
in altzeit,icr1l ;Zeitstempel Impulsbeginn holen
rjmp impuls_e ;fertig...
impuls_steigend: ;Impulsende (L-aktiv)
ldi xl,icpf ;ICP auf fallende Flanke
out tccr1b,xl ;umschalten
in xl,icr1l ;Zeitstempel holen
sub xl,altzeit ;Zeitstempeldifferenz etwa 512 oder 1536
cpi xl,16 ;Takte? (8 oder 24, da VT=64, Ergebnis im
Carry)
ror sr3 ;Carry von oben ins
ror sr2 ;Eingangs-
ror sr1 ;Schieberegister
ror sr0 ;schieben
brne impuls_e ;unteres Byte 0? (Präambel) nein...
cpi sr1,128 ;Präambel und Startbit?
brne impuls_e ;nein...
mov xl,sr3 ;Prüfsumme
com xl
cp xl,sr2 ;korrekt?
brne impuls_e ;nein...
cp uschuss,sr2 ;Schussnummer geändert?
breq impuls_e ;nein...
mov uschuss,sr2 ;ja, Änderung übernehmen
mov xl,sr2 ;Kopie Uhrschussnummer
subi xl,basis2 ;über oberer Basisnummer?
brsh impuls_1 ;ja...
mov xl,sr2 ;neue Kopie Uhrschussnummer
subi xl,basis1 ;über unterer Basisnummer?
brlo impuls_e ;nein...
impuls_1:
inc xl ;Uhr beginnt mit 0, Verteiler mit 1
cpi xl,(schuesse+1) ;Schussnummer gültig?
brsh impuls_e ;nein...
mov kuschuss,xl ;ja, übernehmen
sbr flags,1<<uhrschuss ;Flag für Hauptschleife setzen
impuls_e:
clr uhrz ;Uhrsignal-Zähler löschen
sbr flags,1<<uhrsig ;Uhrsignal vorhanden
out sreg,srsk ;SREG wiederherstellen
reti ;fertig
Die (für dich) relevanten Stellen befinden sich gleich am Anfang der
ISR. Ich hoffe, das Programm ist aufgrund der Kommentierung lesbar
genug.
Neben dem ICP-Interrupt laufen noch 3 andere Interrupts
(Timer0-Überlauf, Timer1-OCR1a und -OCR1b).
...
Es könnte Missverständnisse geben:
Mein Programm läuft auf dem AT90S8515 mit Quarz 3,6864MHz.
Beim Mega8515 könnte das etwas anders sein, da der Timer1 bedeutend
mehr Features hat und damit andere Bits in den Controlregistern.
Du müsstest also auch den betreffenden Abschnitt in den Datenblättern
beider Controller vergleichen. - Sorry...
...