Hallo, laut dem Artikel zu Interrupts hier wird der loop Code bei Interrupt unterbrochen, der ISR Code ausgeführt und dann fortgesetzt. Wie verhält es sich, wenn der loop Code gerade mit delay pausiert ist und ein Interrupt auftritt? Wird der Code dann mit dem Befehl nach delay fortgesetzt oder wird die restliche Zeit nach Unterbrechung pausiert? Danke für alle Antworten Matthias
Matthias schrieb: > Wird der Code dann mit dem Befehl nach delay > fortgesetzt oder wird die restliche Zeit nach Unterbrechung pausiert? Hallo, Gemeint ist Maschinencode. Maschinencode "delay" gibt es nicht. Programm wird ab nächster Maschinenoperation fortgesetzt. Mit welchen Maschinencoden wird "delay" bei dir realisiert, solltest du in Disassembler kucken. http://www.avr-asm-tutorial.net/avr_de/beginner/commands.html
:
Bearbeitet durch User
Matthias schrieb: > laut dem Artikel zu Interrupts hier wird der loop Code bei Interrupt > unterbrochen, der ISR Code ausgeführt und dann fortgesetzt. > Wie verhält es sich, wenn der loop Code gerade mit delay pausiert ist > und ein Interrupt auftritt? Wird der Code dann mit dem Befehl nach delay > fortgesetzt oder wird die restliche Zeit nach Unterbrechung pausiert? delay ist kein befehl. delay kann auf verschiedene Weise implementiert sein, die dazu führen können das während des ISR der delay-"timer" weiterläuft ... oder auch nicht. https://youtu.be/5ZLtcTZP2js?t=114
Wenn das Delay aus der bei avrlibc-üblichen "Verbrauch n-Clock-Cycles" Warteschleife besteht, dann wird es um die Interrupt-Laufzeit länger. Für exakte Verzögerungen könnte man z.B. einen Timer benutzen und in einer Schleife auf eines von dessen "Interrupt-Flags" warten. Ohne allerdings diese Interrupts freizuschalten. Läuft der μC mit 1MHz und Timer0 läuft mit Teiler 1, dann setzt er nach 256μs das Timer0-Overflow-Flag.
:
Bearbeitet durch User
Exakt ist nicht notwendig.
1 | void loop() { |
2 | digitalWrite(PIN, HIGH); |
3 | delay(10000); |
4 | digitalWrite(PIN, LOW); |
5 | } |
Wenn der Interrupt z.B. nach einer Sekunde eintritt sollte die Pause noch ca. 9 Sekunden andauern. Sind die ersten Gehversuche in dieser Materie ;-)
Matthias schrieb: > void loop() { > digitalWrite(PIN, HIGH); > delay(10000); > digitalWrite(PIN, LOW); > } Hallo, das ist C-Code. Sie wird vom Compiler in Maschinencode umgesetzt. Die Maschinencode ist, womit Mikrocontroller arbeitet. Er hat keine Ahnung von loop und von delay - das ist nur für deine Bequemlichkeit so geschrieben. Nach ISR wird nächste Maschinencode gemacht. Willst du wirklich etwas außer "loop" machen, mit ISR usw, dann solltest du bessere Vorstellung von Mikrocontroller haben. Kenntnisse nur von Arduino-IDE reichen nicht aus, du solltest wissen, was C ist und was Assembler ist. Arduino ist für einfache Sachen konzipiert, für Menschen, die nichts außer "loop" machen wollen.
:
Bearbeitet durch User
Bei Arduino wird der delay nach dem Abarbeiten des Interrupts fortgesetzt. Das heißt, deine gewünschten 10.000ms sind nur eine "mindestens" Angabe, das Delay kann beliebig länger dauern. Außerdem wird der Pin auch ohne Interrupts nicht exakt im 10s Raster umgeschaltet, weil dir digitalWrite() Aufrufe und der Rücksprung zum Anfang der loop auch Zeit kosten. In deinem Code-Beispiel fehlt vermutlich ein zweites Delay ganz unten. Wenn du es genau haben willst, musst du einen Timer verwenden. Zum Beispiel:
1 | unsigned long zeit; |
2 | |
3 | void setup() |
4 | {
|
5 | zeit=millis(); |
6 | }
|
7 | |
8 | void loop() |
9 | {
|
10 | digitalWrite(PIN, HIGH); |
11 | |
12 | while (millis()-zeit < 10000) {}; |
13 | zeit+=10000; |
14 | |
15 | digitalWrite(PIN, LOW); |
16 | |
17 | while (millis()-zeit < 10000) {}; |
18 | zeit+=10000; |
19 | }
|
Selbst wenn die while Schleife tatsächlich länger als 10s dauert, beginnt das nächste Intervall dennoch exakt 10s später weil die Variable Zeit immer exakt auf 10s weiter gesetzt wird.
Matthias schrieb: > Wie verhält es sich, wenn der loop Code gerade mit delay pausiert ist > und ein Interrupt auftritt? Guck es dir einfach an. Setzte vor dem Aufruf von delay() einen IO-Pin auf High und danach wieder auf Low. Das Gleiche machst du für einen anderen IO-Pin am Anfang und Ende der Interrupt-Routine. Den Signalverlauf an den beiden IO-Pins zeichnest du mit einem einfachen Logikanalysator(*) auf. Dann kannst du nach herzenzlust rummessen. (*) z.B. https://www.ebay.de/itm/273246600838
Kommt drauf an, wie das Delay implementiert ist. Wenn mit einem Timer, dann verlängert sich das Delay nicht. Wenn mit einer Zählschleife, dann addiert sich die Zeit des Interrupts. Da typisch Interrupts <1% der CPU-Zeit benötigen, ist das in der Regel kein Problem. Eine genaue Uhr kann man mit Delay eh nicht machen.
:
Bearbeitet durch User
Matthias schrieb:
1 | > void loop() { |
2 | > digitalWrite(PIN, HIGH); |
3 | > delay(10000); |
4 | > digitalWrite(PIN, LOW); |
5 | > } |
> Sind die ersten Gehversuche in dieser Materie ;-)
Das sieht man. Dieser Code wird vermutlich nicht das tun, was du
erwartest. Der Pin wird zwar am Ende der Schleife auf LOW gesetzt, aber
unmittelbar darauf am Anfang der Schleife wieder auf HIGH. Weder mit dem
Auge noch mit den meisten Meßmitteln [1] wirst du überhaupt sehen, daß
der Pin alle 10 Sekunden mal für ein paar Mikrosekunden auf LOW geht.
[1] keine Change mit jeglichem Multimeter. Auch ein Oszilloskop hilft
nur bedingt. Am besten ist noch ein Logikprüfstift mit
Impulsverlängerung.
Axel S. schrieb: > Auch ein Oszilloskop hilft nur bedingt. Quatsch, umgehen können muss man mit dem Oszilloskop allerdings schon.
Wolfgang schrieb: > Axel S. schrieb: >> Auch ein Oszilloskop hilft nur bedingt. > > Quatsch, umgehen können muss man mit dem Oszilloskop allerdings schon. Axel hat vielleicht an einen µC mit GHz-Takt gedacht. Dann sind die Ansprüche an einen Oszi schon ziemlich groß und das "bedingt" passt ;-)
Matthias schrieb: > Achso...Attiny85/Attiny84 Wie ist es dir gelungen, Arduino mit Attiny85 zu machen?
Maxim B. schrieb: > Wie ist es dir gelungen, Arduino mit Attiny85 zu machen? Ich weiss nicht, was der TO empfiehlt. Google sagt z.B.: http://highlowtech.org/?p=1229 https://www.instructables.com/id/Program-an-ATtiny-with-Arduino/
Matthias schrieb: > Wird der Code dann mit dem Befehl nach delay > fortgesetzt Das würde bedeuten, dass der Interrupt erst nach Abarbeitung des Delays auftreten kann und das wäre ein schwerer Softwarefehler. Der Interrupt könnte so ja sekundenlang verzögert werden. Nein, der Interrupt muss den Delay mittendrin unterbrechen (deswegen heisst er Interrupt, siehe auch Coitus Interruptus). Ich würde aber nicht die Hand dafür irgendwohin legen dass das immer so ist, besonders wenn es sich um eine selbstgestrickte Delay-Routine handelt. Nach dem Interrupt wird der Rest des Delay abgearbeitet. Damit der möglichst wenig verfälscht wird darf die Interrupt-Bearbeitung nur sehr kurz laufen. Georg
Wolfgang schrieb: > Guck es dir einfach an. Genau, einfach mal in den SourceCode von delay() schauen. Wenn man nicht die Arduino IDE sondern Visual Studio Code mit PlatformIO verwendet geht das sehr einfach mit einem Mausclick, ansonsten muss man eben mit grep suchen und wird dann hier fündig: https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c#L106: void delay(unsigned long ms) { uint32_t start = micros(); while (ms > 0) { yield(); while ( ms > 0 && (micros() - start) >= 1000) { ms--; start += 1000; } } }
Georg schrieb: > Das würde bedeuten, dass der Interrupt erst nach Abarbeitung des Delays > auftreten kann Wenn das so sein muß - es gibt nichts einfacher. Vor delay cli() schreiben und danach sei().
Die Funktionen '_delay_ms() und '_delay_us()' der AVRLib sind, sofern sie nicht in der ISR selber stehen, immer unterbrechbar. ISR beim AVR sind ja ohne besondere Massnahmen 'blockierend', d.h., sie können selber nicht mehr unterbrochen werden. Ein '_delay_ms()' in einer ISR ist deswegen tabu. AVRGCC und die AVRLib erlauben allerdings unterbrechbare Sonderformen der ISR.
:
Bearbeitet durch User
Maxim B. schrieb: > Wenn das so sein muß - es gibt nichts einfacher. > Vor delay cli() schreiben und danach sei(). Das ist keine gute Idee: Du bringst die Zeitverwaltung durcheinander, da die von millis() und micros() zurückgelieferte Zeit nicht mehr durch die Timer IRQs erhöht wird und quasi stehen bleibt. Möglicherweise funktioniert delay() dann überhaupt nicht mehr, da es selbst micros() verwendet. IRQs dürfen immer nur so kurz wie möglich gesperrt werden. Michael
:
Bearbeitet durch User
Michael D. schrieb: > Das ist keine gute Idee: > Du bringst die Zeitverwaltung durcheinander, da die von millis() und > micros() Ich bin der Meinung, daß IDE Arduino in sich keine gute Idee ist, da keine Debug-Mittel integriert. Weder JTAG-Emulator noch Simulator sind möglich. Wenn man so IDE benutzt, kann man kaum noch etwas schlechter machen.
Hi Nun, einige Antworten sind ja schon in die richtige Richtung, bei anderen bezweifle ich, das die Schreiber wissen, was ein Interrupt ist.(gut, es gibt verschiedene Arten, aber bei einem µC ist es so ziemlich immer gleich) Ein Programm wird nach Maschinencode abgearbeitet. Maschinencode ist nicht Assembler oder gar eine andere Sprache, sondern ganz schlicht elektrische Zustände, gespeichert in einem (elektrisch) adressierten Speicher ausgedrückt für die Programmierer in "1" und "0". Diese sind dann 8, 16 oder auch mal 32 Bit breit. Diese Bitmuster werden im Controller in der Befehlsmatrix zu einem Befehl umgesetzt. (Oberflächlich erklärt) Nun zum Interrupt. Einige Hardwarekomponenten sind in der Lage, den Programmablauf zu stören, also einzugreifen und das Adressregister für die Befehlsspeicher einfach auf einen anderen Speicherbereich zu setzen. Dort steht dann entweder der Programmcode für die Interruptbearbeitung, oder einfach ein Rücksprung. Ablauf ist etwa so: Interrupt löst aus: Adresse vom Adressregister für den Programmbereich wird zwischengespeichert. Adresse wird auf einen festen Wert passend zum Interrupt im Programmspeicher gesetzt. (Stichwort Interruptvektortabelle) Dort steht entweder ein Sprungbefehl zur Bearbeitung (Interruptserviceroutine oder ISR) mit abschließendem "Return from Interrupt" oder nur ein "Return from Interrupt" (RETI) der die Adresse des letzten Befehles wieder in das Adressregister für das Programm schreibt. (Rücksprung) Nun ist ein Delay ein Befehl, der entweder in einer Schleife eine Anzahl unnützer Befehle (NOP) ausführt, um Zeit totzuschlagen oder auch eine etwas aufwändigere Programmierung über Zeitregister (Timer). Ersteres ist eine berechnete Anzahl von Wiederholungen, da der Controller für jede Bearbeitung Zeit benötigt. Etwa so: Befehl lesen und Adressrregister erhöhen (nächste Befehlsadresse) Adresse liefert Befehl Befehl: tu nix (NOP) Dieser Schritt kann auch ausgelassen werden, entsprechend mehr Schleifendurchläufe braucht es dann. Weiter: Befehl lesen und Adressrregister erhöhen (nächste Befehlsadresse) Adresse liefert Befehl: Erhöhe einen Zähler (INC was auch immer) Befehl lesen und Adressrregister erhöhen (nächste Befehlsadresse) Adresse liefert Befehl: Vergleiche Zähler mit Vorgabe (CP was auch immer) Befehl lesen und Adressrregister erhöhen (nächste Befehlsadresse) Adresse liefert Befehl: Sprung wenn Flag (Flag ist ein Bit und wird beim Vergleich je nach Ergebnis gesetzt) Entweder wird also wieder mit dieser Befehlsfolge erneut gearbeitet und Zeit vertrödelt, wenn die vorgegebene Anzahl der Schleifendurchläufe noch nicht erreicht ist oder die "normale" Programmbearbeitung fortgesetzt. Ein Interrupt schiebt sich, egal wo, einfach dazwischen und ob in einer Schleife oder den laufenden Programmcode, (Auch letztlich eine Schleife) der Controller landet immer wieder beim nächsten Befehl vor der Interruptauslösung. (Wenn man nicht irgendeinen Blödsinn in der ISR programmiert....) Allerdings verlängert sich in diesem Fall die Zeit um die Befehlsverarbeitungszeit in der ISR. Es ist möglich, das ein Interrupt mehrfach in einer Schleife erzeugt wird und somit auch entsprechend große Abweichungen der Delay-Zeit entsteht. Das Delay über Timer erzeugt selbst einen Interrupt mit einer eigenen ISR und bremst den Programmzyklus nicht aus. In C-Programmen wird die Bearbeitung so nicht deutlich. Da ich mit C nix am Hut hab, kann ich noch nicht mal sagen, ob der Programmierer weiß, das ein Delay eine programmzyklusverlängernde Wirkung hat oder einen Interrupt auslöst. Das könnt ihr besser. Gruß oldmaX
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.