Richiamo di una funzione

Buongiorno,

mi si presenta il seguente problema:

dovrei far eseguire blocchi di programma a seconda della posizione di un selettore hardware.
Per fare questo, ho creato delle funzioni (void PROG1(), void PROG2(), ecc.) che se per testarle le invoco direttamente dal loop funzionano.
Ho creato una variabile con cui identifico le posizioni del selettore, e degli IF che testano il valore assunto dalla variabile e richiamano la funzione corrispondente.

Es.:
In void LOOP:

if (stato_commut == 0 && stato_avvio == 1)
PROG1();

Il tutto gira, però all' interno della funzione PROG1 vengono eseguite solo le istruzioni incondizionate mentre gli IF non funzionano.

Cortesemente qualcuno avrebbe qualche suggerimento?
Grazie.

Potrebbe essere un problema di visibilità delle variabili che usi. Posta il codice, altrimenti è difficile dare una risposta certa

Senza vedere il programma è difficile se non impossibile trovare il problema, si può solo ipotizzare-immaginare un possibile problema :slight_smile:

Hai detto che se richiami le funzioni direttamente dal loop(), funzionano correttamente mentre se le richiami attraverso una condizione non funzionano. La differenza che se le richiami nel loop() le funzioni vengono ripetute ciclicamente e quindi le condizioni all'interno delle funzioni verificate di continuo, mentre se le chiami con un if() vengono eseguite una sola volta cosi anche le condizioni al suo interno.

Sarebbe un problema, se ad esempio all'interno della funzioni leggessi un pulsante, non leggeresti di continuo il suo stato, dando l'impressione che gli if() non funzionano.

Ma è solo un pensiero, se non mostri il codice non si può trovare il vero problema...

Grazie a tutti.
Allego il codice (da finire e ripulire).

sketch.ino (11.6 KB)

Non è che non viene richiamato prog1() ma è che questo codice

unsigned long tempo_pres = (millis);
tempo_iniz = tempo_pres;
long diff = millis()- tempo_iniz;

reimposta sempre tempo_iniz prelevandolo da una non ben specificata (millis) e quindi credo che il problema sia nel delta che non raggiungerà mai il valore voluto. tempo_iniz lo inizializzi nel setup e poi reimpostalo nel loop solo quando cambi stato forse questo potrebbe già bastare, purtroppo non posso compilare il tuo sketch perché non ho le librerie che usi

La parte di codice che mi hai citato era un tentativo di reimpostare a zero il valore del timer, in quanto PROG1 può venire chiamato anche parecchio tempo dopo che il loop gira (nell' HMI il selettore indica quale programma scelgo che poi avvio con un pulsante).

In ogni caso avevo provato anche senza tempi, ponendo semplicemente nell' IF la verifica di un digitalRead, ma le cose non cambiano.

Grazie del tempo che mi stai dedicando.

Il programma è un po lungo :slight_smile:

Nella funzione PROG1() gli "else" dovrebbero essere eseguiti comunque.

Mentre questo pezzo di codice

unsigned long tempo_pres = (millis);
tempo_iniz = tempo_pres;
long diff = millis()- tempo_iniz;

non calcola il tempo come vorresti, e non succede mai che passi più di qualche frazione di secondo "millisecondi o microsecondi" tra la prima e la terza istruzione, dovresti rivedere la cosa

Sorry!

L'ho allegato per intero solo per dare idea di dove vado a prendere le informazioni che impostano le variabili.

Allora, prova a eliminare la parte di codice della temporizzazione e nel loop assegni a tempo_iniz il valore di millis() ad ogni ciclo se e solo se non devi eseguire un programma ovvero ogni cilo di loop se le condizioni impongono di richiamare un qualsiasi programma non vari tempo_iniz, in modo che dopo il tempo prestabilito che richiami un programma (PROG1) questo partirà perchè la differenza tra millis() e tempo_iniz sarà maggiore dei valori impostati

giv62:
Sorry!

L'ho allegato per intero solo per dare idea di dove vado a prendere le informazioni che impostano le variabili.

E' sempre bene allegare l'intero programma altrimenti si richia di non capire dove sta l'errore, in molti postano solo frazioni di codice rendendo arduo il tentativo di capire l'errore

Fatto.

All' inizio ho aggiunto:

unsigned long tempo_iniz

Da PROG1 ho eliminato le righe:

unsigned long tempo_pres = (millis);
tempo_iniz = tempo_pres;

ed in loop ho aggiunto:

tempo_iniz = millis.

Era questo che mi consigliavi?

Si, tranne che millis necessita delle parentesi tonde essendo una funzione e che devi assegnare il suo valore nel loop alla variabile tempo_iniz se e solo se non sei nel caso di ingresso in un programma, altrimenti tempo_iniz sarà sempre (o quasi) uguale a millis() e il delta non raggiungerà mai uno dei valori impostati per eseguire le funzionalità richieste

Scusa per le parentesi, le ho tralasciate nel post.

Ora ho fatto due prove dopo le modifiche:

  • se richiamo PROG1 dalla condizione dell' IF, resta bloccato con il pin 34 alto;

  • se inserisco PROG1(); direttamente nel loop il ciclo funziona, ma parte casualmente a seconda di quando premo AVVIO.

Ciao, potresti spiegare a parole cosa vorresti fare, cosi magari ci si inventa una soluzione.

Ad esempio il tempo deve essere contato dall'accensione della scheda arduino ??
non so accendo la scheda e conto il tempo, se richiamo una funzione verifico quanto tempo è passato.

In pratica il tempo a cosa si riferisce, cosa deve fare il programma a grandi linee "senza entrare nei dettagli"

Perché io pensavo di fare un contatore di tempo nella funzione loop() e poi inviare il tempo come parametro alle altre funzioni.

Spero di riuscire a spiegarmi:

Arduino è collegato ad un monitor Touch Screen 4DSystem che genera una HMI tramite un suo processore interno.
In questa HMI ci sono varie videate, una delle quali contiene un commutatore a 16 posizioni ed un pulsante di Avvio.
Arduino ed il monitor sono collegati sulla porta seriale 1 e colloquiano tramite questa.

Il loop inizia a girare da subito quindi.

A questo punto l' operatore sceglie tramite il commutatore quale programma svolgere (PROG1, PROG2 ....).

Quando preme il pulsante avvio lancia il programma scelto ed è qui che il timer deve partire.

All' interno delle 16 funzioni ci sarà un codice che pilota delle elettrovalvole che si aprono e chiudono sequenzialmente ad intervalli di tempo prestabiliti.
Le funzioni sono 16 (PROG1...PROG16) perchè sono previste 16 diverse lavorazioni con tempi diversi.

Il problema, come precisavo nei miei post precedenti, è che anche se non utilizzo tempi ma vado solo a leggere lo stato di un digitalWrite per far accendere un led, all' interno delle funzioni gli IF non funzionano.

Grazie e scusate se non sono stato abbastanza chiaro.

Quando un programma è in funzione è possibile fermarlo, azzerarlo e farne partire un altro oppure una volta avviato deve arrivare a termine? Quando un programma sta eseguendo le varie operazioni arduino deve poter intercettare altri eventi dal display?

Senza entrare nel merito del programma, ma solo come indicazione generica

Sei troppo prolisso

Semplificati, con uso di array e cicli

Poi, le sequenze da eseguire sono a tempo o a condizione?

Come a dire, apri valvola 1 e aspetta 5 minuti

Oppure apri valvola 1 e aspetta pressostato?

Poi come chiede fabpolli
Cosa succede in caso di cambio
È previsto uno stop?

Ci sono altri due pulsanti sull' HMI: STOP e RESET ed un potenziometro slide (Trackbar):

STOP richiama la funzione STOP() che apre una parte di valvole e, dopo un delay, fa un reset software.Questa parte ora sta funzionando.

RESET non comunica con Arduino in quanto fa un reset hardware tramite un PinOut del monitor.

Durante lo svolgimento di un programma, Arduino prende i dati dai due pulsanti AVVIO e STOP e dalla Trackbar che regola la pressione (anche questo ora funziona).

In questa versione le sequenze sono solo a tempo. Nel senso:

apri valvola 1 (G1), aspetta N secondi, chiudi valvola 1 e apri valvola 2 (G2) e così via.

Grazie.

Ok non si può utilizzare i delay perché devi poter intercettare lo stop. A questo punto mi viene da dire che se le modifiche apportate non ti portano al funzionamento l'unica cosa da fare è mettere in piedi un po' di messaggi di debug sulla seriale, ho visto che tanto il display lo gestisci sulla serial1, per verificare i parametri di funzionamento, ovvero traccerei:
stato_commut
stato_avvio (che se va a zero allora non ti richiama più il programma e forse è per questo che sembra non funzionare)
e poi dentro PROG1:
diff (che se le modifiche apportate sono corrette dovrebbe via via incrementarsi)

Per curiosità mia, suppongo che il reset hardware sia stato introdotto nel caso di blocchi di Arduino, ma nel caso in cui un programma sia stato avviato e sia nel bel mezzo della sua esecuzione e viene premuto il reset, cosa succede alle valvole? Se una è aperta non si rischia che continui a erogare in modo incontrollato? Forse nel setup ti converrebbe pensare alla procedura che resetti lo stato in modo sicuro in modo tale da portare il sistema in condizione di non danneggiarsi/danneggiare nessuno un po' come dovrebbe essere la gestione del fungo d'emergenza nei macchinari industriali

  • stato_commut l'ho già monitorato: si incrementa (e decrementa) da 0 a 15 a seconda della posizione del commutatore (da PR 01 a PR 16).

  • stato_avvio lo verifico domattina (non lo avevo fatto perchè ho programmato il pulsante avvio sul monitor come Momentary = No, e quindi un interruttore aperto/ chiuso.

  • diff lo verifico domattina

Il tasto RESET, oltre a resettare Arduino e monitor, anche disattiva un teleruttore togliendo alimentazione a compressore e valvole. E' anche previsto (come da UNI) un segnale di allarme alimentato a batteria (in caso di blackout) che si aziona se la pressione scende a causa del blocco del compressore.

Le elettrovalvole, per inciso a 12 Vdc, si chiudono tutte in mancanza di alimentazione.

In realtà macchine simili a questa ne ho già funzionanti, ma hanno solo controlli hardware e sono senza HMI.

Grazie a tutti per la vostra disponibilità!