Cette question revient de temps en temps, alors, j'ai rassemblé dans ce tuto un certain nombre de réponse aux questions qui ont été posées. Le codeur incrémental existe sous deux formes, rotatif ou linéaire. La mécanique est différente, le traitement électrique est le même.
What is it?
Un codeur incrémental génère 3 signaux :
- Un signal A
- Un signal B
- Un signal Top Zéro
Les niveaux électriques sont :
- Haute tension (24V par exemple)
- TTL (0/5V)
- RS422 Dans ce cas, on a les signaux A et /A , B et /B , Z et /Z il faut passer par un récepteur de ligne RS422 (avec sa résistance d'adaptation)
- Un simple contact sec et il faut une PullUp (ces codeurs, qui remplacent des potentiomètres, ne donnent pas de Top Zéro)
Principe de fonctionnement
Dans la suite, on oubliera la gestion du TopZéro qui ne sert qu'a recaler le compteur électronique en synchronisme avec la position zéro du codeur.
Les signaux A et B sont décalés en quadrature (on dit aussi à 90° ou en Grecque) et chaque période de A (et donc de B) indique que le codeur a fait un pas sachant que le nombre de pas par tour peut aller de 32 à 8096 suivant le prix du codeur.
Pour détecter le sens de rotation, Il faut regarder si les transitions positives de A sont avant ou après les transitions positives de B . Par contre, si on est un peu futé, on peut augmenter la résolution apparente par quatre en utilisant toutes les transitions.
Pour le moment, tout ça c'est de la théorie ... En effet les signaux A et B sont entachés par des rebonds au moment des transitions. Ces rebonds proviennent :
- Du contact électrique si celui-ci est fait par deux lamelles de cuivre
- De l'hésitation en rotation du codeur quand il y a des vibrations
La réalisation de la fonction de décodage avec des bascules et des circuits RC est vouée à l'échec et donne des montages qui tombent en marche . La seule solution valable est la méthode par échantillonnage. On regarde la valeur du signal et on la compare avec la valeur lue précédemment .
Pour qu'aucune transition utile ne soit perdue, il faut au moins un échantillon du signal pendant une période " stable ", donc une fréquence d'échantillonnage d'au moins 4 fois la fréquence maximum de sortie du codeur.
Par exemple :
- Codeur de 1024 pas qui tourne à 1000 tour/minute
- Fout= 1024*1000/60=17067 Hertz
- Féchantillonnage > 17067*4=68267 Hertz
Algorithme
Cela consiste à faire une machine d'état (en soft ou en Hard). En fonction des deux entrées lues et des deux entrées mémorisées, il y a 16 états ( dont 4 impossibles, on ne peut pas lire 01 et avoir en mémoire 10 par exemple). Et pour chaque état, une action à faire : compter, décompter ou ne rien faire
RéalisationCode:Etat précédent de AB =00 Etat lu de AB=01 Compte=+1 Etat précédent de AB =00 Etat lu de AB=00 Compte=0 Etat précédent de AB =00 Etat lu de AB=10 Compte=-1 Etat précédent de AB =01 Etat lu de AB=11 Compte=+1 Etat précédent de AB =01 Etat lu de AB=01 Compte=0 Etat précédent de AB =01 Etat lu de AB=00 Compte=-1 Etat précédent de AB =11 Etat lu de AB=10 Compte=+1 Etat précédent de AB =11 Etat lu de AB=11 Compte=0 Etat précédent de AB =11 Etat lu de AB=01 Compte=-1 Etat précédent de AB =10 Etat lu de AB=00 Compte=+1 Etat précédent de AB =10 Etat lu de AB=10 Compte=0 Etat précédent de AB =10 Etat lu de AB=11 Compte=-1
Il y a trois choix de technologie pour résoudre ce problème :NB : Certains automates programmables ont cette fonction dans leurs modules I/O
- Circuit spécialisé genre HCTL2000
- Circuit PAL genre GAL16V8
- Microcalculateur (si le Timer et le programme en interruption peut tourner assez vite)
Simulation
Le bon fonctionnement de l'algorithme est montré sur cette simulation qui utilise des bascules et des portes (l'équivalent d'un GAL16V8)
Programme pour microcalculateur
Notre ami Canaillou2k5 a utilisé cette algorithme pour programmer un PIC . Le but est d'utiliser un bouton rotatif codeur pour faire évoluer une variable entre 0 et 100
Comme je suis nul en programmation, j'hésite à donner un avis mais je pense que l'exécution serait plus rapide (mais le programme plus long en place mémoire) si on n'utilisait pas des procédures mais des macrosCode:unsigned char var_a=0, var_b=0, var=0; //variables globales void stockage() //stockage des anciennes valeurs { var_a=PIND.2; var_b=PIND.3; } void var_plus() //fonction incrémenter { if(var<100)var++; //on incrément si on est en dessous de la valeur maxi. stockage(); //stockage des anciennes valeurs } void var_moins() //fonction décrémenter { if(var>0)var--; //on décrément si on est au dessus de la valeur mini. stockage(); //stockage des anciennes valeurs } interrupt[14] void gray() // interruption sur compteur (toutes les 1,6ms) { if(var_a==0 && var_b==0) { if(PIND.2==0 && PIND.3==1)var_plus(); //fonction incrémenter else if(PIND.2==1 && PIND.3==0)var_moins(); //fonction décrémenter } else if(var_a==0 && var_b==1) { if(PIND.2==1 && PIND.3==1)var_plus(); else if(PIND.2==0 && PIND.3==0)var_moins(); } else if(var_a==1 && var_b==1) { if(PIND.2==1 && PIND.3==0)var_plus(); else if(PIND.2==0 && PIND.3==1)var_moins(); } else if(var_a==1 && var_b==0) { if(PIND.2==0 && PIND.3==0)var_plus(); else if(PIND.2==1 && PIND.3==1)var_moins(); } }
-----