Ciao a tutti, ho comprato da poco un arduino UNO e sto provando a fare i miei primi esperimenti modificando gli esempi a disposizione. Ho ricavato questo codice partendo dal sorgente "button" nel quale si accende il led quando viene premuto un pulsante. Modificandolo, volevo creare un programma che cambi lo stato del led (da on a off o viceversa) ogni volta che premo il pulsante, ad ogni suo fronte di salita.
Una volta compilato e caricato il codice che segue su arduino però il programma non funziona Sembra funzionare solo la prima volta fino a che non si accende il led, poi non riesco più a spegnerlo. Forse proprio perché ho appena cominciato ho fatto un semplice errore a livello di codice ma non riesco a trovarlo... qualcuno potrebbe aiutarmi? Grazie in anticipo, Temeraire XD
P.S. All'inizio del codice ho scritto di comporre un piccolo circuito con una resistenza, ma poi ho preferito usare la resistenza di pull-up interna sul pin 2. So che avrei potuto cercare un'altra soluzione in rete ma sarei più interessato a capire perché questa non funziona.
/*
Led_fronte
Cambiare lo stato di un led ogni volta che premo un pulsante
Componiamo un circuito formato da:
* un LED connesso fra il pin 13 e GND
* un interruttore fra il pin 2 e GND
* una resistenza da 10K connessa tra il pin 2 e +5V
* Nota: su molti Arduino è già presente un led connesso fra il pin 13 e GND.
*/
// COSTANTI:
const int buttonPin = 2; // il pin a cui è connesso l'interruttore
const int ledPin = 13; // il pin a cui è collegato il led
// VARIABILI:
int buttonState = 0; // variabile per leggere lo stato dell'interruttore
int fronte = 0; // variabile per scegliere se cambiare lo stato del led
void setup() {
// inizializzo il pin del led come output:
pinMode(ledPin, OUTPUT);
// inizializzo il pin dell'interruttore come input:
pinMode(buttonPin, INPUT);
// attivo la resistenza di pull-up interna - l'interruttore è normalmente attivo alto:
digitalWrite(2, HIGH);
}
void loop(){
// leggo lo stato dell'interruttore:
buttonState = digitalRead(buttonPin);
// controlla se l'interruttore viene premuto.
// se succede, cambia lo stato dell'interruttore:
if (buttonState > fronte) {
if (ledPin == HIGH) {
// spegni il led:
digitalWrite(ledPin, LOW);
}
else {
// accendi il led:
digitalWrite(ledPin, HIGH);
}
}
else {
}
// salva l'ultimo stato rilevato dell'interruttore:
fronte = buttonState;
}
L'errore è qui.
buttonState non potrà mai essere maggiore di fronte perché entrambi possono assumere o 0 o 1.
Le costanti LOW e HIGH hanno rispettivamente valore 0 e 1.
Quando il pulsante è premuto, tu leggi HIGH, cioè 1.
Memorizzandolo quindi in fronte, alla successiva pressione il confronto con buttonState diventa:
Ti ringrazio, non mi aspettavo una risposta così immediata :), ma non sono sicuro che questo risolva il problema:
Ogni volta che esegue il confronto, alla fine assegna il valore letto a fronte in ogni caso, anche se il confronto non risulta vero.
Nel momento in cui io premo il pulsante e fronte vale 0 (primo fronte di salita), il led si accende. Però se tengo premuto il pulsante troppo tempo l'arduino riesce a leggere più volte lo stato del tasto e devo fare in modo che non cominci a fare attacca-stacca. Di conseguenza a me dovrebbe andare bene che risulti 1>1. Solo che una volta che smetto di premere il pulsante, arduino avrebbe dovuto assegnare il nuovo valore del tasto (0) a fronte e ottenere il confronto 0>0, cioè ancora falso e non modificare lo stato del led.
In questo modo fronte torna ad essere 0 e la prossima volta che premo il pulsante ottengo di nuovo 1>0.
Questo, almeno, era stato il mio ragionamento iniziale, ma qualcosa non funziona.
Non so se si capisce bene e ora non ho il tempo di disegnarlo sul computer, domani aggiungo in un post il flow chart.
Se sei ancora convinto della tua risposta, potresti farmi un piccolo esempio di come risolveresti il problema? Così forse riesco a capire meglio l'inghippo :~
Ah, vero. Non avevo notato bene che l'assegnazione era esterna all'if.
Potrebbe essere anche un caso di "rimbalzo" del pulsante, ossia di letture causate da falsi contatti che fanno vedere all'Arduino diverse pressioni successive del pulsante.
Prova con questo sketch:
void setup() {
buttonState = 0;
.... il resto del tuo codice
}
void loop(){
if (digitalRead(buttonPin) == HIGH) {
delay(30); //piccola attesa per evitare i rimbalzi
if (digitalRead(buttonPin) == HIGH) { //se il pulsante è ancora premuto si continua
//inverto lo stato del led
if (buttonState == 0) {
buttonState = 1;
} else {
buttonState = 1;
}
digitalWrite(ledPin, buttonState); //imposto il led = buttonState;
}
}
}
Non testato, ma dovrebbe funzionare.
E' facile da capire. In una variabile mi tengo lo stato del led, non lo stato della lettura del pulsante.
Ogni volta che premo il pulsante, alterno lo stato e poi imposto il led in base a questo stato.
Scusa se rispondo solo ora ma sono stato occupato e ho avuto giusto il tempo di vedere la risposta ma non quello di rispondere. Comunque il tuo programma sarebbe una bellissima soluzione se stessi programmando un interruttore di un impianto luce. Però in questo caso non lavoriamo più solo sul fronte perché se tengo premuto il pulsante senza rilasciarlo il led continua a cambiare stato.
Visto che il mio è solo un esercizio per imparare ad utilizzare arduino la cosa non è poi tanto irrilevante. Ma secondo te comunque il mio programma è giusto? Il mio problema non è nel software? Grazie
Di seguito ho aggiunto il tuo programma completo se qualcuno che legge la conversazione è interessato:
// COSTANTI:
const int buttonPin = 2; // il pin a cui è connesso l'interruttore
const int ledPin = 13; // il pin a cui è collegato il led
// VARIABILI:
int buttonState = 0; // variabile per salvare lo stato del led
void setup() {
// inizializzo il pin del led come output:
pinMode(ledPin, OUTPUT);
// inizializzo il pin dell'interruttore come input:
pinMode(buttonPin, INPUT);
// attivo la resistenza di pull-up interna - l'interruttore è normalmente attivo alto:
digitalWrite(2, HIGH);
}
void loop(){
if (digitalRead(buttonPin) == HIGH) {
delay(30); //piccola attesa per evitare i rimbalzi
if (digitalRead(buttonPin) == HIGH) { //se il pulsante è ancora premuto si continua
//inverto lo stato del led
if (buttonState == 0) {
buttonState = 1;
} else {
buttonState = 0;
}
digitalWrite(ledPin, buttonState); //imposto il led = buttonState;
delay(1000); //fermo la situazione per avere il tempo di lasciare il pulsante
}
}
}
se vuoi evitare l'isterismo del led metti un while dopo il secondo if, in modo da bloccare il codice finché l'utente non rilascia il pulsante:
if (digitalRead(buttonPin) == HIGH) {
delay(30); //piccola attesa per evitare i rimbalzi
if (digitalRead(buttonPin) == HIGH) { //se il pulsante è ancora premuto si continua
while (digitalRead(buttonPin) == HIGH); //si ferma in attesa che si levi il dito
//inverto lo stato del led[code]
....
[/code]
mi pare corretto. Volendo puoi usare una novità introdotta con le ultime versioni dell'IDE:
pinMode(buttonPin, INPUT_PULLUP); // pin in input con resistenza di pull-up interna
Trovato!!! XD XD XD
L'errore era nel secondo if. Quando confrontavo lo stato del led con quello precedente guardando ledPin stavo confrontando sempre la costante ledPin=13 e perciò ovviamente non si verifica mai 13==HIGH. Io, come quelli che hanno letto il codice, mi sono confuso pensando che ledPin rappresentava il led e perciò la tensione sul pin 13, sbagliando.
if (ledPin == HIGH) {
// spegni il led:
digitalWrite(ledPin, LOW);
}
else {
// accendi il led:
digitalWrite(ledPin, HIGH);
}
}
Per risolvere ho aggiunto una variabile che salva lo stato del led.
Poi ho anche dovuto aggiungere il delay iniziale di 1ms altrimenti mi dava dei rimbalzi e il circuito non rispondeva correttamente come suggerito da leo72.