Interrupt e ritorno ad inizio loop()

Salve a tutto il forum, ho gia trovato una risposta al mio dilemma ma non ho ben capito il meccanismo e come impostare il tutto... sob

Parto dal fatto che il programma in questione è una simulazione semplificata di quello reale...in partica il SW deve fare accendere e spegnere dei led in sequenza solo quando un pulsante a leva è on, il mio problema sta nell'interuppt collegatro al pin 2, funziona tutto solo che vorrei poter tornare all'inizio del
loop() dove è posto l'if di contrrollo su tasto a leva...

vi posto il codice :slight_smile:

spero possiate aiutarmi grazie a tutti e buona giornata :slight_smile:

int tastoleva = 0;
const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, INPUT);    //tasto leva

  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, HIGH);
}

void loop() {
  tastoleva = digitalRead  (8);
  if  (tastoleva == HIGH) {

    digitalWrite(4, HIGH);
    delay(1000);
    digitalWrite(4, LOW);
    delay(1000);
    digitalWrite(5, HIGH);
    delay(1000);
    digitalWrite(5, LOW);
    delay(1000);
    digitalWrite(6, HIGH);
    delay(1000);
    digitalWrite(6, LOW);
    delay(1000);
    digitalWrite(7, HIGH);
    delay(1000);
    digitalWrite(7, LOW);
    delay(1000);
  }

}

void blink() {
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  delay(3000);
  asm volatile (" jmp 0");
  delay(3000);
}

interr.ino.ino (932 Bytes)

Buongiorno,
essendo il tuo primo post, ti chiederei cortesemente di presentarti QUI (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con attenzione il REGOLAMENTO ... Grazie.

Guglielmo

... avessi capito una parola di quello che devi fare :smiley: :smiley: :smiley:

Puoi descrivere un po meglio in cosa consiste il progetto, quali pin e quali sensori sono coinvolti e cosa dovrebbe fare esattamente il codice ?

Guglielmo

Manfredi_994:
Salve a tutto il forum, ho gia trovato una risposta al mio dilemma ma non ho ben capito il meccanismo e come impostare il tutto... sob

Parto dal fatto che il programma in questione è una simulazione semplificata di quello reale...in partica il SW deve fare accendere e spegnere dei led in sequenza solo quando un pulsante a leva è on, il mio problema sta nell'interuppt collegatro al pin 2, funziona tutto solo che vorrei poter tornare all'inizio del loop() dove è posto l'if di contrrollo su tasto a leva...ho letto di mette un flag e controllarne il suo valore all'interno del loop e nella subroutin dell'interrupt....ma non ho capito quante volte e dove lo devo controllare.... mi è stato anche detto di usare il comando asm volatile (" jmp 0") se prima di questa istr metto un delay non me lo legge; sono un po nabbo con arduino, ma coi pic me la cavo molto meglio:)
vi posto il codice :slight_smile:
spero possiate aiutarmi grazie a tutti e buona giornata :slight_smile:

parti con
inizio=1; nel setup

if (inizio==1) esegui lo schetch "standard"

in una riga del alla fine della routine dell'interrupt metti

inizio=0;

poi

ìf (inizio==0) esegui lo duplicato schetch "standard" senza la routine dellinterrupt con prima riga

inizio=1;

detto in altro modo l'interrupt cambia in la variabile ""inizio" da 1 a zero e le righe di programma se inizio è a zero non si eseguono

Chiedo venia per non essermi espresso abbastanza bene (sono un po di fretta x via della maturita e del progetto) .... praticamente vorrei che dopo aver richiamato una funzione tramite interrupt allla fine di essa, il programma tornarsse all'inizio del loop() e non ritornare all'istr dopo la chiamata dell'interrupt

chiedo scusa ancora (provvedero subito a presentarmi meglio)

E' sbagliato proprio il concetto di chiamare una funzione dentro una ISR !!!

Le ISR devono essere le più veloci possibili, quindi, dentro una ISR tu alzi solamente una flag e termini subito, sarà poi dentro al loop() che verificherai lo stato della flag e, se la trovi alzata, farai quello che devi fare, la resetterai e tornerai a girare nel loop().

Guglielmo

no non voglio chiamare funzioni dentro la isr della subroutine voglio solo che alla fina di tale il programma reinizi dala prima riga dell loop()

come posso integrarlo nel mio codice? sperio di essere stato piu chiaro

@Manfredi_994: Ti rinnovo l'invito a presentarti QUI (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) ed a leggere con attenzione il REGOLAMENTO ...

... inoltre, proprio in conformità al suddetto regolamento, punto 7, devi editare il tuo post (in basso a destra del post, bottone More -> Modify) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone fatto così: </>, tutto a sinistra).

Guglielmo

P.S.: Se si chiede la presentazione NON è per chissà quale curiosità; è perché prima di rispondere si va a vedere chi si ha difronte e si cerca di adattare la risposta alla sua preparazione, quindi, più completa è, più chi risponde sa fino a che punto spingersi.

... ti ripeto, le ISR DEVONO essere il più brevi possibili e ... sicuramente NON usare la delay() ... queste cose si fanno nel loop(), nella ISR si mette solo una flag per indicare che alcune cose vanno fatte.

Guglielmo

P.S.: Edita il tuo post ed aggiungi i tag CODE come richiesto, grazie.

ok ho sistemato tutto, inclusa la presentazione....ora qualcuno potrebbe spiegarmi meglio come devo fare

scusate ancora e grazie per la pazienza

Sei in un loop() che gira sempre e che ricomincia sempre dall'inizio ...

... dichiari una variabile : volatile boolean miaFlag = false;
... nella ISR metti solo miaFlag = true;
... nel loop() metti

if (miaFlag) {
  miaFlag = false;
  ...
  ... quello che devi fare
  ...
}

... e poi vedi tu come organizzare il resto del loop() ...

Guglielmo

in questo modo? coplilare compila ma quando lo provo sulla board non funziona

c'è sicuramente qualcosa che mi sfugge

int tastoleva = 0;
const byte interruptPin = 2;
volatile byte state = LOW;
volatile boolean miaFlag = false;

void setup() {
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, INPUT);    //tasto leva

  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, HIGH);

}

void loop() {

  tastoleva = digitalRead  (8);
  if  (tastoleva == HIGH) {
    if (miaFlag) {
      miaFlag = false;
      digitalWrite(4, HIGH);
      delay(1000);
      digitalWrite(4, LOW);
      delay(1000);
      digitalWrite(5, HIGH);
      delay(1000);
      digitalWrite(5, LOW);
      delay(1000);
      digitalWrite(6, HIGH);
      delay(1000);
      digitalWrite(6, LOW);
      delay(1000);
      digitalWrite(7, HIGH);
      delay(1000);
      digitalWrite(7, LOW);
      delay(1000);
    }
   }
  }

  void blink() {
    delay (1000);
    miaFlag = true;
  }

T'ho detto che la delay() NON si deve usare dento le ISR ... perché continui ad infilarcela ?

Perché verifichi l'avvenire di un interrupt dentro un'altri IF ? ? ? Esso deve essere del tutto indipendente !

A che servono tutti quei delay() ? Sai che la delay() BLOCCA il programma ?

Non ci hai ancora fornito uno schema dei collegamenti e quindi NON sappiamo cosa c'è attaccato a quei pin e non possiamo darti suggerimenti ...
Non ci hai ancora fornito una descrizione esatta di quello che vuoi fare e quindi NON capiamo che sequenze ti occorrono ...
... possibile che bisogna ogni volta strappare le informazioni cone le pinze ? ? ? :o E' nel vostro interesse fornire più informazioni possibili per avere l'aiuto più mirato !!!

Guglielmo

  1. delay nel blink, levalo.
  2. e il pezzo che era nel blink che spegne i 4 pin ?? Te lo sei perso!

Per me quello che non hai spiegato bene e quello che deve fare il programma, ci sono delle cose non chiare.
Hai una sequenza di 4 led, solo se una leva è attiva. Bene.
Ma se su un altro pin scatta un evento/interrupt devi spegnere tutto. Bene. Ma con quali tempistiche ?
Spegni per quanto tempo ? Se la leva è attiva, scatta evento e spegni ma se riprende la sequenza si riattiva subito o deve passare del tempo ? Almeno a me non è chiara tutta la sequenza temporale dei vari "momenti"

Guglielmo, questa discussione mi ha fatto sorgere un dubbio, quindi se permetti una domanda in tema ... la ISR rientra nel loop dal punto successivo a quello in cui il loop si trovava quando e' scattata, giusto ? ...

Quello che voglio dire, che poi e' il dubbio che mi e' venuto, lo espongo con un'esempio ... mettiamo di avere il classico sketch, con la sua ISR all'inizio, poi il loop ed in un certo punto del loop una serie di comandi, diciamocome esempio 20 righe che contengono ognuna un comando ... ad un certo punto, quando lo sketch ha eseguito, sempre come esempio, la decima riga di quel pacchetto di comandi, scatta la ISR ... quando termina ed esce, ricominciera' dall'undicesima riga del pacchetto di comandi (cioe', in pratica, dal punto in cui era lo sketch quando e' stata chiamata), e non dal termine del codice della ISR, giusto ?

Se e' cosi, indifferentemente da dove mettessi l'if di controllo nello sketch, tutto quello che sta' fra questa riga in cui rientra e l'if per controllare la flag, verra' comunque eseguito, prima di poter entrare nell'if e controllare la flag, giusto ? ... e dato che io non posso prevedere in quale punto dello sketch l'ISR verra' attivata, a meno di non piazzare un'if ogni riga di sketch, ci sara' sempre la possibilita' che lo sketch, all'uscita dell'ISR, esegua qualcosa, poco o tanto che sia, prima che la flag venga controllata ... o sbaglio ragionamento ?

ok non sono buono neanche a spiegare :frowning: :frowning: :frowning:

spiego nei migliore dei modi

pin2 tasto interrupt
pin8 tasto leva

pin4 led verde
pin5 led rosso
pin6 led giallo
pin7 led blu

il programma deve:
leggere il tasto leva
vedere se il suo valore è alto o basso
nel primo caso deve accendere il primo led e dopo 500ms spegnerlo per poi dopo altri 500ms accendere quello rosso e dopo altri 500ms spegnerlo (idem per i restanti due led)

l'interrupt, quando avviene, deve fermarmi il programma e riportarmi al controllo del tasto leva

Esatto Etem ...
... difatti questa tecnica NON è adatta a situazione di "emergenza" in cui, ad esempio, qualunque cosa tu stia facendo, devi immediatamente fare un qualche cosa (es. spegnere tutto perché c'è un'emergenza).

In tal caso ovviamente le cose di emergenza le fai nella ISR dato che comunque, nel loop(), il test lo fai una (... o più volte, a tua scelta) per ogni giro della loop().

Insomma, se stai solo contando gli impulsi di un encoder, fai variabile++; e via; se dei segnarti che è avvenuto un evento per cui devi fare un qualche cosa, usi la flag e poi la controlli; se devi risolvere un problema serio ... lo devi fare nella ISR ...

Guglielmo

Manfredi_994: ok ... già è più chiaro, ma come sono collegati questi tasti ? ... e che tasti sono ? .. hai tenuto conto dei "rimbalzi" (che ogni tasto ideale ha) ? Perché se non ne hai tenuto conto ... ogni volta che pigi un tasto hai una "raffica" di impulsi, non uno, con ... le conseguenze del caso.

Detto questo e sperando che tu abbia dei circuiti di "debouncing" hardware sugli ingressi ... se vuoi una risposta quasi "in tempo reale" NON puoi usare la delay() che ti ferma l'esecuzione del programma ma devi organizzare il codice in modo che il ciclo della loop() NON si fermi MAI (quindi NESSUN delay()), ma i tempi degli ON/OFF dei LED li devi organizzare con la funzione millis().

Per imparare ad usare correttamente la funzione millis() devi studiare prima QUI, poi QUI ed infine leggi anche QUI e QUI ... alla fine dovresti avere un'idea di come essa si applica per creare temporizzazioni che NON arrestano il programma.

Se fai così ti basta ...

void loop() {
   if (miaFlag) {
      miaFlag = false;
      ...
      ... è avvenuto l'interrupt e faccio quello che devo fare
      ...
   }
   else {
      ...
      ... non c'è interrupt, faccio il resto
      ...
      ...
   }
}

... e, come vedi, se viene rilevato l'interrupt, viene eseguito quello che si deve eseguire e si torna ALL INIZIO di loop().

Guglielmo

in realta sto gestendo dei motori di un impianto di autolavaggio.....quindi come dovrei fare?
aiutatemi perche contiuno ad imballarmi :frowning:

Manfredi_994:
in realtà sto gestendo dei motori di un impianto di autolavaggio....

Allora semplicemente NON lo devi fare dato che è ILLEGALE ...
... prendo in prestito le parole di Astrobeed ...

astrobeed:
Molto semplice, Arduino non rispetta i requisiti richiesti dalle varie certificazioni per l'uso in ambito civile/industriale/militare etc., pertanto non può essere utilizzato per nessun scopo che non sia la realizzazione di prototipi, test di laboratorio, supporto allo sviluppo, studio e ricerca.

In linea di massima, con Arduino puoi fare quello che ti pare a patto che rimane sul tavolo del laboratorio e non lo colleghi a nessun impianto dove è obbligatorio usare solo parti certificate/omologate, p.e. l'impianto elettrico di casa.

Quanto sopra si applica a tutte le schede Arduino, nessuna è certificata per uso industriale/civile e non sono in nessun modo certificabili a tale uso, questo non significa che non si può usare l'ambiente di sviluppo (IDE) di Arduino per prodotti commerciali, puoi farlo a patto che sviluppi un hardware Arduino Like che sia in regola con le vigenti normative per la destinazione d'uso.

Rimane comunque vietato, senza se e senza ma, l'uso di Arduino in tutti quei settori ove ci sono anche delle restrizioni software oltre che hardware, p.e. nel mondo automotive non potrai mai usare Arduino perché il suo ambiente di programmazione non risponde alle specifiche richieste, molto severe per ovvi motivi.

Guglielmo