Encoder lpd3860-360bm-g5-24c e arduino uno [Risolto]

Salve a tutti, vorrei misurare la distanza in mm con l’encoder in descrizione però ho notato che ruotando l’encoder non è preciso perde 1 mm circa ,veramente perde i passi perchè non ho ancora convertito in mm.

Volevo chiedervi secondo voi è un problema di codice da migliorare o qualcosa che trascuro che non so, oppure è l’encoder economico (cinese) da sostituire con uno professionale.

Grazie per l’aiuto.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);


volatile unsigned int temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder
unsigned long val;



void setup() {
  Serial.begin (9600);

  pinMode(2, INPUT_PULLUP); // internal pullup input pin 2

  pinMode(3, INPUT_PULLUP); // internal pullup input pin 3
  //Setting up interrupt
  pinMode (5, INPUT);

  iniziolcd();

  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);

  //B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
  attachInterrupt(1, ai1, RISING);
}




void loop() {
  // Send the value of counter
  if (digitalRead(5) == HIGH)counter = 0;

  if ( counter != temp ) {

    lcd.backlight();
    lcd.display();
    lcd.setCursor(7, 1);
    lcd.print("     ");
    lcd.setCursor(7, 1);
    lcd.print(counter);
    Serial.println((counter);
    temp = counter;
    val = millis();


  }

  if ((millis() - val) > 60000) { //tempo per spegnere display 1minuto
    lcd.noBacklight();
    lcd.noDisplay();
    val = millis();

  }
}


void iniziolcd() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(2, 0);
  lcd.print("misura");
  delay(1000);
  lcd.setCursor(4, 1);
  lcd.print("VER. 0.1");
  delay(1000);

  lcd.setCursor(2, 0);
  lcd.print("misura");
  lcd.setCursor(0, 1);
  lcd.print("MISURA:");
  lcd.setCursor(7, 1);
  lcd.print("      ");
  lcd.setCursor(13, 1);
  lcd.print("MM");

  temp = counter;

}









void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if (digitalRead(3) == LOW) {
    counter--;
  } else {
    counter++;
  }
}

void ai1() {
  // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if (digitalRead(2) == LOW) {
    counter++;
  } else {
    counter--;
  }
}

Secondo me usando digitalRead() perde del tempo. Bisognerebbe leggere i pin direttamente a basso livello.
Oppure puoi provare con delle librerie già fatte per gli encoder, esempio (un pò vecchia):

Perde passi in modo costante o solo ad esempio quando giri troppo velocemente?
La funzione digitalRead() è notoriamente "lenta", soprattutto su ATMega328. Dovresti provare con l'accesso diretto alle porte.

Ad esempio visto che stai usando D2 e D3 al posto di digitalRead() potresti usare la macro bitRead() che risulta essere più veloce all'incirca di un ordine di grandezza rispetto a digitalRead() ovviamente a scapito della flessibilità

if( bitRead(PIND, 2) ) {
  etc etc
}

Edit
Mi sono sovrapposto per l'ennesima volta :smiley:

Perde passi se giro velocemente proverò con bitRead non lo conoscevo questo comando o con le librerie come consigliato .Grazie :wink:

Salve,ho modificato il codice inserendo bitREAD come consigliato.

ho provato a convertire anche in mm ma sapendo che 4235 giri del encoder si sposta di 1000mm ho diviso ogni passo per 4,235 ma sul dispaly invece di 1000 ,cioè 4235/4,235 visualizzo 1058.
Potreste dirmi come mai e come risolvere Grazie

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define ZERO 4235
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);


volatile unsigned int temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder
unsigned long val;
long x=0;

void setup() {
  Serial.begin (9600);

  pinMode(2, INPUT_PULLUP); // internal pullup input pin 2

  pinMode(3, INPUT_PULLUP); // internal pullup input pin 3
  //Setting up interrupt
  pinMode (5, INPUT);

  iniziolcd();

  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);

  //B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
  attachInterrupt(1, ai1, RISING);
}




void loop() {
  // Send the value of counter
  if (digitalRead(5) == HIGH)counter = ZERO; //azzeramento impostato a 1000mm

  if ( counter != temp ) {

    lcd.backlight();
    lcd.display();
    lcd.setCursor(7, 1);
    lcd.print("     ");
    lcd.setCursor(7, 1);
    x=counter/4,235;
    lcd.print(x);
    Serial.println(counter);
    temp = counter;
    val = millis();


  }

  if ((millis() - val) > 60000) { //tempo per spegnere display 1minuto
    lcd.noBacklight();
    lcd.noDisplay();
    val = millis();

  }
}


void iniziolcd() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(2, 0);
  lcd.print("ATEL PLASTIK");
  delay(1000);
  lcd.setCursor(4, 1);
  lcd.print("VER. 0.1");
  delay(1000);

  lcd.setCursor(2, 0);
  lcd.print("ATEL PLASTIK");
  lcd.setCursor(0, 1);
  lcd.print("MISURA:");
  lcd.setCursor(7, 1);
  lcd.print("      ");
  lcd.setCursor(13, 1);
  lcd.print("MM");

  temp = counter;

}









void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if (bitRead(PIND,3) == LOW) {
    counter--;
  } else {
    counter++;
  }
}

void ai1() {
  // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if (bitRead(PIND,2) == LOW) {
    counter++;
  } else {
    counter--;
  }
}
volatile unsigned int temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder

Il commento dice che la variabile si incrementa o decrementa, ma la dichiari unsigned int . Cosa succede quando è 0 e la decrementi?

Ciao, Ale.

Non so che libreria usi per il display. A me lcd.init() dà errore. Mi dice di usare lcd.begin().

L'istruzione
x=counter/4,235;
è sbagliata. Devi usare il punto "." non la virgola "," per i decimali.
x=counter/4.235;
Inoltre x deve essere dichiarato float non long, altrimenti darà sempre un valore intero.

Dovresti stampare il numero dei giri per essere sicuro che 1000mm corrispondano a 4235 giri.

Ciao,
P.

ilguargua:

volatile unsigned int temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder

Il commento dice che la variabile si incrementa o decrementa, ma la dichiari unsigned int . Cosa succede quando è 0 e la decrementi?

Ciao, Ale.

riparte dal massimo 659999 che riesce a misuare l'encoder a scalare

pgiagno:
Non so che libreria usi per il display. A me lcd.init() dà errore. Mi dice di usare lcd.begin().

L'istruzione
x=counter/4,235;
è sbagliata. Devi usare il punto "." non la virgola "," per i decimali.
x=counter/4.235;
Inoltre x deve essere dichiarato float non long, altrimenti darà sempre un valore intero.

Dovresti stampare il numero dei giri per essere sicuro che 1000mm corrispondano a 4235 giri.

Ciao,
P.

Grazie per il suggerimento metterò il. invece di , :D.
Io stampo con Serial.print il numero di giri del encoder per questo so che è 4235

Se non l'hai ancora fatto ti suggerirei una lettura del Reference di Arduino alla voce float.

Ciao,
P.

Buongiorno ,sono riuscito a convertire in mm però non è preciso di 2mm alcune volte si altre no.
dipende dal encoder oppure dal codice ::slight_smile:

mi dite anche come visualizzare solo un numero dopo la virgola.Grazie

Sono quasi certo che sia il software, ma non ho capito se hai applicato o meno i suggerimenti ricevuti.

penso di si…allego il codice aggiornato

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define ZERO 4235
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);


volatile unsigned int temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder
unsigned long val;
float x=0;

void setup() {
  Serial.begin (9600);

  pinMode(2, INPUT_PULLUP); // internal pullup input pin 2

  pinMode(3, INPUT_PULLUP); // internal pullup input pin 3
  //Setting up interrupt
  pinMode (5, INPUT);

  iniziolcd();

  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);

  //B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
  attachInterrupt(1, ai1, RISING);
}




void loop() {
  // Send the value of counter
  if (digitalRead(5) == HIGH)counter = ZERO; //azzeramento impostato a 1000mm

  if ( counter != temp ) {

    lcd.backlight();
    lcd.display();
    lcd.setCursor(7, 1);
    lcd.print("     ");
    lcd.setCursor(7, 1);
    x=counter/4.235;
    lcd.print(x);
    Serial.println(counter);
    temp = counter;
    delay(150);
    val = millis();


  }

  if ((millis() - val) > 60000) { //tempo per spegnere display 1minuto
    lcd.noBacklight();
    lcd.noDisplay();
    val = millis();

  }
}


void iniziolcd() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(2, 0);
  lcd.print("ATEL PLASTIK");
  delay(1000);
  lcd.setCursor(4, 1);
  lcd.print("VER. 0.1");
  delay(1000);

  lcd.setCursor(2, 0);
  lcd.print("ATEL PLASTIK");
  lcd.setCursor(0, 1);
  lcd.print("MISURA:");
  lcd.setCursor(7, 1);
  lcd.print("      ");
  lcd.setCursor(13, 1);
  lcd.print("MM");

  temp = counter;

}









void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if (bitRead(PIND,3) == LOW) {
    counter--;
  } else {
    counter++;
  }
}

void ai1() {
  // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if (bitRead(PIND,2) == LOW) {
    counter++;
  } else {
    counter--;
  }
}

Per favore, butta via tutte quelle linee vuote dal codice, non servono a nulla e allungano la visione del codice inutilmente, non è un temino che più pagine fai meglio è :smiley: :wink:

La libreria encoder.h, visionandola dentro, non solo usa la lettura sui pin diretta (usando i registri della MCU), ma ha anche alcune parti in assembly, forse proprio per non avere delle perdite negli impulsi.

Per la virgola, prova a vedere se la libreria lcd che usi accetta il numero di virgole nella print():
lcd.print(x,1);

Suppongo tu voglia scrivere il valore di x
x=counter/4.235;

Innanzi tutto devi ricavare la parte intera
int z=(int)x;

e scriverla sul display, poi aggiungi il punto o la virgola a seconda di cosa ti piace di più. Poi ricavi la prima cifra decimale in questo modo:
int y=((int)(x*10.0))%10;

e la scrivi sul display.

Ciao,
P.

ho riscritto il codice utilizzando <Encoder.h> domani provo a caricarlo per vedere se migliora la precisione. Grazie

Salve, utilizzando Encoder.h sembra funzionare meglio ha raddoppiato il numero di conteggi del encoder lo testerò meglio in questi giorni.
Grazie per il supporto :wink:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Encoder.h>

#define ZERO 8470
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);
Encoder myEnc (2, 3);

volatile long temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder
unsigned long valore = millis(); //usato per registare millis

boolean controllo;



void setup() {
  Serial.begin (9600);
  pinMode (5, INPUT);
  controllo = true;
  iniziolcd();

}




void loop() {
  counter = myEnc.read() / 8.470;
  if (digitalRead(5) == HIGH)myEnc.write(ZERO);


  if ( counter != temp ) {
    while (controllo) {             //ciclo verifica mancata corrente
      lcd.display();
      delay(500);
      lcd.noDisplay();
      delay(500);

      if (digitalRead(5) == HIGH) {
        controllo = false;

      }
    }

    lcd.backlight();
    lcd.display();
    lcd.setCursor(7, 1);
    lcd.print("         ");
    lcd.setCursor(7, 1);
    lcd.print(counter);
    Serial.println(counter);
    temp = counter;
    delay(100);
    valore = millis();


  }

  if ((millis() - valore) > 300000) {   //tempo per spegnere display 5minuti
    lcd.noBacklight();
    lcd.noDisplay();
    valore = millis();

  }
}


void iniziolcd() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(2, 0);
  lcd.print("ATEL PLASTIK");
  delay(1000);
  lcd.setCursor(4, 1);
  lcd.print("VER. 1.0");
  delay(1000);
  lcd.setCursor(0, 1);
  lcd.print("MISURA:");
  lcd.setCursor(7, 1);
  lcd.print("         ");
}