Eseguire una funzione(X) durante funzione bloccante(X) richiamandola tramite interrupt attivato da presenza byte in buffer porta seriale

Ciao a tutti.
Ho trovato questo esempio in rete,
ho controllato a cosa servono i registri utilizzati ( i commenti li ho aggiunti io )
ma non riesco a capire perchè non funziona, cioè perchè la funzione ser() non viene mai eseguita;

Scheda Mega2560

( ho rimosso una parte che non serve e creava confusione )

void setup() 
{
  Serial.begin(115200);
  UCSR0B |= (1 << RXCIE0);  // abilita interrupt  ricezione
  sei();  // abilita gli interrupt
}

ISR(USART_RX_vect)  // funzione che dovrebbe essere richiamata dall'interrupt
{
    Serial.print( F( "\n si è verificato un  interrupt? " ) );
    ser();
}

void loop() 
{
     while(1)
{ 
     delay(2000);   
     Serial.print( F( "\nsto aspettando" );
}
}

void ser()
{
  while(Serial.available())
  {
      Serial.write( Serial.read() );
  }
}

type or paste code here

Prima di entrare nello specifico della gestione degli interrupt, mi chiedevo: ma perché hai bisogno di usare gli interrupt per gestire la seriale? La classe predefinita Serial usa ovviamente gli interrupt per questo scopo, non puoi limitarti a controllare Serial.available() nel loop()?

Tra l'altro la "while(1)" che hai messo proprio nella loop() è inutile, perché loop() è già lei stessa un ciclo...

PS: modifica il post, hai racchiuso in "code" due volte il codice ed anche il tuo testo... Il tag deve stare solo prima e dopo il solo codice

Dimenticavo: dovresti anche dire di quale board Arduino stiamo parlando...

Ho aggiornato il primo post col modello della board (Mega 2560) aggiungendo anche a cosa mi serve , o servirà in futuro, risolvere questo problema.

Ancora non mi è chiaro perché ti serva fare questo, anche perché dipende anche da COSA dovresti fare all'atto della ricezione di un carattere sulla seriale, e spesso richieste simili implicano una qualche mancanza di pianificazione della struttura del codice, in particolare cicli (spero non infiniti come quello che hai postato nello sketch di esempio) e temporizzazioni che in genere si devono gestire con macchine a stati finiti lasciando "libera" la funzione loop() di lavorare alla massima velocità possibile.
Ma se vuoi evitare di ristrutturare il tuo codice (che non abbiamo visto) puoi anche creare una funzione (es. "checkSerial()") da richiamare in tutti i punti dove hai necessità di rilevare qualcosa che arriva dalla seriale e fare "qualcosa" (che ancora non sappiamo).
Se ci fai vedere qualcosa più specifico possiamo forse trovare l'"incastro".

Per quanto ne so puoi anche farlo, ma per quanto riguarda lo sketch di esempio ricorda che dentro ad una ISR non puoi utilizzare nulla che dipenda da interrupts, come Serial.print() o millis(): questi non puoi utilizzarli in una funzione interrupt. E quindi torniamo al discorso di prima: se non sappiamo in quale contesto devi agire e cosa vuoi fare nella funzione interrupt, difficile darti una risposta utile diversa da "usa Serial.available() nel codice".

EDIT: non so se QUESTA libreria possa in qualche aiutarti...

il codice è molto lungo, non ci sono segreti industriali e posso tranquillamente caricarlo.
Anche se funziona già posso comunque ristrutturarlo.

Ok, non lo sapevo.
nel mio caso allora , forse, il programma funziona ma non mi dava segni di vita perchè richiamavo proprio una funzione di queste.
Ora provo ad accendere e spegnere il led in funzione del carattere ricevuto.

Quello che devo fare comunque è leggere 3 caratteri, il primo indica a quale variabile ( delle due in questo caso ) fa riferimento.
Glia altri due caratteri rappresentano il valore numerico di dette variabili.
ad esempio ricevendo A10 verrà richiamata una funzione che imposterà la prima variabile a 10, B40 lo stesso per la seconda variabile;

continua a non funzionare.

void setup() 
{
  Serial.begin(115200);
  UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
  UCSR0B |= (1 << RXCIE0);// abilita interrupt  ricezione
  sei(); // Abilita gli interrupt globali
}
boolean a=true;
void loop() 
{
  while(a){delay(2000);}
  Serial.print( F( "\n sono fuori ?" ) );
}

ISR(USART_RX_vect) 
{
  a=false;
}

La Seriale è gestita tramite interrupt dal core di Arduino ... NON puoi andare ad usare gli interrupt che già sta utilizzando il "core", quindi scordati di usare interrupt sulla seriale.

Tra l'altro, per quello che devi fare tu ... assolutamente NON servono!.

Guglielmo

Non è (solo) quello. E' anche che l'interrupt seriale lo gestisce il core di Arduino e non puoi rimapparlo (ossia viene chiamata sempre la sua ISR e non la tua). E' quello che intendevo chiarire successivamente quando scrissi "Prima di entrare nello specifico della gestione degli interrupt"... :wink:

EDIT: @gpb01 mi ha preceduto per il discorso dell'interrupt seriale... Troppo forte, chi lo batte??!:sunglasses:

Certo, per il motivo che dicevo prima. E comunque le variabili che modifichi in una ISR (qualunque essa sia) devono essere dichiarate "volatile":

volatile boolean a=true;
1 Like

Più che "non puoi" io direi che devi tenere conto che in una ISR non puoi aspettarti che funzioni il codice legato ad altre ISR.

Cerco di spiegarmi meglio: all'interno di una ISR nessuno ti vieta ti chiamare la funzione millis() ad esempio per salvarne il valore in qualche variabile o cose simili.
Devi però assolutamente tenere conto che millis() resituirà l'ultimo valore generato dalla relativa ISR e che se lo infili in qualche ciclo o cose simili non funzionerà mai come ti aspetti perché il valore sarà sempre e soltanto quello.

Comunque tornando alla richiesta di @Rob123 io più che altro qui ci vedo un bel "XY Problem"

1 Like

Grazie a tutti per aver risposto.

Non lo so se è un problema XY, ma il problema, quello che mi ha fatto aprire la discussione, me lo avete risolto.Ora so perchè non posso usare quella soluzione.

Parlando del mio esempio, è appunto solo un esempio ridotto ai minimi termini per contestualizzare al meglio la domanda e soprattutto per non perdere tempo su cosa vuol dire per me
bloccante.

Ho rimosso la descrizione del mio programma dal primo post perchè non serve.

In realtà, anche se prima d'ora non ne ho mai avuto bisogno, mi sembra una funzione abbastanza necessaria.
Preferirei, leggere il primo byte e usare quello per decidere cosa fare dei successivi. Potrebbe anche essere che per trasmettere l'informazione sia suff. un singolo byte.
Quello che sto provando a fare in questo momento è inviare un indirizzo e il valore da scrivere a quell'indirizzo.
Devo aprire una nuova discussione o possiamo continuare qua?

Continua pure qui.
Come ti hanno detto, non ti servono gli interrupt. Lo fa già il core di Arduino. Inutile forzare una cosa solo per fare delle prove.
Spiega cosa intendi quando dici che il primo byte indica un "indirizzo"
in precedenza avevi scritto:
"Quello che devo fare comunque è leggere 3 caratteri, il primo indica a quale variabile ( delle due in questo caso ) fa riferimento."

... già questo dimostra che NON servono ... tu comunque ricevi TUTTI i bytes, e quindi ... puoi tranquillamente decidere cosa fare con i successivi senza complicare la cosa.

Per inciso, stai reinventando l'acqua calda :wink: ... prova a cercare la mia libreria SerialCmd (la trovi sia su Github con tutta la documentazione sia nel "library manager" del IDE) :slight_smile:

Guglielmo

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.