Interrupt handling, interrupt werkt wel maar functie loopt niet.

Hallo allemaal,

Ik heb een schakeling met een stepper motor die wat moet bewegen.
Bij het inschakelen van de schakeling gebeurd er eerst niet. Als we dan op Start drukken, gaat er eerst gehomed worden, dat werkt.

Als er gehomed is, en er wordt weer gestart, gaat de stepper motor de andere kant op draaien en komt uiteindelijk een andere schakelaar tegen welke de stepper nog 140 keer laat steppen en dan wordt er 30 seconden gewacht.
Na 30 seconden gaat de stepper weer naar de home positie.

Nu heb ik ook een stopknop welke ik middels een interrupt wil aanroepen dat zodra deze wordt ingedrukt, de home functie wordt aangeroepen en de stepper weer terugkeert.

Ik heb verschillende zaken geprobeerd, rising, falling, change, met en zonder debounce maar de interrupt wordt wel aangeroepen maar de functie home stop, ik zie stroom door de wikkelingen lopen maar de stepper motor draait niet.

Wat mis ik hier?

#include <Arduino.h>
#include "BasicStepperDriver.h"

// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 200

// All the wires needed for full functionality
#define DIR 8
#define STEP 9
#define ENBL 11

// Since microstepping is set externally, make sure this matches the selected mode
// 1=full step, 2=half step etc.
#define MICROSTEPS 1

BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP, ENBL);

const int buthome = 7;     // the number of the pushbutton pin
const int buteut = 6;     //Aanslag
const int ledPin =  13;      // the number of the LED pin
const int faultPin = 5;    //fault pin van de DRV8825
const int butstart = 4;   // startknop
const int butstop = 2;    // stopknop

boolean stop1 = false;
boolean homed = false;



void setup() {
    /*
     * Set target motor RPM.
    */
    stepper.setRPM(250);
// initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbuttons pins as an input:
  pinMode(buthome, INPUT);
  pinMode(buteut, INPUT);
  pinMode(faultPin, INPUT);
  pinMode(butstart, INPUT);  
  pinMode(butstop, INPUT);      
  attachInterrupt(digitalPinToInterrupt(butstop), back, RISING); //attach the interrupt
  
}

void loop() {
  stepper.setMicrostep(MICROSTEPS);
  stepper.disable();
  digitalWrite(ledPin, LOW);
  if (digitalRead(butstart) == HIGH){
   if (homed == false) {
    home(); 
    }
   else {
    homed = false;
    moveeut();
    if (stop1 == false) {
    holdeut();   
    }
    }
 }
}
void home() {
     stepper.enable();
     while (digitalRead(buthome) == LOW)
      {
       stepper.rotate(-45);
       if (digitalRead(buthome) == HIGH){
       homed = true;
       break;
       } 
      }
     
     }


void moveeut(){
  stepper.enable();
    while (digitalRead(buteut) == HIGH) {
    stepper.rotate(45);
    if (digitalRead(butstop) == HIGH) {
     home(); 
     stepper.disable();
     break;     
    }
  }
  while (digitalRead(buteut) == LOW) {
   stepper.move(500*MICROSTEPS);
   if (digitalRead(butstop) == LOW) {
   stepper.disable();
   break; 
  }
  }
}

void holdeut(){
  stepper.disable();
  for (int i=0; i <= 140; i++){
      digitalWrite(ledPin, HIGH);
      delay(100);
      digitalWrite(ledPin, LOW);
      delay(100);
  }
  stepper.enable();
  home();  
}

void back() {
   digitalWrite(ledPin, HIGH);
   static unsigned long last_interrupt_time = 0;
 unsigned long interrupt_time = millis();
 // If interrupts come faster than 200ms, assume it's a bounce and ignore
 if (interrupt_time - last_interrupt_time > 100)
 {
   home();
 }
 last_interrupt_time = interrupt_time;
}

Hoi Leroy 2007.

Je hebt een quote gebruikt om je code te plaatsen.
Het kost net zoveel moeite om de code tussen [code] [/code]tags te zetten, als tussen [quote] [/quote] tags.
Het voordeel van code tags is dat daarmee de tekst niet word omgezet naar smilies (dat was bij jouw code niet van toepassing) of andere ongewenste bewerkingen, maar ook dat de tekst zo heel eenvoudig geselecteerd en gekopieerd kan worden naar bijvoorbeeld de IDE.

Jouw eigen bevindingen zijn hier belangrijk.
Want je vertelde dat de home functie werkt, en dat de interrupt ook werkt.
Daarmee moet er dus wat dat betreft niks aan de hand zijn.
Ik zie wel iets wat mijn rechter wenkbrauw doet rijzen:

Je hebt je interrupt gemaakt en daarmee roep je de functie back op als je op pin 2 een rising edge ziet.
Maar in je code zit je ook naar pin 2 te kijken (of die al hoog is, das dus na de rising edge).
Daarmee denk ik dat je 2 keer hetzelfde zit te doen (want als die pin 2 hoog is ga je ook weer naar de functie home).

Een interrupt doet precies dat wat de naam suggereert:
Het onderbreekt het lopende programma, maar stopt het niet.
Dat wil zeggen dat de handeling die er op dat moment gedaan word, verder gaat na aflopen van de interrupt.
Als deze code alles is wat er moet gebeuren, dan is het maar de vraag of het wel zo verstandig is om een interrupt te gebruiken.
Want de afhandeling van die code hoeft helemaal niet lang te duren.
Je laat je motor een x aantal stappen doen (ik zie een keer de waarde 500 voor x voorbij komen).
Dat betekent dat je in dat geval dus moet wachten tot de 500 stappen gezet zijn.
Je kunt ook 500 keer een stap zetten.
Het voordeel daarvan is dat je dus telkens tussendoor naar pin 2 kunt kijken.
Als je op pin 2 ziet waar je op zat te wachten, dan kun je de stappenmotor aansturing laten stoppen door het aftellen van x kort te sluiten; je vertelt je code dat de 500 stappen al gezet zijn.
Wanneer je code veel groter is dan wat je hier hebt laten zien, of veel groter moet gaan worden, dan moet je even goed nadenken of je het op de door mij hierboven beschreven wijze wil doen.

In ieder geval ga je met je huidige code 2 keer hetzelfde doen, en ik weet even niet of je misschien de stappenmotor dan meerdere commando's door elkaar zit te geven.
Ik zou deze redundantie in elk geval uit de code halen; de interrupt overruled vrijwel alles en er is dan gaan andere controle op de status van pin 2 meer nodig (in dit geval, want er kunnen wel meer trucs worden uitgehaald).

Je hebt ook nog een stukje ontdender (debounce) in je code zitten, met incorrect commentaar overigens.
Kijk daar nog eens goed naar.
Want je reset die als tweede actie als je een interrupt gaat afhandelen.
En dat doe je zelfs 2 keer, omdat je 'm na starten van de functie aanmaakt waarbij je m dan ook nog eens naar nul zet.
Maar die moet je pas resetten als de interrupt is afgehandeld, anders wordt nooit aan de voorwaarde voldaan bij een interrupt (wel als je op een andere wijze deze functie aanroept, wat je nu ook doet.
Overigens is 0,2 seconden (200 mS), een zee van tijd.
Het is een beetje een vreemde combinatie als je 200 mS wachttijd koppelt aan een interrupt.

Een heel verhaal alweer van iemand die zelf nog nooit met interrupts heeft gewerkt en die ook nog nooit iets in de richting van jouw code heeft gebouwd.
Maar bekijk de opmerkingen eens en doe er je voordeel mee.

Die hele structuur van dat programma rammelt eigenlijk een beetje....
Hij doet er beter aan om iets met een enumeratie van de verschillende stappen die mogelijk zijn.
bijvoorbeeld:

enum {
   noAction,
   forward,
   back,
   hold,
   home
};

In de loop bepaalt hij eerst welk van die stappen hij wil aan de hand van buttons of andere acties.

Met een switch case bepaal je vervolgens wat je wilt. Echter ga je dan geen while() oid uitvoeren maar slechts een stapje verplaatsen. Blijkt dat je home bent, dan zet je de actie op noAction. anders verplaats je een stapje richting home.
Wil je voorwaards, verplaats je een stapje voorwaards... enz

Je bereikt dat je daarmee alle delays de nek om draait. Spelen met LEDS aan en uit kun je gewoon mee werken.

En een interrupt moet je zo kort mogelijk houden. Dus stel de noodknop is ingedrukt dan zet je de actie op home en klaar. Meer hoef je niet te doen.

In de loop komt de switch case de home actie tegen en verplaatst een stapje richting home. Ben je er eenmaal dat zet je de actie op noAction.

Verder kun je jezelf nog afvragen of het nog wel nodig is om de interrupt te gebruiken voor de noodknop. Het lezen van de knop zal in reactie tijd relatief geen verschil maken (omdat het menselijk lichaam nu eenmaal veeeeeel te traaaag is).

Verder is het beter om alle settings van de stepper in de setup() uit te voeren. Niet in de loop().

Los van het feit dat het programma, voor de experts, wellicht niet oogstrelend mooi is, reikt mijn kennis van de programmeertaal niet ver genoeg om iets te doen met enumeraties. Daarnaast speelt de factor tijd een rol en hoewel ik erg graag een aantal dagen of weken zou willen prutsen met deze set-up, laten andere factoren dat helaas niet toe.

Enfin, gelet op het geleverde commentaar besloten de interrupt te verwijderen en gewoon met if statements de stopknop gaan detecteren.
De gehele toepassing, een testopstelling, is aan bepaalde regels gebonden qua naderingssnelheid (10 - 25 mm/sec) en dus niet erg tijdskritisch. Het gaat er om dat als iets niet loopt in de test zoals dat zou moeten (in dit geval een brandtest), dat de slede teruggetrokken wordt.

Met het huidige programma doet het wat het moet doen. Er komt nog een displaytje (OLED op I2C) op om aan te geven wat het programma aan het doen is en om 30 seconden af te tellen (ipv de delays).

Bedankt in ieder geval voor het commentaar, die zaken die ik heb kunnen doen, zijn verwerkt!

#include <Arduino.h>
#include "BasicStepperDriver.h"

// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 200

// All the wires needed for full functionality
#define DIR 8
#define STEP 9
#define ENBL 11

// Since microstepping is set externally, make sure this matches the selected mode
// 1=full step, 2=half step etc.
#define MICROSTEPS 1

BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP, ENBL);

const int buthome = 2;     // the number of the pushbutton pin
const int buteut = 3;     //Aanslag
const int ledPin =  13;      // the number of the LED pin
const int butstart = 4;   // startknop
const int butstop = 5;    // stopknop

boolean stop1 = false;
boolean homed = false;
float naloop = 0;


void setup() {

    /*
     * Set target motor RPM.
    */
    stepper.setRPM(250);
    stepper.setMicrostep(MICROSTEPS);
// initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbuttons pins as an input:
  pinMode(buthome, INPUT);
  pinMode(buteut, INPUT);
  pinMode(butstart, INPUT);  
  pinMode(butstop, INPUT);      
    
}

void loop() {
  stepper.disable();
  digitalWrite(ledPin, LOW);
  if (digitalRead(buthome) == LOW) {
   //if (homed == false) {
    home(); 
   }
   else {
    homed = true;
    if (digitalRead(butstart) == HIGH){
    moveeut();
    holdeut();
    }
    else {
    stepper.disable();   
    }
    }
 }
//}
void home() {
     stepper.enable();
     while (digitalRead(buthome) == LOW)
      {
       stepper.rotate(-40);
       if (digitalRead(butstop) == HIGH){
       homed = false;
       break;
       } 
      else { homed = true; }
      }
     }


void moveeut(){
  stepper.enable();
    while (digitalRead(buteut) == HIGH) {
    stepper.rotate(40);
   if (digitalRead(butstop) == HIGH) {
   home(); 
   stepper.disable();
   break;     
   }
  }
  while (digitalRead(buteut) == LOW) {
   stepper.move(500*MICROSTEPS);
   if (digitalRead(butstop) == HIGH) {
   home();
   stepper.disable();
   break; 
  }
  }
}

void holdeut(){
  stepper.disable();
  naloop = 0;

  while (naloop < 140){
    naloop++;
      digitalWrite(ledPin, HIGH);
      delay(100);
      digitalWrite(ledPin, LOW);
      delay(100);
      if (digitalRead(butstop) == HIGH) {
          delay(500);
          home(); 
          stepper.disable();
          break;     
         }
  }
  stepper.enable();
  home();  
}