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