ho un problema con un encoder incrementale da 500 impulsi per rotazione
al massimo della velocità compie 3/4 di giro al secondo circa,
nell'arco di una traslazione completa compie circa 13500 conteggi , ma non è molto preciso,
andando da zero a 13500 e poi di nuovo a zero sbaglia di un centimetro su una lunghezza di 1000 mm, e se non gli faccio fare lo zero, l'errore si somma nel ciclo successivo...
il cavo è lungo un metro, è il suo originale schermato,
la schermatura è collegata
ho messo due resistori di pull-down da 1k sui 2 canali
cosa può essere secondo voi?
il codice che gestisce la lettura dell'encoder è questo
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis1 > interval1) {
previousMillis1 = currentMillis; //save the last time I blinked the LED
//if the LED is off turn it on and vice-versa:
ledState ^= 1;
digitalWrite(steptra, ledState);
}
currentMillis = millis();
if (currentMillis - previousMillis2 > interval2) {
previousMillis2 = currentMillis; //save the last time I printed on the serial
//Serial.println(Counter1++);
Serial.println(encoder0Pos);
// Serial.println(Count1);
Serial.println(Count50);
}
{
n = digitalRead(encoder0PinA);
if ((encoder0PinALast == LOW) && (n == HIGH)) {
if (digitalRead(encoder0PinB) == LOW) {
encoder0Pos--;
} else {
encoder0Pos++;
}
}
encoder0PinALast = n;
}
lupastro81:
il codice che gestisce la lettura dell'encoder è questo
void loop() {
{
n = digitalRead(encoder0PinA);
if ((encoder0PinALast == LOW) && (n == HIGH)) {
if (digitalRead(encoder0PinB) == LOW) {
encoder0Pos--;
} else {
encoder0Pos++;
}
}
encoder0PinALast = n;
}
La lettura in certi momenti potrebbe essere troppo lenta. anche se ca 350 Impulsi per secondo non dovrebbe essere un problema. A che velocitá hai settato la seriale?
Ciao Uwe
non ci sono delay sparsi nel programma completo,
ma però ci sono 6 contatori, ho provato a togliere tutta la parte software che gestisce le postazioni ed è migliorato leggermente, ma non è ancora come dovrebbe essere, se lo faccio andare da zero a 8000 poi a 3000 , 5000 , 11000 quando torna a zero è fuori di un paio di centimetri...
Usa gli interrupt per incrementare/decrementare la variabile di posizione.
Sei sicuro che Ti servono resistenze pulldown?
Che tipo di variabile é encoder0Pos
Usa gli interrupt per incrementare/decrementare la variabile di posizione.
non so come fare... ho messo mano su questo linguaggio di programmazione un paio di anni fa quando ho acquistato la prima arduino :~
usare un interrupt è dare "una corsia preferenziale" all'elaborazione del conteggio per evitare ritardi?
la variabile encoder0pos è INT,
senza resistori è pressochè inutilizzabile, ho fatto diverse prove a scendere da 10k in giù e 1k mi pare la soluzione migliore
Il codice che hai scritto è giusto per leggere l'encoder come X1 cioè come PPR, è giusto anche se siccome è in polling devi passarci dentro almeno 4000 volte al secondo senza mai fare attese su altre parti di codice, se non vuoi o puoi usare gli interrups esterni genera un interrupt ciclico con il timer0 ogni circa 250uSec e fai il polling alla risposta. Così puoi anche usarlo come RTC e cosa più importante puoi eseguire in main anche qualsiasi routine con delay , compreso la trasmissione di dati verso USART
"Siccome è in polling devi passarci dentro almeno 4000 volte al secondo senza mai fare attese su altre parti di codice":
R: 4000 volte/sec perchè hai un encoder 1024 PPR e circa 45RPM, ....per non saltare fronti devi campionarlo almeno 4 volte cioè almeno 1024 x 4 x 0.75 = 3072 ....meglio abbondare: 4000 campionamenti/sec
"genera un interrupt ciclico con il timer0 ogni circa 250uSec e fai il polling alla risposta."
R: Devi impostare il Timer0 (è l'unico a 8 bit quindi il "peggiore") in modo che generi un interrupt ogni 250uSec circa , se lo fai a 200 va bene lo stesso ma non 300 o 350, alla risposta all'interrupt metti il tuo programma che aggiorna la variabile di posizione
"Così puoi anche usarlo come RTC"
R: significa che se all'interrup timer0 aggiorni una o più variabili puoi avere la concezione del tempo trascorso quindi creare quanti timer vuoi senza pesare sul firmware
" e cosa più importante puoi eseguire in main anche qualsiasi routine con delay compreso la trasmissione di dati verso USART"
R: nella main sub puoi inviare dati alla seriale o mettere comandi delay senza RTC (o con RTC) oppure accedere a una i2c o altro senza paura di perdere un solo impulso encoder.
ri-grazie per la risposta icio ma...
faccio un taccone facendogli fare lo zero ogni tot cicli, considerando che non mi serve tutta la precisione che è in grado di fornire l'encoder, mi dispiace un pò non sfruttarlo al 100% ma io attualmente più in la di lì non ce la fo!
ciao
a breve dovrò usare anche io un encoder da 360 impulsi/giro e utilizzerò degli interrupt, li ho già utilizzati per fare un contatore, come ti hanno anche consigliato, non sono difficili da comprendere
Stefano
ti allego uno sketch da cui partirò
/* Read Quadrature Encoder
* Connect Encoder to Pins encoder0PinA, encoder0PinB, and +5V.
*
* Sketch by max wolf / www.meso.net
* v. 0.1 - very basic functions - mw 20061220
*
*/
int val;
int canaleA=HIGH;
int canaleB=HIGH;
int encoder0PinA=2;
int encoder0PinB=3;
int encoder0Pos=0;
int encoder0PinALast=LOW;
int n=LOW;
void setup()
{
attachInterrupt(0,encoderA,RISING); //sensore collegato al pin 2
attachInterrupt(1,encoderB,RISING); //sensore collegato al pin 3
pinMode (encoder0PinA,INPUT);
digitalWrite(encoder0PinA, HIGH);//enable pullup resistor
pinMode (encoder0PinA,INPUT);
digitalWrite(encoder0PinA, HIGH);//enable pullup resistor
pinMode (encoder0PinB,INPUT);
Serial.begin (9600);
}
void loop() {
n = digitalRead(encoder0PinA);
if ((canaleA==LOW))
{
if (digitalRead(encoder0PinB) == LOW)
{
encoder0Pos--;
} else
{
encoder0Pos++;
}
Serial.print (encoder0Pos);
Serial.print ("/");
}
encoder0PinALast = n;
}
void encoderA() //pin 2 a cui attaccare il canale A dell'encoder
{
canaleA=LOW;
}
void encoderB() //pin 3 a cui attaccare il canale B dell'encoder
{
canaleB=LOW;
}
una domanda idiota,
leggendo un tutorial di mauroalfieri;
sono sufficienti queste 2 righe di codice per abilitare l'interrupt su due canali collegati ai pin 2 e 3 ?
ciao , si , appena posso provo con quello sketch , l'avevo già provato ma probabilmente avevo sbagliato qualcosa,
ops no non l'avevo visto, lo provo al più presto ! Grazie!
Quando arriva un interrupt, se non è già in corso l'esecuzione di una ISR (nel qual caso quell'interrupt viene accodato), qualunque cosa il tuo programma stia facendo, viene interrotto (... sempre che gli interrupt siano abilitati) e il controllo passa alla ISR specificata per quell'interrupt.
La delay() non ha alcuna influenza sugli interrupt.
ok grazie Guglielmo!
non vedo l'ora di metterci mano...
si Guglielmo ho dato un'occhiata ma sono moooooolto indietro con questo linguaggio di programmazione,
Gli interrupt non hanno niente a che fare con i linguaggi , sono meccanismi di tutti i microprocessori che fino dal loro primo inizio mezzo secolo fà sono sempre stati implementati, qualsiasi linguaggio si usa comprende l'uso degli interrupt.
In 2 parole: chi non usa interrupts NON sà programmare, i loro programmi saranno sempre banali e elementari, deboli, critici e poco potenti, molto differenti da chi sà usare appieno tutte le risorse hardware del MC impiegando tutte le tecniche di programmazione conosciute, facendo fare ad un economico MC a 8 bit operazioni che che il dilettante non risce a fare nemmeno in uno a 32bit
tra un'interrupt sull'atmega e uno su un plc s7 (per esempio) mi sembra di vedere delle differenze,
"mi sembra", considerando che il c/c++ per me è similaramaico
che il fine sia lo stesso ok, ma il meccanismo che mi porta al risultato voluto non lo vedo tanto simile,
per chi come me ieri era allo starter kit già solo la sintassi basilare è una bella gatta da pelare... pensa a che livello sono...
ho impiegato una decina di ore solo per scrivere una rampa di accelerazione/decelerazione per uno stepper, utilizzando 1k di righe di codice, essendo consapevole del livello di banalità/ridondanza del capolavoro partorito dalla mia ignoranza,
però funziona! (che soddisfazione è?!!! )
io non so programmare (non l'ho mai nascosto, anzi! ) se non fosse per l'aiuto dei santi qui presenti sul forum mi sarei fermato alla prima arduino...
bè.. grazie santi ! ! ! XD XD XD
Beh , il mio commento è un incentivo ad usare abbondantemente gli interrupts, non è difficile basta capire il concetto.
Devi sapere che anche il corpo umano possiede degli interrupts, sono a circa 30hz, cioè circa 30 volte al secondo viene fatto una scansione "del sistema nervoso" in modo che venga controllato che degli stimoli primari non vengano trascurati per il beneficio e la salute del corpo, ad esempio se succede che uno ti viene alle spalle senza farsi sentire e ti accenda la fiammella di un accendino sul sedere o in una qualsiasi parte del corpo anche se tu non lo hai visto dopo una frazione di secondo avverti il dolore e reagisci, non è che ogni mm del tuo corpo è collegato con il cervello SEMPRE ma il corpo effettua una scansione ciclica di ogni puntino del corpo in modo da controllare tutto, e questo avviene anche se stai mangiando, dormendo o facendo altro, sembra che il corpo stia facendo tutto contemporaneamemte ma non è così, Nel main program ci sono i programmi : "mangia" "parla" "ascolta" "guarda" etcc.. Nel interrupt ciclico del timer0 c'è la "scansioni di tutti i puntini"le cellule" del corpo" se succede qualcosa di importante nei puntini viene interrotto il programma principale "il main" e viene eseguita la routine "emergenza" "REAGISCI:STAI PRENDENDO FUOCO" , ti è più chiaro il concetto dell'importanza SEMPRE di un interrupt ciclico?