Forum: Mikrocontroller und Digitale Elektronik DutyCycle - InputCapture Interrupt


von Martin (Gast)


Lesenswert?

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!!!

von Hannes L. (hannes)


Lesenswert?

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).

...

von Martin (Gast)


Lesenswert?

Danke Hannes, ich übernehme mal die für mich relevanten Teile in mein
Programm und schaue ob es dann die Flanke richtig erkennt.

...

von Hannes L. (hannes)


Lesenswert?

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...

...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.