mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR - Interruptpin in der Interruptroutine abfragen ASM


Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte innerhalb der Interruptroutine, welche durch einen externen 
Interrupt an INT0 (Tiny13) ausgelöst wurde, überwachen wie der Status 
dieses Pins weiterhin ist.
Kann ich einfach mit cbi DDRB,1 (Pin als Eingang schalten) und sbis bzw 
sbic den PIN weiterhin überwachen ?

Hintergrund: Ich möchte ein 8Bit über den INT0 Eingang empfangen.
Sobald der Level auf der Leitung von 5 auf 0 Volt wechselt löst der 
Interrupt aus. Innerhalb dieser Routine möchte dann die wieteren 
Pegeländerungen (Bits) auswerten um dann nach 8 Bits oder auch nach 
einem möglichen Timeout (Störimpuls auf der Leitung) die 
Interruptroutine zu verlassen und auf das nächste Byte warten.

Gruß

Günter

Autor: Dennis U. (atmegadennis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich nehme an du willst ne Serielle schnittstelle simulieren,

dazu gibt es 2 Möglichkeiten die zum gewünschten Ziel führen

Zum einen kannst du deine Aktivität am Pin über einen gewissen Zeitraum 
überwachen.

Zum anderen deaktivierst du den nterrupt und somit kannst du dn Pin in 
irgendwelchen anderen schleifen als ganz "normalen" eingang verwenden.

Und erst wenn du mit der auswertung fertig bist enablest du den 
Interrupt wieder.

Gruß

Dennis

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich war immer davon ausgegangen, dass der Interrupt innerhalb der 
Routine automatisch deaktiviert und erst am Ende durch reti wieder 
aktiviert wird.
Ich möcht nicht ständig den Eingangspin abfragen, sondern sobald ein 
Byte kommt in die Interruptroutine springen und dort dann die 8 Bits 
auswerten um dann die Routine verlassen.

Beispiel
interrupt:
Abfrage an Pin int0 (PB1)
Bitzeiten der 8 Bit bzw eventuellen Timeout durch Zähler auswerten.
Anschliessend
Status 1 oder 0
RXBxte = ???
Reti

Autor: Dennis U. (atmegadennis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso,

ja, die Abfrage des einzelnen Pins in der Interrupt routine ist kein 
Problem, man sollte nur bedenken, das für die Zeit der Routine wie du 
oben auch schon beschrieben hast die anderen Interrupts blockiert 
werden. Wenn in dieser Zeit zum Beispiel ein Timeroverflow passiert, 
wird dieser erst nach der "Empfangsroutine" ausgeführt, was vielleiht zu 
zeitlichen Problemen führen kann. Deshalb sollte versucht werden, diese 
Routinen so kurz wie möglic zu halten.

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Timer benutze ich aufgrund fehlender Erfahrung noch nicht.
Die Bit_Auswertung mache ich mit Schleifen und Abfragen.
Ich hatte nur Bedenken, ob es möglich ist, den Pin, der vorher als 
Interrupt-Pin gedient hat, in der Interruptroutine selber als einfachen 
Eingang zu verwenden.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guenter Bru wrote:
> Timer benutze ich aufgrund fehlender Erfahrung noch nicht.

Schade eigentlich, denn das Verwenden eines Timers macht Vieles 
einfacher.

> Die Bit_Auswertung mache ich mit Schleifen und Abfragen.
> Ich hatte nur Bedenken, ob es möglich ist, den Pin, der vorher als
> Interrupt-Pin gedient hat, in der Interruptroutine selber als einfachen
> Eingang zu verwenden.

In der ISR eines externen Interrupts das gesamte Telegramm einzulesen, 
ist keine gute Idee, aber sicherlich nicht unmöglich.

Ich würde (für UART) beim Int den Timer starten und mir vom Timer die 
nächsten Abfragetermine generieren lassen. Bei anderen seriellen 
Übertragungsarten (z.B. 25/75%-Protokoll oder Servoimpuls) würde ich im 
ext. Interrupt den Timerstand abfragen und auswerten, also bei 
Impulsbeginn Zeitstempel merken und bei Impulsende den gemerkten vom 
neuen Zeitstempel subtrahieren. Das erlaubt genaue Zeitmessung 
(Software-ICP), während die Compare-Einheiten nebenher noch den Takt für 
andere Dinge bereitstellen können.

...

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>In der ISR eines externen Interrupts das gesamte Telegramm einzulesen,
>>ist keine gute Idee, aber sicherlich nicht unmöglich.

Was meinst du mit "sicherlich nicht unmöglich" ?
So schwierig ? Ich programmiere eher selten.
Timer mögen eleganter sein, aber während der uP das Byte einliest, 
braucht er nicht unbedingt etwas anderes zu machen.
Anbei meine noch nicht so ganz funktionierende Interruptroutine:

int0_handler: ;Empfängt Byte 
cbi ddrb,bus  ;Pin als Eingang schalten
ldi RXByte,0  ;Byte löschen

rcall Empfang_Bit   ;Bit empfangen
cpi status,1        ;Bit ok ?
brne Byte_verwerfen ;Wenn nicht Byte verwerfen, Status=0, Exit Routine

ldi Bitzaehler,7    ;restliche 7 Bits
loop_Bits:

rcall Empfang_Pause ;Pause empfangen
cpi status,1        ;Bit ok ?
brne Byte_verwerfen ;Wenn nicht Byte verwerfen, Status=0, Exit Routine

rcall Empfang_Bit   ;Bit empfangen
cpi status,1        ;Bit ok ?
brne Byte_verwerfen ;Wenn nicht Byte verwerfen, Status=0, Exit Routine

dec Bitzaehler      ;Letztes Bit ?
brne loop_Bits       ;wenn nicht weiter auswerten

Byte_ok:
ldi Status,1
com rxbyte
reti

Byte_verwerfen:
ldi Status,0
reti


Empfang_Bit:

ldi Zaehler,0    ;Zähler auf Null
ErhoehenA:
inc Zaehler    ;Zähler um 1 erhoehen
rcall bit_delay    ;Delay
cpi Zaehler, 20   ;Zählerüberlauf ? dann Status=0 und Ret
brne loopA
ldi status,0       ;Fehler Status auf 0 setzten   
ret
loopA:
sbis Pinb,Bus    ;Pin = 1 dann fertig
rjmp ErhoehenA    ;sonst weiterzählen
cpi Zaehler,laenge  ;Wenn über 5 dann Carry clear sonst Carry set
ror RXByte    ;Carry in Empfangsbyte schieben
ldi Status,1    ;Status ok

ret

Empfang_Pause:
   
ldi Zaehler,0    ;Zähler auf Null
ErhoehenB:
inc Zaehler      ;Zähler um 1 erhoehen
rcall bit_delay      ;Delay
cpi Zaehler, 20    ;Zählerüberlauf ? dann Status=0 und Ret
brne loopB
ldi status,0        ;Fehler Status auf 0 setzten
ret
loopB:
sbic Pinb,Bus    ;Pin = 0 dann fertig
rjmp ErhoehenB    ;sonst weiterzählen
cpi Zaehler,laenge    ;Wenn über 5 dann gültig (Carry Clear)
brcs endeB      ;Status auf Fehler,lassen wenn Carry Set
ldi Status,1    ;und Status ok setzten
EndeB:
ret



Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe jetzt einige Zeit (erfolglos) herumprobiert:
Folgender Code funktioniert nicht bzw die Befehle sbic oder auch sbis 
funktionieren nicht.
Kann mir einer sagen warum das so ist ?
Habe ich irgendetwas übersehen ?
Bei L-Pegel soll der Interrupt auslösen, was er auch macht.
Aber jede weitere Abfrage des Pins in der Interruptroutine ignoriert der 
Tiny13.
Hier die Interruptroutine:
MCUCR 01000000  ;LowPegel -> Interrupt
GIMSK 01000000  ;INT0 enabled

int0_handler: ;Empfängt Byte 
cbi ddrb,1  ;Pin als Eingang schalten
sbic portb,1
LED_aus:
sbi portb,3 ;LED aus
rjmp loop
reti
LED_an:
cbi portb,3 ;LED an
reti

Was passiert eigentlich mit weiteren INT0 Interrupts, welche während 
eines INT0 Interrupts auftreten ?
Werden die verworfen oder in eine Warteschlange gestellt ?

Gruß

Günter

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Wieso schaltest du das Pin erst in der Interruptroutine als Eingang? 
Wenn du einen Interrupt auslösen willst geht das nur mit einem Eingang.

MfG Spess

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Was passiert eigentlich mit weiteren INT0 Interrupts, welche während
>eines INT0 Interrupts auftreten ?
>Werden die verworfen oder in eine Warteschlange gestellt ?

Oh ja, die werden in eine gestellt, aber in eine, deren Länge auf 1 
begrenzt ist. :-) Die "Warteschlange" ist das INTF0-Flag im GIFR.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
int0_handler:         ;Empfängt Byte
 cbi ddrb,1  ;Pin als Eingang schalten
Unfug, der Int-Pin sollte schon beim Warten auf den Int. Eingang sein...

 sbic portb,1
LED_aus:              ;Label ist eigentlich nicht erforderlich
 sbi portb,3 ;LED aus ;Richtig, LED aus, wenn PB1 gesetzt war

 rjmp loop
 reti
Was soll das denn??? LED_an wird dadurch nie erreicht...

LED_an:
 cbi portb,3 ;LED an
 reti


Versuch's mal so:

int0_handler:       ;Empfängt Byte
 sbic portb,1           ;ist H-Pegel an PB1? - nein, skip...
 sbi portb,3            ;ja, mach LED aus
 sbis portb,1           ;ist L-Pegel an PB1? - nein, skip...
 cbi portb,3            ;ja, mach LED an
 reti                   ;fertig und zurück...

...

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich möchte ein 8Bit über den INT0 Eingang empfangen.
>Sobald der Level auf der Leitung von 5 auf 0 Volt wechselt löst der
>Interrupt aus. Innerhalb dieser Routine möchte dann die wieteren
>Pegeländerungen (Bits) auswerten um dann nach 8 Bits oder auch nach
>einem möglichen Timeout (Störimpuls auf der Leitung) die
>Interruptroutine zu verlassen und auf das nächste Byte warten.

Mit externen Interrupts wird man da erfahrungsgemäß wenig glücklich. 
Die Alternative ist: Konfigurier einen Timer so, das er mit einer 
passenden Frequenz tickt, und frag in dessen Interrupthandler den 
Leitungspegel zyklisch ab. Mit dem jeweils aktuell eingelesenen Pegel 
fütterst Du eine State Machine, in der der Bitstrom geeignet verrechnet 
wird.

Autor: guenter bru (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe den Code nochmal berichtigt. (Habe schon sehr viele Versuche 
probiert und den Code entsprechend oft geändert gehabt .)

@spess53
Nur zur Sicherheit. Ich habe in der Initroutine auch schon ein cbi 
DDRB,1 stehen.
@all
Wie gesagt der Interrupt wird ausgelöst. Nur sbis und sbic funktionieren 
in der Interruptroutine nicht.
sbis portb,1 müsste doch eigentlich prüfen, ob Eingang 1 an Port B H 
oder L ist und dementsprechend den RJMP Befehl ausführen oder 
überspringen.
Bei unten stehendem Code wird der sbic folgende Befehls immer 
ausgeführt.
Da bei portb,1 = L der Interrupt ausgeführt wird, müsste der kurze Zeit 
später immer noch auf L liegende Eingang doch bewirken, dass rjmp 
übersprungen wird.
Bin ziemlich ratlos.
MCUCR 01000000  ;LowPegel -> Interrupt
GIMSK 01000000  ;INT0 enabled

int0_handler: ;Empfängt Byte 
cbi ddrb,1  ;Pin als Eingang schalten
sbic portb,1
rjmp LED_an
LED_aus:
sbi portb,3 ;LED aus (gegen 5V)
reti
LED_an:
cbi portb,3 ;LED an (gegen 5V)
reti


Gruß

Günter

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Den Status eines Eingangspins wird mit PinX nicht mit PortX abgefragt.

MfG Spess

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt. Danke vielmals für die Hilfe. Da hätte ich noch lange suchen 
können.

Gruß

Günter

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

No Problem. Aber bei meinem letzten Posting sind bei mir Kopf und Finger 
in verschiedene Richtungen gewandert. Aber wenns hilft.

MfG Spess

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 wrote:
> Hi
>
> Den Status eines Eingangspins wird mit PinX nicht mit PortX abgefragt.
>
> MfG Spess

Und das habe ich aufgrund der anderen Fehler auch noch übersehen, 
schäm...

...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.