Go Down

Topic: "Sospendere" loop  (Read 2793 times) previous topic - next topic

chinca7

Buongiorno,
premetto che ho cercato in lungo e in largo senza avere un idea su come procedere.

Premessa: quello che stò realizzando è un semplice timer, prima si imposta un valore col potenziometro (che verrà tradotto in secondi), alla pressione del pulsante il relè viene eccitato per il tempo prefissato.
PROBLEMA! vi sono casi nel quale il tempo d'eccitazione del relè è molto basso ( 0,30 sec.) ora vorrei impostare che, dopo aver eccitato il rele, la seguente eccitazione avverrà solo se lo stato del pulsante è passato da HIGH a LOW,  evitando un treno di impulsi indesiderati, facendo poi "ripartire" il loop.

Consigli? Grazie mille per la disponibilità!



Code: [Select]
const int bottone = 7;  // bottone avviamento è collegato al pin 7, sarà un DIGITAL READ
int statobottone = 0;  // variabile che memorizza lo stato del bottone tra LOW e HIGH
const int rele = 12;  // l'eccitazione del rele sarà data dal pin 12, DIGITAL OUTPUT
const int potenziometro = A0; // il valore letto dal potenziometro al pin ANALOG 5


void setup() {
pinMode (bottone,INPUT);  // pin impostato per leggere lo stato
pinMode (rele,OUTPUT);  // pin impostato per dare il segnale d'eccitazione del rele
pinMode (potenziometro,INPUT);  // il pin A5 usato per leggere il valore del potenziometro
}

void loop() {
 

statobottone = digitalRead (bottone);  //la variabile statobottone sarà HIGH o LOW a seconda del segnale in ingresso sul pin 7
int valorepot = analogRead (potenziometro);  // la variabile valorepot assumerà il valore letto dal potenziometro
float timer = valorepot * 6;  // parametro che verrà utilizzato per variare la durata del timer


if (statobottone==HIGH){  //se il pulsante è premuto viene eseguito il codice nelle graffe
digitalWrite (rele,HIGH);  // eccita il rele per un periodo indefinito, verrà spento con il digitalWrite LOW utilizzando
delay (timer);             // come delay il tempo impostato dal potenziometro
digitalWrite (rele,LOW);
}
QUI IL CODICE CHE CONTROLLA LO STATO DEL PULSANTE

}



SukkoPera

"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

Maurotec

Il loop si può fermare impedendo che il codice raggiunga l'ultima parentesi } che circoscrive il blocco di codice appartenente alla funzione loop().

In breve:
Code: [Select]

void loop() {

    while(true);   // ripete questa riga all'infinito.
}


Quando la funzione loop() termina, il core di arduino la chiama nuovamente, però prima di chiamarla esegue del codice, per questo motivo non è consigliabile fermare il loop().

Hai a disposizione gli stantment if (cond) { } else {} Oppure  if (cond) {} else if (cond) {} else {} o se preferisci lo statment 'switch' e relativi 'case'.

Code: [Select]

void loop() {

    switch(gState) {
    case 255:   // se gState vale 255, esce dalla funzione loop()
         return:
    case 'A': //  Sintassi valida perché 'A' (apici singoli) viene valutato come il corrispondente codice ascii, cioè 65
        break;
    }
}


Ciao.

pablos71

#3
Nov 01, 2015, 01:34 pm Last Edit: Nov 01, 2015, 01:37 pm by pablos
Code: [Select]
const byte bottone = 7;  // bottone avviamento è collegato al pin 7, sarà un DIGITAL READ
bool statobottone = false;  // variabile che memorizza lo stato del bottone tra LOW e HIGH
const byte rele = 12;  // l'eccitazione del rele sarà data dal pin 12, DIGITAL OUTPUT
L'esperienza è il tipo di insegnante più difficile ....
Prima ti fa l'esame e poi ti spiega la lezione.

chinca7

Intanto ringrazio tutti per le risposte:

@pablos, credo intendessi correggere la sintassi del codice, in effetti lo stato è o basso o alto.

@sukkopera: con i millis ora come ora vado in crisi, più o meno penso di aver capito a cosa servano pur non sapendoli utilizzare.

@Maurotec: ho provato il while (statobottone == HIGH){}, fà il suo lavoro bloccandomi il codice, però come si fà a farlo ripartire?

gpb01

@sukkopera: con i millis ora come ora vado in crisi, più o meno penso di aver capito a cosa servano pur non sapendoli utilizzare.
Puoi studiarti come si usa la millis() prima QUI, poi QUI ed infine leggi anche QUI e QUI ... vedrai che ti sarà tutto più chiaro ;)

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

chinca7

Buonasera,
ho provato a seguire i vostri consigli ma non ho ricavato un ragno dal buco, in primis non saprei come utilizzare i millis in questo frangente, ho provato con while, con switch ma inchioda tutto il codice.
Il codice così com'è funzionerebbe, ma c'è quel però, sapete.. :smiley-confuse: . quella virgola fuori posto acc!

Code: [Select]
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27,16,2);

const byte bottone = 7;  // bottone avviamento è collegato al pin 7, sarà un DIGITAL READ
bool statobottone = false;  // variabile che memorizza lo stato del bottone tra LOW e HIGH
const byte rele = 12;  // l'eccitazione del rele sarà data dal pin 12, DIGITAL OUTPUT
const int potenziometro = A0; // il valore letto dal potenziometro al pin ANALOG 5

void setup() {
pinMode (bottone,INPUT);  // pin impostato per leggere lo stato
pinMode (rele,OUTPUT);  // pin impostato per dare il segnale d'eccitazione del rele
pinMode (potenziometro,INPUT);  // il pin A5 usato per leggere il valore del potenziometro
lcd.init();


}

void loop() {
 
statobottone = digitalRead (bottone);  //la variabile statobottone sarà HIGH o LOW a seconda del segnale in ingresso sul pin 7
int valorepot = analogRead (potenziometro);  // la variabile valorepot assumerà il valore letto dal potenziometro
float timer = valorepot * 4;  // parametro che verrà utilizzato per variare la durata del timer

if (statobottone==HIGH){  //se il pulsante è premuto viene eseguito il codice nelle graffe
digitalWrite (rele,HIGH);  // eccita il rele per un periodo indefinito, verrà spento con il digitalWrite LOW utilizzando
delay (timer);             // come delay il tempo impostato dal potenziometro
digitalWrite (rele,LOW);} // diseccita il relè

lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("TEMPO SALDATURA");
  lcd.setCursor(5,1);
  lcd.print(timer/1000);
  lcd.setCursor ( 10,1);
  lcd.print( "sec.");
    
}




SukkoPera

Hai letto il link che ti ho passato? Hai capito cos'è il debouncing, a cosa serve e come si mette in pratica?
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

Maurotec

Quote
@Maurotec: ho provato il while (statobottone == HIGH){}, fà il suo lavoro bloccandomi il codice, però come si fà a farlo ripartire?
Puoi uscire dal blocco di codice appartenente al while in almeno 3 modi.
Code: [Select]

while (statobottone == HIGH){
   if (cond)
      break;
}


Se "cond" viene valutata vera, viene eseguito il break, ovviamente se quel codice è inserito dentro la funzione loop verra eseguito al prossimo ciclo.

while (statobottone == HIGH), dove while è l'istruzione e ciò che si trova tra parentesi è una "espressione" che può essere valutata true o false. Come espressione essa può essere più complessa di questa e includere gli operatori && e || che comportano l'uso di altre variabili di stato come è appunto "statobottone".

Gli algoritmi possono usare tutte quelle istruzioni, ma se operano su un numero limitato di variabili di stato, l'algoritmo non può comportarsi come si vuole. Quindi un ragionamento tipico è quello di isolare porzioni di codice condizionandone l'esecuzione per mezzo delle istruzioni e di variabili di stato.

Per un comportamento ricercato si possono creare più algoritmi diversi, ognuno può essere preferibile in base al contesto, perché magari si integra meglio con il resto del codice.

La strada è quella giusta, io più che tentare di raggiungere il comportamento aspettato, mi concentrerei nello studio/sperimentazione di quelle istruzioni. Eviterei di coinvolgere molto codice durante gli esperimento, invece isolare il codice strettamente necessario a comprendere il meccanismo.

Spesso viene usato un trucchetto; si creano due variabili simili ma una contiene un valore vecchio di un ciclo, mentre l'altra contiene il valore nuovo o corrente.

Code: [Select]

boolean oldState = false;
boolean currentState = true;

if (oldState != currentState)  {
   // se qui dentro assegni ad oldState il valore di currentState, ottieni l'esecuzione di codice condizionale, dove
   // valori differenti eseguono il codice, valori uguali non lo eseguono
   oldState = currentState;
 
}
   

La soluzione adotta ad un problema ricorrente viene detta "pattern", conoscere e sperimentare questi pattern
ti permette di usare il pattern adatto.

PS: Tuo compagno fedele dovrebbe essere un buon libro C/C++ o una buona risorsa online. Pensa che di compagni fedeli io ne ho più d'uno.

PS: È mia opinione che il linguaggio lo si deve imparare senza fare uso di arduino, poi quando ci si sente pronti
si passa a scrivere codice per arduino e se si ha qualche dubbio che può essere sperimentato sul PC si torna a scrivere applicazione per PC, per poi tornare su arduino.

Ciao.

chinca7

Buonasera a tutti,
ancora vi ringrazio per il supporto tecnico, anche se il problema persiste ho nuovi spunti su cui studiare.

Il debouncing non è un requisito: come arduino rileva HIGH, parte il timer (delay) al relè, (al peggio 300ms) quindi in questo frangente non rileverebbe gli spuri del pulsante* , uscito dal timer, mi deve controllare se lo stato del pulsante è ancora HIGH, e bloccarmi l'esecuzione del codice fintanto che non passa su LOW, da qui riprenderlo.

* Può essere che faccia partire un segnale HIGH mentre lo si rilascia, ma per adesso vedo di sistemare il problema del loop.

Millis non saprei come integrarlo per svoglere questo compito, mi sembra un lavoro "lineare", premi bottone -> timer relè -> spegni relè -> controlli pulsante e BAM qui si dirama! visto che il codice non si può fermare, è come se dovessi mettere un semaforo in uscita ad una rotonda: una volta arrivatoci se è rosso continui a girare, appena scatta il verde ritorni nel circuito.

ho provato con uno scontato ( per me!)

while (statobottone == true){
  if (statobottone != true)
     break;
}

ovviamente non funzia e impalla il codice, ho cercato di seguire il ragionamento di MauroTec e ho sentito qualche rotella girare dentro la testa, ma nulla è scattato.

Sto rileggendo i link da voi consigliatomi oltre un PDF Elementi base del linguaggio di programmazione di Arduino, magari mi scatterà questa rotella!  :)  Son deciso a cavarmi questa scimmia dalla testa!

Intanto Buonanotte e grazie ancora!

Etemenanki

IL DEBOUNCE SI FA HARDWARE !!!


(oh, avevo proprio voglia di urlarlo, per una volta :P :D :D :D)

Come negli esempi in allegato, secondo quello che ti serve ;)

Per quanto riguarda la pressione del tasto, se cerchi nei vecchi post avevo gia postato alcuni esempi per eseguire delle funzioni solo alla pressione, oppure solo al rilascio, di un pulsante ... quello "solo alla pressione" esegue le operazioni solo una volta, poi ignora il pulsante finche' non viene rilasciato e premuto di nuovo, magari ti puo servire come traccia per quello che vuoi fare tu ;)
"Sopravvivere" e' attualmente l'unico lusso che la maggior parte dei Cittadini italiani,
sia pure a costo di enormi sacrifici, riesce ancora a permettersi.

Maurotec

Code: [Select]

const byte bottone = 7;  // bottone avviamento è collegato al pin 7, sarà un DIGITAL READ
// bool statobottone = false;  // variabile che memorizza lo stato del bottone tra LOW e HIGH
const byte rele = 12;  // l'eccitazione del rele sarà data dal pin 12, DIGITAL OUTPUT
const int potenziometro = A0; // il valore letto dal potenziometro al pin ANALOG 5
float timer = 0;  // la variabile che viene usata nella funzione delay()

byte gState = 0; // Sarebbe meglio usare una 'typedef' per definire un nuovo tipo 'enum'

/* Note: case 255 e 'A' si possono togliere o modificare */

void loop() {

    switch(gState) {
    case 255:   // se gState vale 255, esce dalla funzione loop()
         return:
    case 'A': //  Sintassi valida perché 'A' (apici singoli) viene valutato come il corrispondente codice ascii, cioè 65
        break;
    case 0:
        // viene eseguito all'accensione
        if ( digitalRead (bottone) == HIGH ) {
            timer = analogRead ( potenziometro ) * 4; // forse delay() prende solo interi (no float)
            gState = 1;
        }
        break;
    case 1:
        // se sono qui vuol dire che il pulsante è stato premuto
        // eccita il rele per un periodo indefinito, verrà spento con il 
        // digitalWrite LOW utilizzando come delay il tempo impostato dal potenziometro

        digitalWrite ( rele, HIGH ); 
        delay ( timer );                               // forse delay() prende solo interi (no float)
        digitalWrite ( rele, LOW );
        break;
    }
}


L'ho scritto direttamente nel forum e quindi sarà pieno di errori di battitura, del resto
non avevo intenzione di scrivere il programma completo e funzionante, ma ti ho voluto
mostrare il pattern. Non pensare di scrivere <<case 92,50:>> o <<case "mamma":>>
perché non funziona così, per cui documentati su swhich case.

Ciao.

Go Up