Un problema con Interrupt.

Ho scritto un codice caratterizzato, essenzialmente, da due cicli for. Il primo per acquisire dei dati, il secondo per memorizzarli in Sd-Card. Il primo ciclo (acquisizione) si esaurisce in circa 300msec. Il secondo (memorizzazione in SD-Card) si esaurisce in circa 100 sec, un minuto e mezzo. Durante la fase di memorizzazione potrebbe però presentarsi la necessità di acquisire una nuova serie di dati. Ho pensato, perciò, di inserire nel codice un "attachInterrupt()" che congeli temporaneamente la memorizzazione per passare di nuovo all'acquisizione. Tengo a precisare che per avviare la prima acquisizione (a SD-Card vuota) ho usato un "digitalRead()" che testa lo stato di un pin a cui è collegato un pulsante che fa da trigger. Ho annidato "attachInterrupt()" nel successivo ciclo di memorizzazione associandolo allo stesso pin del pulsante di trigger. Succede però che la stessa acquisizione si avvia due volte per il contemporaneo effetto del trigger e dell'Interrupt. Ovvio che ciò non può essere accettato. Ma cosa posso fare se il pin per il trigger è e deve essere lo stesso che per l'interrupt? Non saprei come risolvere. Chiedo una mano. Saluto e ringrazio tutti.

Potresti usare la libreria PinCangeInterrupt… e li assegni un altro pin…

Nel momento in cui stai salvando i dati puoi impostare il pin di trigger come output: esso così non viene più "letto" dal codice ma solo dall'interrupt, che può funzionare anche con i pin impostati appunto su output.

PS: Non so se sia "sano" affidare ad un interrupt un compito lungo 300 ms.

detachInterrupt() per “staccare” un’interrupt, anche se non ho capio moltissimo dal tuo post

Non deve staccare l'interrupt (se stacca l'interrupt non può fare la lettura mentre sta scrivendo sulla SD) ma mettere il pin come output per evitare di avere poi una doppia registrazione (quella dell'interrupt e, poi, quella del codice).

100 secondi per scrivere sulla SD mi sembrano tanti.
Ci fai vedere il codice?
Ciao Uwe

Credo che il mio problema non ammetta soluzione. Ho provato ad utilizzare le funzioni “attachInterrupt()” e “detachInterrupt()” inserendole nei più svariati punti del codice ma senza ottenere risultati. Stessa cosa invertendo il pin di trigger da INPUT ad OUTPUT.

Come detto, volevo interrompere la memorizzazione dei dati con un interrupt, per passare ad una nuova acquisizione+memorizzazione degli stessi per poi tornare a completare la precedente memorizzazione lasciata in “sospeso”. Mi sono reso conto che ciò è pretendere troppo. L’azione sarebbe possibile se il codice, eseguita la subroutine, ritornasse di nuovo su una istruzione. Ma interrompere l’iterazione di un ciclo for e pretendere, una volta eseguita la subroutine, di rientrare nello stesso ciclo (non in un’altra istruzione) per poi proseguire con la successiva iterazione, non è consentito.
La mia subroutine è caratterizzata da due cicli for per una nuova acquisizione+memorizzazione. Ebbene, uscito, ad es. dalla 125esima iterazione ed eseguita correttamente la nuova acquisizione+memorizzazione, invece di rientrare e proseguire con la 126esima iterazione, il codice rieseguiva la fase di memorizzazione della subroutine appena completata. Qui ho gettato la spugna!
Grazie e un saluto cordiale a tutti.

Una descrizione del codice non é la stessa cosa del il codice. Ciao Uwe

Come già detto in un altro topic, ormai si è diffusa la convinzione che questo Forum sia praticato da gente esperta nello spionaggio industriale, che aspetta solo di vedere del codice e sfruttarlo secondo le proprie esigenze, o magari per venderlo alle agenzie di spinaggio mondiale :stuck_out_tongue_closed_eyes:

menniti: Come già detto in un altro topic, ormai si è diffusa la convinzione che questo Forum sia praticato da gente esperta nello spionaggio industriale, che aspetta solo di vedere del codice e sfruttarlo secondo le proprie esigenze, o magari per venderlo alle agenzie di spinaggio mondiale :stuck_out_tongue_closed_eyes:

eddai, sarà la timidezza della prima volta ]:D

Secondo me tu sei proprio uno di quelli che incutono timore 8)

La scheda usata è Arduino MEGA1280. Questo è il codice:

include

int led=13; const int chipSelect = 53;

int pulsante=2; //pulsante (che farà da trigger)collegato al pin digitale 2 che abilita anche l'INTERRUPT int pulsante_State; //variabile in cui memorizzare lo stato del pulsante int val[2500]; int a,b,c,cont; unsigned long tempo, tempo1,t;

void setup() {

Serial.begin(9600); Serial.print("Initializing SD card..."); // make sure that the default chip select pin is set to // output, even if you don't use it: pinMode(pulsante, INPUT); pinMode(led,OUTPUT);

// see if the card is present and can be initialized: if (!SD.begin(chipSelect)) { Serial.println("Card failed, or not present"); // don't do anything more: return; } Serial.println("card initialized."); }

void loop() {

// make a string for assembling the data to log: String dataString = "";

/********************ACQUISIZIONE1***************/

pulsante_State=digitalRead(pulsante); //il micro testa in continuazione lo stato del pulsante if(pulsante_State==HIGH) //quando il pulsante viene premuto, stato logico HIGH, parte l'ADC

{ tempo=millis(); for(a=0;a<2500;a++) { digitalWrite(led,HIGH); //Flag ADC on val[a] = analogRead(0); digitalWrite(led,LOW); //Flag ADC off } tempo1=millis(); t=tempo1-tempo;

/**********************MEMORIZZAZIONE1**************/ File dataFile = SD.open("datalog.txt", FILE_WRITE); attachInterrupt(0,acquisizione,RISING);

for(b=0;b<2500;b++) {

dataString = String(val*);* ** if (dataFile) {** ** digitalWrite(led,HIGH); //Flag inizio scrittura in SD-CARD on** ** dataFile.print(dataString); //stampa il dato nell'SD-CARD senza carriage return** ** dataFile.print(" "); //stampa un vuoto tra un dato e l'altro senza carriage return**

** if(b==2499)** ** {** ** dataFile.print("end=");** ** dataFile.println(t);** ** }** ** digitalWrite(led,LOW); //Flag fine scrittura in SD-CARD off**

** Serial.print(b); //stampa il valore della variabile a senza carriage return ** ** Serial.print("="); //stampa il carattere = senza carriage return** ** Serial.println(dataString); //stampa il valore di dataString CON carriage return**

** }**

** // if the file isn't open, pop up an error:** ** else {** ** Serial.println("error opening datalog.txt");** ** }**

** }** *detachInterrupt(); *

** }**

}

__ /********************ACQUISIZIONE2************/__ * void acquisizione() ** {** ** for(c=0;c<2500;c++)** ** {**

** digitalWrite(led,HIGH); //Flag ADC on ** ** val** ```c ** = analogRead(0);           digitalWrite(led,LOW);                  //Flag ADC off           }          
            /**********************MEMORIZZAZIONE2*************/         String dataString = "";         File dataFile = SD.open("datalog.txt", FILE_WRITE);        
                      for(c=0;c<2500;c++)                       {                       dataString = String(val[c]);                                                   if (dataFile) {                                   digitalWrite(led,HIGH);                  //Flag inizio scrittura in SD-CARD on                                   dataFile.print(dataString);              //stampa il dato nell'SD-CARD senza carriage return                                   dataFile.print(" ");                    //stampa un vuoto tra un dato e l'altro senza carriage return                                   if(b==2499)                                             {                                             dataFile.print("end=");                                             dataFile.println(t);                                             }                                   digitalWrite(led,LOW);                  //Flag fine scrittura in SD-CARD off         Serial.print(c);            //stampa il valore della variabile a senza carriage return                     
    Serial.print("=  ");          //stampa il carattere = senza carriage return     Serial.println(dataString);  //stampa il valore di dataString CON carriage return                                           }                                                                 }                           }   Grazie a tutti per l'attenzione.
* ```

Vedo 2 problemi:

usare una funzione così dispendiosa in termini di risorse come routine di interrupt ed usare la scrittura su SD all'interno dell'interrupt. Ho dato un'occhiata alla libreria SD e questa usa la funzione millis() per recuperare dei tempi. Però NON si possono chiamare da dentro ad un interrupt funzioni agganciate ad altri timer/interrupt perché un interrupt blocca gli altri. Siccome millis e delay sono agganciate al timer 0 ed aggiornate mediante un interrupt sull'overflow del contatore, esse non funzionano dall'interno di un interrupt.

Quindi devi rivedere la logica del tuo programma.

PS: La prox volta racchiudi il codice nell'apposito tag CODE. Così è illeggibile

leo72:
Quindi devi rivedere la logica del tuo programma.

approvo su tutta la linea… negli interrupt attivi delle variabili che poi il loop gestirà con il codice SD e tutto quello che vuoi, essendo molto lento il loop, devi prevedere di memorizzare più interrupt insieme

Ciò che è riportato nell’allegato flowchart è quanto avrei voluto ottenere con il già noto codice. In realtà ho ottenuto quanto evidenziato con la freccia tratteggiata: il rientro della subroutine avviene su “Acquisizione 2” invece che su “Memorizzazione 1 Parte 2^ (post Interrupt)”. Ho provato di tutto ma niente da fare. Ahimè!

Codice:

#include <SD.h>

int led=13;
const int chipSelect = 53;

int pulsante=2;                //pulsante (che farà da trigger)collegato al pin digitale 2 che abilita anche l'INTERRUPT
int pulsante_State;            //variabile in cui memorizzare lo stato del pulsante
int val[2500];
int a,b,c,cont;
unsigned long tempo, tempo1,t;

void setup()
{
  
  Serial.begin(9600);
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(pulsante, INPUT);
  pinMode(led,OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}

void loop()
{
  
  
  // make a string for assembling the data to log:
  String dataString = "";
  
         /***********************ACQUISIZIONE1******************/
         
 pulsante_State=digitalRead(pulsante);    //il micro testa in continuazione lo stato del pulsante
 if(pulsante_State==HIGH)                 //quando il pulsante viene premuto, stato logico HIGH, parte l'ADC
  
      {
         tempo=millis();
           for(a=0;a<2500;a++)
           {
           digitalWrite(led,HIGH);                  //Flag ADC on       
           val[a] = analogRead(0);
           digitalWrite(led,LOW);                   //Flag ADC off
           }
         tempo1=millis();
         t=tempo1-tempo;
         
         /*************************MEMORIZZAZIONE1*****************/
         File dataFile = SD.open("datalog.txt", FILE_WRITE);
         attachInterrupt(0,acquisizione,RISING);
         
                      for(b=0;b<2500;b++) 
                      {
                        
                      dataString = String(val[b]);
                             if (dataFile) {
                                   digitalWrite(led,HIGH);                  //Flag inizio scrittura in SD-CARD on
                                   dataFile.print(dataString);              //stampa il dato nell'SD-CARD senza carriage return
                                   dataFile.print(" ");                     //stampa un vuoto tra un dato e l'altro senza carriage return
                                   
                                                                   
                                   
                                   
                                  
                                    
                                   if(b==2499)
                                            {
                                             dataFile.print("end=");
                                             dataFile.println(t);
                                            } 
                                   digitalWrite(led,LOW);                   //Flag fine scrittura in SD-CARD off
    
    Serial.print(b);             //stampa il valore della variabile a senza carriage return                       
    Serial.print("=");           //stampa il carattere = senza carriage return 
    Serial.println(dataString);  //stampa il valore di dataString CON carriage return 
     
                                    } 
                                    
  // if the file isn't open, pop up an error:
                                   else {
                                        Serial.println("error opening datalog.txt");
                                        } 
                                      
                      }
                      
                      
                      
  }
  
}



 
           /***********************ACQUISIZIONE2******************/
   void acquisizione()
   {
   for(c=0;c<2500;c++)
           {
            
           digitalWrite(led,HIGH);                  //Flag ADC on       
           val[c] = analogRead(0);
           digitalWrite(led,LOW);                   //Flag ADC off
           }
           
            /*************************MEMORIZZAZIONE2*****************/
         String dataString = "";
         File dataFile = SD.open("datalog.txt", FILE_WRITE);
         
                      for(c=0;c<2500;c++) 
                      {
                      dataString = String(val[c]);
                      
                             if (dataFile) {
                                   digitalWrite(led,HIGH);                  //Flag inizio scrittura in SD-CARD on
                                   dataFile.print(dataString);              //stampa il dato nell'SD-CARD senza carriage return
                                   dataFile.print(" ");                     //stampa un vuoto tra un dato e l'altro senza carriage return
                                   if(b==2499)
                                            {
                                             dataFile.print("end=");
                                             dataFile.println(t);
                                            } 
                                   digitalWrite(led,LOW);                   //Flag fine scrittura in SD-CARD off
    
    Serial.print(c);             //stampa il valore della variabile a senza carriage return                       
    Serial.print("=  ");           //stampa il carattere = senza carriage return 
    Serial.println(dataString);  //stampa il valore di dataString CON carriage return 
                                          }
                                          
                      }
                      
    }

Diagramma_flusso.docx (12.1 KB)

Ripeto, così com'è scritto non funzionerà mai. Non puoi mettere in una routine di interrupt la chiamata ad una funzione che si basa su un interrupt. Nello specifico la lib SD usa il contatore di millisecondi di Arduino che, all'interno di un interrupt, non avanza. E poi non puoi mettere una funzione lunga 100s in una routine di interrupt.

Devi riscrivere lo sketch, prevedendo anche una funzione di scrittura che sia più corta di 100s! Com'è possibile che un'acquisizione tu la faccia in 300 ms e la scrittura dei dati con un tempo 300 volte superiore?

Dunque il diagramma non lo posso vedere perchè openoffice lo mostra in modo inleggibile.

Ogni volta che il pulsante_State (usa pulsante_state o pulsanteState non immischiare) è HIGH agganci l’interrupt alla funzione acquisizione. Dopo il valore di pulsante_State è sempre HIGH se non lo azzeri. Poi una funzione di quelle dimensioni agganciata ad un’interrupt è un bel problema.

Io vedo il codice un bel pò in confusione e non ho capito realmente cosa devi fare.

Io ho capito questo:
se premo pulsante
parte l’acquisizione (1)
scrive i dati nella sd (2)

durante il tempo impiegato per portare a compimento l’operazione 2 tu vuoi che premendo nuovamente il pulsante parta una nuova acquisizione
interrompendo la scrittura nella sd card.

Se è questo che vuoi ottenere devi rivedere il tutto in modo più logico.

Una funzione che scrive nella sd card il contenuto di un buffer che riempi tu ogni volta che premi il pulsante per aquisire, se il buffer è vuoto
non scrive. Questa fuzione scrive in modo atomico un byte in modo non interrompibile terminata la scrittura se c’è in pendenza una richiesta di interrupt questa allora verra eseguita.

La funzione per aqcuisire è attaccata all’interrupt, questa (la funzione) farà l’acquisizione e basta, non infilarci altre cose, manipolazioni calcoli ecc. Se devi fare qualche manipolazione la fai nel loop.

Capisco che messa così non è molto chiara, il fatto e che si può fare in tanti modi.

Ciao.

Devi riscrivere lo sketch, prevedendo anche una funzione di scrittura che sia più corta di 100s! Com’è possibile che un’acquisizione tu la faccia in 300 ms e la scrittura dei dati con un tempo 300 volte superiore?

Forse ha pensato di stare li ad aquisire per tot tempo accumulando il risultato in un’oggetto stringa, mentre dovrebbe fare la cosa contraria, cioè acuisire il minimo data nel minore tempo possibile e poi fare il resto.

Bisogna capire quanti dati legge dal sensore, se cioè può creare due array in memoria per contenere i dati letti. Se così fosse, basterebbe creare un ciclo di scrittura sulla SD che legga, ad ogni iterazione, lo stato di un flag aggiornato dall'interrupt. Se vede questo flag attivo significa che sono in arrivo nuovi dati e richiama la funzione per leggerli, lasciando in sospeso la prima scrittura. Terminata la seconda lettura, finisce la prima scrittura e poi inizia la seconda scrittura.

Se le scritture durano davvero 100s, allora forse è meglio usare una EEPROM esterna in cui "parcheggiare" momentaneamente i dati in attesa di scrittura, e via via riversarli sulla SD mentre non ci sono letture da fare.

MauroTec:

Devi riscrivere lo sketch, prevedendo anche una funzione di scrittura che sia più corta di 100s! Com'è possibile che un'acquisizione tu la faccia in 300 ms e la scrittura dei dati con un tempo 300 volte superiore?

Forse ha pensato di stare li ad aquisire per tot tempo accumulando il risultato in un'oggetto stringa, mentre dovrebbe fare la cosa contraria, cioè acuisire il minimo data nel minore tempo possibile e poi fare il resto.

secondo me devi vedere qualche esempio di programmazione parallela, in particolare gli esempi su producer e consumer. Anche se l'atmega non possiede processi, l'esecuzione di un interrupt durante il loop ricrea gli stessi identici problemi. l'interrupt produce molti valori, piazzati in un array o una lista "buffer", e il consumer, ovvero il loop prende questo elenco e lo salva. Per evitare casini, il loop dovrà bloccare gli interrupt, spostare l'array e dare un nuovo indirizzo per l'array "buffer", dopo di che rendere attivi di nuovo gli interrupt. In questo modo sei sicuro che anche se avviene un ionterrupt mentre salvi i dati, l'interrupt non sarà perso e soprattutto i dati non diventino inconsistenti.

per far ciò devi saper usare una malloc, e usare le funzioni sei() e un'altra che non ricordo, che permettono di inibire e far ripartire gli interrupt. Le funzioni le trovi nel reference, la malloc dovresti già saperla, se ti butti sugli interrupt :)

sei() e cli() ossia SetInterrupt e ClearInterrupt