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à
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
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.
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
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 è
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;
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
#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(" ");
}