Interrupt, questo sconosciuto!!!

Buongiorno a tutto il forum, sto sperimentando con arduino uno rev.3 In particolare mi interessa utilizzare gli interrupt che su arduino uno, come tutti saprete, sono disponibili sui pin digitali 2 e 3 (int0 e int1).

Ho messo su un circuito molto semplice, due pulsanti che abilitano ciascuno i 5v sui pin 2 e 3 (con resistenza di pull-down da 10k) ed un led sul pin 8. Di seguito lo sketch:

//#################################################################
int ledpin = 8;
volatile int state = LOW;
int oldstate=LOW;
volatile int con = 0;
volatile int coff = 0;
void setup()
{
  pinMode(ledpin , OUTPUT);

  digitalWrite(ledpin , state);

  attachInterrupt(0, blinkon, RISING);
  attachInterrupt(1, blinkoff, RISING);

  Serial.begin(9600);
  Serial.println("Chronos Started...>");
}

void loop()
{

  if (oldstate!=state)
  {
    Serial.print("cambio stato -> ");
    Serial.print(state);
    Serial.print(" - ");
    Serial.print(con);
    Serial.print(",");
    Serial.println(coff);

    oldstate=state;
    digitalWrite(ledpin , state);
  }
  

}

//INT 0 led on
void blinkon()
{
  state = HIGH;
  con=con+1;
}

//INT 1 led off
void blinkoff()
{
  state = LOW;
  coff=coff+1;
}
//#################################################################

Come vedete è molto semplice. La routine blinkon() sull'interrupt 0 intercetta il fronte di salita (RISING) e setta HIGH la variabile di stato. La routine blinkoff() sull'interrupt 1 fa lo stesso e setta LOW lo stato della variabile che determina l'accensione e lo spegnimento del led. Nel loop il led viene acceso o spento a seconda della variabile di stato. Purtroppo, la pressione del pulsante collegato al pin 2 (int0), causa non solo il rilascio dell'interrupt 0 ma anche il rilascio dell'interrup 1. Inizialmente non avevo messo l'output sulla seriale e non capivo perchè il led avesse un comportamento quasi casuale alla pressione di uno dei due tasti. Di fatto, alla prima pressione del tasto sul pin 2, anche la variabile coff viene incrementata!!!!

Sapete dirmi dove sbaglio ??? grazie

edit by mod: per favore includi il codice usando gli appositi tag

Stai usando i pin dell'interrupt sia per input che per output?

PS: non l'ho provato ma il tuo codice non può compilare: in setup() hai messo un digitalWrite su "pin" ma "pin" non l'hai dichiarato.

scusa hai ragione,
è che ho fatto copia e incolla del codice e per renderlo più leggibile ho cambiato il nome della variabile in ledpin dimenticandomene una :wink:

in tutti gli esempi che ho trovato, quando viene utilizzata la funzione attachinterrupt(), non viene mai dichiarato se il pin è in input o in output e quindi non l’ho fatto nemmeno io.
sostanzialmente coumunque i due pin (2-3) sono esclusivamente in input!

Scusa, la domanda era nata leggendo questo passaggio:

xmas69: Ho messo su un circuito molto semplice, due pulsanti che abilitano ciascuno i 5v sui pin 2 e 3 (con resistenza di pull-down da 10k)

Ho capito male ;)

Io ho provato questo codice:

//#################################################################
const byte ledpin = 13;
volatile byte state = LOW;
byte oldstate=LOW;
volatile int con = 0;
volatile int coff = 0;
void setup()
{
  pinMode(ledpin , OUTPUT);
    pinMode(2, INPUT_PULLUP);
    pinMode(3, INPUT_PULLUP);
  digitalWrite(ledpin, state);

  attachInterrupt(0, blinkon, FALLING);
  attachInterrupt(1, blinkoff, FALLING);

  Serial.begin(19200);
  Serial.println("Chronos Started...>");
}

void loop()
{

  if (oldstate!=state)
  {
    Serial.print("cambio stato -> ");
    Serial.print(state);
    Serial.print(" - ");
    Serial.print(con);
    Serial.print(",");
    Serial.println(coff);

    oldstate=state;
    digitalWrite(ledpin , state);
  }
  

}

//INT 0 led on
void blinkon()
{
  state = HIGH;
  con=con+1;
}

//INT 1 led off
void blinkoff()
{
  state = LOW;
  coff=coff+1;
}
//#################################################################

Siccome non avevo breadboard libere, ho usato un ponticello con un filo e per questo ho invertito la logica dell'interrupt per poter usare le pull-up interne dei pin 2 e 3. A parte i notevoli rimbalzi che si leggono (come vedi, con un semplice pulsantino o ponticello l'interrupt legge decine di pressioni), il led a me non si comporta in modo strano. Sei sicuro di non avere problemi di contatti sulla board di test?

grazie per il test, probabilmente si tratta di problemi di DEBOUNCE. Ho visto che hai aggiunto queste due istruzioni: pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP); servono veramente?

Vorrei riprodurre in qualche modo la situazione per cui mi serve questo progetto. In realtà ai pin 2 e 3, quando sarà tutto pronto, dovrò collegare due fotocellule a catarifrangente per rilevare il passaggio su una porta. Come potrai immaginare il passaggio, e quindi l'interruzione del fascio della fotocellula, potrà essere nell'ordine dei decimi di secondo.

Come posso riprodurre questa situazione senza utilizzare i pulsanti che causano questi problemi di debounce???

Per il software non lo so, ma a livello hardware i rimbalzi li elimini piuttosto facilmente (a meno che non usi pulsanti residuo della seconda guerra punica ;) :D) ... usi resistenze di pulldown da 10K, quindi quelle ci sono gia, mettici in parallelo due condensatori da 220nf o 330nF ceramici, e due resistenze da 100 ohm in serie al pulsante (uno per ogni ingresso ovviamente) ... non ti elimina TUTTO, ma almeno il 90% dei rimbalzi dovrebbe sparire gia cosi, senza diventare matti con routine di debounce ;)

EDIT: se invece vuoi simulare le uscite delle fotocellule ad impulso, usa un normale 4093 o 40106, un paio di porte configurate a monostabile con la temporizzazione uguale a quella che ci si aspetta dalle fotocellule ti fanno il tuo simulatore a spesa quasi zero :D

Grazie mille !!!!! mi metto subito a lavoro :)

Ho trovato questo schemino

Qui c'è: 1 pull-up da 10K (si può evitare attivando la pull-up interna di Arduino) 1 condensatore in parallelo da 100nF 1 resistenza in serie da 470 ohm.

Sono valori diversi da quelli da te menzionati; possono andare bene ugualmente?

I valori non sono critici, e ci si puo giocare in un'intervallo abbastanza ampio ... cambia solo una cosa, piu e' alto il valore del condensatore (e delle resistenze), piu toglie i disturbi, ma allo stesso tempo abbassa il tempo di risposta ... se ad esempio ci metti 1uF o piu, toglie ancora piu disturbi, ma potrebbe non leggerti pressioni ripetute molto ravvicinate e veloci ... di solito si gioca con quei valori in base all'utilizzo che ne vuoi fare.

A proposito, e' un pull-up. mi sembra di capire che lui ha usato un pull-down (ma il discorso di base non cambia, e' lo stesso principio :) )

@paolop ma in quello schema r1 e c1 non sono in parallelo al pulsante recentemente ho affrontato il problema con questa soluzione scritta in un altro linguaggio ma credo si possa intuire, se hai problemi dimmi che lo traduco

'funzione interrupt
GETINT0: 'sul pin 20
statosensore=1 'stato del sensore
If statosensore=1 Then  'sezione per i falsi allarmi
    Debug Cr,"cambiamento dello stato falso allarme", Cr
    Delay 80    'intervallo regolabile
If In(20)=0 Then
    statosensore=1 'segnale valido
    Else
    statosensore=0
    Endif
Endif

stefano

Mettere un delay dentro un'interrupt è un nonsenso. E come se mettessi una persona di guarda ma gli dici di dormire. La R1 è la resistenza di pull-up. La R2 è in serie mentre C1 risulta in parallelo col pulsante.

Gli interrupt non sono solo disponibili ai piedini 2 e 3, ma qualsiasi piedino di ingresso può essere configurato come interrupt.

Per farlo è necessario infilare dentro l' IDE Arduino, un po' di codice C puro, ma niente di trascendentale. Questi ulteriori Interrupt funzionano solo con un Change di stato, per cui va abbinato un digitalWrite per vedere se il Change è andato in LOW o in HIGH.

Inoltre il delay dentro un interrupt funziona benissimo. L'ho usato per una prova rapida con il proposito di sostituirlo con un Timer Hardware configurato in C puro, ma funziona tanto bene, e senza jitter, che l'ho lasciato.

Per la cronaca, oscilloscopio digitale alla mano, usando la funzione Trigger per analizzare i fronti in ingresso-uscita di un delay, con 320mSec di ritardo di codice, in uscita avevo un fronte ESATTAMENTE a 320,00 mSec di ritardo, quindi precisione assoluta fino ai decimi di nanoSec.

stefa24:

ma in quello schema r1 e c1 non sono in parallelo al pulsante

Non sono in parallelo perche’ quello e’ un’ingresso pull-up con chiusura a massa, ed R1 e’ la resistenza di pull-up, appunto … rimangono invece in parallelo quando usi un ingresso in pull-down con chiusura al positivo, ed R1 diventa la resistenza di pull-down, che va a massa e quindi rimane in parallelo al condensatore.

BaBBuino: Inoltre il delay dentro un interrupt funziona benissimo. L'ho usato per una prova rapida con il proposito di sostituirlo con un Timer Hardware configurato in C puro, ma funziona tanto bene, e senza jitter, che l'ho lasciato.

Per la cronaca, oscilloscopio digitale alla mano, usando la funzione Trigger per analizzare i fronti in ingresso-uscita di un delay, con 320mSec di ritardo di codice, in uscita avevo un fronte ESATTAMENTE a 320,00 mSec di ritardo, quindi precisione assoluta fino ai decimi di nanoSec.

Se hai messo un ritardo di 320 ms in un interrupt hai fatto l'ultima delle cose che si deve fare con un interrupt, ossia renderlo luuuungo ;) Un interrupt deve essere il più breve possibile, se hai bisogno di un delay in un interrupt allora non ti serve un interrupt :P

Eh, lo so che è una porcata (un Informatico userebbe il termine "deprecato"), però avevo già esaurito gli interrupt quelli boni (che cmq rimangono a più alta priorità) e quindi ho dovuto usare una porta con la funzione Hardware PCINTx. Il problema più grosso è che quando setti il registro con la maschera degli Interrupt, non puoi agire su una singola porta, ma vai ad agire su tutta la sezione (es. tutto il PortB) della MCU, e poi è un interrupt farlocco, mezzo mascherabile e che funziona solo su CHANGE.

Però alla fine ha funzionato, perchè mentre agisce quel ritardo, non funziona niente di particolare.

So come funzionano i PCINT, ma ripeto che mettere un ciclo di attesa in un interrupt non ha molto senso. Potresti fare la stessa cosa in tanti altri modi, ad esempio avviare un timer impostato per andare in overflow dopo un preciso periodo (i tuoi 320 ms) e, tramite un interrupt agganciato all'overflow, eseguire l'azione che ti serve.

Il proposito iniziale era esattamente quello, ma visto che funziona perfettamente, ho lasciato il "deprecabile" delay.

ciao
volevo sapere se questo schema è utilizzabile anche con un fotoaccoppiatore sostituendo il pulsante con i contatti di un fotoaccoppiatore

stefano

PaoloP:
Ho trovato questo schemino

Qui c’è:
1 pull-up da 10K (si può evitare attivando la pull-up interna di Arduino)
1 condensatore in parallelo da 100nF
1 resistenza in serie da 470 ohm.

Sono valori diversi da quelli da te menzionati; possono andare bene ugualmente?

Perchè deve essere per forza sostituibile, cioè ti serve comandare l’ingresso dal pulsante e anche dal fotoaccoppiatore o ti serve solo isolare un ingresso.

Il 4n35da un lato ha un led e dall’altro un transistor, il lato del transistor si deve collegare con il collettore al pin e questo ad una resistenza di pull-up da 10k, il pin del transistor E (emitter) deve essere connesso a gnd.
Dal lato del led devi usare un R di opportuno valore che dipende dal e dalla tensione che fornisci.

Ciao.

ciao
@ MauroTec
scusa credo di essere stato troppo vago, lato 12v ho un sensore induttivo, uso il fotoaccoppiatore per adattare i livelli di tensione ad arduino, la parte di schema cerchiata prende spunto dallo schema sopra indicato da Paolop per ridurre i disturbi provocati dall’accensione di lampade al neon e di macchinari, per non avere dei falsi positivi sull’interrupt, ma io non sono un esperto quindi prima di mettermi a saldare cercavo una opinione, anche perchè in rete non ho trovato niente che mi convincesse

stefano