Go Down

Topic: Pulsante, interrupt e led (Read 575 times) previous topic - next topic

mefore

Buonasera a tutti.
Qualcuno mi sa sistemare questo sketch in modo che non sbagli un colpo?

info:
Pulsante normalmente aperto chiude verso massa il pin 2 di interrupt, alla pressione del tasto il led sul pin 13 deve cambiare di stato.
A me succede che una volta su 10 pigiando il pulsante il led cambia di stato, ma rilasciando il pulsante il led cambia ancora di stato! dov'è l'inghippo?

questo è il codice:

void setup()
{
  pinMode(LED, OUTPUT); // definiamo pin output
  pinMode(int0, INPUT); // definiamo pin input
  attachInterrupt(0, blink, FALLING);


void loop()
{
  if(change)
  {
    noInterrupts();
    change=false;
    state=!state;
    digitalWrite(LED, state);
    while(digitalRead(int0)==LOW)
    {
      delay(200);
    }
    delay(200);
    interrupts();
  }
}
void blink()
{
  change=true;
}

gpb01

#1
Apr 19, 2018, 06:33 am Last Edit: Apr 19, 2018, 06:33 am by gpb01
Buongiorno,
prima di tutto, essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione il su citato REGOLAMENTO ...

... poi, in conformità al suddetto regolamento, punto 7, devi editare il tuo post (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More -> Modify che si trova in basso a destra del tuo post) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag: [code] _il _tuo_ codice_ [/code] così da non venire interpretato e non dare adito alla formazione di caratteri indesiderati o cattiva formattazione del testo. Grazie.

Guglielmo
Search is Your friend ... or I am Your enemy !

Silente

Dopo che avrai fatto quanto richiesto da Guglielmo ti do un consiglio:
Mettiti di fronte ad un foglio di carta e scrivici quello che vuoi che succeda nei diversi stadi del tasto, che sono:
Nulla successe, tasto rilasciato
Tasto appena prenuto
Tasto in pressione
Tasto in rilascio.
Scrivi quello che vuoi che succeda, e NON pensare a come farlo succedere.
Poi mostra il risultato che ne parliamo

gpb01

#3
Apr 19, 2018, 07:40 am Last Edit: Apr 19, 2018, 07:41 am by gpb01
... più che altro, DOPO aver fatto quello che ti ho chiesto al post #1, dicci se hai messo una rete RC per il debouncing del pulsante, altrimenti è ovvio che NON ti funzioni bene ... ::)

Guglielmo
Search is Your friend ... or I am Your enemy !

gpb01

#4
Apr 19, 2018, 03:20 pm Last Edit: Apr 19, 2018, 03:22 pm by gpb01
... ho letto la tua presentazione e, considerando quello che scrivi, aggiungo ... sicuro che per uno come te NON sia più adatto utilizzare Atmel Studio (è gratuito) invece che l'IDE di Arduino?

Vista sia la preparazione che il tuo piacere a lavorare a livelli più "bassi" ... è l'ambiente ideale ;)

Guglielmo
Search is Your friend ... or I am Your enemy !

mefore

Grazie della info Guglielmo, probabilmente si, tempo permettendo proverò anche l'Atmel Studio...sfruttando la board di arduino e i suoi vari shield, per non ricadere nel paranoico incubo di realizzare gli stampati.

Comunque sono daccordo con te, se mettessi una rete RC funzionarebbe, ma in questo momento non mi interssa tanto farlo funzionare quanto capire a fondo perchè con quelle 4 righe di codice ogni tanto sbarella.
Il debouncing dovrei riuscire a farlo con il delay(200) nel ciclo di while (con interrupts disattivati).
Al rilascio del pulsante ho inserito un ulteriore delay di 200ms prima che vengono riattivati gli interrupts, non vedo motivi per il quale al rilascio del pulsante ogni tanto si retriggera l'interrupt commutandomi l'uscita LED.

Per Silente:

Tasto rilasciato---> Led nello stato della precedente pressione.
Tasto premuto---> Led inverte di stato.
Tasto in pressione---> Led mantiene lo stato aquisito.
Tasto in rilascio---> Led DEVE mantenere lo stato già aquisito...fino a prossima pressione.

Grazie ancora

gpb01

... devi sistemare il codice come ti ho chiesto al post #1. Grazie

Guglielmo
Search is Your friend ... or I am Your enemy !

docdoc

..e comunque a parte il discorso dei tag (che devi sistemare), il codice non è completo perché manca la graffa di chiusura della setup() e soprattutto DOVE hai definito la variabile "change" (che tra l'altro deve essere dichiarata "volatile" se la modifichi nell'ISR)???

Devi postare tutto il codice esatto altrimenti se anche uno volesse provarlo per proprio conto deve poterlo compilare, senza dover impazzire ad "indovinare" cosa tu ti sia scordato...

Fallo, correggi il tuo primo post con il codice completo ed esattamente quello che usi per provare, poi scrivi qui un nuovo post per spiegare esattamente cosa fa QUELLA versione (e quindi cosa NON fa), così possiamo aiutarti.
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

mefore

Scusate, sistemato il sorgente con la procedura corretta.
Ho dimenticato di specificare che sul pulsante non c'è rete RC ma è comunque presente una R di pullup.
So bene inoltre di essere paranoico con questa richiesta, ma è un sassolino nella scarpa che mi voglio levare capire perchè mi parte l'interrupt al rilascio del pulsante.
Ciao

Code: [Select]


void setup()
{
  pinMode(LED, OUTPUT); // definiamo pin output
  pinMode(int0, INPUT); // definiamo pin input
  attachInterrupt(0, blink, FALLING);


void loop()
{
  if(change)
  {
    noInterrupts();
    change=false;
    state=!state;
    digitalWrite(LED, state);
    while(digitalRead(int0)==LOW)
    {
      delay(200);
    }
    delay(200);
    interrupts();
  }
}
void blink()
{
  change=true;
}


gpb01

#9
Apr 19, 2018, 04:50 pm Last Edit: Apr 19, 2018, 04:51 pm by gpb01
... poi, in conformità al suddetto regolamento, punto 7, devi editare il tuo post (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More -> Modify che si trova in basso a destra del tuo post) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).
Ma è così difficile capire che devi editare il tuo PRIMO post e non scriverne uno nuovo ? ? ? Eppure è scritto in modo chiaro ...

Guglielmo
Search is Your friend ... or I am Your enemy !

Claudio_FF

#10
Apr 19, 2018, 05:14 pm Last Edit: Apr 19, 2018, 05:16 pm by Claudio_FF
capire perchè mi parte l'interrupt al rilascio del pulsante.
L'interrupt parte sul fronte di discesa.

Se parte al rilascio vuol dire che sente un fronte di discesa.

E perché al rilascio, dopo cui dovrebbero esserci i 200ms di pausa per togliere i rimbalzi c'è comunque un fronte di discesa?

L'errore è nel dare per scontato di restare nel while che attende il rilascio.

Ma così evidentemente non è.

Hai filtrato solo i rimbalzi al rilascio, ma non quelli alla pressione.

Quindi al rilascio qualche volta si è già fuori dal while, e i rimbalzi del rilascio vengono visti come pressione.
* * * *    if non è un ciclo   * * * *

* * * Una domanda ben posta è già mezza soluzione. * * *

Silente

Tanto per incominciare ti chiedo se non sarebbe più utile e comodo effettuare il debounce hardware e non software de pulsante (chiedi e guarda in giro per maggiori info in merito). Credo che, infatti, il debounce software NON sia strada percorribile.
In secondo luogo ti ringrazio di avermi chiarito quello che deve succedere. In sintesi nel momento in cui sento che il tasto sta venendo premuto il led deve cambiare di stato.
In terzo luogo mi domando e dico, non potrei scrivere un programma con una loop vuota, che contiene soltanto la setup() e una funzione di interrupt di una sola riga chiamata al RISING de pin del tasto?
Inoltre mi rispondo che si potrebbe, e sarebbe facile. Devi però avere una serie di conoscenze base:
1)sapere comandare un interrupt
2)sapere scrivere una funzione
3)sapere comandare un led
4)sapere leggere un pulsante.
Lo sai fare?
Infine, PRIMA DI RISPONDERE ti chiedo di seguire le direttive di lord Guglielmo, che temo sia intenzionato a chiudere la baracca se non lo fai

gpb01

#12
Apr 19, 2018, 08:49 pm Last Edit: Apr 19, 2018, 08:50 pm by gpb01
...
Inoltre mi rispondo che si potrebbe, e sarebbe facile. Devi però avere una serie di conoscenze base:
1)sapere comandare un interrupt
2)sapere scrivere una funzione
3)sapere comandare un led
4)sapere leggere un pulsante.
Lo sai fare?
Se leggi la sua presentazione (cosa da fare sempre prima di rispondere) vedi che ha un ampia esperienza anche a basso livello ;)

Guglielmo
Search is Your friend ... or I am Your enemy !

mefore

Buonasera a tutti.
Tra impegni famigliari e rogne sul lavoro è sempre difficile entrare qua, ma quando riesco (anche alle 3 di notte) è sempre un piacere.
Postando nel precedente messaggio il mio codice in effetti è mancato qualcosa...nel ripulirlo dai commenti e dalle parti di codice di debug ho ranzato un po troppo. Riallego quindi il codice completo di tutti i commenti e del led verde aggiunto solo come debug.
Infinitamente semplice nella sua essenzialità...ma non funziona!

Code: [Select]

int pin = 13; // Led rosso
int verde =12;  // Led verde...test point per il ciclo di while
int int0 = 2; // pin di interrupt esterno
volatile bool change=false;  // abilita cambio di stato del led rosso
int state = LOW;  //Variabile di stato del led rosso

void setup()
{
  pinMode(pin, OUTPUT);
  pinMode(verde, OUTPUT);
  pinMode(int0, INPUT);
  attachInterrupt(0, blink, FALLING);
  digitalWrite(verde,LOW);
}

void loop()
{
  if(change)
  {
    noInterrupts(); // disabilito interrupts per non farmi buttar fuori dall'if se ci fosse un rimbalzo del pulsante.
    change=false; // riarmo change per non farmi rientrare nel if fino alla prossima pressione del pulsante
    state=!state; // not della variabile di stato del led rosso
    digitalWrite(pin, state); // che poi vado a scrivere sull'uscita del led rosso
    while(digitalRead(int0)==LOW) // mentre ho ancora gli interrupt disabilitati giro in questa while finche il pulsante è premuto
    {
      digitalWrite(verde,HIGH); // accendo un led verde per conferma che non esco dal while
      delay(200); // delay di 200ms tanto per fare qualcosa
    }
    digitalWrite(verde,LOW);  // se sono qui è perchè il pulsante è stato rilasciato...
                              // mentre l'interrupt è ancora disabilitato
    delay(200);       // al rilascio del pulsante aspetto ulteriori 200ms di debuncing prima di riabilitare gli interrupt
    interrupts();   // se sono qui è perchè il pulsante è stato rilasciato e sono terminati tutti i rimbalzi...quindi posso riarmare l'interrupt
                  // e attendere, senza far nulla,  la nuova pressione del pulsante.
  }
}
void blink()
{
  change=true; // triggerato interrupt sul pin int0. Al prossimo ciclo della loop()il program counter mi entra nel condizionale if(change)
}




L'errore è nel dare per scontato di restare nel while che attende il rilascio.

Claudio ti ringrazio per l'interessamento ma purtroppo non è nemmo come dici tu...se rileggi il codice colpleto che ho postato qui sopra vedi che nel ciclo di while ci ho messo un led verde che rimane acceso fintanto che sono nel while, ed in effetti cosi è. Quindi ho la prova che nella while ci rimango finche c'è il pulsante premuto, quando lo rilascio il led verde si spegne e solo dopo che il led verde si è spento e sono trascorsi ulteriori 200ms vado a riarmare l'iterrupt. Ma spesso, oltre a spegnersi il led verde, mi cambia ancora di stato il led rosso.


Tanto per incominciare ti chiedo se non sarebbe più utile e comodo effettuare il debounce hardware e non software de pulsante (chiedi e guarda in giro per maggiori info in merito). Credo che, infatti, il debounce software NON sia strada percorribile.
Perdonami silente ma temo di non essere daccordo, con un pic e piu o meno le stesse righe di codice tutto funziona alla grande.
Ma a parte questo so bene che un debuncing hardware con una RC, o meglio ancora un flip flop con due nand, sarebbe la soluzione ideale...ma confidando un giorno di poter fare con arduino qualcosa di piu utile di un led che cambia stato, sviscerare a fondo il comportamento degli interrupt è un passo fondamentale, piu precisamente è fondamentale capire come il compilatore dell IDE di arduino traduce in assembler le righe di codice che gli diamo in pasto.


Per Guglielmo, ti ringrazio infinitamente per la stima che ti ha suscitato in me la mia presentazione, ma credimi, alla soglia dei 50 quando riguardo il codice che scrivevo 15/20 anni fa mi gia la testa!
Ad oggi (complice anche mansioni diverse di lavoro che mi trovo a fare rispetto a tempo fa)  mi ritengo un esordiente totale!
Ciao a tutti e grazie per l'interssamento.

Silente

Il massimo aiuto che ti so dare, visto che non so programmare a basso livello, è dirti che:
1)credo che il tuo programma non vada perché, tra l'altro, la funzione di interrupt è chiamata FALLING, quindi agisce quando il pulsante viene rilasciato (almeno se esso risulta normalmente aperto), mentre a te pare interessi funzioni alla pressione.
2)con il debounce hardware dei pulsanti il programma sarebbe potuto venire (penso) una cosa del tipo:
Code: [Select]

#define LED 13//define dovrebbe sostituire a ogni volta che trova la stringa scritta prima tra i due spazi (nel caso LED) con quello scritto dopo di essa (nel caso il numero tredici, ma può essere una stringa o un insieme di funzioni)
void setup()
{
attachInterrupt(0, funzione, RISING);
pinMode (13, OUTPUT);//su Arduino Uno un led sul pin 13 è già posto
}
void loop()
{
}
void funzione()
{
digitalWrite (LED, !digitalRead (LED));
}

Mi scuso per la non indentazione ma non ho usato ide o altro
3)senza i debounce hardware devo fare un minimo di quello software. Per cominciare esso mi basta che sia sulla pressione, e non sul rilascio, quindi posso aggiungere queste cose:
dichiaro una boolean globale volatile che mi dica se la interrupt è intervenuta (indovina dove la alzo)
la loop si compone di un controllo su quella flag, se alta ...
se alta la abbassa, ferma gli interrupts, aspetta abbastanza tempo, e gli riarma.
Non testato, ma a livello teorico va

Go Up