Salpa Ancora.

Buonasera a tutti,
è la prima volta che posto e chiedo scusa in anticipo se sbaglio. In pratica, scopiazzando qua e la ho realizzato un progetto Salpa Ancora che conta i metri in discesa e salita di quest’ultima… Avrei bisogno di una dritta per inserire delle pause in millis, al posto di delay che mi blocca e di conseguenza falsa il conteggio in metri.
Solitamente cerco di risolvere da solo ma sono giorni che provo utilizzando alcune guide ma mi incasino sempre.
Provo ad inserire il listato sperando che qualcuno mi dia una mano.
Grazie

Salpa_ancora.ino (1.94 KB)

Benvenuto,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione tutto il su citato REGOLAMENTO ... Grazie. :slight_smile:

nid69ita

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto. :wink:

>osvaldocs: intanto, usando la funzione del IDE Strumenti → Formattazione Automatica (CTRL-T) riformatta il codice che … così come è, è terribile da leggere :smiley: … ottenendo questo:

#include<LiquidCrystal.h>
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
int led = 4;
int led2 = 6;
int reset = 5;
int contatore;
byte attivo;


void setup()
{
  lcd.begin(16, 2);
  lcd.print("   CONTAMETRI");
  lcd.setCursor(0, 6);
  lcd.print ("     ANCORA");
  pinMode(led, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode (5, INPUT);
}

void loop(void)
{
  if (digitalRead(5) == HIGH) // procedura reset
  { contatore = 0;
    lcd.begin(16, 2);
    lcd.print("      RESET");
    lcd.setCursor(0, 6);
    lcd.print ("   CONTAMETRI");
    delay(1500);
  } else

  { if (digitalRead(2) && digitalRead(3)) //  sensori 2 e 3 attivati
    { attivo = 1;
    } else

    { if (digitalRead(2))  // attivato solo sensore 2
      { if (attivo == 1)
        { attivo = 2;
        }
      } if (digitalRead(3))  // attivo solo sensore 3
      { if (attivo == 1)
        { attivo = 3;
        }

      } if (!digitalRead(2) && !digitalRead(3))  // nessun sensore attivato
      { if (attivo == 2)  //  attivo primo sensore

        { contatore--;
          attivo = 0;
          digitalWrite (led, HIGH);
          digitalWrite (led2, LOW);
          lcd.clear();
          lcd.print("RISALITA ANCORA --");
          lcd.setCursor(0, 6);
          lcd.print ("   Prof.Mt.");
          lcd.print(contatore);
          digitalWrite (led, LOW);

          if (contatore == 7)
          { digitalWrite(led2, HIGH);
            lcd.clear();
            lcd.print(" ANCORA METRI 7");
            lcd.setCursor(0, 6);
            lcd.print ("   STOP MOTORE");
            delay(2000);
          }

        } if (attivo == 3)  // oppure attivato il secondo sensore
        { contatore++;
          attivo = 0;
          digitalWrite (led2, HIGH);
          digitalWrite (led, LOW);
          lcd.clear();
          lcd.print(" DISCESA ANCORA ++");
          lcd.setCursor(0, 6);
          lcd.print ("   Prof.Mt.");
          lcd.print(contatore);
          digitalWrite (led2, LOW);

          { if (contatore == 10)
            { digitalWrite(led2, HIGH);
              lcd.clear();
              lcd.print("ANCORA METRI 10");
              lcd.setCursor(0, 6);
              lcd.print ("ASSIST. MOTORE");
              delay(2000);
            }
          }
        }
      }
    }
  }
}

… che puoi tranquillamente includere nei tag CODE (come ho fatto io) senza obbligare chi legge a scaricare un allegato. Grazie :slight_smile:

Poi … NON si possono semplicemente sostituire le delay() con millis() senza ripensare piuttosto pesantemente il codice, quindi … cosa vorresti fare “a tempo” e cosa di continuo?

Guglielmo

Buonasera e grazie per la risposta...
Avevo capito che bisogna intervenire abbastanza pesantemente sul codice, infatti ho provato diversi codice ma non ho trovato la soluzione. In pratica mi serve temporizzare i messaggi che appaiono nel display per alcuni secondi mentre il contatore continua ad incrementare senza fermarsi per i delay...
Risolto questo raggiungo un buon punto nello sviluppo del resto del codice tipo aggiungere buzzer, attivare motore ecc...
Grazie in anticipo per eventuali aiuti.

Buongiorno provo a ripostare sperando di farlo nel modo giusto…
Nel codice ho commentato in maiuscolo i punti dove intervenire sostituendo delay() con millis().
Preciso che gli incrementi della variabile “contatore” sono ottenuti con due sensori di Hall e contano perfettamente gli impulsi up/down ma quando vengono richiamati i messaggi il delay blocca il conteggio e di conseguenza quando finisce la pausa i metri conteggiati non sono più precisi.
Come dicevo ho provato alcune soluzioni raggiungendo qualche piccolo risultato ma sempre a metà tipo che mentre il contatore incrementa o decrementa correttamente il messaggio appare senza la chiamata ecc…
Vi chiedo gentilmente di darmi una mano così, mentre io imparo, faccio contento anche il cognato…; D
Grazie a tutti

#include<LiquidCrystal.h>
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
int led = 4;
int led2 = 6;
int reset = 5;
int contatore;
byte attivo;


void setup()
{
  lcd.begin(16, 2);
  lcd.print("   CONTAMETRI");
  lcd.setCursor(0, 6);
  lcd.print ("     ANCORA");
  pinMode(led, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode (5, INPUT);
}

void loop(void)
{
  if (digitalRead(5) == HIGH) // procedura reset
  { contatore = 0;
    lcd.begin(16, 2);
    lcd.print("      RESET");
    lcd.setCursor(0, 6);
    lcd.print ("   CONTAMETRI");
    delay(1500);                      //QUI IL DELAY NON DA FASTIDIO ESSENDO IL PRIMO AVVIO
  } else

  { if (digitalRead(2) && digitalRead(3)) //  sensori 2 e 3 attivati
    { attivo = 1;
    } else

    { if (digitalRead(2))  // attivato solo sensore 2
      { if (attivo == 1)
        { attivo = 2;
        }
      } if (digitalRead(3))  // attivo solo sensore 3
      { if (attivo == 1)
        { attivo = 3;
        }

      } if (!digitalRead(2) && !digitalRead(3))  // nessun sensore attivato
      { if (attivo == 2)  //  attivo primo sensore

        { contatore--;
          attivo = 0;
          digitalWrite (led, HIGH);
          digitalWrite (led2, LOW);
          lcd.clear();
          lcd.print("RISALITA ANCORA --");
          lcd.setCursor(0, 6);
          lcd.print ("   Prof.Mt.");
          lcd.print(contatore);
          digitalWrite (led, LOW);

          if (contatore == 7)
          { digitalWrite(led2, HIGH);
            lcd.clear();
            lcd.print(" ANCORA METRI 7");
            lcd.setCursor(0, 6);
            lcd.print ("   STOP MOTORE");
            delay(2000);                       //QUI DELAY() VA SOSTITUITO CON MILLIS()
          }

        } if (attivo == 3)  // oppure attivato il secondo sensore
        { contatore++;
          attivo = 0;
          digitalWrite (led2, HIGH);
          digitalWrite (led, LOW);
          lcd.clear();
          lcd.print(" DISCESA ANCORA ++");
          lcd.setCursor(0, 6);
          lcd.print ("   Prof.Mt.");
          lcd.print(contatore);
          digitalWrite (led2, LOW);

          { if (contatore == 10)
            { digitalWrite(led2, HIGH);
              lcd.clear();
              lcd.print("ANCORA METRI 10");
              lcd.setCursor(0, 6);
              lcd.print ("ASSIST. MOTORE");
              delay(2000);                       //QUI DELAY() VA SOSTITUITO CON MILLIS()
            }
          }
        }
      }
    }
  }
}

Hai scritto una serie enorme di if uno dentro l'altro (programmazione strutturata), con dei delay ben incastrati in fondo.

Purtroppo bisogna riscrivere tutto in modo completamente diverso.

Quella struttura if va disannidata e semplificata.

In particolar modo scrivendo il programma, con quegli if hai pensato a delle situazioni/fasi implicite (se x allora fase di attesa si 2 secondi ecc).

È necessario invece pensare alle fasi/situazioni in modo esplicito, e strutturare il programma sotto forma di domande:

in che fase sono?
a cosa devo stare attento (eventi)?
cosa devo fare se riconosco un evento?

In questo modo una fase di attesa è solo una domanda che per un certo tempo darà risposta negativa:

sono nella fase di attesa z?
se si, è trascorso il tempo?
se si cosa faccio?

Se le condizioni non sono verificate si prosegue subito oltre.

Le fasi possono essere valori a piacere memorizzati in qualche variabile.

Quello che conta è ripensare lo stesso procedimento/logica/sequenza, in termini di fase / evento / azione

if (1==fase  &&  ...evento...) { ...azioni... }
else if (2==fase  &&  ...evento...) { ...azioni... }
else if (3==fase  &&  ...evento...) { ...azioni... }
 
ecc

Grazie per la risposta Claudo...
In pratica, come ho scritto nel primo post, non è tutta farina del mio sacco come proprio la struttura degli if che incrementa i metri. L'ho inserita così come era perchè mi conteggia bene gli impulsi dei sensori di Hall senza false letture, rimbalzi o conteggi multipli che, altre soluzioni provate, mi davano. Io ho aggiunto il resto.
Comunque non ho capito come procedere ossia dovrei sostituire la struttura esistente degli if con quella da te descritta? Potresti inserire un esempio nel mio listato cosi da farmi un'idea e proseguire poi da solo? Grazie in anticipo.

Non si può inserire niente nel tuo listato, va ripensato da zero/riscritto grosso modo come l'esempio che ho riportato.

La prima parte di lavoro consiste quindi nello stabilire (cioè elencare chiaramente su carta) quali sono le fasi di funzionamento in cui ti puoi trovare e gli eventi/condizioni a cui prestare attenzione in ciascuna di esse (cosa fare se), si tratta di disegnare una logica che non mi è chiara, io tra tutti quegli if nidificati (scritti tra l'altro in modo poco ortodosso) mi perdo.

In particolare, anche se eliminiamo un po' di nidificazione al loop rendendolo molto più flat:

void loop(void)
{
  if (digitalRead(5) == HIGH) // procedura reset
  { 
    contatore = 0;
    lcd.begin(16, 2);
    lcd.print("      RESET");
    lcd.setCursor(0, 6);
    lcd.print ("   CONTAMETRI");
    delay(1500);                      //QUI IL DELAY NON DA FASTIDIO ESSENDO IL PRIMO AVVIO
    return;
  }
  
  if (digitalRead(2)  &&  digitalRead(3)) { attivo = 1;  return; } // sensori 2 e 3 attivati
  if (digitalRead(2)  &&  (attivo == 1))  { attivo = 2; }          // attivato solo sensore 2
  if (digitalRead(3)  &&  (attivo == 1))  { attivo = 3; }          // attivo solo sensore 3
  if (digitalRead(2) || digitalRead(3))   { return; }              // almeno un sensore attivato
  
  if (attivo == 2)  //  attivo primo sensore
  { 
    contatore--;
    attivo = 0;
    digitalWrite (led, HIGH);
    digitalWrite (led2, LOW);
    lcd.clear();
    lcd.print("RISALITA ANCORA --");
    lcd.setCursor(0, 6);
    lcd.print ("   Prof.Mt.");
    lcd.print(contatore);
    digitalWrite (led, LOW);

    if (contatore == 7)
    { 
      digitalWrite(led2, HIGH);
      lcd.clear();
      lcd.print(" ANCORA METRI 7");
      lcd.setCursor(0, 6);
      lcd.print ("   STOP MOTORE");
      delay(2000);                       //QUI DELAY() VA SOSTITUITO CON MILLIS()
    }

  } 
  
  if (attivo == 3)  // oppure attivato il secondo sensore
  { 
    contatore++;
    attivo = 0;
    digitalWrite (led2, HIGH);
    digitalWrite (led, LOW);
    lcd.clear();
    lcd.print(" DISCESA ANCORA ++");
    lcd.setCursor(0, 6);
    lcd.print ("   Prof.Mt.");
    lcd.print(contatore);
    digitalWrite (led2, LOW);
     
    if (contatore == 10)
    { 
      digitalWrite(led2, HIGH);
      lcd.clear();
      lcd.print("ANCORA METRI 10");
      lcd.setCursor(0, 6);
      lcd.print ("ASSIST. MOTORE");
      delay(2000);                       //QUI DELAY() VA SOSTITUITO CON MILLIS()
    }
  }

}

e sorvolando sulla logica dei sensori che do per scontato che abbia senso (le quattro righe di if digitalRead dopo la procedura di reset), ancora non individuo bene "le fasi" temporizzate che ti servono.

Per far avanzare i contatori intanto li farei uscire dalle parti che si occupano di visualizzare:

if (attivo == 2)  //  attivo primo sensore
{ 
    contatore--;
    attivo = 0;
}
  
if (attivo == 3)  // oppure attivato il secondo sensore
{ 
    contatore++;
    attivo = 0;
}

Dopo di che rimane la parte che deve visualizzare/temporizzare. Boh, avrà due distinte fasi, una in cui aggiorna i valori, e una in cui li mantiene. È così? Se è così allora si può usare una logica come la seguente:

se fase 1 e attivo==2 
  se contatore == 7
    scrivi la roba da mantenere
    memorizza tempo millis
    fase = 2
  altrimenti
    scrivi quello che serve

altrimenti se fase 1 e attivo==3 
  se contatore == 10
    scrivi la roba da mantenere
    memorizza tempo millis
    fase = 2
  altrimenti
    scrivi quello che serve

altrimenti se fase 2 e trascorsi 2 sec
  fase = 1

Il delay è sostituito con il tempo in cui in fase 2 rimane falsa l'ultima condizione, e non c'è più niente che blocca

Gentilissimo, in pratica il funzionamento è questo: sulla puleggia della catena è montato un magnete che girando attiva i due sensori prima 1 e subito dopo l'altro per poter attivare il conteggio sia UP che Down e questo avviene in modo perfetto e puntuale; nella discesa arrivati a metri 10 di profondità si attiva il messaggio che indica l'entrata in funzione del motore; proprio questo messaggio deve restare visibile per alcuni secondi ma, nello stesso tempo il contatore deve continuare ad incrementare i metri i quali, alla scomparsa del messaggio vengono visualizzati correttamente cosa che non avviene per colpa del delay che congela arduino per il tempo di ritardo e di conseguenza i metri non sono reali.
Stessa cosa avviene nella risalita dell'ancora.
Grosso modo questo è il problema o il funzionamento...

Dimenticavo di precisare che il codice è strutturato in modo che, sia in discesa che in risalita i sensori, essendo attivati quasi contemporaneamente prima uno e poi l'altro, evita l'incrementare e, di conseguenza, il decrementare dei metri.

in pratica il funzionamento è questo: sulla puleggia della catena è montato un magnete che girando attiva i due sensori prima 1 e subito dopo l'altro per poter attivare il conteggio sia UP che Down e questo avviene in modo perfetto e puntuale

Quindi in pratica funziona come un normale encoder in quadratura: leggendo la sequenza con cui i sensori vengono impegnati stabilisci il verso di rotazione, giusto?
Però c'è allora una inconguenza nel codice (che pure dice che funziona, problema del delay() a parte) :

if (digitalRead(2) && digitalRead(3)) //  sensori 2 e 3 attivati

Questo non dovrebbe mai succedere, se non a causa di rimbalzi o simili, e in genere nel codice usato per leggere gli encoder questa condizione viene segnalata come inconguente.
Per maggiore chiarezza puoi indicare quali sono le condizioni possibili dei 2 sensori, es. nessuno dei 2 impegnato, solo uno dei 2, entrambi.
Poi, ancora per capire, può succedere che il meccanismo si fermi lasciando uno dei 2 sensori impegnati?
Ad ogni scatto (definisco così la sequenza dei 2 sensori impegnati in successione) equivale 1 metro?

Ciao, Ale.

Grazie per la risposta anche a te, come scritto sopra i sensori sono vicinissimi e comunque, per come li ho montati io, si attiva il primo e poi il secondo e viceversa ed essendo vicini quando il magnete di trova al centro si attivano entrambi, comunque il conteggio è impeccabile...

sulla puleggia della catena è montato un magnete che girando attiva i due sensori

Quanto tempo ci mette per fare un giro?

Mi sembra di capire che i delay stanno solo dopo alcune visualizzazioni sul display! A che servono??? Ciò che è scritto rimane finché non viene cancellato… Forse il problema sta nel fatto che altre cose vanno a scriverci sopra? Questo si risolve riorganizzando il display, o facendo in modo che per due secondi da quella visualizzazione (if(millis()-t_visual<2000){…} non possa essere scritto altro, oppure ancora usando un display 20x4… :slight_smile:

Buongiorno a tutti e buona domenica,

essendomi necessario risolvere questo problema in fretta cercherò di essere più chiaro:

@Savoriano, grazie per la risposta, il motore della puleggia ha il controllo della velocità che dalla minima alla massima potenza riavvolge da 0,5 a 2 metri al secondo;

@Datman, grazie della risposta, si le pause sono solo nei messaggi che mostra il Display;

di seguito e per chiarezza descrivo il funzionamento:

1)sganciata l’ancora, questa scende liberamente fino a circa 10 metri di profondità (in seguito mi piacerebbe inserire i metri a piacere) e nel display vengono mostrati il messaggio Ancora in discesa e la profondità in metri e fin qui tutto bene;

2)raggiunti i 10 metri si attiva il motore per assistere la velocità di discesa e qui appare il messaggio "Ancora 10 metri Assist. motore che, se lasciato con il delay, viene mostrato correttamente; il problema nasce qui perchè, trascorsi i due secondi del delay(), riappare il conteggio in metri che è rimasto a 10 mentre in realtà l’ancora, che nel frattempo ha continuato a scendere, sarà a 14 metri mostrando di conseguenza una falsa profondità raggiunta;

3)lo stesso discorso vale per la risalita dell’ancora che però diventa pericolosa com’è facilmente intuibile.

quindi il problema da risolvere è inserire delle pause in Millis() che non sono bloccanti al posto dei delay() e cosentire una precisa e continua lettura dei metri contati;
più sopra ho descritto anche qualche specie di soluzione provata ma con scarsi risultati…

Capisco che dovrei ripensare il tutto ma al momento quel poco che conosco di programmazione (maggiormente Visual Basic) che sto cercandi di trasformare in C/C++, non me lo consente e prima di postare ho provato per diverse ore al giorno;

Ringrazio tutti per l’aiuto.

ps. la puleggia riavvolgiancora, facilmente sganciabile e sostituibile, all’occorrenza potrà essere usata anche come salpapalamito ecco perchè mi serve maggiore precisione nel conteggio dei metri.

osvaldocs:
quindi il problema da risolvere è inserire delle pause in Millis() che non sono bloccanti al posto dei delay();

Hai visto la soluzione pseudocodice del post #8?

La soluzione elementare è usare un display 20x4, così la profondità può essere visualizzata continuamente, senza interferire con gli altri messaggi.

Sbagli nel concetto di voler inserire delle pause: tu devi avere il controllo su tutto ciò che accade e i messaggi devono apparire quando vuoi tu: se deve apparire un messaggio al posto dei metri, puoi memorizzare il tempo nel momento in cui il messaggio viene scritto: t_info=millis();
Poi, nella visualizzazione della profondità, metti:
if(millis()-t_info>2000){scrivi_metri();}

N.B.:
lcd.setCursor(0, 6);
in un display 16x2 non ha senso!

Grazie a tutti,
@ Datman, grazie per il suggerimento che proverò subito e vi aggiorno....
Penso che avrò bisogno ancora.. ;D