chiarimenti sugli interrupt

Rifacciamo il punto, sennò qui non ci capisco più nulla neanch'io.
Io ti ho dato questo link:
http://www.arduino.cc/playground/Main/PcInt
Quello è uno sketch già pronto per essere usato così com'è. Se vuoi riusarlo in un tuo progetto, togli le funzioni loop() e setup() che ci sono in fondo e scrivici le tue.

Secondo link:
http://arduino.cc/playground/Main/PinChangeInt
Questo l'hai pubblicato tu, quindi immaginavo lo conoscessi ma sembra di no :wink:
A metà pagina c'è un collegamento:
Google Code Group che porta ad un elenco di file scaricabili. Io ho semplicemente aperto quello che si chiama PinChangeIntv1.72.zip ed ho trovato 3 cartelle compresa la cartella PinChangeInt. Come ti ho detto, questa è una libreria vera e propria e va copiata nella tua cartella /sketchbook/libraries o \Arduino\libraries, a seconda che usi Linux o Windows.

Nel primo caso non devi aggiungere nessun , nel secondo sì.

ok perfetto adesso ho capito! grazie mille! :smiley:

io però uso un mega2560, non penso vada bene la prima opzione, ovvero usare questo codice: http://www.arduino.cc/playground/Main/PcInt
quindi devo usare la libreria no?

esiste un solo registro ad 8 bit per ogni porta logica del micro, ogni porta mappa 8 piedini. Inoltre quando si attiva un interrupt, se ne arriva un altro questo viene messo in attesa. Ma sui PCINT bisogna stare attenti: siccome appunto ogni registro PCINT mappa 8 porte, se si attiva il flag di un PCINT, il micro lo esegue, poi terminata l'esecuzione, resetta il flag relativo. Però se arrivano 2 o più segnali sullo stesso pin, solo il primo verrà eseguito, i successivi saranno persi.

per risolvere questo problema posso collegare un solo interrupt per porta, e siccome uso un mega ho un buon numero di porte disponibili, o questa è solo una cazzata? quanti interrupt posso usare al massimo?
grazie ancora per l'aiuto :slight_smile:

er_like_no_other:

esiste un solo registro ad 8 bit per ogni porta logica del micro, ogni porta mappa 8 piedini. Inoltre quando si attiva un interrupt, se ne arriva un altro questo viene messo in attesa. Ma sui PCINT bisogna stare attenti: siccome appunto ogni registro PCINT mappa 8 porte, se si attiva il flag di un PCINT, il micro lo esegue, poi terminata l'esecuzione, resetta il flag relativo. Però se arrivano 2 o più segnali sullo stesso pin, solo il primo verrà eseguito, i successivi saranno persi.

per risolvere questo problema posso collegare un solo interrupt per porta, e siccome uso un mega ho un buon numero di porte disponibili, o questa è solo una cazzata? quanti interrupt posso usare al massimo?
grazie ancora per l'aiuto :slight_smile:

In allegato la piedinatura dell'Atmega168, è identica a quella del 328. Inoltre il discorso si applica anche al Mega2560.
Vedi come sono denominati i pin? PC6, PD0, PD1 ecc... PCx è una porta logica quindi tutti i suoi piedini sono numerati da 0 a 7, per un totale di 8 (non è detto che tutti siano poi mappati esternamente). Questo vale anche per PCx e per PBx. Prendiamo il caso che tu usi i pin dell'Arduino dal 9 al 13 che, come vedi dal disegno, sono mappati sui piedini PB1..PB5. Se arriva un segnale su PB1 e poi su PB2, perdi quello su PB2 perché il flag della porta relativa viene pulito dopo l'esecuzione dell'interrupt di PB1 (così capisco dal datsheet, non ho mai usto più PCINT contemporaneamente, non posso confermare). Se arriva un segnale su PB1 mentre è già in esecuzione una routine di gestione dell'interrupt (ISR) sempre su PB1, il secondo segnale lo perdi perché non appena esci dalla ISR di PB1 viene azzerato il suo flag.
Quindi puoi gestire tanti interrupt quanti sono i pin del tuo micro ma poi hai i problemi di cui sopra. Inoltre se infili tanti interrupt nel codice ed i segnali arrivano in continuazione rischi di rallentare talmente tanto l'esecuzione del codice che poi i segnali li perdi lo stesso.

Atmega168PinMap2.png

mmmmm la storia sembra più complicata del previsto :sweat_smile: però penso di aver capito :slight_smile:
nel codice però posso attivare e disattivare un interrupt quando mi serve no? l'importante è non averne troppi attivi nello stesso momento...

non mi hai detto del mega2560, è diverso dal 328? ho problemi se uso quel codice o quella libreria che dicevi prima?
grazie :slight_smile:

i pcint del mega non coincidono col 328, potrebbero cambiare anche i raggruppamenti, ma la libreria dovrebbe essere già ok

ok, come immaginavo, grazie mille :wink: domani faccio qualche prova speriamo bene....

allora ho scaricato la libreria e nel pacchetto c'era anche questo codice, l'ho provato sull'arduino 2009 e va.. ma io volevo farlo andare anche sul mega2560, ma non so come fare a modificarlo per renderlo compatibile... :blush: potete spiegarmi dove mettere le mani?
grazie in anticipo! :wink:

/ PinChangeIntExample, version 1.1 Sun Jan 15 06:24:19 CST 2012
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
//-------- define these in your sketch, if applicable ----------------------------------------------------------
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts
// on any one or two of the three ports.  If only a single port remains, the handler will be declared inline
// reducing the size and latency of the handler.
//#define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
//#define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts
// if there is only one PCInt vector in use the code can be inlined
// reducing latency and code size
// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation.
// #define       DISABLE_PCINT_MULTI_SERVICE
//-------- define the above in your sketch, if applicable ------------------------------------------------------
#include <PinChangeInt.h>

// This example demonstrates a configuration of 3 interrupting pins and 2 interrupt functions.
// All interrupts are serviced immediately, but one of the pins (pin 4) will show you immediately
// on the Terminal.  The other function connected to 2 pins sets an array member that is queried in loop().
// You can then query the array at your leisure.
// This makes loop timing non-critical.

// Add more Pins at your leisure.
// For the Analog Input pins used as digital input pins, and you can use 14, 15, 16, etc.
// or you can use A0, A1, A2, etc. (the Arduino code comes with #define's
// for the Analog Input pins and will properly recognize e.g., pinMode(A0, INPUT);
#define PIN1 2
#define PIN2 3
#define PIN3 4

uint8_t latest_interrupted_pin;
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins
void quicfunc() {
  latest_interrupted_pin=PCintPort::arduinoPin;
  interrupt_count[latest_interrupted_pin]++;
};

// You can assign any number of functions to any number of pins.
// How cool is that?
void pin3func() {
  Serial.print("Pin "); Serial.print(PIN3, DEC); Serial.println("!");
}

void setup() {
  pinMode(PIN1, INPUT); digitalWrite(PIN1, HIGH);
  PCintPort::attachInterrupt(PIN1, &quicfunc, FALLING);  // add more attachInterrupt code as required
  pinMode(PIN2, INPUT); digitalWrite(PIN2, HIGH);
  PCintPort::attachInterrupt(PIN2, &quicfunc, FALLING);
  pinMode(PIN3, INPUT); digitalWrite(PIN3, HIGH);
  PCintPort::attachInterrupt(PIN3, &pin3func, CHANGE);
  Serial.begin(115200);
  Serial.println("---------------------------------------");
}

uint8_t i;
void loop() {
  uint8_t count;
  Serial.print(".");
  delay(1000);
  for (i=0; i < 20; i++) {
    if (interrupt_count[i] != 0) {
      count=interrupt_count[i];
      interrupt_count[i]=0;
      Serial.print("Count for pin ");
      if (i < 14) {
        Serial.print("D");
        Serial.print(i, DEC);
      } else {
        Serial.print("A");
        Serial.print(i-14, DEC);
      }
      Serial.print(" is ");
      Serial.println(count, DEC);
    }
  }
}

IMHO conviene riscriverla da 0.
o trovi qualcosa di già fatto oppure ti tocca scaricare il manuale del 328, e confortare i registri con quello del 2560. I manuali li trovi sul sito della atmel(il produttore), son tomi da oltre 500 pagine se non erro, se serve una mano chiedi pure ma sappi che è un'avventura impegnativa ma molto istruttiva

Quoto lesto.
La libreria è scritta per gli Atmega168/328.
Se il numero di PCINT da gestire non è elevato, conviene andare di codice, senza stare a scrivere una libreria apposita. Alla fine, si tratta di configurare una manciata di registri del micro.

eheh spero di non essere l'unico ad aver bisogno di usare qualche interrupt sul mega :sweat_smile:
comunque leggevo sulla pagina dell'arduino mega http://arduino.cc/en/Main/ArduinoBoardMega2560

External Interrupts: 2 (interrupt 0), 3 (interrupt 1), 18 (interrupt 5), 19 (interrupt 4), 20 (interrupt 3), and 21 (interrupt 2). These pins can be configured to trigger an interrupt on a low value, a rising or falling edge, or a change in value. See the attachInterrupt() function for details.

quindi ho già 6 interrupts disponibili, no? potrebbero anche bastarmi, ma io voevo usarne di più per poter fare una specie di sistema multitask...

un'altra domanda: se io ho un interrupt durante la funzione pulseIn, cosa succede? mi interrope il processo o no?
grazie :wink:

L'interrupt interrompe qualsiasi cosa sia in corso , altrimenti devi usare un detachinterrupt
Ciao Niko

er_like_no_other:
eheh spero di non essere l'unico ad aver bisogno di usare qualche interrupt sul mega :sweat_smile:
comunque leggevo sulla pagina dell'arduino mega http://arduino.cc/en/Main/ArduinoBoardMega2560

External Interrupts: 2 (interrupt 0), 3 (interrupt 1), 18 (interrupt 5), 19 (interrupt 4), 20 (interrupt 3), and 21 (interrupt 2). These pins can be configured to trigger an interrupt on a low value, a rising or falling edge, or a change in value. See the attachInterrupt() function for details.

La gestione degli INT è integrata in Arduino per cui la gestione di essi non comporta problemi.

quindi ho già 6 interrupts disponibili, no? potrebbero anche bastarmi, ma io voevo usarne di più per poter fare una specie di sistema multitask...

Anche se tempo fa sono stato affascinato dai sistemi operativi multitasking per micro ad 8 bit, col tempo ho poi riflettuto sulle complicazioni che essi hanno.
Questi SO usano interrupt per suddividere il tempo di calcolo della Cpu del micro tra i vari processi. Ma se un processo è agganciato ad una funzione HW che richiede un certo tempo per essere eseguita, come ad esempio la lettura di un pin analogico, che si fa? Si interrompe il processo falsando così la lettura o la si fa terminare, alterando i tempi di esecuzione degli altri processi?

un'altra domanda: se io ho un interrupt durante la funzione pulseIn, cosa succede? mi interrope il processo o no?
grazie :wink:

Sì, quindi si torna a ciò che ti ho detto poco sopra.

ok quindi provo a guardare se riesco a trovare qualcosa di già pronto per il mega e poi vedo di inventarmi qualcosa da SW per creare una specie di multitask...
ma terminato l'interrupt il programma riprende dal punto in cui era stato interrotto no? quindi il problema è solo nell'interropere le funzioni di lettura che richiedono un po' di tempo per essere eseguite, tipo il pulseIn e l'analogRead, come dici te...potrei fare che quando finisce l'interrupt va a ripetere la misura che stava facendo, se stava facendo una misura... comunque, però, vado a buttare dei microsecondi...
grazie per l'aiuto! vi so dire se trovo qualcosa per il mega :wink:

Bah... se strutturi bene il programma non hai bisogno di multitasking. Anche perché puoi simulare multitasking e tick usando bene millis e seguendo una buona logica dei compiti da eseguire.

sisi infatti, ci sto pensando :wink:

allora, stavo provando questo codice per leggere un sensore, da questo sensore ricevo un impulso di durata variabile... speravo di ottenere gli stessi risultati di quando uso la funzione pulseIn ma non è così... sembra che mettendo 2 tipi di interrupt sullo stesso pin non funzionino tutti e due ma uno solo, mi confermate questa cosa o ho sbagliato da qualche altra parte?
grazie in anticipo! :wink:

unsigned long Time=0;
unsigned long t=0;

void setup()
{
 pinMode(2, INPUT);
 pinMode(3, OUTPUT); 
 Serial.begin(115200);
}

void loop()
{
 t=millis();

 digitalWrite(3, HIGH);  
 delayMicroseconds(10);
 digitalWrite(3, LOW); 

 attachInterrupt(0, StartTimer, RISING);
 attachInterrupt(0, StopTimer, FALLING);
 while(millis()-t<=50){}

 detachInterrupt(0);
}

void StartTimer(){ Time=micros(); Serial.println("s");}
void StopTimer() { Time=(micros()-Time)/58; Serial.println(Time,DEC);}

sì, ora non ricordo se è un attachInterrupt alla volta o uno per pin...

@er:
mi spiace, non puoi fare una roba del genere :stuck_out_tongue_closed_eyes:
Prima attivi l'interrupt 0 con un tipo di segnale e poi dopo lo stesso interrupt con un altro segnale! E' normale che te ne venga eseguito solo 1 :stuck_out_tongue:
Anzi, mi meraviglio di come il compilatore non ti dia errore dicendoti che il vettore di interrupt risulta già dichiato :wink:

nel (vecchio) reference dicono che questo caso è preso in considerazione.
Il puntatore alla funzione di interrupt è sovrascritto.
ora, non ricordo se c'è un solo puntatore a funzione, o se ce ne è una per pin