Rotary Encoder (ROT)

Υλοποίηση με εξωτερική διακοπή (IRQ) στον ATmega2560

 

Συγγραφέας: Πορλιδάς Δημήτριος

Βιογραφικό Σημείωμα

electronics@porlidas.gr

Facebook

Linkedin


 

 

Ο Rotary encoder είναι ένας μηχανικός κωδικοποιητής περιστροφής incremental encoder[1]. Αποτελείται από ένα άξονα, ο οποίος περιστρέφεται και δύο διακόπτες οι οποίοι κλείνουν – ανοίγουν με μια συγκεκριμένη σειρά που εξαρτάται από τη φορά περιστροφής του άξονα. Ο άξονας έχει ένα μηχανισμό με θέσεις συγκράτησης (detents) κατά την περιστροφή. Οι δύο διακόπτες (A, B) έχουν το ένα άκρο τους κοινό και το άλλο ελεύθερο. Το κοινό άκρο συνδέεται συνήθως στη γείωση και τα ελεύθερα άκρα Α και Β σε εισόδους του μικροελεγκτή με ενεργοποιημένες τις εσωτερικές pull up αντιστάσεις ή με συνδεδεμένες εξωτερικές. Συνήθως υπάρχει και ένας τρίτος ανεξάρτητος διακόπτης που κλείνει με πάτημα του άξονα και έχει δύο ελεύθερους ακροδέκτες, οι οποίοι συνδέονται με τον ίδιο τρόπο, ο ένας στη γείωση και ο άλλος στον μικροελεγκτή. Αν αρχίσουμε να περιστρέφουμε τον άξονα συνεχώς, οι δύο διακόπτες θα παράγουν τετραγωνικούς παλμούς με διαφορά φάσης. Όταν ο αριθμός των θέσεων συγκράτησης είναι ίσος με τον αριθμό των παλμών, τότε έχουμε τον έναν τύπο ROT (detents = pulses) όπου στις θέσεις συγκράτησης οι διακόπτες είναι πάντα ανοιχτοί. Όταν ο αριθμός των θέσεων συγκράτησης είναι διπλάσιος από τον αριθμό των παλμών, έχουμε το δεύτερο τύπο ROT (detents = 2*pulses) όπου στις θέσεις συγκράτησης εναλλάσσονται είτε και οι δύο ανοιχτοί είτε και οι δύο κλειστοί. Στο σχήμα παρουσιάζεται ο πρώτος τύπος ROT όπου δείχνονται οι θέσεις συγκράτησης. Για τον δεύτερο τύπο υπάρχουν και ενδιάμεσες θέσεις.

Στις περισσότερες εφαρμογές η κίνηση του ROT αυξάνει ή ελαττώνει ένα μετρητή, ο οποίος χρησιμοποιείται στη συνέχεια σε κάποια λειτουργία. Το λογισμικό αναγνωρίζει την κίνηση του άξονα αν είναι κατά τη φορά δεικτών του ρολογιού (CW) ή αντίθετη (CCW). Η αναγνώριση γίνεται ελέγχοντας την κατάσταση των Α, Β. Ο πιο ασφαλής τρόπος είναι τα Α, Β να προκαλούν το καθένα εξωτερική διακοπή στον μικροελεγκτή και η ρουτίνα της διακοπής να διαχειρίζεται τη μεταβολή του μετρητή. Στη συνέχεια παρουσιάζεται ένα παράδειγμα χρήσης ROT γραμμένο σε γλώσσα προγραμματισμού C:

#include <avr/interrupt.h>

volatile int i1;           // Has to be "volatile" if other routine than ISR(INTx_vect) affects "reg1bin"

 

void InitROT (void)                      // Start up, initialization routine

{

EICRB |= (1<<ISC41);                 // Interrupt by the falling edge INT4

EICRB |= (1<<ISC51);                 // Interrupt by the falling edge INT5

EIMSK |= (1<<INT4);                  // Enable INT4 interrupt

EIMSK |= (1<<INT5);                  // Enable INT5 interrupt

sei();                               // Enable interrupts

DDRE &= ~((1<<4)|(1<<5));            // Port E4, E5 inputs

PORTE |= (3<<PORTE4);                // Port E4, E5 Enable pull up

}

 

ISR(INT4_vect)                           // INT4, PE4 Rot A, CW Increase, start moving (A->0, B=1)

{

//sei();                             // Enable interrupts (if necessary)

//cli();                             // Disable interrupts (if necessary)

_delay_ms(1);

while (!(bit_is_set(PINE,4)));       // A=0

_delay_ms(1);

if ((bit_is_set(PINE,4)) && (!(bit_is_set(PINE,5))))      // A=1, B=0

i1++;                                // Increase

while (!(bit_is_set(PINE,5)));       // B=0

_delay_ms(1)          

}

 

ISR(INT5_vect)                           // INT5, PE5 Rot B, CCW Decrease, start moving (B->0, A=1)

{

//sei();                             // Enable interrupts (if necessary)

//cli();                             // Disable interrupts (if necessary)

_delay_ms(1);

while (!(bit_is_set(PINE,5)));       // B=0

_delay_ms(1);

if ((bit_is_set(PINE,5)) && (!(bit_is_set(PINE,4))))      // B=1, A=0

i1--;                                // Decrease

while (!(bit_is_set(PINE,4)));       // A=0

_delay_ms(1);

}

Οι έξοδοι Α, Β του ROT είναι συνδεδεμένοι στις εισόδους INT4, INT5 (PE4, PE5) του μικροελεγκτή. Η βιβλιοθήκη avr/interrupt είναι απαραίτητη για τη λειτουργία των διακοπών και η μεταβλητή i1 πρέπει να είναι volatile αν θέλουμε να υπάρχει δυνατότητα να αλλάξει η τιμή της και από άλλες ρουτίνες. Η ρουτίνα InitROT(void) ενεργοποιεί τις διακοπές στο κατερχόμενο μέτωπο και προγραμματίζει τα PE4, PE5 εισόδους με ενεργοποιημένες τις εσωτερικές pull up αντιστάσεις. Οι δύο επόμενες ρουτίνες, ISR(INT4_vect) και ISR(INT5_vect), εκτελούνται με την αντίστοιχη διακοπή.

Αν περιστρέψουμε τον άξονα κάποιο από τα Α, Β θα περάσει πρώτο σε λογικό 0 και το κατερχόμενο μέτωπο θα προκαλέσει τη διακοπή INT4 ή INT5 ανάλογα με τη φορά περιστροφής. Αν το Α προκαλέσει τη διακοπή αρχίζουν να εκτελούνται οι εντολές της ρουτίνας ISR(INT4_vect). Σε περίπτωση που θέλουμε να υπάρχει δυνατότητα κάποια άλλη διακοπή να εμπλακεί μπορούμε να ενεργοποιήσουμε τις διακοπές (στο παράδειγμα η εντολή είναι σε σχόλιο). Εκτελείται αρχικά μια καθυστέρηση για τους παρασιτικούς παλμούς του διακόπτη και στη συνέχεια το πρόγραμμα παραμένει στη while για όσο το Α βρίσκεται σε λογικό 0. Καθώς συνεχίζει να περιστρέφεται ο άξονας το Β θα περάσει σε λογικό 0 και αυτό πριν το Α περάσει σε λογικό 1 ξανά. Όταν το Α περάσει σε λογικό 1 το πρόγραμμα βγαίνει από τη while και εκτελείται μια καθυστέρηση για τους παρασιτικούς παλμούς. Αν το Α είναι σε λογικό 1 και το Β σε λογικό 0 επιβεβαιώνεται τότε η φορά περιστροφής CW και αυξάνει ο μετρητής i1. Το πρόγραμμα περιμένει να περάσει και το Β σε λογικό 1, εκτελείται μια καθυστέρηση για τους παρασιτικούς παλμούς, ενεργοποιούνται ξανά οι διακοπές αν είχαν απενεργοποιηθεί και βγαίνει από τη ρουτίνα διακοπής δίνοντας τον έλεγχο στο κυρίως πρόγραμμα. Αν η περιστροφή είναι αντίθετη (CCW), το Β θα προκαλέσει τη διακοπή INT5 και θα αρχίσει να εκτελείται η ρουτίνα ISR(INT5_vect), η οποία εκτελεί ίδιες εντολές που όμως το Α βρίσκεται στη θέση του Β και το αντίθετο και ελαττώνει τον μετρητή i1.   

 

©2019 Πορλιδάς Δημήτριος

 


[1] Η άλλη κατηγορία μηχανικών κωδικοποιητών είναι absolute encoder.

 

Σας ευχαριστώ για την υποστήριξή σας ώστε να γίνει η ιστοσελίδα μου καλύτερη.

© 2019 Πορλιδάς Δημήτριος