Was statt delay in ISR nutzen?

Hallo,

ich bastel gerade an einer Schrittmotorsteuerung mittels eines Arduino UNO. Alles funktioniert auch so wie es soll. Ein Problem habe ich allerdings immer noch. Da der Schrittmotor auf der einen Seite ein Ende hat, befindet sich dort eine Lichtschranke, die bei betätigung eine ISR auslöst. Das funktioniert auch wunderbar, allerdings bräuchte ich ind er ISR einen Delay. Der Motor soll nämlich wieder aus der Schranke herausgefahren werden. Der Schrittmotor bewegt sich bei jedem Stromstoß um einen Schritt. Zur Bewegung des Motors benutze ich folgende Schleife:

for (int x = 0; x < 10; x++)
{
digitalWrite(motor, HIGH);
delay(10);
digitalWrite(motor, LOW);
delay(10);
}

Allerdings funktioniert das in der ISR natürlich nicht. Wie kann ich das lösen?

Auch das ist wieder eine völlig falsche Verwendung von Interrupts. Und zwar von Grund auf, weil hier keine Interrupts nötig sind.

Wenn du unbedingt nicht davon loslassen kannst dann setzte in der ISR nur ein Flag auf dass du in loop() abfragst. Dann findet der eigentliche Code außerhalb statt.

Wieso ist es die falsche Verwendung? Ich bin noch neu im Programmieren und in der Nutzung mit dem Arduino. Es geht halt darum, egal wo man sich im code befindet, wenn man die Lichtschrranke durchquert soll er alles resetten. Würde er weiter drehen, könnte er die Apperatur beschädigen. (Das ganze soll in einem wissenschaftlichen Experiment eingesetzt werden.)

Ich dachte ein Interrupt wäre ideal, da er immer Priorität hat?

Wie soll ich es deiner Meinung nach lösen?

Dann frag doch innerhalb deines Sketches die Lichtschranke ab und stoppe den Motor.
Die delays solltest du aber durch die Funktion "millis()" ersetzen, damit der Durchlauf immer ohne Pausen gewährleistet ist.

Aber ich weiß doch nicht, wann er durch die Lichtschranke fährt? Er soll jederzeit und immer unterbrechen, wenn die Lichschranke zu ist.

NJay289:
Aber ich weiß doch nicht, wann er durch die Lichtschranke fährt?

Wer fährt durch die Lichtschranke ?

Evtl. solltest du dein Projekt mal besser beschreiben und deinen kompletten Sketch posten.
Den Sketch bitte in Code-Tags setzen.

In den meisten Fällen schafft man es dass loop() schnell genug läuft um auf allgemeine Ereignisse reagiert. Vor allem auf sowas langsames und unregelmäßiges wie einen Endschalter. Dafür muss man aber auf Verzögerungen und Schleifen verzichten.

ISRs sind normal kurz und werden schnell wieder verlassen damit der Rest des Programms nicht zu sehr gestört wird.
delay() geht nicht weil eine ISR nicht durch andere Interrupts unterbrochen werden kann. Das heißt Timer0 wird nicht inkrementiert wodurch millis() und micros() nicht mehr für Zeiten >1ms gehen.

Was theoretisch geht ist delayMicroseconds(). Das dreht sich einfach in der while-Schleife. Aber das so zu machen ist eine absoluter Ausnahmefall

Okay, ich versuche euch das Projekt genauer zu beschreiben:

Ich bastel an einer Steuerung für einen Schrittmotor, welcher später eine Blende bewegen wird. Der Nutzer soll hierbei einfach eingeben können, an welche Position die Blende, bzw der Schrittmotor fahren soll. Aktuell nutze ich dafür eine Skala von 0-999, wobei jeder schritt 1,8Grad entsprechen. Gesteuert wird der Schrittmotor über Impulse, jeder Impuls bewegt den Motor um einen Schritt vorran. Die Richtung wird durch ein weiteres Signal angegeben, das an oder aus sein kann. Es wird zwei Endpunkte geben, die durch Lichschranken begrenzt werden. Der Schrittmotor darf diese auf gar keinen Fall überschreiten, egal wo er hin will, weiter als dort geht nicht, da sonst der Versuch beschädigt werden kann. Gleichzeitig kann es vorkommen, dass der Arduino seine Position vergisst (Stromausfall, etc.) Sodass er dann kalibriert werden muss. Dafür soll er gegen eine der beiden Lichtschranken fahren, dann stoppen, 10 Schritte zurück fahren (Also wieder aus der Lichtschranke raus) und seine Position auf 0 setzen. Doch um ihn die 10 Schritte fahren zu lassen, benötige ich einen Delay. Der ganze Code sieht folgendermaßen aus:

#define NUMLENGTH 3
int schranke = 0;
int motor = 10;
volatile int location = 200;
int richtung = 4;
int LED = 13;
volatile int zahl = 0;
volatile int rot = 0;

void setup() {
pinMode(motor, OUTPUT);
pinMode(richtung, OUTPUT);
pinMode(2, INPUT);
pinMode(LED, OUTPUT);
Serial.begin(115200);
delay(100);
attachInterrupt(schranke, interrupt, LOW);
}


void loop() {
 if(Serial.available() > 2) {
   char tmp[NUMLENGTH];
   for(unsigned char i=0; i<NUMLENGTH; i++) {
     tmp[i] = Serial.read();
   }
   zahl = atoi(tmp);
   Serial.println(tmp);
   Serial.println(zahl);

   if(zahl < location){
    digitalWrite(richtung, LOW);
   }
   if(zahl > location){
    digitalWrite(richtung, HIGH);
   }

   rot = location - zahl; 
   rot = abs(rot);   
   for (int x = 0; x < rot; x++)
  {
       digitalWrite(motor, HIGH);   
       delay(10);                      
       digitalWrite(motor, LOW);    
       delay(10);  
  }
   if(digitalRead(richtung) == HIGH){
     location = location + rot;
   }
   if(digitalRead(richtung) == LOW){
     location = location - rot;
   }
  
  
  }
  }
void interrupt(){
  digitalWrite(motor, LOW); 
  digitalWrite(LED, HIGH);
  digitalWrite(LED, LOW);
  digitalWrite(richtung, HIGH);
  for (int x = 0; x < 10; x++)
  {
       digitalWrite(motor, HIGH);   
       delay(10);                      
       digitalWrite(motor, LOW);    
       delay(10);  
  }
  location = 0;
  zahl = 0;
  rot = 0;
  
  }

Der Motor fährt ja nur in die Lichtschranke wenn er angesteuert wird.
Wie steuerst Du den Motor genau an?

Wenn Du mal die Position des Motors kalibriert hast weißt Du durch zählen der Schritte genau in welcher Position sich der Motor in jedem Moment befindet. Da braucht es eigentlich keine Endschalter die den Motor stoppen sondern nur einen Zähler. Ich sehe auch keine notwendigkeit aus der Lichtschranke herausfahren zu müssen. Es genügt daß er sich nicht weiter in diese Richtung dreht.

Grüße Uwe

uwefed:
Der Motor fährt ja nur in die Lichtschranke wenn er angesteuert wird.

Was bedeutet dass man vor oder nach jedem Schritt abfragen kann ob man im Endschalter steht

Doch um ihn die 10 Schritte fahren zu lassen, benötige ich einen Delay.

Du benötigst das delay().
Die Applikation würde auch gut ohne delay() auskommen.

Selbst mit delay() geht es. Da es eben ein Schrittmotor ist. Der läuft nicht einfach, sondern man hat genaue Kontrolle wann er sich wie weit bewegt. Also kann man einen Schritt machen -> schauen ob man im Endschalter ist -> nächsten Schritt machen -> etc..

Hallo,

ich könnte mir vorstellen das NJay die 10 Schritte zum genauen justieren als Offset benötigt. Bei mir auf Arbeit fahren die Antriebe beim "homen" auch erst in die Lichtschranke. Das wird 2x gemacht aus immer der gleichen Richtung. Das sind dann die Home-Positionen. Das sind noch lange nicht die Zero Positionen. Die Zero wird per Software kalibriert. Man arbeitet mit Offsets. Damit muss man nicht am Sensor fummeln was eh ungenauer wäre wie alles andere was die Antriebe an Genauigkeit leisten.

NJay289:
Aber ich weiß doch nicht, wann er durch die Lichtschranke fährt? Er soll jederzeit und immer unterbrechen, wenn die Lichschranke zu ist.

Er kann doch nur dann die Lichtschranke erreichen wenn du einen Schritt bewegst. Also fragst du einfach vor dem Schritt die Lichtschranke ab. Steht er drin, muss er sich eben wieder rausgewegen. Dazu noch ein Flag setzen, das du weist, das Ende ist erreicht und ab jetzt muss ich was anderes machen. zB mich in die andere Richtung bewegen.

Die Ersparniss im Interrupt ist Null. Weil du ja Motorschritte machen musst um reinzufahren, also auch nur an dieser Stelle überhaupt eine Bewegung hast. Bist du nicht an diesem teil des Programmes, bewegt sich der Motor garnicht.