Инкрементный Энкодер с кнопкой подключение к ATmega8

Статья о поворотном энкодере, который применяется в принтерах и мышках для компьютеров уже была.
Данная статья об инкрементном энкодере, который применяется во многих приборах. Инкрементный энкодер имеет три степени свободы:
1. Вращение влево,
2. Вращение вправо,
3. Кнопка.

Таким образом инкрементные энкодеры просто идеальны для организации одномерного циклического меню.
То есть пункты меню переключаются только на одном уровне и последний пункт после очередного поворота ручки энкодера замещается первым. Ярким примером служит применение инкрементного энкодера в автомагнитолах.

Выглядит энкодер как показано на рис. 1

инкрементный энкодер
Рис.1 инкрементный энкодер

Преимущества такого устройства перед обычными кнопка очевидны, минимум механических частей, высокое удобство пользования, отсутствие необходимости нажимать большое количество раз для достижения нужного пункта меню.

Внутри инкрементный энкодер состоит из двух пар контактов, которые при вращении вала энкодера замыкаются по определенному алгоритму, рис. 2
сигналы на выходе энкодера

Рис. 2 выходные сигналы на энкодере.

Таким образом для определения направления вращения, необходимо иметь информацию, какая пара контактов была замкнута первой. То есть при вращении влево замыкаются пары контактов №1 а потом №2, при вращении вправо происходит наоборот №2 а потом №1. Текст программы для определения направления вращения вала энкодера представлен ниже:

  1. #include <inttypes.h>
  2. #include <avr/io.h>
  3. #include <avr/interrupt.h>
  4. #include <avr/sleep.h>
  5.  
  6. #define nop() {asm("nop");}
  7.  
  8. void USART_Transmit( unsigned char data );
  9. void delay(int t);
  10.  
  11. int h=0,x;
  12.  
  13. // function delay
  14. void delay(int t)
  15. {for (x=t; x>0 ;x--) nop (); }
  16.  
  17. // --- Обработчик прерывания INT0
  18. SIGNAL(SIG_INTERRUPT0)
  19. {
  20. if((((PIND) & (1<<PD2)) == 0) ^ (((PIND) & (1<<PD4)) == 0))
  21. {
  22. h=h+1; if(h>7) {h=0x01;}
  23. USART_Transmit(h);
  24.  
  25. USART_Transmit(0x0d);
  26. USART_Transmit(0x0a);
  27. delay(5000);
  28. }
  29. else
  30. {
  31. h=h-1; if (h<1) {h=0x07;}
  32. USART_Transmit(h);
  33.  
  34. USART_Transmit(0x0d);
  35. USART_Transmit(0x0a);
  36. delay(5000);
  37. }
  38. }
  39.  
  40. SIGNAL(SIG_INTERRUPT1)
  41. {
  42. USART_Transmit('E');
  43. USART_Transmit('n');
  44. USART_Transmit('t');
  45. USART_Transmit('e');
  46. USART_Transmit('r');
  47.  
  48. USART_Transmit(0x0d);
  49. USART_Transmit(0x0a);
  50. delay(5000);
  51. }
  52.  
  53.  
  54. void USART_Transmit( unsigned char data ) //Функция отправки данных
  55. {
  56. while ( !(UCSRA & (1<<UDRE)) ); //Ожидание опустошения буфера приема
  57. UDR = data; //Начало передачи данных
  58. }
  59.  
  60. void USART_Init( unsigned int ubrr)
  61. {
  62. /* Set baud rate */
  63. UBRRH = (unsigned char)(ubrr>>8);
  64. UBRRL = (unsigned char)ubrr;
  65. /* Enable receiver and transmitter */
  66. UCSRB=(1<<RXEN)|(1<<TXEN);
  67. UCSRB |= (1 << RXCIE);
  68.  
  69. //UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
  70. /* Set frame format: 8data, 2stop bit */
  71. UCSRC=0x86;//
  72. UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
  73. }
  74.  
  75. int main (void)
  76. {
  77. // Конфигурирование порта D на вход
  78. DDRD = ~_BV(PD2) | ~_BV(PD3) | ~_BV(PD4); // - PD 2,3,4 на вход
  79. PORTD = _BV(PD2) | _BV(PD3) | _BV(PD4); // - Подтягивающие резисторы для PD 2,3,4
  80.  
  81. // Настройка прерывания INT0 по изменению состояния
  82. SREG|= (1<<7); //разрешаем общие прерывания
  83. GICR|=(1<<6); //разрешаем прерывание по INT0
  84. GICR|=(1<<7); //разрешаем прерывание по INT1
  85. MCUCR|=(1<<1); //прерывание по ниспадающему фронту сигнала на INT0
  86. MCUCR|=(1<<3); //прерывание по ниспадающему фронту сигнала на INT1
  87.  
  88. USART_Init (12);//19200 4mHz
  89.  
  90. USART_Transmit('!');
  91. USART_Transmit('O');
  92. USART_Transmit('k');
  93. USART_Transmit('!');
  94.  
  95. USART_Transmit(0x0d);
  96. USART_Transmit(0x0a);
  97.  
  98. while (1)
  99. {
  100. sleep_mode();
  101. }
  102. }

В программе так же обрабатывается нажатие кнопки на энкодере, то есть данную программу можно считать модулем, который можно внедрять в любые другие проекты, которые требуют органов управления.

Схема подключения энкодера к микроконтроллеру Atmega8 показана на рис. 3

схема подключения энкодера к atmega8
Рис. Схема подключения энкодера

Конденсаторы 0,1 мкФ
Коротко о схеме:
Наличие конденсаторов просто необходимо, они помогают уменьшить влияние переходных процессов при замыкании контактов энкодера и избавится от дребезга контактов. Для того чтобы при вращении на одно деление команда выполнялась не более одного раза, должны стоять конденсаторы обязательно.

Коротко о коде программы:
Я думаю все и так понятно благодаря комментариям, если возникнут вопросы - пишите комментарии.
Да, алгоритм программы следующий:
при вращении в какую-либо сторону программа отправляет по USART данные с указанием направления вращения. При нажатии на кнопку, выводится сообщение "Enter" по USART.

Скачать файл проекта

Видео работы, проект совмещает три проекта:
1. Работа с поворотным инкрементным энкодером,
2. Работа с ЖКИ от NOKIA 3310,
3. Древовидное меню для микроконтроллеров

Статья в стадии написания