Ah vero, perdono. La vedevo come ripetizione dell'else, ma non lo è
ok modifiche effettuate, ma adesso l'errore me lo da all'ultima parentesi graffa alla fine del codice:
unsigned long t1=0;
byte p1=0;
byte pronto2=0;
byte p2=0;
byte pronto3=0;
byte p3=0;
void setup()
{
pinMode(13,OUTPUT); // Inizializzazione I/O 13 in uscita:
pinMode(2,INPUT_PULLUP); // Inizializzazione I/O 2 in entrata:
}
void loop()
{
if(digitalRead(2)==LOW && p1==0) {p1=1; t1=millis();}
if(p1==1)
{
if(millis()-t1<2000)
{
if(digitalRead(2)==HIGH) pronto2=1;
if(pronto2 && digitalRead(2)==LOW) p2=1;
if(p2 && digitalRead(2)==HIGH) pronto3=1;
if(pronto3 && digitalRead(2)==LOW) p3=1;
}
else {t1=0; p1=0; pronto2=0; p2=0; pronto3=0; p3=0;}
if(p3) // ACCESO!
{
t1=0; p1=0; pronto2=0; p2=0; pronto3=0; p3=0;
digitalWrite(13,HIGH);
delay(2000);
digitalWrite(13,LOW);
} ERRORE!!!!!!!
Mancano delle parentesi graffe di chiusura dei blocchi di istruzioni. Per la precisione ne mancano due. L'IDE di Arduino ti viene in aiuto in casi come questo: se clicchi, ovvero porti il cursore, sulla parentesi graffa che apre un blocco vedrai evidenziata quella di chiusura, se presente. Se non ne viene evidenziata nessuna, significa che non l'hai inserita e quindi il blocco non è chiuso, da cui l'errore. Esempio di un blocco con parentesi graffe di inizio e fine:

Prova a trovare tu dove mancano le parentesi di chiusura.
Due?... Ne mancava una! (Anche adesso sto al telefonino, eh, non ho l'IDE per verificare...)
Datman:
Due?... Ne mancava una! (Anche adesso sto al telefonino, eh, non ho l'IDE per verificare...)
Va bene la precisione al quadrato e il rimbeccare gli altri visto che si discute di argomenti tecnici, però almeno la correzione dev'essere giusta e verificata per non creare confusione a chi non ha esperienza.
A parte che pure se fossero state 5 o 10 le parentesi mancanti, comunque sono due, e non me ne fossi accorto data l'ora tarda e l'indentazione del codice che non aiuta proprio, non era quello il punto. Il punto era che l'OP imparasse in autonomia a trovare l'errore e a far sua una tecnica basilare di debug.
Si noti che mi riferisco alla sola correttezza formale (sintassi) del codice, non sono sceso nel merito di cosa deve fare.
Ah, ecco, ho trovato dove mancava l'altra parentesi graffa. Con il monitor 17" del computer portatile è un po' più facile che con il telefonino!
Perdonatemi.
Credo di averle trovate le parentesi mancanti ma risolvo un problema e se ne genera un'altro
:
void loop()
{
if(digitalRead(2)==LOW && p1==0) {p1=1; t1=millis();}
if(p1==1)
{
if(millis()-t1<2000)
{
if(digitalRead(2)==HIGH) pronto2=1;
if(pronto2 && digitalRead(2)==LOW) p2=1;
if(p2 && digitalRead(2)==HIGH) pronto3=1;
if(pronto3 && digitalRead(2)==LOW) p3=1;
}
} else {t1=0; p1=0; pronto2=0; p2=0; pronto3=0; p3=0;}
}
if(p3) // ACCESO! ERRORE!!!!!!!
{
t1=0; p1=0; pronto2=0; p2=0; pronto3=0; p3=0;
digitalWrite(13,HIGH);
delay(2000);
digitalWrite(13,LOW);
}
Ho provato ad aggiungere anche il ; dopo if(p3) ma niente...
Dovresti dire che errore...
if(p3) deve essere così. Seguono le graffe.
Il programma nel mio messaggio n.14 è aggiornato con tutte le correzioni.
ok da un confronto ho notato che ho sbagliato io a inserire le graffe. Oggi lo provo a caricare (ho già il circuito pronto) e ti faccio sapere...per ora grazie.
x Datman:
ho provato il codice ma non funziona, il led non si accende...
Così ti assicuro che funziona:
#define ingresso 2
unsigned long t1=0;
byte p1=0;
byte pronto2=0;
byte p2=0;
byte pronto3=0;
byte p3=0;
void setup()
{
pinMode(13,OUTPUT); // Inizializzazione I/O 13 in uscita:
pinMode(ingresso,INPUT_PULLUP); // Inizializzazione I/O 8 in entrata:
}
void loop()
{
if(digitalRead(ingresso)==0 && p1==0) {p1=1; t1=millis();}
if(p1==1)
{
if(millis()-t1<2000)
{
if(digitalRead(ingresso)==1) {pronto2=1; if(p2) pronto3=1;}
else if(pronto2) {p2=1; if(pronto3) p3=1;}
}
else {t1=0; p1=0; pronto2=0; p2=0; pronto3=0; p3=0;}
}
if(p3) // ACCESO!
{
t1=0; p1=0; pronto2=0; p2=0; pronto3=0; p3=0;
digitalWrite(13,HIGH);
delay(2000);
digitalWrite(13,LOW);
}
}
L'algoritmo in if(millis()-t1<2000){} discende direttamente da quello che avevo scritto prima [l'else equivale a if(digitalRead(ingresso)==0) && ...].
Come antirimbalzo ho messo 2,2uF (va bene anche 1uF) tra l'ingresso e massa, in parallelo al pulsante.
allora ho avuto modo di provare il programma: funziona relativamente ma raramente il led si accende dopo 3 pressioni, si accende spesso con due e con una. credo che nel codice manchi il debounce e quindi il programma legge più volte la pressione per pulsante anche premendolo una sola volta. Faccio presente che come antirimbalzo io ho usato un resistore tra pin e massa da 10k.
Devi mettere un condensatore, non un resistore!
Ciao Datman, scura se ti assillo con questo schech ma ho sostituito il resistore con un condensatore non polarizzato da un microfarad tra pin n°2 e massa e addirittura il circuito non funziona. Se invece utilizzo il resistore da 10k in sostituzione il circuito funziona ma irregolarmente. Anche se molto semplice ti allego lo schema dei collegamenti.
Ciao
Il pulsante va tra il 2 e massa, con il condensatore in parallelo! ![]()
csalvo1570:
Anche se molto semplice ti allego lo schema dei collegamenti.
csalvo, tu stai ragionando con pulsante a Vcc e resistenza di pull-down.
Dataman invece sta ragionando con pulsante a massa e resistenza di pull-up (peraltro interna invece che esterna).
Entrambi i metodi sono ugualmente validi.
Ma: o modifichi il codice per farlo funzionare in configurazione pull-down (mantenendo il tuo schema), o adatti il collegamento esterno per farlo funzionare in configurazione pull-up (mantenendo il codice di Dataman).
In entrambi i casi ci va un condensatore di debounce tra l'ingresso e massa.
In alternativa al condensatore, ma solo per questo caso specifico, e solo se si effettua una unica digitalRead in un solo punto e non tante sparse lungo il programma, basterebbe aggiungere un delay(100) nel loop per rallentarlo a dieci giri al secondo, tagliando così fuori tutti i rimbalzi del pulsante.
Le resistenze interne sono di pullup perché è uno standard per i comandi di molti dispositivi.
Sul fatto della logica diciamo così "inversa" l'ho capito dopo. Intanto ti ringrazio datman per l'aiuto che mi hai fornito, ma dato che a me non piace imparare le cosa a pappagallo ho commentato le linee di codice che sono riuscito a capire (vedi allegato) e mi farebbe piacere se commentassi il resto (praticamente la maggior parte) in modo che io possa capire il codice nella sua completezza e imparare nuove istruzione. Ti ringrazio ancora.
#define ingresso 2 // ?
unsigned long t1=0; // dichiarazione e settaggio variabile a zero
byte p1=0; // dichiarazione e settaggio variabile a zero
byte pronto2=0; // dichiarazione e settaggio variabile a zero
byte p2=0; // dichiarazione e settaggio variabile a zero
byte pronto3=0; // dichiarazione e settaggio variabile a zero
byte p3=0; // dichiarazione e settaggio variabile a zero
void setup()
{
pinMode(13,OUTPUT); // Inizializzazione I/O 13 in uscita:
pinMode(ingresso,INPUT_PULLUP); // Inizializzazione I/O 2 in entrata + resistore virtuale di pullup
}
void loop()
{
if(digitalRead(ingresso)==0 && p1==0) {p1=1; t1=millis();} // legge se pin 2 è a zero, il resto non l'ho capita
if(p1==1) //
{
if(millis()-t1<2000) //se non sono passati 2 secondi passa all'istruzione successiva
{
if(digitalRead(ingresso)==1) {pronto2=1; if(p2) pronto3=1;}
else if(pronto2) {p2=1; if(pronto3) p3=1;}
}
else {t1=0; p1=0; pronto2=0; p2=0; pronto3=0; p3=0;}
}
if(p3) // ACCESO!
{
t1=0; p1=0; pronto2=0; p2=0; pronto3=0; p3=0;
digitalWrite(13,HIGH); // porta al livello alto il pin 13
delay(2000); // attende due secondi
digitalWrite(13,LOW); // porta al livello basso pin 13, termina il loop e ricomincia
}
}
La logica del programma di Dataman è abbastanza complessa da seguire, e accidentalmente ricalca al 100% il funzionamento dello schema a relé che avevo postato in precedenza: p1, pronto2, p2, pronto3, p3 sono "variabili flag" che corrispondono come funzione esattamente ai miei relé w1 w2 w3 w4 q.
Una variabile flag è un indicatore che si imposta per segnalare al programma in che situazione/fase si trova.
La logica di Dataman (e dello schema a relé) è di discriminare ogni pressione e ogni rilascio "accendendo" ogni volta il flag seguente. Alla prima pressione va a 1 il flag 'p1', al primo rilascio va a 1 il flag 'pronto2', e così via "accendendo" i vari flag in sequenza ad ogni pressione e rilascio.
Alla terza pressione che avviene entro due secondi dalla prima, viene impostato a 1 il flag 'p3'. Quindi diventa vera la condizione if(p3) che genera l'impulso.
Se invece scade il tempo tutti i flag vengono riazzerati e tocca ricominciare la sequenza. I flag vengono riazzerati anche quando la sequenza viene completata.
E questa è la logica.
Poi c'è l'implementazione, cioè il codice che la realizza, che è scritto un po' "velocemente" e sfrutta qualche "trucchetto" per compattarlo, il che non aiuta a comprenderlo.
#define, crei un nome di comodo, o etichetta, per non scrivere i numeri dei pin nel resto del programma, serve solo per chiarezza e non confondersi. Ovunque scrivi 'ingresso' è come se avessi scritto 2
... && p1==0, ... e contemporaneamente il flag p1 vale 0, cioè stiamo rilevando la primissima pressione
Potrebbe essere riscritto in modo forse un po' più prolisso, ma secondo me più leggibile:
#define INGRESSO 2 // pin ingresso con R pull-up interna
#define PRESS_LEVEL LOW // livello letto a pulsante premuto
#define USCITA 13 // pin di uscita acceso = HIGH
#define ON_LEVEL HIGH // livello che accende uscita
#define OFF_LEVEL LOW // livello che spegne uscita
unsigned long t1 = 0;
bool p1 = false; // variabili flag per memorizzare
bool rilascio1 = false; // l'avanzamento delle fasi
bool p2 = false;
bool rilascio2 = false;
bool p3 = false;
void setup()
{
pinMode(USCITA, OUTPUT);
pinMode(INGRESSO, INPUT_PULLUP);
}
void loop()
{
bool premuto = (digitalRead(INGRESSO) == PRESS_LEVEL);
if (premuto && !p1) // rileva prima pressione
{
p1 = true; // impostando il relativo flag
t1 = millis(); // e salvando il tempo attuale
}
if (p1) // se e` stata già rilevata la prima pressione
{
if((millis() - t1) < 2000) // se non sono trascorsi 2 sec
{
if (!premuto) // se rilasciato
{
rilascio1 = true;
if (p2) { rilascio2 = true; }
}
else if (rilascio1) // altrimenti se ripremuto
{
p2 = true;
if (rilascio2) { p3 = true; }
}
}
else // se scaduti 2 secondi azzera i flag
{
p1 = false;
rilascio1 = false;
p2 = false;
rilascio2 = false;
p3 = false;
}
}
if (p3) // se rilevata terza pressione
{
p1 = false;
rilascio1 = false;
p2 = false;
rilascio2 = false;
p3 = false;
digitalWrite(USCITA, ON_LEVEL);
delay(2000);
digitalWrite(USCITA, OFF_LEVEL);
}
}
Una logica più semplice dove non serve rilevare i rilasci (perché viene rilevato il solo istante di pressione), e dove non servono tanti flag ma una sola variabile 'fase' può essere la seguente:
#define INGRESSO 2 // pin ingresso con R pull-up interna
#define PRESS_LEVEL LOW // livello letto a pulsante premuto
#define USCITA 13 // pin di uscita acceso = HIGH
#define ON_LEVEL HIGH // livello che accende uscita
#define OFF_LEVEL LOW // livello che spegne uscita
unsigned long t1 = 0;
byte fase = 0;
bool prem_prec = false;
void setup()
{
pinMode(USCITA, OUTPUT);
pinMode(INGRESSO, INPUT_PULLUP);
}
void loop()
{
bool prem = (digitalRead(INGRESSO) == PRESS_LEVEL);
bool premuto = (prem && !prem_prec);
prem_prec = prem;
if ((fase > 0) && ((millis() - t1) >= 2000)) { fase = 0; }
else if ((0 == fase) && premuto) { fase = 1; t1 = millis(); }
else if ((1 == fase) && premuto) { fase = 2; }
else if ((2 == fase) && premuto)
{
fase = 0;
digitalWrite(USCITA, ON_LEVEL);
delay(2000);
digitalWrite(USCITA, OFF_LEVEL);
delay(3000);
}
}
Ciao a tutti
Come funziona si capisce meglio dal programma nel mio messaggio n.26, in cui si vede chiaramente che c'è uno "scatto" ogni volta che si preme o si lascia il pulsante. Poi ho "semplificato" (da un punto di vista logico) il programma.
In alternativa, si potrebbe incrementare una variabile ogni volta che lo stato del pulsante passa da non premuto a premuto (anche con un interrupt, volendo, purché ci sia il condensatore antirimbalzo). Se arriva a 3 dalla prima pressione entro il tempo stabilito, il relè si eccita, altrimenti il conteggio va a zero.
