Guten Morgen habe soeben hier gelesen das ein AVR keine verschachtelten Interuppts kann. Hab nähmlich das Problem das ein TIMER0_OVF kein INT0 zulässt. Wenn das so ist dann verstehe ich nicht warum es eine Interuppt-Prio-Liste gibt? Danke für euere Hilfe!!! Hier Auszüge aus meinem Code: .ORG 0x0000 RJMP RETURN .ORG 0x0001 RJMP INT_INT0 .ORG 0x0008 RJMP TIMER1_OVF .ORG 0x000B RJMP TIMER0_OVF // TIMER0 LDI temp, (1<<WGM02)|(1<<CS00) OUT TCCR0B, temp IN temp, TIMSK0 SBR temp, (1<<TOIE0) OUT TIMSK0, temp //INT0-Freigabe IN temp, MCUCR SBR temp, (1<<ISC01) //Fallende FLanke OUT MCUCR, temp IN temp, GIMSK SBR temp, (1<<INT0) OUT GIMSK, temp Wenn ich folgenden TIMER0 Code auskommentiere funktioniert INT0: IN temp, TIMSK0 SBR temp, (1<<TOIE0) OUT TIMSK0, temp Gruß und Dank Bernd
BerndB schrieb: > Hab nähmlich das Problem das ein TIMER0_OVF kein INT0 zulässt. Das wäre aber auch ne saudämliche Idee, in einem Interrupt auf nen anderen zu warten. Ein Interrupt macht sein Ding und kehrt sofort zum Main zurück. Und dann kommt der andere Interrupt ran. BerndB schrieb: > Hier Auszüge aus meinem Code: Schön für Dich. Und wie arbeiten die zusammen? Und wo sind die Interrupthandler? Mit Schnipselchen kann keiner was anfangen. Peter
BerndB schrieb: > habe soeben hier gelesen das ein AVR keine verschachtelten Interuppts > kann. Falsch. Wenn Du in einer Interrupt-Serviceroutine ein 'sei' ausführst, kann auch ein weiterer Interrupt ausgelöst werden. Braucht aber - normalerweise - kein Mensch. Vorausgesetzt, er hat sich vor dem Schreiben des Programms einige Gedanken zum Konzept gemacht.
BerndB schrieb: > warum es eine Interuppt-Prio-Liste gibt? Die gibt es um zu entscheiden welcher Interrupt zuerst bedient wird, wenn mehrere Interrupts zur gleichen Zeit aktiv werden.
Sorry Peter, habe viele deiner Beiträge gelesen die mir oft sehr geholfen habe. Danke dafür! Also in einer TIMER0 ISR kontrolliere ich über ADC permanent alle 4ms eine Spannung. Durch drücken eines Tasters (verbunden mit INT0) soll ein Port meines ATtiny44A gesetzt werden. Wenn ich das Ganze im AVR Studio debugge funktioniert das auch. Leider nicht in Wirklichkeit. Hier mein TIMER0_OVF: TIMER0_OVF: IN temp, SREG PUSH temp INC R26 TST R26 BREQ TIMER0_OVF_REGULATION RJMP TIMER0_OVF_END TIMER0_OVF_REGULATION: RCALL SET_CHANNEL_ADC1 //Kanal: 1 LDI temp5, LOW(OUTPUT_700mA) //Sollwert LDI temp6, HIGH(OUTPUT_700mA) LDS temp, (START_UP_VALUE) //Status TST temp //0: BRSH noch nicht erreicht 1: BRSH bereits errreicht BREQ STARTING_UP RJMP TIMER0_OVF_CONTROLL STARTING_UP: RCALL GET_VOLTAGE RCALL DELAY_1_MSEC CP ADC_VAL_LOW, temp5 CPC ADC_VAL_HIGH, temp6 BRLO STARTING_UP_LOW_OUTPUT BRSH STARTING_UP_SAME_OR_HIGHER_OUTPUT STARTING_UP_LOW_OUTPUT: IN temp, OCR0B INC temp OUT OCR0B, temp RJMP STARTING_UP STARTING_UP_SAME_OR_HIGHER_OUTPUT: IN temp, OCR0B //aktuellen Wert holen STS (START_UP_VALUE), temp RJMP TIMER0_OVF_END TIMER0_OVF_CONTROLL: LDI temp5, LOW(OUTPUT_700mA +80) LDI temp6, HIGH(OUTPUT_700mA +80) RCALL SET_CHANNEL_ADC1 RCALL GET_VOLTAGE CP ADC_VAL_LOW, temp5 CPC ADC_VAL_HIGH, temp6 BRSH OUTPUT_SAME_OR_TO_HIGH LDI temp5, LOW(OUTPUT_700mA +40) LDI temp6, HIGH(OUTPUT_700mA +40) CP ADC_VAL_LOW, temp5 CPC ADC_VAL_HIGH, temp6 BRLO OUTPUT_TO_LOW RJMP TIMER0_OVF_END OUTPUT_TO_LOW: IN temp, OCR0B INC temp OUT OCR0B, temp RJMP TIMER0_OVF_END OUTPUT_SAME_OR_TO_HIGH: IN temp, OCR0B DEC temp OUT OCR0B, temp RJMP TIMER0_OVF_END TIMER0_OVF_END: POP temp OUT SREG, temp RETI Hier mein INT0 ISR: INT_INT0: IN temp, SREG PUSH temp sbi porta, 5 TST temp_var BREQ SWITCH_ON RJMP INT_INT0_END SWITCH_ON: INC temp_var LDS temp, (SWITCH_ON_STATUS) INC temp STS (SWITCH_ON_STATUS), temp CPI temp, 1 BREQ POWER_ON CPI temp, 2 BREQ FLASHING_ONE CPI temp, 3 BREQ FLASHING_TWO CPI temp, 4 BREQ FINISH RJMP INT_INT0_END POWER_ON: SBI PortA, 0 //N-FET Freigabe // RCALL START_PHASE_POWER RJMP INT_INT0_END FLASHING_ONE: LDI temp, 1 STS (FLASH_STATUS), temp RJMP INT_INT0_END FLASHING_TWO: LDI temp, 2 STS (FLASH_STATUS), temp RJMP INT_INT0_END FINISH: CBI PortA, 0 //N-FET gesperrt CLR temp STS (SWITCH_ON_STATUS), temp STS (FLASH_STATUS), temp RJMP INT_INT0_END INT_INT0_END: POP temp OUT SREG, temp RETI
Graesslichst ... Kompletter Schrott. Klop das in die Tonne. Das macht man nicht so. Der Timer interrupt setzt ein Flag, das man im main abfragt. Und wenn das Flag dann kam, wandelt man. Auch der ADC Interrupt, so man das will, liest den ADC in eine speicherstelle und setzt ein Flag.
Knut Ballhause schrieb: > Falsch. Wenn Du in einer Interrupt-Serviceroutine ein 'sei' ausführst, > kann auch ein weiterer Interrupt ausgelöst werden. Braucht aber - > normalerweise - kein Mensch. Vorausgesetzt, er hat sich vor dem > Schreiben des Programms einige Gedanken zum Konzept gemacht. Ich frage mich manchmal, wie viele Gedanken sich die Menschen vor dem Posten machen. Vor Allem, wenn es so pauschale und arrogante Aussagen sind. Interrupthandling mit Prioritaeten und mehreren Ebenen ist seit Jahrzehnten gaengige Technik und natuerlich gibt es dafuer zig sinnvolle Anwendungsfaelle. Natuerlich braucht man das nicht fuer kleine Feld-Wald-Wiesen Mikrocontroller-Anwendungen und man sollte schon eine gewisse Kompetenz haben, bevor man sich an sowas ranwagt. Genauso wie beim Posten von grossen Aussagen in Foren...
Vielen Dank! Werde nun mein Programm so umschreiben das ich in der main-Funktion das TIFR0 abfrage und dann in eine entsprechende Funktion verzweige. Ich gehe davon aus das meine ISR zu lang ist. Gruß Bernd
BerndB schrieb: > Durch drücken eines Tasters (verbunden mit INT0) soll ein Port meines > ATtiny44A gesetzt werden. Aha. Tasten prellen. Daher ist dafür ein externer Interrupt schlecht und unnütz zugleich. BerndB schrieb: > Also in einer TIMER0 ISR kontrolliere ich über ADC permanent alle 4ms > eine Spannung. 4ms Intervall ist auch gut geeignet für eine Entprellroutine. Mach also die Tastenentprellung und -abfrage hier mit. Peter
xXx schrieb: > Ich frage mich manchmal, wie viele Gedanken sich die Menschen vor dem > Posten machen. Vor Allem, wenn es so pauschale und arrogante Aussagen > sind. Interrupthandling mit Prioritaeten und mehreren Ebenen ist seit > Jahrzehnten gaengige Technik und natuerlich gibt es dafuer zig sinnvolle > Anwendungsfaelle. Hallo?! Wir reden hier von einem AVR. Leg´ Dich ruhig wieder hin.
BerndB schrieb: > Werde nun mein Programm so umschreiben das ich in der main-Funktion das > TIFR0 abfrage Das wird nicht funktionieren! Das Register wird eigentlich nur von der Hardware verwendet: Entsprechendes Bit gesetzt -> ISR aufrufen -> Bit löschen.
Sorry, ich möchte trotzdem zu meiner Frage zurückkehren und fragen kann nun ein ATtiny44A verschachtelte Interrupts oder nicht? Gruß Bernd
BerndB schrieb: > Sorry, > ich möchte trotzdem zu meiner Frage zurückkehren und fragen kann nun > ein ATtiny44A verschachtelte Interrupts oder nicht? > > Gruß > Bernd Ja, das geht. Ist aber mit höchster Warscheinlichkeit nicht sinnvoll. Knut Ballhause schrieb: > Falsch. Wenn Du in einer Interrupt-Serviceroutine ein 'sei' ausführst, > kann auch ein weiterer Interrupt ausgelöst werden. Braucht aber - > normalerweise - kein Mensch. Vorausgesetzt, er hat sich vor dem > Schreiben des Programms einige Gedanken zum Konzept gemacht.
Und nochmal. Ja, er kann. Und nein, man benutzt es normalerweise nicht. Es besteht bei einem sauberen Programmaufbau auf einem AVR normalerweise keine NOtwendigkeit dafür. Und nein, Tastenabfrage mittels Interrupt ist meistens eine ganz blöde Idee. Wenn eine Taste überhaupt einen Interrupt auslösen können soll, dann beschränkt sich das darauf, dass die Taste den AVR aus dem Tiefschlaf holen muss. Die eigentliche Abfrage macht man dann wieder über ganz normales Polling (weldches zb über Timer-Interrupts getrieben wird).
Mist! Gestern gingen bei meinem XMEGA noch priorisierte Interrupts. Ich hoffe der liest diesen Thread nicht und machts heute trotzdem noch.
Stefan schrieb: > Mist! > Gestern gingen bei meinem XMEGA noch priorisierte Interrupts. Schön für deinen XMEGA. Millionen von AVR-Programmierer (Tiny und Mega) kommen bei ihren Programmen ohne das Feature aus, dass ein Interrupt einen anderen unterbrechen muss. Und das ohne dass ihre Programme deswegen schlecht funktionieren oder schlecht zu lesen wären. Ganz im Gegenteil.
Stefan schrieb: > Mist! > Gestern gingen bei meinem XMEGA noch priorisierte Interrupts. > Ich hoffe der liest diesen Thread nicht und machts heute trotzdem noch. Vielleicht kann der aber lesen und merkt, dass er kein tiny44 ist?
HI >ich möchte trotzdem zu meiner Frage zurückkehren und fragen kann nun >ein ATtiny44A verschachtelte Interrupts oder nicht? Wie schon gesagt, ja. Aber um den ADC zu starten brauchst du keinen Interrupt. Dafür hat der ADC eine Autotriggerfunktion. Im AD Complete Interrupt setzt du ein Flag (ADC fertig) und liest ggf. die ADC-REgister aus. Dazu reichen etwa 10 Befehle, also ein paar µs. MfG Spess
BerndB schrieb: > ich möchte trotzdem zu meiner Frage zurückkehren und fragen kann nun > ein ATtiny44A verschachtelte Interrupts oder nicht? Nein, das kann er nicht. Man kann sowas nur in Software nachbilden. Das bedingt aber einen beträchlichen Aufwand im niederpriorisierten Interrupt (Sichern und Sperren all niederpriorisierten Freigaben), der einige CPU-Zyklen kostet, ehe der höherpriorisierte wieder bearbeitet werden kann. Oftmals wird gedankenlos nur ein SEI im Interrupt empfohlen. Das macht aber noch lange keine Prioritäten, dafür aber schnell einen Stacküberlauf. Peter
Sorry das ich hier nicht mit der dem Thema angemessenen entspechenden Ernsthaftigkeit geantwortet habe. Ich wollte nur darauf hinweisen das AVR's,und darum ging es, durchaus solche Features bieten. >> Millionen von AVR-Programmierer (Tiny und Mega) kommen bei ihren Programmen ohne das Feature aus Und die kommen auch ohne dieses vollkommen unnütze Eventsystem und diesen schwachsinnigen DMA aus.
Hi >Und die kommen auch ohne dieses vollkommen unnütze Eventsystem und >diesen schwachsinnigen DMA aus. Wieso? Es gibt doch AVRs mit diesem überflüssigen Zeugs. MfG Spess
Stefan schrieb: >>> Millionen von AVR-Programmierer (Tiny und Mega) kommen bei ihren > Programmen ohne das Feature aus > > Und die kommen auch ohne dieses vollkommen unnütze Eventsystem und > diesen schwachsinnigen DMA aus. Das wiederrum hab ich nicht gesagt oder behauptet. Aber ist ein wenig kontraproduktiv, mit den Fähigkeiten eines XMEGA zu argumentieren, wenn die Community einem Neuling beibringen will, wie man auf einem Tiny (oder klassischem Mega, also nicht XMega) das Interrupt-System zu seinem Nutzen einsetzt, wenn er sich in einer falschen Vorstellung verlaufen hat oder einer Lösung nachläuft, die ihn nicht weiterbringt.
Ich danke euch allen! Nun werde ich mich auf nur einen Interrupt beschränken und meine anderen Anforderungen in dieser ISR einbinden! DANKE
BerndB schrieb: > und meine anderen Anforderungen in dieser ISR einbinden! Nicht 'in'! Höchstens ein Flag setzen. Bei nur einer (Timer-)ISR braucht man wahrscheinlich nicht mal das.
BerndB schrieb: > Ich danke euch allen! > Nun werde ich mich auf nur einen Interrupt beschränken und meine anderen > Anforderungen in dieser ISR einbinden! > Genau das ist der WEg, den du NICHT gehen sollst. Die bewährte Programmstrategie sieht so aus: Deine Aktionen kommen alle in die Hauptschleife. Dazu gibt es zb ein Register, in dem ein Bit eine Aktion anstösst. Ist das Bit gesetzt, dann wird die Aktion gemacht, ist es nicht gesetzt, dann wird sie nicht gemacht. ISR reagieren auf irgendwelche Ereignisse und stossen Aktionen an. Sie führen aber die Aktion nicht selber aus, sondern setzen nur das Bit im Register. Die eigentliche Aktion wird dann von der Hauptschleife aus gemacht. Also in etwa so
1 | Vorgeplänkel wie Register einstellen, Hardware konfigurieren |
2 | Interrupts einstellen, etc. |
3 | |
4 | sei |
5 | |
6 | main_loop: |
7 | |
8 | wenn Job-Bit 1 gesetzt |
9 | setze Job-Bit 1 zurück |
10 | führe die zugehörige Aktion aus, zb den ADC starten |
11 | |
12 | wenn Job-Bit 2 gesetzt |
13 | setze Job-Bit 2 zurück |
14 | führe die zugehörige Aktion aus, zb den ADC auslesen |
15 | und verarbeiten |
16 | |
17 | wenn Job-Bit 3 gesetzt |
18 | setze Job-Bit 3 zurück |
19 | führe zugehörige Aktion aus, zb Timer einschalten |
20 | |
21 | etc. |
22 | etc. |
23 | |
24 | jmp main_loop |
die ISR wiederrum, setzen nur das Job bit. Zb der Interrupt mit dem der ADC seine Fertigsein verkündet
1 | ISR ( ADC_COMPLETE ) |
2 | ev. den ADC Wert abholen |
3 | setzte Job-Bit 2 |
4 | reti |
oder der Timer Overflow, der einen ADC-AUslesevorgang anstösst
1 | ISR ( TIMER_OVERFLOW ) |
2 | setze Job-Bit 1 |
3 | (da das starten des ADC nicht lange dauert, könnte man |
4 | den ADC auch direkt hier starten) |
5 | reti |
Aber auch wenn der Timer-Overflow den ADC startet, er wartet nicht darauf, dass dieser fertig wird. Ein ADC der fertig wird, ist selber wieder ein Ereignis, welches einen Interrupt feuern kann, welcher dann (durch das Job-Flag) die Auswertung des Ergebnisses veranlasst - in der main-loop auf die Art laufen die Dinge geordnet und ganz wichtig: keine ISR braucht lange! So ein Aufbau ist der Schlüssel zu einem Programm, bei dem der µC scheinbar mehrere Dinge gleichzeitig machen kann. Daher ist es gut, wenn du dir frühzeitig eine derartige Struktur angewöhnst. Wieviel man dann tatsächlich in der ISR machen lässt und wieviel in die main_loop kommt, variiert. Eine ISR muss nicht zwanghaft nur aus dem Setzen des Job-Bits bestehen. Man kann dort durchaus schon auch Aktionen machen. Grundprinzip ist aber immer: Das darf alles nicht lange dauern. Übermässig viel auszuführender Code, oder gar Warteschleifen, sind allerdings verboten! Tu was du in der ISR tun musst, aber nicht mehr. Das mehr gehört in die Hauptschleife.
Ralf, meinst du ein Flag setzen und dann von der "main-Routine" aus agieren?
Oh Karl Heinz, jetzt habe ich das auch verstanden!!! Ich freue mich über deine/euere Hilfe. Vielen Dank! Bernd
BerndB schrieb: > Ralf, > meinst du ein Flag setzen und dann von der "main-Routine" aus agieren? Genau. So, wie es Karl Heinz ausführlich erläutert hat. Wenn du dir allerdings sicher sein kannst, dass du alles 'selbst steuern kannst', dann brauchst du nicht mal das Flag:
1 | ; Initialisierungen |
2 | ; ... |
3 | ; z.B. Timer auf 1ms (!) mit Interrupt |
4 | ; Register für 'Status' reservieren |
5 | ldi reg_s, 1 |
6 | |
7 | loop: |
8 | sleep |
9 | |
10 | sbrc reg_s, 0 |
11 | rcall prog1 |
12 | sbrc reg_s, 1 |
13 | rcall prog2 |
14 | sbrc reg_s, 2 |
15 | rcall prog3 |
16 | sbrc reg_s, 3 |
17 | rcall prog4 |
18 | |
19 | lsl reg_s |
20 | brhc reg_s |
21 | ldi reg_s, 1 |
22 | |
23 | rjmp loop |
Ich hoffe, das darf man so machen ;-) Ich find's so übersichtlich. Da hast du außer ADC und Taste noch zwei Unterprogramme 'in Reserve'. Wenn's mehr sein muss, läuft reg_s eben bis acht Bit.
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.