ho riscontrato un piccolo problema con arduino, relativo alla lettura dei pin...
vi spiego cosa dovrei fare:
ho una variabile (boolean funct = false;)
e voglio che quando si clicchi un button, e quindi l'input di quel pin è HIGH, mi alterni funct se è true, a false, e viceversa...
metto un pezzo di code, per far capire meglio ciò che devo fare:
const int IN_PIN = 5;
const int V_LED = 8;
const int G_LED = 11;
const int R_LED = 13;
int btstate = 0;
boolean funct = false;
void setup() {
pinMode(IN_PIN, INPUT);
pinMode(V_LED, OUTPUT);
pinMode(G_LED, OUTPUT);
pinMode(R_LED, OUTPUT);
Serial.begin(9600);
}
void loop() {
digitalWrite(R_LED, LOW);
digitalWrite(G_LED, LOW);
digitalWrite(V_LED, LOW);
if (funct == true) {
// mia funzione, nella quale ci sono anche dei delay
}
btstate = digitalRead(IN_PIN);
if (btstate == HIGH) {
if (funct == false) {
funct = true;
}
else {
funct = false;
}
}
}
però, quando clicco il button, mi cambia da false a true, ed esegue la funzione, ma non riesco più a stopparla...
premetto, che il pulsante è collegato tra il pin 5v ed il pin 5, e tra il pin 5 ed il gnd, c'è una resistenza da 10k (ho visto questo sul playground).
il problema é che non inverti lo stato solo la prima volta ma di continuo fince hai il bottone schiacciato.
prendi una seconda variabile e con quella controlla se il bottone é stato csciacciato appena oppure é schiacciato da piú di un ciclo.
Ciao Uwe
Ciao Ultra Phonic 2
Dovrebbe funzionare cosí:
if (btstate == HIGH && btstateold == LOW) é vero solo durante il primo ciclo dopo aver azionato il pulsante.
dopo
btstateold = btstate ;
mette lo stato attuale nella variabile di stato precedente. Da adesso in poi col pulsante premuto la condizione soprariportata non é piú vera.
Il delay serve per il debouce.
dopo al rilascio del pulsante nel primo ciclo viene ripristinato al condizione di partenza:
if (btstate == LOW && btstateold == HIGH) { // pulsante rilasciato
btstateold = btstate ;
Ciao Uwe
const int IN_PIN = 5;
const int V_LED = 8;
const int G_LED = 11;
const int R_LED = 13;
int btstate = 0;
boolean funct = false;
int btstateold =0;
void setup() {
pinMode(IN_PIN, INPUT);
pinMode(V_LED, OUTPUT);
pinMode(G_LED, OUTPUT);
pinMode(R_LED, OUTPUT);
Serial.begin(9600);
}
void loop() {
digitalWrite(R_LED, LOW);
digitalWrite(G_LED, LOW);
digitalWrite(V_LED, LOW);
if (funct == true) {
// mia funzione, nella quale ci sono anche dei delay
}
btstate = digitalRead(IN_PIN);
if (btstate == HIGH && btstateold == LOW) { // primo ciclo pulsante azionato
btstateold = btstate ;
delay (10);
if (funct == false) {
funct = true;
}
else {
funct = false;
}
}
if (btstate == LOW && btstateold == HIGH) { // pulsante rilasciato
btstateold = btstate ;
delay (10);
}
}
ho provato lo sketch
aggiungendo
digitalWrite(IN_PIN, HIGH); nel setup() e mettendo il pulsante tra pin 5 e massa e aggiungendo una negazione nella riga
btstate = !digitalRead(IN_PIN);
mi funziona.
ciao Uwe
ancora lo sketch completo:
const int IN_PIN = 5;
const int V_LED = 8;
const int G_LED = 11;
const int R_LED = 13;
int btstate = 0;
boolean funct = false;
int btstateold =0;
void setup() {
pinMode(IN_PIN, INPUT);
digitalWrite(IN_PIN, HIGH);
pinMode(V_LED, OUTPUT);
pinMode(G_LED, OUTPUT);
pinMode(R_LED, OUTPUT);
Serial.begin(9600);
}
void loop() {
digitalWrite(R_LED, LOW);
digitalWrite(G_LED, LOW);
digitalWrite(V_LED, LOW);
if (funct == true) {
// mia funzione, nella quale ci sono anche dei delay
Serial.println("funct");
delay (200);
}
btstate = !digitalRead(IN_PIN);
if (btstate == HIGH && btstateold == LOW) { // primo ciclo pulsante azionato
btstateold = btstate ;
delay (10);
if (funct == false) {
funct = true;
}
else {
funct = false;
}
}
if (btstate == LOW && btstateold == HIGH) { // pulsante rilasciato
btstateold = btstate ;
delay (10);
}
}
ho provato il code, collegando il button come hai detto tu, ma siamo sempre allo stesso punto, la funzione inizia, e non riesco a terminarla, ne alla fine, ne in tempo reale...
Cosí vedi se viene riconosciuto bene il pulsante. Ti deve dare 1 se il pulsante é premuto e 0 se non lo é.
Se lí tutto é bene aggiungi altre righe e Ti fai trasmettere i valori delle variabili.
grazie uwe, ma dopo prove e altre prove, ho trovato il problema:
i problemi sono 2, dopo ogni click del button ho dovuto mettere un delay da 200, in modo che il click venga riconosciuto unico e non multiplo, ed il secondo problema non so come risolverlo, ma è legato ai delay...
nella mia funzione, ci sono delay di 5 /6 secondi, che si susseguono con i vari comandi, quindi il conteggio complessivo dei delay è di 15/20 secondi...
in questi 15/20 secondi il click del pulsante non viene letto, e quindi la funzione riparte, perchè la variabile è ancora a true...
io faccio così.. ma non so se sia la soluzione migliore ... comunque al posto di Delay(r) ... definisco una finzione ritardo (r) n questo modo:
unsigned long viaPulsante ; // contatore, parte alla pressione del pulsante acceso|spento onDisplay
const int onDisplay = 6; // pulsante accende|spegne il display
void ritardo (long r) // simula un delay(r).. ma con controlli all'interno
{
unsigned long r1 = millis();
while ((millis()-r1) < r) //esegue il lop fintanto che non sono passati almeno r millisecondi
{
if ( digitalRead(onDisplay) &&( millis()-viaPulsante>2000))
{viaPulsante = millis();
if (boolean1){ funzione1;} else {funzione2;}; ... //con boolean controlla se è attiva la funzione 1 o la funzione 2
}
}
}
praticamente quando richiamo questo ritardo, in realtà esegue un loop che controlla la pressione del tasto collegato sul pin onDisplay controllando che contemporanemante che millis()-viaPulsante>2000 cioè non viene eseguito se sono passati meno di 2 secondi....
qiundi il secondo if annidato controlla con la variabile boolean se prima ho eseguito funz 1 o funz 2 ed inverte, ovvero se l'ultima volta sono passato su funz2, adesso passa su funz 1... scusa non so se sono stato abbastanza chiaro...
Nello Sketch puó esserci solo una funzione loop().
È strano che devi mettere 200msec per eliminare il rimbalzo del pulsante (debounce); normalmente bastano tempi tra 10 e 50msec.
Che pulsante usi?
Per il tempo di esecuzione della Tua funzione non so aiutarti alla ceca. Se vuoi aiuto manda la funzione. Come Paolo S dice devi sostituire i delay() con milli(), ma per fare questo devi modificare tutto il codice della Tua funzione.
Un alternativa potrebbe essere pilotare col pulsante l' interrupt. Ci sono 2 problemi: il debounce devi farlo via hardware e devi anche cambiare la logica della Tua funzione.
Visto che la funzione chiamata ci mette 20 secondi ad finire solo dopo viene letto il pulsante. ci mette un altro ciclo per essere visto rilasciato per poi essere visto come premuto; percui la Tua funzione viene eseguita al minimo 2 volte.
Se lo fai con l'interrupt le cose migliorano ma mica tanto.
int led() {
digitalWrite(V_LED, LOW);
digitalWrite(R_LED, HIGH);
delay(1000); // blocca il programma per 1 secondo
digitalWrite(V_LED, HIGH);
digitalWrite(R_LED, LOW);
delay(1000); // blocca il programma per 1 secondo
}
in:
...
int ritardo = 0;
unsigned long tempo = 0;
...
int led() {
if (ritardo == 0) // accende i LED e memorizza il tempo attuale
{
digitalWrite(V_LED, LOW);
digitalWrite(R_LED, HIGH);
ritardo = 1;
tempo = milli();
}
if ( (ritardo == 1) && (tempo + 1000 >= milli() ))
{
// aspetta che siano passate 1 secondo e cambia il colore dei led
digitalWrite(V_LED, HIGH);
digitalWrite(R_LED, LOW);
ritardo = 2;
tempo = milli();
}
if ( (ritardo == 2) && (tempo + 1000 >= milli() ))
{
// aspetta ancora un secondo e mette la variabile per partire dal inizio.
ritardo = 0;
}
}
Ciao Ultra Phonic 2
Scusami se Ti ho dato un codice non funzionante ma come sapevi non avevo testato. :-[
Ma hai fatto un po di pratica di programmazione.
Un suggerimento:
non scrivere "if(... && tempo == millis()) " perché se per qualsiasi ritardo non Ti controlla il tempo in quell millisecondo la condizione si avvera di nuovo dopo ca 50 ore. Meglio scrivere " tempo <= millis() ".