Encodeur rotatif digital sur ATmega8

Ce type de composant est extrêmement utile pour incrémenter un nombre, une fréquence par exemple, en tournant un simple bouton. Son utilisation est très agréable puisqu'on sent les pas du bout des doigts, sans devoir pour autant forcer comme un malade. Le temps de réaction est rapide et le résultat est fiable. (On peut compter les coups et... ça suit). Quant au prix, ce qui était du luxe dans les années 70 est devenu très abordable (10 encodeurs pour 4€ en 2014 !). Le seul inconvénient était de nécessiter un microcontrôleur et de savoir le programmer. Et c'est ce dernier point que je vous offre ici.

1 La bestiole vue de près :

Le codeur est pourvu de 5 pattes. Le groupe de 3 sert à l'encodage digital en code Gray. Le deux autres situés au premier plan correspondent à un simple bouton poussoir qui se ferme lorsqu'on pousse sur l'axe.

2 Le schéma :

Les deux condensateurs de 10nF servent à éliminer les "rebondissements".

3 Le principe :

codeur incrémental code Gray avec en plus fonction bouton poussoir
le codeur rotatif utilisé est toujours à 11 en position stable
dans le sens CW il fait 11->01->00->10->11
et par conséquent dans le sens CCW il fait 11->10->00->01->11


11
01
00
10
11


Il suffit de connecter un bit sur le pin INT0 (PD2) et de déclencher l'INT (interruption logicielle) sur front descendant (passage de 0 à 1) Cette INT lira alors l'état de l'autre bit (connecté à PD0 par exemple). Cet état diffère suivant le sens de rotation. L'INT incrémentera ou décrémentera le nombre à piloter en fonction de cet état.

4 Le programme pour un ATmega8

CODE SOURCE en langage C
  1. /*==============================================================================
  2. par Silicium628
  3. derniere mise à jour 18 aout 2014
  4. ================================================================================
  5. ATmega8
  6. Generateur HF 200MHz - DDS AD9951 et ATmega8
  7. -Affichage LCD 2 x 16 caractères
  8. ================================================================================
  9.  
  10.  
  11. */
  12.  
  13.  
  14. #define F_CPU 16000000
  15.  
  16. #include <avr/io.h>
  17. #include <avr/interrupt.h>
  18. #include <util/delay.h>
  19.  
  20. #include "dm_lcd.c" // l'attribution des pins/ports pour le LCD (et le type de LCD) est faite dans le fichier "dm_lcd.h"
  21.  
  22. #define bouton_L 0b00000001
  23. // #define bouton_U 0b00000010
  24. // #define bouton_D 0b00000100
  25. #define bouton_R 0b00001000
  26.  
  27.  
  28. char * version = "1.0";
  29.  
  30.  
  31. uint16_t valeur16b;
  32. uint16_t frequence;
  33.  
  34. uint8_t pos;
  35. uint8_t pos_curseur;
  36.  
  37. uint8_t etat;
  38. uint16_t compteur1;
  39.  
  40.  
  41.  
  42.  
  43. void init_ports (void) // ports perso
  44. // 0 = entree, 1=sortie ; les 1 sur les pins en entrees activent les R de Pull Up (tirage à VCC)
  45. {
  46. DDRB |= 0b11111111; // portB[1] = sortie (OC1A = sortie PWM 16 bits du timer1)
  47. PORTB = 0b00000000;
  48.  
  49. DDRC = 0b11111111;
  50. PORTC = 0b00000000;
  51.  
  52. DDRD = 0b11111010; // portD[0] entrée codeur_ROT ; portD[2] entee INT0
  53. PORTD = 0b00000101;
  54. }
  55.  
  56.  
  57. void InitADC (void)
  58. {
  59. ADCSRA = _BV(ADEN) | _BV(ADPS2); // Activate ADC with Prescaler 16 --> 1Mhz/16 = 62.5kHz
  60. ADMUX |= 0b11000101; //Bit 7:6 – REFS1:0: ADC Reference Selection Bits =11 -> Internal 2.56V Voltage Reference with external capacitor at AREF pin ; Bits 0:3 - Analog Channel Selection Bits
  61. // ici Select pin ADC5 using MUX avec ref tension interne = 2.56V
  62.  
  63. }
  64.  
  65.  
  66. void InitINTs (void)
  67. {
  68. GICR |= 0b01000000; // gere les INTs - bit9 ->INT0 request - voir page 67 du pdf
  69. MCUCR |= 0b00000010; // The falling edge of INT0 generates an interrupt request. p:67 du pdf
  70. }
  71.  
  72.  
  73.  
  74. void init_variables(void)
  75. {
  76.  
  77. frequence = 1000;
  78.  
  79. }
  80.  
  81. /************************
  82. // traitement du codeur_rot()
  83.  
  84. // codeur incrémental code Gray avec en plus fonction bouton poussoir
  85. // le codeur rotatif utilisé est toujours à 11 en position stable
  86. // dans le sens CW il fait 11->01->00->10->11
  87. // et par conséquent dans le sens CCW il fait 11->10->00->01->11
  88.  
  89. // 11
  90. // 01
  91. // 00
  92. // 10
  93. // 11
  94.  
  95. // il suffit de connecter un bit sur le pin INT0 (PD2) et de déclencher l'INT sur front descendant (passage de 0 à 1)
  96. // cette INT lira alors l'état de l'autre bit (connecté à PD0 par exemple). Cet état diffère suivant le sens de rotation
  97.  
  98. *************************/
  99.  
  100.  
  101. ISR(BADISR_vect)
  102. {
  103. // évite de planter si une int est enable et pas de procedure associée écrite (ce qui fait reseter l'ATmega)
  104. }
  105.  
  106.  
  107. ISR (INT0_vect)
  108. {
  109. //interruption sur front descendant sur l'entree Int0
  110. // declenchee par la rotation du codeur_ROT
  111.  
  112. etat = PIND & 0b00000001;
  113. if (etat == 0) { frequence ++;} else {frequence--;}
  114.  
  115. }
  116.  
  117.  
  118.  
  119.  
  120. void lcd_gotoxy_clrEOL (int x, int y)
  121. // place le curseur en x,y et efface jusqu'a la fin de la ligne
  122. {
  123. lcd_gotoxy(x, y);
  124. uint8_t i;
  125. for (i=x; i<20; i++)
  126. { lcd_puts(" "); }
  127. lcd_gotoxy(x, y);
  128. }
  129.  
  130.  
  131.  
  132. void lcd_aff_nb (uint16_t valeur, uint8_t nb_chiffres, uint8_t nb_decimales)
  133. {
  134. //affiche un nombre en representation decimale
  135. unsigned char r ;
  136. char tbl[7];
  137. uint8_t i;
  138.  
  139. for (i=1; i<=nb_chiffres; i++)
  140. {
  141. r=48 + valeur % 10; // modulo (reste de la division)
  142. valeur /= 10; // quotient
  143. tbl[i]=r;
  144. }
  145. for (i=1; i<=nb_chiffres; i++)
  146. {
  147. if (i== (nb_chiffres - nb_decimales +1) ) { lcd_puts("."); }
  148. lcd_putc(tbl[nb_chiffres +1 -i]);
  149. }
  150. }
  151.  
  152.  
  153.  
  154. void lcd_aff_bin (unsigned long int valeur, int nb_digits)
  155. {
  156. //affiche un nombre en representation binaire
  157. // 16 bits max
  158. unsigned char r ;
  159. char tbl[17];
  160. uint8_t i;
  161.  
  162. for (i=1; i<=nb_digits; i++)
  163. {
  164. r= 48 + valeur % 2; // modulo (reste de la division)
  165. valeur /= 2; // quotient
  166. tbl[i]=r;
  167. };
  168.  
  169. for (i=1; i<=nb_digits; i++)
  170. {
  171. lcd_putc(tbl[nb_digits +1 -i]);
  172. }
  173. }
  174.  
  175.  
  176. void affiche_frequence()
  177. {
  178. lcd_gotoxy_clrEOL (0, 1);
  179. lcd_aff_nb (frequence, 5, 0);
  180.  
  181. }
  182.  
  183.  
  184.  
  185. /*
  186. void test_codeur_rot()
  187. {
  188. // pour test des états (diffèrent suivant modèles) du codeur rotatif pas à pas code gray
  189. // le mien est toujours à 11 en position stable
  190. // dans le sens CW il fait 11->01->00->10->11
  191. // et par conséquent dans le sens CCW il fait 11->10->00->01->11
  192. lcd_clrscr();
  193. while (1)
  194. {
  195. code_rot = PIND & 0b00000011;
  196. lcd_gotoxy(0,0);
  197. lcd_aff_bin (code_rot, 2);
  198. _delay_ms(10);
  199. }
  200. }
  201. */
  202.  
  203.  
  204.  
  205. int main (void)
  206. {
  207. init_variables();
  208. init_ports();
  209. InitINTs();
  210.  
  211. // InitADC();
  212.  
  213. lcd_init(LCD_DISP_ON_CURSOR);
  214. lcd_clrscr();
  215. lcd_home();
  216. lcd_puts("GeneHF AD9951");
  217. lcd_gotoxy(0,1);
  218. lcd_puts("version ");
  219. lcd_puts(version);
  220.  
  221. _delay_ms(1000);
  222.  
  223. //lcd_clrscr();
  224.  
  225. sei();
  226.  
  227.  
  228. while(1)
  229. {
  230. compteur1++;
  231. if (compteur1 >= 10000)
  232. {
  233. affiche_frequence();
  234. compteur1=0;
  235. }
  236.  
  237. _delay_us(10);
  238. }
  239.  
  240. }
  241.  
  242.  

5 -

Tout le traitement tient en deux lignes, celles de l'interruption INT0 ! Si vous êtes attentifs aux détails, vous savez maintenant sur quoi je travaille actuellement ! Mais chut ! Je publierai ça prochainement sur ce site lorsque... j'aurai reçu le composant AD9951 en question.

6 -



10182