Buongiorno,
ho fatto un piccolo programma arduino per comandare l'accensione di una motopompa che uso orami da 1 anno però delle volte mi trovo un problema. quando la motopompa è avviata ed ha accellerato dopo circa 20 o 25 minuti di utilizzo e il programma e in loop sulla riga di programma 68-69 e il programma è fermo in attesa che spengo l'ingresso del pin 1. mi porta lo stato del pin 6 e 7 su HIGH e mi toglie l'acceleratore anche se ancora non ho mai variato lo stato del pin1. cosa potrebbe essere il programma? oppure potrebbe essere qualcosa hardware?
grazie
//CONTROLLO MOTOPOMPA
void setup() {
// set the digital pin as output:
pinMode(1, INPUT); //ricevitore stato elettrovalvola
digitalWrite(1, LOW);
pinMode(2, OUTPUT); //invio consendo accensione motopompa
pinMode(3, OUTPUT); //invio input motorino d'avviamento
pinMode(4, OUTPUT); //invio input polo positivo accelleratore MAX
pinMode(5, OUTPUT); //invio input polo negativo accelleratore MAX
pinMode(6, OUTPUT); //invio input polo positivo accelleratore MIN
pinMode(7, OUTPUT); //invio input polo negativo accelleratore MIN
pinMode(LED_BUILTIN, OUTPUT); //led su scheda se acceso pin1 = HIGH
Serial.begin(9600); // inizio scrittura seriale
}
void loop() {
int evpompa = digitalRead(1); //assegnato stato elettrovalvola a evpompa
//Serial.println(evpompa); // scrittura su seriale valore evpompa
digitalWrite(LED_BUILTIN, LOW); // spegni Led su scheda
delay(2000); //attendi 2 secondi
if (evpompa == HIGH) {
Serial.println("elettrovalvola aperta");
digitalWrite(LED_BUILTIN, HIGH); // accendi Led su scheda
delay(5000); //attendi 5 secondi (20 secondi totali)
Serial.println("passati 5 secondi");
evpompa = digitalRead(1); //legge se nel frattempo è cambiato lo stato del pin1
if (evpompa == HIGH) { //se l'elettrovalvola è stata chiusa non esegue i comandi dentro la funzione if
delay(5000); //attendi 5 secondi
Serial.println("passati 10 secondi");
}
evpompa = digitalRead(1); //legge se nel frattempo è cambiato lo stato del pin1
if (evpompa == HIGH) { //se l'elettrovalvola è stata chiusa non esegue i comandi dentro la funzione if
delay(5000); //attendi 5 secondi
Serial.println("passati 15 secondi");
}
evpompa = digitalRead(1); //legge se nel frattempo è cambiato lo stato del pin1
if (evpompa == HIGH) { //se l'elettrovalvola è stata chiusa non esegue i comandi dentro la funzione if
delay(5000); //attendi 5 secondi
Serial.println("passati 20 secondi");
}
evpompa = digitalRead(1); //verifica se è ancora aperta l'elettrovalvola altrimenti va al ciclo di stop
if (evpompa == HIGH) { //se l'elettrovalvola è stata chiusa non esegue i comandi dentro la funzione if
digitalWrite(2, HIGH); //consenso ON motopompa
delay(2000); //attendi 2 secondi
digitalWrite(3, HIGH); //motorino avviamento ON
delay(3000); //attendi 2 secondi
digitalWrite(3, LOW); //motorino avviamento OFF
}
evpompa = digitalRead(1); //verifica se è ancora aperta l'elettrovalvola altrimenti va al ciclo di stop
if (evpompa == HIGH) { //se l'elettrovalvola è stata chiusa non esegue i comandi dentro la funzione if
delay(30000); // attendi 30 secondi attendi 60 secondi
Serial.println("mancano 30 secondi prima di accellarare al massimo");
evpompa = digitalRead(1); //legge se nel frattempo è cambiato lo stato del pin1
if (evpompa == HIGH) { //se l'elettrovalvola è stata chiusa non esegue i comandi dentro la funzione if
delay(30000); //attendi 30 secondi
Serial.println("adesso inizia ad accellarare");
}
digitalWrite(4, HIGH); //Accelleratore MAX +
digitalWrite(5, HIGH); //Accelleratore MAX -
delay(10000); //attendi 10 secondi
digitalWrite(4, LOW); // STOP INPUT Accelleratore MAX +
digitalWrite(5, LOW); // STOP INPUT Accelleratore MAX -
Serial.println("attesa chiusura elettrovalvola");
}
while(evpompa==HIGH) {
evpompa = digitalRead(1);
}
//inizia il ciclo di stop
Serial.println("hai chiuso l'elettrovalvola");
delay(1000); //attendi 1 secondo
digitalWrite(2, LOW); //consenso OFF motopompa
delay(2000); //attendi 1 secondo
digitalWrite(6, HIGH); //Accelleratore MIN +
digitalWrite(7, HIGH); //Accelleratore MIN -
delay(10000); //attendi 10 secondi
digitalWrite(6, LOW); // STOP INPUT Accelleratore MIN +
digitalWrite(7, LOW); // STOP INPUT Accelleratore MIN -
digitalWrite(LED_BUILTIN, LOW); // spegni Led su scheda
}
Serial.println("elettrovalvola chiusa attesa apertura");
}
Tenderei ad escludere il problema di programma perché, se come dici è fermo nel while della lettura del pin 1 non può andare in errore.
Probabilmente è legato all'hardware, interferenze oppure anche l'utilizzo dei cavetti dupont e della breadboard come connessioni finali non sono proprio il massimo.
Un possibile workaround software potrebbe essere quello di uscire dal while solo dopo che N letture sono state rilevate come LOW, ad esempio:
In questo modo introduciamo un ritardo di 100ms ogni lettura LOW e dopo 5 letture tutte a LOW si esce dal ciclo. Utilizzando il delay e il numero di letture non esci immediatamente ma dopo almeno 500ms da quando il pin è andato LOW, se non è un problema puoi adottare la soluzione software.
Io ti consiglio di trovare però il problema hardware che si annida dietro al problema perché è sempre meglio risolvere la causa e non aggirare l'errore.
Una breadboard per un montaggio definitivo???...!!! E' inconcepibile! Bisogna saldare o, almeno, usare dei morsetti.
Anche tutti quei delay non sono la strada giusta... Durante un delay non si può fare nulla, nemmeno verificare che tutto stia funzionando correttamente. Va fatto con una macchina a stati finiti.
Concordo che sarebbe meglio farlo con una macchina a stati finiti, ma se per l'OP durante le varie attese non deve essere fatto null'altro allora anche il delay può andare.
Per il discorso breadboard anch'io ho espresso le mie perplessità
Prendi con le pinze quello che scrivo, perché non conosco bene quella scheda che mi pare uno R4 WIFI.
Se è compatibile con la uno R3 i pin 0 e 1 sono riservati alla seriale, per cui è bene non usarli come gpio.
Per il resto, prendi quanto segue come legge suprema(1):
come ti hanno fatto notare la breadboard si usa solo in laboratorio per i prototipi e anche in laboratorio dopo avere testato il circuito lo si replica con basetta mille fori o altra soluzione più affidabile.
(1) Suprema a me stesso che scrivo.
PS: Scioccante che ti sia convinto ad usare una breadboard all'interno di una cassetta, ancora peggio che tu abbia installato la cassetta a muro che equivale a considerare il tutto compatibile con la destinazioni d'uso.
Se cerchi su Google (Es. Questa pagina ad esempio) o sul forum troverai centinaia di topic riguardanti le macchine a stati finiti (Es. Questo ad esempio)
Sono utilissime per poter gestire più compiti (Es. mentre attendo il cambio stato di un pin aggiorno il display) ma serve ribaltare la logica del programma che usa i delay.
Il tuo programma è relativamente semplice quindi potrebbe essere una buona palestra per convertirlo non usando più i delay ma la macchina a stati finiti, nel tuo caso mentre attendi 5,10,15 secondi potresti comunque controllare se qualcosa succede per interrompere la sequenza, cosa che non puoi fare se sei fermo in un delay.
Per "controllare se succede qualcosa" non intendo però controlli di sicurezza, ad esempio la gestione di un eventuale pulsante d'emergenza (il classico fungo d'emergenza) non può essere gestita all'acqua di rose ma deve prevedere le relative sicurezze hardware/software (Es. utilizzo di interrupt), ma potresti ad esempio decidere che se il motore sta partendo ma rilevi che non arriva più acqua allora interrompi il ciclo.
ti volevo ringraziare soprattutto perchè ho testato la tua soluzione e funziona perfettamente ma poi per i consigli e aiuti sul codice costuttivi e non commenti che non ti lasciano niente come succede con altri utenti. inoltre ho già ordinato una basetta millefori per eseguire tutti i collegamenti. parallelamente proverò a studiare anche la macchina a stati finiti
if (evpompa == HIGH) {
Serial.println("elettrovalvola aperta");
digitalWrite(LED_BUILTIN, HIGH); // accendi Led su scheda
delay(5000); //attendi 5 secondi (20 secondi totali)
Serial.println("passati 5 secondi");
evpompa = digitalRead(1); //legge se nel frattempo è cambiato lo stato del pin1
if (evpompa == HIGH) { //se l'elettrovalvola è stata chiusa non esegue i comandi dentro la funzione if
delay(5000); //attendi 5 secondi
Serial.println("passati 10 secondi");
}
evpompa = digitalRead(1); //legge se nel frattempo è cambiato lo stato del pin1
if (evpompa == HIGH) { //se l'elettrovalvola è stata chiusa non esegue i comandi dentro la funzione if
delay(5000); //attendi 5 secondi
Serial.println("passati 15 secondi");
}
evpompa = digitalRead(1); //legge se nel frattempo è cambiato lo stato del pin1
if (evpompa == HIGH) { //se l'elettrovalvola è stata chiusa non esegue i comandi dentro la funzione if
delay(5000); //attendi 5 secondi
Serial.println("passati 20 secondi");
}
evpompa = digitalRead(1); //verifica se è ancora aperta l'elettrovalvola altrimenti va al ciclo di stop
ho provato a cercare su internet ma non riesco a trovare qualche esempio simile che mi aiuti. visto che sono alle prime armi e vorrei migliorare il codice. nella porzione di codice qui sopra io vado a verificare se il pin è in high e aspetto con un delay 5 secondi poi ricontrollo e così via fino ad arrivare a 30 secondi. volevo sapere se esiste una funzione o un modo per far si che mentre scorrono i 30 secondi io posso controllare con una certa cadenza tipo 200milli secondi se lo stato del pin 1 è variato e nel caso lo fosse interrompo e proseguo. parallelamento sto provando a sviluppare anche la macchina a stati finiti ma essendo un principiante sto facento tanta fatica ma piano voglio imparare anche quella
Ciò che descrivi di voler fare è fattibile, nell'ambiente Arduino, utilizzando la funzione millis(), dai un'occhiata prima QUI, poi QUI e QUI e QUI e tutti gli articoli che sono in QUESTA pagina ... vedrai che poi ti sarà tutto più chiaro
Scusa la curiosità, a parte una resistenza, perchè uso della breadboard (o cumunque di una millefori) ?
Mi pare in alcuni casi hai semplicemente usato la breadboard per collegare insieme vcc oppure dei gnd. Non avevi altri di questi ?
oppure puoi usare brutalmente dei mammuth o pipette da elettricista
Per macchina a stati finiti in italiano magari questi possono aiutarti:
adesso ho saldato tutto sulla basetta.
inoltre ho provato con l'aiuto dei vostri asticoli e qualche esempio online a fare una prima BOZZA di programma a stati finiti ma mi trovo d'avanti a un problema quando sono sullo stato 3 da circa 15/20 minuti in attesa e l'aduino ogni 300 millisecondi controlla se il pin 1 è andato in low e se lo trova il LOW dovrebbe proseguire per poi tornare sullo stato 0 ma questo non succede anche se riporto il pin1 a LOW rimane ferma sullo stato 3 ho sbagliato qualche funzione?
const int pin1 = 1;
const int pin2 = 2;
const int pin3 = 3;
const int pin4 = 4;
const int pin5 = 5;
const int pin6 = 6;
const int pin7 = 7;
enum State { STATE_0, STATE_1, STATE_2, STATE_3 };
State currentState = STATE_0;
unsigned long previousMillis = 0;
unsigned long stateStartMillis = 0;
int pin1HighCount = 0;
int pin1LowCount = 0;
void setup() {
pinMode(pin1, INPUT);
pinMode(pin2, OUTPUT);
pinMode(pin3, OUTPUT);
pinMode(pin4, OUTPUT);
pinMode(pin5, OUTPUT);
pinMode(pin6, OUTPUT);
pinMode(pin7, OUTPUT);
Serial.begin(9600);
}
void loop() {
unsigned long currentMillis = millis();
switch (currentState) {
case STATE_0:
// Stato 0: controllo ogni 2 secondi se il pin1 è HIGH
if (currentMillis - previousMillis >= 2000) {
previousMillis = currentMillis;
if (digitalRead(pin1) == HIGH) {
pin1HighCount++;
Serial.println("pin1 è HIGH");
} else {
pin1HighCount = 0;
}
if (pin1HighCount >= 3) {
currentState = STATE_1;
stateStartMillis = currentMillis;
pin1LowCount = 0;
Serial.println("Passo a STATE_1");
}
}
break;
case STATE_1:
// Stato 1: attesa di 30 secondi, controllo ogni 3 secondi se pin1 è LOW
if (currentMillis - previousMillis >= 3000) {
previousMillis = currentMillis;
if (digitalRead(pin1) == LOW) {
pin1LowCount++;
Serial.println("pin1 è LOW");
} else {
pin1LowCount = 0;
}
if (pin1LowCount >= 2) {
currentState = STATE_0;
Serial.println("Torno a STATE_0");
} else if (currentMillis - stateStartMillis >= 30000) {
currentState = STATE_2;
stateStartMillis = currentMillis;
Serial.println("Passo a STATE_2");
}
}
break;
case STATE_2:
// Stato 2: imposta pin2 e pin3 HIGH per 2 secondi, poi pin3 LOW, attesa di 60 secondi
digitalWrite(pin2, HIGH);
digitalWrite(pin3, HIGH);
delay(2000);
digitalWrite(pin3, LOW);
stateStartMillis = currentMillis;
pin1LowCount = 0;
Serial.println("Imposto pin2 e pin3 su HIGH per 2 secondi, attesa di 60 secondi");
// Attesa di 60 secondi con controllo ogni 5 secondi
while (currentMillis - stateStartMillis < 60000) {
currentMillis = millis();
if (currentMillis - previousMillis >= 5000) {
previousMillis = currentMillis;
if (digitalRead(pin1) == LOW) {
pin1LowCount++;
Serial.println("pin1 è LOW");
} else {
pin1LowCount = 0;
}
if (pin1LowCount >= 2) {
currentState = STATE_0;
Serial.println("Torno a STATE_0");
break;
}
}
}
if (currentState != STATE_0) {
currentState = STATE_3;
stateStartMillis = currentMillis;
Serial.println("Passo a STATE_3");
}
break;
case STATE_3:
// Stato 3: imposta pin4 e pin5 su HIGH per 10 secondi
digitalWrite(pin4, HIGH);
digitalWrite(pin5, HIGH);
delay(10000);
digitalWrite(pin4, LOW);
digitalWrite(pin5, LOW);
stateStartMillis = currentMillis;
pin1LowCount = 0;
Serial.println("Imposto pin4 e pin5 su HIGH per 10 secondi e poi LOW");
// Controllo ogni 1 secondo se pin1 è LOW
byte numeroLettureLow = 0; //setto il numero di letture Low a 0
while(numeroLettureLow<5) { // se il valore "numeroLettureLow" è minore di 5 procedi sul while
digitalRead(pin1); //legge lo stato del del pin 1 se l'elettrovalvola è ancora aperta
if(pin1 == HIGH){ // se il valore del pin 1 e HIGH prosegue sulla riga successiva
numeroLettureLow = 0; //se il pin 1 è in HIGH setta numeroLettureLow = a 0
}
else{
numeroLettureLow++; // se lo stato precendetemente letto del pin 1 era low somma +1 a numeroLettureLow se questa cosa si ripete per 5 volte esce dal ciclo e spegne la motopompa
delay(300); // ettesa 2 millisecondi
digitalWrite(pin2, LOW);
digitalWrite(pin6, HIGH);
digitalWrite(pin7, HIGH);
delay(10000);
digitalWrite(pin6, LOW);
digitalWrite(pin7, LOW);
currentState = STATE_0;
Serial.println("Torno a STATE_0, pin2 LOW, pin6 e pin7 HIGH per 10 secondi");
break;
}
}
if (currentState != STATE_0) {
currentState = STATE_0;
Serial.println("Ritorno a STATE_0");
}
break;
}
}
Innanzitutto complimenti per aver affrontato lo studio della macchina a stati finiti e l'uso di millis, perché di solito avendo un programma che funziona la maggior parte degli utenti (in cui mi includo ) non si mette a stravolgere tutto.
Visto che sei nel pieno dello sviluppo del progetto avrei una domanda, ma i pin che vai a leggere sono dotati di anti rimbalzo hardware? Dalla foto non mi pare.
Potrebbe essere un altro ottimo spunto di studio e miglioramento del progetto.
Cerca hardware dobounce o antirimbalzo hardware Arduino e anche in questo caso trovi tantissimi spunti
grazie mille adesso funziona perfettamente e arriva fino alla fine.
devo fare la stessa cosa anche sulle funzioni e stati precedenti?
grazie mille per tutti i consigli mi piace imparare adesso studierò anche l'antirimbalzo
const int pin1 = 1;
const int pin2 = 2;
const int pin3 = 3;
const int pin4 = 4;
const int pin5 = 5;
const int pin6 = 6;
const int pin7 = 7;
enum State { STATE_0, STATE_1, STATE_2, STATE_3 };
State currentState = STATE_0;
unsigned long previousMillis = 0;
unsigned long stateStartMillis = 0;
int pin1HighCount = 0;
int pin1LowCount = 0;
void setup() {
pinMode(pin1, INPUT);
pinMode(pin2, OUTPUT);
pinMode(pin3, OUTPUT);
pinMode(pin4, OUTPUT);
pinMode(pin5, OUTPUT);
pinMode(pin6, OUTPUT);
pinMode(pin7, OUTPUT);
Serial.begin(9600);
}
void loop() {
unsigned long currentMillis = millis();
switch (currentState) {
case STATE_0:
// Stato 0: controllo ogni 2 secondi se il pin1 è HIGH
if (currentMillis - previousMillis >= 2000) {
previousMillis = currentMillis;
if (digitalRead(pin1) == HIGH) {
pin1HighCount++;
Serial.println("pin1 è HIGH");
} else {
pin1HighCount = 0;
}
if (pin1HighCount >= 3) {
currentState = STATE_1;
stateStartMillis = currentMillis;
pin1LowCount = 0;
Serial.println("Passo a STATE_1");
}
}
break;
case STATE_1:
// Stato 1: attesa di 30 secondi, controllo ogni 3 secondi se pin1 è LOW
if (currentMillis - previousMillis >= 3000) {
previousMillis = currentMillis;
if (digitalRead(pin1) == LOW) {
pin1LowCount++;
Serial.println("pin1 è LOW");
} else {
pin1LowCount = 0;
}
if (pin1LowCount >= 2) {
currentState = STATE_0;
Serial.println("Torno a STATE_0");
} else if (currentMillis - stateStartMillis >= 30000) {
currentState = STATE_2;
stateStartMillis = currentMillis;
Serial.println("Passo a STATE_2");
}
}
break;
case STATE_2:
// Stato 2: imposta pin2 e pin3 HIGH per 2 secondi, poi pin3 LOW, attesa di 60 secondi
digitalWrite(pin2, HIGH);
digitalWrite(pin3, HIGH);
delay(2000);
digitalWrite(pin3, LOW);
stateStartMillis = currentMillis;
pin1LowCount = 0;
Serial.println("Imposto pin2 e pin3 su HIGH per 2 secondi, attesa di 60 secondi");
// Attesa di 60 secondi con controllo ogni 5 secondi
while (currentMillis - stateStartMillis < 60000) {
currentMillis = millis();
if (currentMillis - previousMillis >= 5000) {
previousMillis = currentMillis;
if (digitalRead(pin1) == LOW) {
pin1LowCount++;
Serial.println("pin1 è LOW");
} else {
pin1LowCount = 0;
}
if (pin1LowCount >= 2) {
currentState = STATE_0;
Serial.println("Torno a STATE_0");
break;
}
}
}
if (currentState != STATE_0) {
currentState = STATE_3;
stateStartMillis = currentMillis;
Serial.println("Passo a STATE_3");
}
break;
case STATE_3:
// Stato 3: imposta pin4 e pin5 su HIGH per 10 secondi
digitalWrite(pin4, HIGH);
digitalWrite(pin5, HIGH);
delay(10000);
digitalWrite(pin4, LOW);
digitalWrite(pin5, LOW);
stateStartMillis = currentMillis;
pin1LowCount = 0;
Serial.println("Imposto pin4 e pin5 su HIGH per 10 secondi e poi LOW");
// Controllo ogni 1 secondo se pin1 è LOW
byte numeroLettureLow = 0; //setto il numero di letture Low a 0
while(numeroLettureLow<5) { // se il valore "numeroLettureLow" è minore di 5 procedi sul while
int pinval=digitalRead(pin1); //legge lo stato del del pin 1 se l'elettrovalvola è ancora aperta
if(pinval == HIGH){ // se il valore del pin 1 e HIGH prosegue sulla riga successiva
numeroLettureLow = 0; //se il pin 1 è in HIGH setta numeroLettureLow = a 0
}
else{
numeroLettureLow++; // se lo stato precendetemente letto del pin 1 era low somma +1 a numeroLettureLow se questa cosa si ripete per 5 volte esce dal ciclo e spegne la motopompa
delay(300); // ettesa 2 millisecondi
digitalWrite(pin2, LOW);
digitalWrite(pin6, HIGH);
digitalWrite(pin7, HIGH);
delay(10000);
digitalWrite(pin6, LOW);
digitalWrite(pin7, LOW);
currentState = STATE_0;
Serial.println("Torno a STATE_0, pin2 LOW, pin6 e pin7 HIGH per 10 secondi");
break;
}
}
if (currentState != STATE_0) {
currentState = STATE_0;
Serial.println("Ritorno a STATE_0");
}
break;
}
}
No qui no. Fai tutto in un unico passaggio.
È come se il compilatore facesse la lettura, mette il valore in variabile nascosta e poi facesse il test su quella variabile
Che debba attendere minuti non c0è dubbio ma se quando legge becca un rimbalzo ha falsi positivi o negativi, tantiè che prima gli ho suggerito di ripetere le letture e così facendo ha risolto. Con l'antirimbalzo hardware al 99% non serve neanche più leggere N volte per scongiurare i falsi positivi