Forum: Mikrocontroller und Digitale Elektronik Probleme bei verschachtelten Interuppt


von BerndB (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

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.

von Volkmar D. (volkmar)


Lesenswert?

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.

von BerndB (Gast)


Lesenswert?

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

von Purzel H. (hacky)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

Siehe Interrupt. Die Beispiele sind zwar in C, die Erklärung aber 
nicht ;-)

MFg
Falk

von xXx (Gast)


Lesenswert?

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

von BerndB (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

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.

von BerndB (Gast)


Lesenswert?

Ok danke Peter,

das werde ich versuchen!

von Ralf G. (ralg)


Lesenswert?

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.

von BerndB (Gast)


Lesenswert?

Sorry,
ich möchte trotzdem zu meiner Frage zurückkehren und fragen kann nun
ein ATtiny44A verschachtelte Interrupts oder nicht?

Gruß
Bernd

von Ralf G. (ralg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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

von Stefan (Gast)


Lesenswert?

Mist!
Gestern gingen bei meinem XMEGA noch priorisierte Interrupts.
Ich hoffe der liest diesen Thread nicht und machts heute trotzdem noch.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Ralf G. (ralg)


Lesenswert?

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?

von spess53 (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Stefan (Gast)


Lesenswert?

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.

von spess53 (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von BerndB (Gast)


Lesenswert?

Ich danke euch allen!
Nun werde ich mich auf nur einen Interrupt beschränken und meine anderen 
Anforderungen in dieser ISR einbinden!

DANKE

von Ralf G. (ralg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von BerndB (Gast)


Lesenswert?

Ralf,
meinst du ein Flag setzen und dann von der "main-Routine" aus agieren?

von BerndB (Gast)


Lesenswert?

Oh Karl Heinz,

jetzt habe ich das auch verstanden!!!
Ich freue mich über deine/euere Hilfe.

Vielen Dank!
Bernd

von Ralf G. (ralg)


Lesenswert?

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
Noch kein Account? Hier anmelden.