modifica timer

salve a tutti, ho fatto un timer countdown e per regolare il tempo ho utilizzato un encoder solo che vorrei implementare una funzione che se ruoto l’encoder piano mi avanza di una unità e se ruoto veloce mi avanza per esempio di decine, non avendo trovato niente in rete chiedo a voi come fare.
grazie a chi mi aiuterà
estrapolo solo il listato del timer, sicuramente non compilerà perchè ci sono variabili inerenti il listato completo

porzione_solo_timer.ino (8.59 KB)

Ciao! Premetto che non ho mai usato un encoder ma vorrei proporti la soluzione che mi viene in mente.
Velocità spazio/tempo, per un encoder potremmo definirla impulsi/tempo.
Allora alla lettura dell'encoder inizio il conteggio del tempo tramite funzione millis(),finita la lettura, divido tempo trascorso diviso impulsi, e ho la media del tempo, se la media del tempo è superiore a una soglia considero piano, se la media è inferiore a una soglia considero veloce.

Con la struttura if, se piano incremento di uno, se veloce incremento di 10.

Si può anche misurare quanto passa dall'ultima variazione. Se il risultato è più piccolo di un tot millisecondi (da quantificare sperimentalmente) si sta muovendo veloce.

torn24 e secondo te in codice come verrebbe tradotto? oppure Claudio_FF la tua soluzione come verrebbe tradotta in codice?

… con una sola if, ne dubito … pero’ potresti mettere nella ISR sia la variabile che ti dice se incrementi o decrementi (esempio 1 incrementi 2 decrementi), sia un’altra unsigned long tipo “tempo=millis()” …

Poi fuori fai (pseudocodice)

se variabile e’ 1
se millis - tempo minore di (esempio) 5 fai +10 e rimetti variabile a 0
altrimenti fai +1 e rimetti variabile a 0

se variabile e’ 2
se millis - tempo minore di (esempio) 5 fai -10 e rimetti variabile a 0
altrimenti fai -1 e rimetti variabile a 0

Ma e’ tutta da verificare … ed in ogni caso, anche se funzionasse, il primo step sarebbe sempre considerato “lento”, ma non credo sia un grosso problema, esssendo solo uno per ogni azionamento …

RoccoStragapede:
salve a tutti, ho fatto un timer countdown e per regolare il tempo ho utilizzato un encoder ...

avevo risolto l'impostazione delle cifre tramite encoder prendendo un encoder col pulsante incorporato
pigiando la prima volta la manopola la prima cifra inizia a lampeggiare e ruotandolo la cifra aumentava/diminuiva
cosi via la seconda terza cifra etc alla fine tutto veniva anche memorizzato nelle memorie e il timer era gia impostato sull'ultimo valore al riavvio

if (encoderPos == 1) {         //ruoto in senso orario
        dt1 = millis() - t1;   
        if (dt1 > 100) {
          hours = hours + 1;
          dt1 = 0;
        } else {
          hours = hours + 10;
          dt1 = 0;
        }
      }

ho abbozzato questo spezzone di codice sulle sole ore ma non mi funziona come mai?

elrospo:
pigiando la prima volta la manopola la prima cifra inizia a lampeggiare e ruotandolo la cifra aumentava/diminuiva
cosi via la seconda terza cifra etc

Anche secondo me questo è il metodo più user-friendly e che personalmente preferisco.
Se devi cambiare il setpoint di un valore di qualsiasi entità lo fai rapidamente e con precisione senza ruotare in continuazione l'encoder.

ho provato altre strade ma niente ancora.
Vorrei attuare questa logica: se ruoto l'encoder con una frequenza per esempio di uno scatto ogni 500mS avanzo la variabile hours di 1 ma se ruoto l'encoder di 10 scatti per esempio entro i 500mS allora avanzo la variabile hours di 10, mi potreste dare una mano a scrivere l codice?

Nel codice esistente sorvolo sull’ uso di rotating (e mi domando come può funzionare un delay dentro una ISR).

Piuttosto vedo che le variabili comuni usate sotto interrupt NON sono state dichiarate volatile, questo può dare problemi.

Poi la logica di utilizzo delle variabili prodotte dagli interrupt, vedo che è scritta così:

rotating = true;
encoderPos = constrain(encoderPos, -1, 1);
if (lastReportedPos != encoderPos) 
{
    ... 
    ... 
    if (encoderPos == 1) ...
    ... 
    ... 
    encoderPos = 0;
    lastReportedPos = encoderPos;
}

Ma la variabile lastReportedPos è ridondante, e anche il constrain non serve a nulla, tanto la lettura degli encoder non produce mai nulla di diverso da -1 e 1, quindi tutto si semplifica in:

rotating = true;
if (encoderPos != 0) 
{
    ... 
    ... 
    if (encoderPos == 1) ...
    ... 
    ... 
    encoderPos = 0;
}

Adesso si vuole sapere se l’encoder si muove lento o veloce, basta misurare il tempo tra uno scatto e l’altro, quindi prima di tutto ad ogni scatto si deve memorizzare il tempo attuale (variabile tRot):

//=================================================
void doEncoderA()
{
    if (rotating) delay (1);

    if (digitalRead(encoderPinA) != A_set)
    {
        A_set = !A_set;

        if (A_set and !B_set)
        {
              encoderPos = -1;
              tRot = millis();
        }

        rotating = false;
    }
}
//=================================================
void doEncoderB()
{
    if (rotating) delay (1);

    if (digitalRead(encoderPinB) != B_set)
    {
        B_set = !B_set;

        if (B_set and !A_set)
        {
              encoderPos = 1;
              tRot = millis();
        }

        rotating = false;
    }
}
//=================================================

Ed infine si può usare una variabile lastRot per calcolare il tempo trascorso dallo scatto precedente (appunto last):

rotating = true;
if (encoderPos != 0) 
{
    unsigned long elapsed = tRot - lastRot;
    bool avanti           = (elapsed >  100) && (1 == encoderPos);
    bool avantiVeloce     = (elapsed <= 100) && (1 == encoderPos);
    bool indietro         = (elapsed >  100) && (-1 == encoderPos);
    bool indietroVeloce   = (elapsed <= 100) && (-1 == encoderPos);
    ... 
    ... 
    if  (avanti) ...
    ... 
    ... 
    encoderPos = 0;
    lastRot = tRot;
}

Claudio_FF:
... mi domando come può funzionare un delay dentro una ISR ...

... purtroppo ... funziona (... delay() NON usa millis(), ma micros() che non si basa sull'interrupt di overflow che usa millis()) ... ma è l'antitesi di quanto si deve fare in una ISR che, per definizione, deve essere la più veloce possibile e dove,di base, si dovrebbe:

  • Keep it short
  • Don't use delay ()
  • Don't do serial prints
  • Make variables shared with the main code volatile
  • Don't try to turn interrupts off or on
    Guglielmo

ok mi funziona benissimo grazie a Claudio_FF
ecco la porzione di codice modificata

  if (encoderPos != 0) {

    unsigned long elapsed = tRot - lastRot;
    bool avanti           = (elapsed >  100) && (1 == encoderPos);
    bool avantiVeloce     = (elapsed <= 100) && (1 == encoderPos);
    bool indietro         = (elapsed >  100) && (-1 == encoderPos);
    bool indietroVeloce   = (elapsed <= 100) && (-1 == encoderPos);
      
      if (HMS == 1) {
      if (avanti)
      hours = hours + 1;
      if (avantiVeloce)
      hours = hours + 10;
      if (indietro)
      hours = hours - 1;
      if (indietroVeloce)
      hours = hours - 10;
      if (hours > 59) hours = 0;
      if (hours < 0) hours = 59;
      lcd.setCursor(0, 3);
      lcd.print(hours);
    } else if (HMS == 2) {
      if (avanti)
      minutes = minutes + 1;
      if (avantiVeloce)
      minutes = minutes + 10;
      if (indietro)
      minutes = minutes - 1;
      if (indietroVeloce)
      minutes = minutes - 10;
      if (minutes > 59) minutes = 0;
      if (minutes < 0) minutes = 59;
      lcd.setCursor(3, 3);
      lcd.print(minutes);
    } else if (HMS == 3) {
      if (avanti)
      seconds = seconds + 1;
      if (avantiVeloce)
      seconds = seconds + 10;
      if (indietro)
      seconds = seconds - 1;
      if (indietroVeloce)
      seconds = seconds - 10;
      if (seconds > 59) seconds = 0;
      if (seconds < 0) seconds = 59;
      lcd.setCursor(6, 3);
      lcd.print(seconds);
    }
...
...
...
...
    encoderPos = 0;
    lastRot = tRot;
    }

visto che sto volevo capire cos’è elapsed e il 100 nelle funzioni <>= a cosa si riferisce, agli scatti o al tempo?

elapsed sono i milisecondi passati tra uno scatto e l'altro

ok grazie tante

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.