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


von Guenter B. (gbl)


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

von Dennis U. (atmegadennis)


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

von Guenter B. (gbl)


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

von Dennis U. (atmegadennis)


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.

von Guenter B. (gbl)


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.

von Hannes L. (hannes)


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.

...

von Guenter B. (gbl)


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:
1
int0_handler: ;Empfängt Byte 
2
cbi ddrb,bus  ;Pin als Eingang schalten
3
ldi RXByte,0  ;Byte löschen
4
5
rcall Empfang_Bit   ;Bit empfangen
6
cpi status,1        ;Bit ok ?
7
brne Byte_verwerfen ;Wenn nicht Byte verwerfen, Status=0, Exit Routine
8
9
ldi Bitzaehler,7    ;restliche 7 Bits
10
loop_Bits:
11
12
rcall Empfang_Pause ;Pause empfangen
13
cpi status,1        ;Bit ok ?
14
brne Byte_verwerfen ;Wenn nicht Byte verwerfen, Status=0, Exit Routine
15
16
rcall Empfang_Bit   ;Bit empfangen
17
cpi status,1        ;Bit ok ?
18
brne Byte_verwerfen ;Wenn nicht Byte verwerfen, Status=0, Exit Routine
19
20
dec Bitzaehler      ;Letztes Bit ?
21
brne loop_Bits       ;wenn nicht weiter auswerten
22
23
Byte_ok:
24
ldi Status,1
25
com rxbyte
26
reti
27
28
Byte_verwerfen:
29
ldi Status,0
30
reti
31
32
33
Empfang_Bit:
34
35
ldi Zaehler,0    ;Zähler auf Null
36
ErhoehenA:
37
inc Zaehler    ;Zähler um 1 erhoehen
38
rcall bit_delay    ;Delay
39
cpi Zaehler, 20   ;Zählerüberlauf ? dann Status=0 und Ret
40
brne loopA
41
ldi status,0       ;Fehler Status auf 0 setzten   
42
ret
43
loopA:
44
sbis Pinb,Bus    ;Pin = 1 dann fertig
45
rjmp ErhoehenA    ;sonst weiterzählen
46
cpi Zaehler,laenge  ;Wenn über 5 dann Carry clear sonst Carry set
47
ror RXByte    ;Carry in Empfangsbyte schieben
48
ldi Status,1    ;Status ok
49
50
ret
51
52
Empfang_Pause:
53
   
54
ldi Zaehler,0    ;Zähler auf Null
55
ErhoehenB:
56
inc Zaehler      ;Zähler um 1 erhoehen
57
rcall bit_delay      ;Delay
58
cpi Zaehler, 20    ;Zählerüberlauf ? dann Status=0 und Ret
59
brne loopB
60
ldi status,0        ;Fehler Status auf 0 setzten
61
ret
62
loopB:
63
sbic Pinb,Bus    ;Pin = 0 dann fertig
64
rjmp ErhoehenB    ;sonst weiterzählen
65
cpi Zaehler,laenge    ;Wenn über 5 dann gültig (Carry Clear)
66
brcs endeB      ;Status auf Fehler,lassen wenn Carry Set
67
ldi Status,1    ;und Status ok setzten
68
EndeB:
69
ret

von Guenter B. (gbl)


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:
1
MCUCR 01000000  ;LowPegel -> Interrupt
2
GIMSK 01000000  ;INT0 enabled
3
4
int0_handler: ;Empfängt Byte 
5
cbi ddrb,1  ;Pin als Eingang schalten
6
sbic portb,1
7
LED_aus:
8
sbi portb,3 ;LED aus
9
rjmp loop
10
reti
11
LED_an:
12
cbi portb,3 ;LED an
13
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

von Spess53 (Gast)


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

von AVRFan (Gast)


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.

von Hannes L. (hannes)


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

...

von AVRFan (Gast)


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.

von guenter bru (Gast)


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.
1
MCUCR 01000000  ;LowPegel -> Interrupt
2
GIMSK 01000000  ;INT0 enabled
3
4
int0_handler: ;Empfängt Byte 
5
cbi ddrb,1  ;Pin als Eingang schalten
6
sbic portb,1
7
rjmp LED_an
8
LED_aus:
9
sbi portb,3 ;LED aus (gegen 5V)
10
reti
11
LED_an:
12
cbi portb,3 ;LED an (gegen 5V)
13
reti


Gruß

Günter

von spess53 (Gast)


Lesenswert?

Hi

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

MfG Spess

von Guenter B. (gbl)


Lesenswert?

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

Gruß

Günter

von Spess53 (Gast)


Lesenswert?

Hi

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

MfG Spess

von Hannes L. (hannes)


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

...

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.