Обработка четырех кнопок на ATmega8

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

В данном коде реализован опрос 4х кнопок, при желании можно увеличить их количество до 8(если использовать все вывода порта С).
Принцип работы программы:
Программа через определенное время постоянно выполняет прерывание по совпадению Таймера 0, то есть по прошествию определенного промежутка времени происходит прерывания по таймеру. В обработчике прерывания реализована проверка нажатой кнопки. Срабатывание на нажатие кнопки выполняется после отпускания кнопки, за этим следит определенная строка программы. Такой механизм позволяет уменьшить влияние дребезга контактов при нажатии на кнопку. После чего переменная принимает одно из 4х значений, проверка и сверка нажатой кнопки происходит в программе ifstatus();

Код программы представлен для микроконтроллера ATmega8

  1. #include <avr/io.h> //Библиотека ввода/вывода
  2. #include <avr/interrupt.h> //Библиотека прерываний
  3.  
  4. unsigned char status=0;
  5.  
  6. void pause (unsigned int a);
  7. void init_timer (void);
  8. void USART_Init( unsigned int ubrr);
  9. void USART_Transmit( unsigned char data );
  10.  
  11.  
  12. //Обработчик прерываний по срабатываю таймера 0
  13. ISR (TIMER0_OVF_vect)
  14. {
  15. if ((PINC&0x01)==0x00)
  16. {
  17. //Обработка нажатия кнопки
  18. pause(1000); //Пауза на 0.01С
  19. if ((PINC&0x01)==0x00) //Если нажата кнопка
  20. {
  21. while ((PINC&0x01)==0x00); //Пока нажата кнопка
  22. if (status==0)
  23. status=1; //Статус становится 1
  24. }
  25. }
  26. else
  27.  
  28. if ((PINC&0x02)==0x00)
  29. {
  30. pause(1000); //Пауза на 0.01С
  31. if ((PINC&0x02)==0x00) //Если нажата кнопка
  32. {
  33. while ((PINC&0x02)==0x00); //Пока нажата кнопка
  34. if (status==0)
  35. status=2; //Статус становится 1
  36. }
  37. }
  38. else
  39.  
  40. if ((PINC&0x04)==0x00)
  41. {
  42. pause(1000);
  43. if ((PINC&0x04)==0x00)
  44. {
  45. while ((PINC&0x04)==0x00);
  46. if (status==0)
  47. status=3;
  48. }
  49. }
  50. else
  51.  
  52. if ((PINC&0x08)==0x00)
  53. {
  54. pause(1000);
  55. if ((PINC&0x08)==0x00)
  56. {
  57. while ((PINC&0x08)==0x00);
  58. if (status==0)
  59. status=4;
  60. }
  61. }
  62. else
  63.  
  64. status=0; //В другом случаи ни одна кнопка не нажата
  65. TCNT0=0x00; //Обнуляем таймер счетчик 0
  66. TIFR=0x00; //Продолжаем ожидать нажатия
  67. return;
  68. }
  69.  
  70. //Программа задержки
  71. void pause (unsigned int a)
  72. {
  73. unsigned int i;
  74. for (i=a;i>0;i--);
  75. }
  76.  
  77. //Программа иницализации Таймера 0 0
  78. void init_timer (void)
  79. {
  80. TIMSK=(1<<TOIE0);
  81. TCCR0=(1<<CS00)|(1<<CS01)|(0<<CS02); //Делитель тактовой частоты на 64
  82. }
  83.  
  84. void USART_Init( unsigned int ubrr)
  85. {
  86. /* Set baud rate */
  87. UBRRH = (unsigned char)(ubrr>>8);
  88. UBRRL = (unsigned char)ubrr;
  89. /* Enable receiver and transmitter */
  90. UCSRB=(1<<RXEN)|(1<<TXEN);
  91. UCSRB |= (1 << RXCIE);
  92.  
  93. //UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
  94. /* Set frame format: 8data, 2stop bit */
  95. UCSRC=0x86;//
  96. UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
  97. }
  98.  
  99. //ПРограмма передачи данных по UART
  100. void USART_Transmit( unsigned char data )
  101. {
  102. while ( !(UCSRA & (1<<UDRE)) );
  103. UDR = data;
  104. }
  105.  
  106. //Программа определения и вывода нажатой кнопки
  107. void ifstatus(void)
  108. {
  109. if (status == 1)
  110. {USART_Transmit('1');
  111. USART_Transmit(0x0d);
  112. status=0;}
  113. else
  114. if (status == 2)
  115. {USART_Transmit('2');
  116. USART_Transmit(0x0d);
  117. status=0;}
  118.  
  119. if (status == 3)
  120. {USART_Transmit('3');
  121. USART_Transmit(0x0d);
  122. status=0;}
  123.  
  124. if (status == 4)
  125. {USART_Transmit('4');
  126. USART_Transmit(0x0d);
  127. status=0;}
  128.  
  129. }
  130.  
  131. int main(void)
  132. {
  133. DDRC=0x00; //Указываем направление работы порта С
  134. PORTC=0xFF; //Включаем подтягивающие резисторы
  135. init_timer(); //Инициализация Таймера 0 0
  136.  
  137. USART_Init (3);//115200 8MHz
  138.  
  139. USART_Transmit('O');
  140. USART_Transmit('k');
  141. USART_Transmit('!');
  142.  
  143. USART_Transmit(0x0d);
  144. USART_Transmit(0x0a);
  145.  
  146. sei(); //Разрешаем глобально прерывания
  147.  
  148. while(1) //Вечный цикл
  149. {
  150. cli(); //Запрещаем прерывания
  151. ifstatus(); //Проверяем какая кнопка была нажата
  152.  
  153. sei(); //Разрешаем опять прерывания
  154. pause(1000); //Пауза
  155. }
  156. return 1;
  157. }

Данный код успешно был применен мною в проекте совместно с дисплеем от NOKIA 3310, при помощи четырех кнопок я сделал рисовалку на графическом экране. Как видно на видео все работает, проблем нет абсолютно никаких.

Все вопросы в комментарии.