Arduino delay(ms) in ISR?

OP #4337981
Lesenswert?
• ▲
▼
Servus,

wie kann ich ein Delay in der ISR des Arduinos verwenden?

Meine  ISR sieht so aus:

-Kofig
1
attachInterrupt(digitalPinToInterrupt(2),fire, RISING);
-ISR
1
void fire(){
2
  for(int i =3;i<7;i++){
3
      digitalWrite(i,HIGH);
4
      delay(1000);
5
      digitalWrite(i,LOW);
6
      delay(1000);
7
    
8
      
9
    }
10
 }

Danke im Voraus!

Gruß
Dani
Gast #4338067
Lesenswert?
• ▲
▼
Ich bin der Überzeugung: Wer delay() verwendet hat offensichtlich nicht 
besseres zu tun.

Wird diese Aussage wörtlich genommen, so ergeben sich zwei sehr einfache 
Schlussfolgerungen:
1. Trifft diese Aussage ohne Einschränkung zu, so kann man problemlos
   auch mal 12 Sekunden in einer Interrupt-Routine rumlungern.
2. Trifft dies aber nicht zu, so hilft nur noch "Üben".

Ob die Patentantwort - "dann verlagere das Problem doch in die 
Hauptschleife" - wirklich hilft, ist eine andere Sache.
#4338148
Lesenswert?
• ▲
▼
Daniel R. schrieb:

> versuche es gerade mit dem flexitimer...werde berichten
> Blinken ist ja leicht aber eine LED 100ms leuchten lassen dann 200ms
> pause und dann wieder von vorne ist nicht so leicht...

doch ist es.
selbes Prinzip. Du hast eine Uhr in Form von millis(). Du bestimmst, 
wann ein Vorgang beendet sein soll, in dem du zum Zeitpunkt an dem der 
Vorgang beginnt die Zeit nimmtst, die geplante Dauer dazuaddierst und 
laufend (bei jedem durchlauf durch loop) überprüfst, ob dieser zeitpunkt 
schon vorbei ist.

Aus praktischen Gründen macht man es technisch ein klein wenig anders. 
Man nimmt die Zeitdifferenz zwischen 'jetzt' (repräsentiert durch 
millis()) und dem Beginn der Aktion und sieht nach ob diese 
zeitdifferenz schon größer ist als die geplante Zeitdifferenz.
Jede Hausfrau kann das. Stellt sie das Gulasch auf den Ofen, schaut sie 
auf die Küchenuhr. ZUr abgelesenen Zeit kommen 2 Stunden dazu und ab zu 
wird auf die Uhr geschaut, ob dieser Zeitpunkt erreicht ist. Wenn sie 
wissen will, wie lange das Gulasch schon kocht, dann liest sie die 
aktuelle Zeit von der Küchenuhr ab, zieht davon die Startzeit ab und 
findet so raus, dass das Gulasch schon seit anderthalb Stunden kocht. 
Das ist weniger als die geplanten 2 Stunden, daher darf es noch weiter 
kochen.


Ganz simpel.
1
unsigned long blinkStart;
2

3
void setup()
4
{
5
  blinkStart = millis();
6
}
7

8
void loop()
9
{
10
  unsigned long now = millis();
11

12
  if( now - blinkStart < 100 )
13
    led einschalten
14

15
  else if( now - blinkStart < 300 )  // 100 + 200; ein kompletter Blinkzyklus dauert daher 300 ms
16
                                     // in der ersten Hälfte des Zyklus war die LED ein
17
                                     // jetzt geht es darum, das sie bis zum Ende
18
                                     // des Blinkzyklus aus sein muss
19
    led ausschalten
20

21
  else                               // ein kompletter Blinkzyklus ist abgelaufen
22
                                     // neuen starten indem man sich merkt
23
                                     // wann das der Fall war.
24
    blinkStart = now;
25
}

und damit gelingt es dann auch ganz problemlos, 2 LED mit völlig 
unterschiedlichen Zeiten blinken zu lassen. Zb die eine mit 100+200 ms 
und die andere mit 400+700ms
1
unsigned long blinkStart1;
2
unsigned long blinkStart2;
3

4
void setup()
5
{
6
  blinkStart1 = millis();
7
  blinkStart2 = millis();
8
}
9

10
void loop()
11
{
12
  unsigned long now = millis();
13

14
  if( now - blinkStart1 < 100 )
15
    led1 einschalten
16

17
  else if( now - blinkStart1 < 100 + 200 )
18
    led1 ausschalten
19

20
  else
21
    blinkStart1 = now;
22

23
  // uuuuuund die 2.te LED
24

25
  if( now - blinkStart2 < 400 )
26
    led2 einschalten
27

28
  else if( now - blinkStart2 < 400 + 700 )
29
    led2 ausschalten
30

31
  else
32
    blinkStart2 = now;
33
}
(Firma: CIA) #4338183
Lesenswert?
• ▲
▼
Wer delay's benutzt kann nicht programmieren. Und das kommt von dem 
absolut untauglichen Einsteigerbeispiel eine LED mit einem delay blinken 
zu lassen. Ein vernünftiges Einsteigerbeispiel wäre es einmal zwei oder 
drei LED's gleichzeitig blinken zu lassen und alle mit einer anderen 
Frequenz und ohne delay's. Dann wäre eine ganze Menge für die Zukunft 
geschient. Und zwar richtig.
Gast #4338230
Lesenswert?
• ▲
▼
Was bisher bei delay() im Interrupt (Arduino Sketch) übersehen wurde:
Funktioniert wohl sowieso nicht, Zitat aus Arduino Reference:

"Since delay() requires interrupts to work, it will not work if called 
inside an ISR"

Daher ist der letzte Ansatz von Karl Heinz schon passend.
Gast #4338266
Lesenswert?
• ▲
▼
Thomas H. schrieb:
> Und das kommt von dem
> absolut untauglichen Einsteigerbeispiel eine LED mit einem delay blinken
> zu lassen. Ein vernünftiges Einsteigerbeispiel wäre es einmal zwei oder
> drei LED's gleichzeitig blinken zu lassen und alle mit einer anderen
> Frequenz und ohne delay's.

Genau und wer als Baby anfängt zu Krabbeln hat sich schon das ganze 
Leben versaut, man hat sofort aufzustehen und über Kopfsteinpflaster zu 
laufen.
Ist das jetzt die Aroganz der Ingenieure oder das Kastendenken der Elite 
die untersich bleiben will und allen den Einstieg möglichst schwer 
machen will?
Natürlich ist das einfachste Blinken mit Delay der beste Anfang um nicht 
gleich gleich abgeschreckt oder als Anfänger mit seinen Fragen in diesem 
Forum vor den Kopf gestossen zu werden.
Gast #4338281
Lesenswert?
• ▲
▼
Geht auch viel einfacher, ganz ohne Variablen und ganz unabhängig 
voneinander ohne blockierendes delay():
1
#define LED_PIN_1 12
2
#define LED_PIN_2 13
3

4
void setup() {
5

6
  pinMode(LED_PIN_1, OUTPUT);
7
  pinMode(LED_PIN_2, OUTPUT);
8
}
9

10

11
void loop() {
12
  if (millis() % 1000 < 500) digitalWrite(LED_PIN_1, HIGH);   // 1000 ist die Periodenlänge (Frequenz), 500 is ON-Zeit
13
  else digitalWrite(LED_PIN_1, LOW);
14
  
15
  if (millis() % 750 < 125) digitalWrite(LED_PIN_2, HIGH);    // zweite LED, völlig unabhängige Zeit
16
  else digitalWrite(LED_PIN_2, LOW);
17
}
Gast #4338299
Lesenswert?
• ▲
▼
Marcel P. schrieb:
> Geht auch viel einfacher
1
const byte LED_PIN_1 = 12;
2
const byte LED_PIN_2 = 13;
3

4
void setup() 
5
{
6
  pinMode(LED_PIN_1, OUTPUT);
7
  pinMode(LED_PIN_2, OUTPUT);
8
}
9

10

11
void loop() 
12
{
13
  digitalWrite(LED_PIN_1,millis() % 1000 < 500);
14
  digitalWrite(LED_PIN_2,millis() % 750  < 125);
15
}
OP #4338541
Lesenswert?
• ▲
▼
vielen Dank für die Antworten!

Frage:
1
int valuemillis = millis() % 1000;
2
    
3
      Serial.println(valuemillis);

bekomme ich am Terminal nicht 0 1 2 3 4,.... sondern, 0 0 0 1 1 1 2 2 3 
3 3

möchte jetzt nach ende einer Periode den Pin wechseln.
zuerst pin 3 dann 4 dann 5 usw...

so funktioniert es ja nicht:
1
  
2
int a =3;
3
int ende = 40;
4

5
if(valuemillis ==0)
6
a++;
7

8
if(valuemillis ==ende)
9
a=3
10

11
//das a setze ich dann beim timer für die Einzelne LED wie oben genannt ein

so würde er ja bei einer Periode gleich 4 5 6 zählen.

Gruss
Daniel
Gast #4338560
Lesenswert?
• ▲
▼
Ulrich F. schrieb:
> Marcel P. schrieb:
>> Geht auch viel einfacher
>
>
1
>   digitalWrite(LED_PIN_1,millis() % 1000 < 500);
2
>   digitalWrite(LED_PIN_2,millis() % 750  < 125);
3

4
>

@Ulrich Du Fuchs ! Daran hab ich noch gar nicht gedacht ^^

@Daniel

Du hast glaube ich nicht verstanden was millis() sowie % bedeutet, oder?

Modulo (%) gibt den Rest einer Division zurück. D.h. deine Variable 
valuemillis zählt immer von 0 ms bis 999 ms hoch, je nachdem wie 
schnell/oft du deine Berechnung aufrufst.
OP #4338883
Lesenswert?
• ▲
▼
Sooo  habs jetzt anderst gelöst:

So praxistauglich?
1
#define LED_PIN_1 4
2
#define LED_PIN_2 5
3
#include <FlexiTimer2.h>
4

5
int i =3;
6
int a =0;
7
int ms = 0;
8
bool starten = false;
9

10
int pulse =  99;
11
int periode= 100;
12

13
void setup() {
14

15
  pinMode(3, OUTPUT);
16
  pinMode(4, OUTPUT);
17
   pinMode(5, OUTPUT);
18
  pinMode(6, OUTPUT);
19
  Serial.begin(115200);
20

21
  FlexiTimer2::set(1, givems); 
22
  FlexiTimer2::start();
23
}
24

25

26
void loop() {
27

28
 }
29
 
30
 void givems(){
31
 ms++;
32
 Serial.println(ms);
33

34
 
35
  if(ms<periode){
36
    digitalWrite(i, LOW);
37
    if(ms<pulse){
38
    digitalWrite(i, HIGH);}
39
  
40
  }else
41
    {
42
      ms=0;
43
      i++;
44
   if(i>6)
45
    i=3;
46
    }
47
 }
48

49
 void  led(){ 
50
  ms=0;
51
 }

Gruß
Dani
(Firma: CIA) #4338961
Lesenswert?
• ▲
▼
Guest schrieb:
> Natürlich ist das einfachste Blinken mit Delay der beste Anfang um nicht
> gleich gleich abgeschreckt oder als Anfänger mit seinen Fragen in diesem
> Forum vor den Kopf gestossen zu werden.

Das Einfachste ist noch lange nicht das didaktisch sinnvollste.

Guest schrieb:
> Genau und wer als Baby anfängt zu Krabbeln hat sich schon das ganze
> Leben versaut, man hat sofort aufzustehen und über Kopfsteinpflaster zu
> laufen.

Die biologische Entwicklung des ZNS, sowie die psychomotorische 
Entwicklung von Lebewesen haben nichts mit der Didaktik in der 
Erwachsenenbildung zu tun!
#4338991
Lesenswert?
• ▲
▼
Marcel P. schrieb:
> Geht auch viel einfacher, ganz ohne Variablen und ganz unabhängig
> voneinander ohne blockierendes delay():
>
>
1
>…
2
>   if (millis() % 1000 < 500) digitalWrite(LED_PIN_1, HIGH);   // 1000 
3
>…
4
>

Tja, ich sehe da zwei Variablen: 1000 und 500. Nur weil du nicht z.B. 
int myVar = 1000; geschrieben hast heißt das nicht, dass die 1000 nicht 
doch eine Variable sind. ;)
#4339202
Lesenswert?
• ▲
▼
Ziegenpeter schrieb:
> Ich weiß ja nicht welche Sprache du sprichst, aber in meiner nennt sich
> sowas Konstante, nicht Variable.

Ja, aber ob das eine (veränderbare Variable) ist oder Konstante ist dem 
Compiler und dem AVR relativ egal, beides wird SRAM benötigen. Es ist 
also raltiv wurscht ob man schreibt myVar1 = myVar2 + myVar3 oder myVar 
= 100 + 400. Der "Vorteil" bei letzterem ist nur, sofern der Compiler 
klug genug ist, dass es ggf. weniger SRAM belegt als ersteres (je 
nachdem wie man myVar2 und myVar3 definiert hat).
Gast #4339209
Lesenswert?
• ▲
▼
Bastler schrieb:
> Was bisher bei delay() im Interrupt (Arduino Sketch) übersehen wurde:
> Funktioniert wohl sowieso nicht, Zitat aus Arduino Reference:
>
> "Since delay() requires interrupts to work, it will not work if called
> inside an ISR"

Diese Schlussfolgerung ist doch wohl Unfug. Warum soll in einer ISR kein 
weiterer Interrupt abgearbeitet werden können?
Was hindert einen nach anfänglichen Aktionen innerhalb der ISR, die 
Abarbeitung von ISR wieder frei zu geben.
#4339221
Lesenswert?
• ▲
▼
Wolfgang schrieb:
> Diese Schlussfolgerung ist doch wohl Unfug. Warum soll in einer ISR kein
> weiterer Interrupt abgearbeitet werden können?
> Was hindert einen nach anfänglichen Aktionen innerhalb der ISR, die
> Abarbeitung von ISR wieder frei zu geben.

Einfach mal nachschaun wie delay() innerhalb der Arduino-Umgebung 
definiert ist. Ganz offenbar so, dass es innerhalb einer ISR nicht 
benutzt werden kann/darf ;)
Gast #4339229
Lesenswert?
• ▲
▼
Wolfgang schrieb:
> Was hindert einen nach anfänglichen Aktionen innerhalb der ISR, die
> Abarbeitung von ISR wieder frei zu geben.
Einen klugen Menschen wird nichts daran hindern....
Aber er wird sich dann über die Eintrittsinvarianz seines eigenen 
Interrupts ebenfalls Gedanken machen dürfen...

Nein!
Delay() in Interrupts ist keine gute Idee.
#4339238
Lesenswert?
• ▲
▼
Ulrich F. schrieb:
> Michael K. schrieb:
>> Ja
> In c/C++ ist relativ klar definiert, was eine Konstante, und was eine
> Variable ist.
> Und wenn du einer Sprachverwirrung unterliegst, dann ist das dein
> Problem.
> Daran kannst du arbeiten, oder es bleiben lassen...

Ja, deshalb heißt es in C/C++ ja auch "Konstante Variable", also eine 
Variable die nach ihrer Initialisierung nicht mehr verändert werden 
kann. Das ändert aber auch nichts daran, dass sie genauso viel RAM 
benötig wie eine Variable, die nach ihrer Initialisierung verändert 
werden kann.

Oben war nur die Rede davon, dass der Code ganz ohne Variable gehen 
würde und dass nur, weil man der "Variablen" keinen Namen verpasst hat. 
Wer das aber glaubt weiß schlicht nicht wie der Compiler arbeitet. Man 
muss sich immer bewusst machen wenn man z.B. irgendwo im Code eine 100 
hin schreibt der Compiler daraus sehr wohl eine "Variable" macht. Und 
die liegt dann im RAM.
Am besten sieht man das IMO bei Strings. Es gibt bei den AVRs ja das 
Makro PSTR(string). Hinter PSTR verbirgt sich aber nur eine Anweisung 
für den Compiler den String nicht ins RAM zu kopieren, was er sonst 
machen würde, sondern ihn im Flash zu lassen.
Gast #4339382
Lesenswert?
• ▲
▼
Michael K. schrieb:
> Wer das aber glaubt weiß schlicht nicht wie der Compiler arbeitet.

Auf die Gefahr hin, dass mich mein Kompiler belügt:
int test = 3 + 5;
Beansprucht 2 Byte Ram auf meinem Arduino getriebenen AVR.
Wenn 3 und 5 konstante Variablen im Ram wären, würde ich 6 Byte 
erwarten.

Vielleicht liebt mich mein Kompiler?
Vielleicht möchte er dir auch einen Stock zwischen die Beine werfen?
Wer kann es wissen...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren