consiglio parte di programma

Ciao a tutti :slight_smile:
per imparare un po' la programmazione, ho fatto un orologio con motori passo passo per muovere le lancette, utilizzo un arduino nano, un modulo DS3231, 2 encoder e 2 sensori ottici per posizione zero.
Ho fatto parte del programma per far funzionare il motorino delle ore (funziona), è questo:

if (ora1fatta == false)                     // verifico se ho già posizionato la lancetta
  {
    if (ora == 1 || ora == 13)            // controllo la variabile ora, che ore sono
    {
      digitalWrite (DIR_ORE, HIGH);      // direzione motore
      digitalWrite (MOT_ORE, LOW);     // accende motore ore
      while (true)
      {
        digitalWrite(STEP_ORE, HIGH);  // step per far avanzare motore passo passo
        delayMicroseconds(14000);
        digitalWrite(STEP_ORE, LOW);
        delayMicroseconds(15000);
        pos_enc_ore = enc_ore.read();  // leggo encoder
        if (pos_enc_ore >= 200)           // se posizone a ore 1
        {
          break;                                 // esco dal ciclo while
        }
      }
      digitalWrite (MOT_ORE, HIGH);    // spengo motore ore
      ora1fatta = true;                      // avviso che ho impostato l'ora
    }
  }

Questo pezzo di programma è ripetuto per ogni ora (quindi 12 volte), per posizionare la lancetta delle ore; ora dovrei fare il posizionamento della lancetta dei minuti, ma dovrei replicare questo blocco per 60 volte....
Penso che ci sia un'altro modo, più veloce, ma non mi viene in mente, qualcuno sa darmi un consiglio? Uno spunto?

Grazie :slight_smile:

Trasformarla in una funzione

E parametrizzarla:

Accetta un argomento intero, ne fa il modulo 12
A cicla il while fino a che encoder non arriva alla posizione corretta

Hai la lista delle posizioni?

Ne fai un array...

Ne so quanto prima :smiley:
Si che ho le posizioni, faccio un array, ok, ma come lo richiamo in base al minuto che è? E come faccio a far si che una volta fatto, non venga ripetuto?

Per la prima domanda:

Usi il minuto come indice dello array

Per la seconda:

Come fai adesso?

proverò a fare qualcosa, ma mi manca proprio le basi :smiley:
faccio qualche prova :wink:
Grazie

Dai, che sei iscritto da 6 anni.

Un po' di basi le avrai pure...

Come ti ha consigliato @standardoil, dovresti prendere quel pezzo di codice e farlo diventare una funzione
Se fai una funzione generica per le ore, anche per i minuti farai una funzione anche lei generica.
Inizia con quella delle ore: prendi il codice del ora 1/13 e confrontalo con quello del ora 2/14; cosa c'e' di diverso?
Fai un passo alla volta, così impari a far diventare un pezzo di codice "generico" e riusabile più volte:

void PosizionaOre(int p_Ore)
{if(p_Ore<=0) return;
  digitalWrite (DIR_ORE, HIGH);      // direzione motore
  digitalWrite (MOT_ORE, LOW);     // accende motore ore
  while (true)
  { digitalWrite(STEP_ORE, HIGH);  // step per far avanzare motore passo passo
    delayMicroseconds(14000);
    digitalWrite(STEP_ORE, LOW);
    delayMicroseconds(15000);
    pos_enc_ore = enc_ore.read();  // leggo encoder
    if (pos_enc_ore >= 200) break;          // se posizone a ore 1
  }
  digitalWrite (MOT_ORE, HIGH);    // spengo motore ore
}
...
  if (ora1fatta == false)                     // verifico se ho già posizionato la lancetta
  {
    if (ora == 1 || ora == 13)            // controllo la variabile ora, che ore sono
    { PosizionaOre(ora);                   // chiamo la funzione con l'ora
      ora1fatta = true;                      // avviso che ho impostato l'ora
    }
  }

Questo il primo passo. La funzione NON è ancora "generica". Credo che 200 (pos_enc_ore a >=200) sia la parte che dipende da ora, o fai array con le 12 posizioni oppure (forse) è calcolabile (formula matematica) ??

Per non ripetere il posizionamento di ora e minuto io farei in maniera diversa. Memorizzerei ora e minuto vecchio, se ora<>oravecchio allora oravecchio=ora e chiamo PosizionaOre (oravecchio inzializzi a -1)
Anche perchè non mi convince quel metodo che hai usato, usando ora1fatta = booleano. Non c'e' tutto codice, quando la rimetti a false ??

Rieccomi,
non mi torna fare una funzione, perchè questa funzione la dovrei fare 60 volte (perchè diverso il numero 200 (che è la posizione dell'encoder per l'ora 1)) Ovvero, ok fare una funzione per fare quella parte di codice, ma come rendo il numero variabile? E poi nel loop mi trovo a fare 60 if diversi per sapere che minuto è?

Il programma ore lo lascio stare, che funziona, farò direttamente la parte minuti.

Il booleano ora1fatta, fa si che una volta che ho impostato la lancetta, non passo più da quella parte di programma, visto che per un'ora la condizione dell'if che cerca l'ora, sarà vera, tutti i boolean dall'ora 1 alle ore 11, vengono azzerati alle ore 00, in modo che il ciclo riparte.

Provo a buttare giù un codice usando un array, vedo cosa riesco a tirare fuori :slight_smile:

Grazie

PS mi correggo, la funzione ok, posso farla e posso cambiare il valore "200" utilizzando una variabile che varierò al momento che devo chiamare la funzione; e un bel po' di righe si risparmiano; ma nel loop io devo verificare i minuti per sapere cosa fare, ed essendo 60, mi trovo a fare 60 richiami alla funzione (cambiando i parametri di posizione) E' quà che mi incarto :smiley:

thedrifter:
PS mi correggo, la funzione ok, posso farla e posso cambiare il valore "200" utilizzando una variabile che varierò al momento che devo chiamare la funzione; e un bel po' di righe si risparmiano; ma nel loop io devo verificare i minuti per sapere cosa fare, ed essendo 60, mi trovo a fare 60 richiami alla funzione (cambiando i parametri di posizione) E' quà che mi incarto :smiley:

Ma se per l'ora fai una funzione unica e generica invece di 12 pezzi di codice,
secondo te non si può ragionare e fare la stessa cosa per i minuti ?!??

Per l'ora, se posti il programma attuale completo, appena posso, provo a farti vedere come si può accorciare con una funzione generica.

certo, quello non è un problema, il problema non è fare la funzione unica, ma come chiamarla, con 60 if?
Adesso per le ore ho fatto 12 pezzi di codice...

L'ora la sistemo stasera, faccio una funzione, ma mi restano 12 if...

thedrifter:
L'ora la sistemo stasera, faccio una funzione, ma mi restano 12 if...

Per il primo passo, la funzione accorpa buona parte del codice che pilota il motore/lancetta.
Ovviamente non siamo all'ottimizzazione completa. Anche perchè hai 12 variabili oraXfatta
L'ideale sarebbe non usare quelle booleane ma come ti dicevo sopra una oldora/oldminuto.
Ma se vuoi usare le booleane... anche loro possono diventare un array... oraFatta[ X ] dove X è l'ora :wink:
Quindi un unico if:

if (oraFatta[ora12] == false)              // verifico se ho già posizionato la lancetta
  { PosizionaOre(ora12);                   // chiamo la funzione con l'ora12  (0-11)
    oraFatta[ora12] = true;               // avviso che ho impostato l'ora
  }

E quando è ora 0 dovrai azzerare con ciclo for l'array di booleane oraFatta
int oraFatta [ 12 ] ha indice 0..11

thedrifter:
il problema non è fare la funzione unica, ma come chiamarla, con 60 if?

Ma no! Ogni volta che cambia il minuto, invii il valore alla funzione pos_minuti(); ogni volta che cambia l'ora, invii il valore alla funzione pos_ore():
Ore 12.58: pos_minuti(58);
Ore 12.59: pos_minuti(59);
Ore 13.00: pos_ore(1); pos_minuti(0);

In realtà, non mi sembra una buona idea far fare un giro intero ogni minuto! Ogni minuto incrementi la posizione dei minuti di un minuto (6°) e ogni 15 minuti incrementi la posizione delle ore di 1/4 d'ora (7,5°). Alle 2 di notte potresti fare un giro completo alla lancetta dei minuti fino allo zero e un giro completo più due ore (60°) alla lancetta delle ore, per correggere eventuali errori verificatisi durante la giornata.

Per fare tutto questo, ti serve un motore da 240 passi/giro; se muovi la lancetta delle ore solo ogni ora, invece (ma proprio non è bello), basta un motore da 60 passi/giro.

thedrifter:
PS mi correggo, la funzione ok, posso farla e posso cambiare il valore "200" utilizzando una variabile che varierò al momento che devo chiamare la funzione; e un bel po' di righe si risparmiano;

Anche qui, occhio. Se passiamo alla funzione ora quindi 0-23, tu dentro alla funzione unica puoi testare quel valore
oppure usare un array che contiene le posizioni oppure (forse) è possibile fare un calcolo matematico.
Se posti le posizioni della lancetta nei 12 casi possiamo vedere se c'e' un calcolo fattibile.
Quindi 1=posizione 200 e poi ... ??
Per semplificare il codice poi, la variabile "ora" falla andare pure da 0 a 23, ma crea una variabile ora12 che invece riduciamo a intervallo 0-11; alla funzione passiamo ora12
ora=... dove calcoli adesso, penso prendi da un rtc ?!?
ora12=ora;
if(ora>11) ora12=ora-12; // intervallo 12-23 ridotto a 0-11

Allora, un bel casino :smiley: ahhahaha
intanto rispondo alle volstre domande, poi vedo di fare qualcosa con array...
Datman, non faccio un giro ogni minuto, come per le ore, ogni cambio la lancetta fa uno step, l'azzeramento dell'encoder avviene alle ore 0 o 12.

Ho cercato per mesi dei passo passo che mi tornassero, ma trovo facilmente solo i nema da 200 o 400 passi giro, e entrambi sono indivisibili sia per 12 che per 60, per questo ho usato encoder, ora ho trovato in cina dei motori a spazzole ridotti, con encoder incorporato, li proverò. (Avevo provato anche con i servo a 360°, ma serve cmq encoder e sono molto rumorosi)

Le ore sono 24, ma uso a 12, in quanto faccio la stessa cosa sia per 01 che 13, sia per 02 che 14 e così via...
Le ore hanno step ora di 200 passi, l'encoder è 2400 impulsi giro, mentre i minuti hanno encoder che fa 2800 impulsi giro, quindi 46,66 al minuto, arrotonati a 46 e 47.
Questo array della posizione encoder dei minuti:

int pos_min [60] = {0,47,93,140,186,233,280,326,373,419,466,513,559,606,652,
699,746,792,839,885,932,979,1025,1072,1118,1165,1212,1258,1305,1352,1399,
1446,1493,1540,1587,1633,1680,1726,1773,1819,1866,1913,1959,2006,2052,2099,
2146,2192,2239,2285,2332,2379,2426,2473,2519,2566,2613,2659,2706,2753};

il valore ora lo prendo da un rtc, quindi va da 0 a 23

Ora studio :slight_smile:

Quindi per le ora la posizione è 0,200,400,600,etc. ??
Se si, ora 0=0 1=200 2=400 3=600 non ci vedi un semplice calcolo ?? pos=ora*200;

E per i minuti, c'e' anche li una funzione matematica di relazione semplice:
min=0 pos=0 min=1,47 min=2,93 ...etc.
pos_min= round( float(min)*46.6); // arrotondando
L'ho verificato facendo una tabella in excel, prima colonna i minuti 0-59, seconda colonna i tuoi valori, terza colonna questo calcolo (usando funzioni excel) e tornano.
posizione minuto 46,6 arrotond delta

posizione minuto 46,6 arrotond delta
0 0
47 1 46,60 47 0,00
93 2 93,20 93 0,00
140 3 139,80 140 0,00
186 4 186,40 186 0,00
233 5 233,00 233 0,00
280 6 279,60 280 0,00
326 7 326,20 326 0,00
373 8 372,80 373 0,00
419 9 419,40 419 0,00
466 10 466,00 466 0,00
513 11 512,60 513 0,00
559 12 559,20 559 0,00
606 13 605,80 606 0,00
652 14 652,40 652 0,00
699 15 699,00 699 0,00
746 16 745,60 746 0,00
792 17 792,20 792 0,00
839 18 838,80 839 0,00
885 19 885,40 885 0,00
932 20 932,00 932 0,00
979 21 978,60 979 0,00
1025 22 1025,20 1025 0,00
1072 23 1071,80 1072 0,00

si, ma non mi riesce assemblarlo :smiley:
allego il codice corretto con la funzione, per ora faccio solo ore, tanto poi è uguale :slight_smile:

Grazie

Motore_passo_passo_orologio_2.1.ino (12.5 KB)

Ho fatto questo:

void posiziona_ore(int p_ore)
{
  digitalWrite (DIR_ORE, HIGH);         // direzione motore
  digitalWrite (MOT_ORE, LOW);          // accende motore ore
  while (true)
  {
    digitalWrite(STEP_ORE, HIGH);
    delayMicroseconds(14000);
    digitalWrite(STEP_ORE, LOW);
    delayMicroseconds(15000);
    pos_enc_ore = enc_ore.read();       // leggo encoder
    if (pos_enc_ore >= passo_ora)
    {
      break;
    }
  }
  digitalWrite (MOT_ORE, HIGH);         // spengo motore ore
}

e questo:

if (ora1fatta == false)
  {
    if (ora == 1 || ora == 13)
    {
      passo_ora = 200;                      // dico la pos. che deve raggiungere l'encoder
      posiziona_ore(ora);                      // chiamo funzione muove lanc ore
      ora1fatta = true;                     // avviso che ho impostato l'ora
      ora0fatta = false;                    // azzero per rifare ore 0
    }
  }

Ma non capisco come la chiamata passando il valore "ora" alla funzione, possa interagire con l'array "passo_ora":if (pos_enc_ore >= passo_ora)

Scusa, ma... Ti conviene fare tanta fatica e spendere soldi per realizzare qualcosa che per pochi euro puoi acquistare già fatto e perfettamente funzionante, che con una piccola pila va avanti per un anno?...

Datman:
Scusa, ma... Ti conviene fare tanta fatica e spendere soldi per realizzare qualcosa che per pochi euro puoi acquistare già fatto e perfettamente funzionante, che con una piccola pila va avanti per un anno?...

Ahahhahahaha, quante cose allora non avrebbero senso, tutti i giorni facciamo cose che non servono a nulla..... :slight_smile:

Intendo dire che se una cosa posso comprarla già fatta come la voglio io a pochi soldi, la compro ed eventualmente la adatto ai miei gusti o alle mie esigenze. Se, invece, come dico io non esiste o costa una cifra spropositata, fosse pure perché fa anche il caffè e la macchina per il caffè c'è l'ho già, o è per una mia esigenza particolare e nessuno l'ha inventata, allora mi ci impegno. :slight_smile: