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
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
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
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.
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.
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. ...
>>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 |
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
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
>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.
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... ...
>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.
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
Hi Den Status eines Eingangspins wird mit PinX nicht mit PortX abgefragt. MfG Spess
Stimmt. Danke vielmals für die Hilfe. Da hätte ich noch lange suchen können. Gruß Günter
Hi No Problem. Aber bei meinem letzten Posting sind bei mir Kopf und Finger in verschiedene Richtungen gewandert. Aber wenns hilft. MfG Spess
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.