Сделай Сам Свою Работу на 5

Не читает АЦП в подразделе меню.

Простое однострочное LCD меню для проектов с использованием Atmega8 и WH1602A

Написал extremist дата Пт, 07/23/2010 - 13:33

  • atmega8
  • key
  • WH1602A
  • меню

Для более наглядного отображения режима работы устройства на микроконтроллерах используют символьный ЖКИ типа WH1602A, вместо обычных светодиодов. В данной статье я расскажу как сделать не большое однострочное меню, названия пунктов которого будут выводиться на экран ЖКИ. Меню будет представлять из себя массив пунктов, которые при нажатии на кнопки "+" и "-" будут прокручиваться, тем самым запуская на выполнение необходимые программы.

В данном примере будет находиться всего 3 пункта: Menu1, Menu2 и Menu3. Так как это простенькое меню и его можно считать отправной точкой для дальнейших экспериментов, то сами названия меню буду не в переменных а задаваться именно при выведении на экран ЖКИ. В дальнейшем будем пробовать сделать массив из пунктов меню и чтобы не занимать лишнее место в ОЗУ микроконтроллера Atmega8 запишем эти переменные в память программ.

Так же советую установить параллельно кнопкам конденсаторы на 0?1vrA? для уменьшения влияния дребезга контактов на переключение пунктов меню.

Алгоритм программы довольно простой и я думаю интуитивно понятный, тем более программа содержит комментарии, по которым очень легко воссоздать алгоритм работы. Программа написана для микроконтроллера Atmega8, возможна переделка кода без потери функционала на микроконтроллер ATtiny2313. Схема подключения ЖКИ к микроконтроллеру взята из статьи о работе микроконтроллера и ЖКИ.

Первоначально кнопки планировалось подключать к выводам внешних прерываний INT0 и INT1, но в дальнейшем решили все таки оставить эти выводы как резерв и использовать выводы порта C для подключения кнопок. А саму программу обработки пунктов меню поместить в основной(вечный) цикл главной программы.

Собственно код программы однострочного меню:

1. #include <avr/io.h>//Стандартная библиотека ввода/вывода

2. #include <avr/interrupt.h>//Библиотека прерываний

3.

4. unsigned char mode=0;//Переменная пункта меню



5. int flag=0;//Флаг вывода на экран пункта меню

6.

7. #define RS 1 //Вывод RS ЖКИ на вывод PD1 МК

8. #define E 3 //Вывод E ЖКИ на вывод PD3 МК

9. #define TIME 10

10.

11.

12.//Прототипы функций

13.void lcd_init (void);//Инициализация ЖКИ

14.void lcd_dat (unsigned char lcd);//Программа записи данных в ЖКИ

15.void lcd_com (unsigned char lcd);//Программа записи комманд в ЖКИ

16.void pause (unsigned int a);//Переменная для программы задержки(паузы)

17.

18.

19.//Обработчик прерываний по таймеру 0

20.ISR(TIMER0_OVF_vect)

21.{

22.if ((PINC&0x00)==0x01)//Если низкий уровень на PC0 есть

23. {

24. pause(1000); //Ждем 0.01с

25. if ((PINC&0x00)==0x01)//Если низкий уровень на PC0 есть

26. {

27. while ((PINC&0x01)==0x00);//Ждем отжатия клавиши

28. mode=(mode+1)%3;//Меняем переменнюу пункта меню в +1

29. flag=0;//Меняем флаг на 0

30. }

31. TCNT0=0x00;//Очищаем счетчик таймера0

32. TIFR=0x00; //и флаг переполнения

33. }

34.

35.else //Если на PC0 нет низкого уровня

36.

37.if ((PINC&0x01)==0x00)//проверяем низкий уровень на PC1

38. {

39. pause(1000); //Если есть Ждем 0.01с

40. if ((PINC&0x01)==0x00) //проверяем низкий уровень на PC1 еще раз

41. {

42. while ((PINC&0x01)==0x00); //Ждем отжатия клавиши

43. mode=(mode-1)%3;////Меняем переменнюу пункта меню в -1

44. flag=0;//Меняем флаг на 0

45. }

46. TCNT0=0x00;//Очищаем счетчик таймера0

47. TIFR=0x00; //И флаг переполнения

48. }

49.return;

50.}

51.

52.//Программа вывода строки на ЖКИ

53.void lcd_string( char *s )

54.{

55.while( *s ) //цикл пока указатель существует

56.lcd_dat( *s++ ); //выводить строку

57.}

58.

59.//Функция задержки(паузы)

60.void pause (unsigned int a)

61.{

62.unsigned int i; //переменная для задержки

63.for (i=a;i>0;i--); //цикл задержки

64.}

65.

66.//Программа передачи комманды в ЖКИ

67.void lcd_com (unsigned char lcd)

68.{

69.unsigned char temp;

70.temp=(lcd&~(1<<RS))|(1<<E); //RS=0 – это команда

71.PORTD=temp; //Выводим на portD старшую тетраду команды, сигналы RS, E

72.asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации

73.

74.PORTD=temp&~(1<<E); //Сигнал записи команды

75.temp=((lcd*16)&~(1<<RS))|(1<<E); //RS=0 – это команда

76.PORTD=temp; //Выводим на portD старшую тетраду команды, сигналы RS, E

77.asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации

78.

79.PORTD=temp&~(1<<E); //Сигнал записи команды

80.pause (20*TIME); //Пауза для выполнения команды

81.}

82.

83.//Программа передачм данных в ЖКИ

84.void lcd_dat (unsigned char lcd)

85.{

86.unsigned char temp;

87.temp=(lcd|(1<<RS))|(1<<E); //RS=1 – это данные

88.PORTD=temp; //Выводим на portD старшую тетраду данных, сигналы RS, E

89.asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации

90.

91.PORTD=temp&~(1<<E); //Сигнал записи данных

92.temp=((lcd*16)|(1<<RS))|(1<<E); //RS=1 – это данные

93.PORTD=temp; //Выводим на portD старшую тетраду данных, сигналы RS, E

94.asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации

95.

96.PORTD=temp&~(1<<E); //Сигнал записи данных

97.pause(10*TIME); //Пауза для вывода данных

98.}

99.

100. ////Программа инициализации ЖКИ

101. void lcd_init (void)

102. {

103. lcd_com(0x2C); //4-проводный интерфейс, 5x8 размер символа

104. pause(200*TIME);//пауза на выполненеи комманды

105. lcd_com(0x0C); //Показать изображение, курсор не показывать

106. pause(200*TIME);//пауза на выполненеи комманды

107. lcd_com(0x01); //Очистить DDRAM и установить курсор на 0x00

108. pause (200*TIME);//пауза на выполненеи комманды

109. }

110.

111. //Программа инициализации таймера 0

112. void init_timer (void)

113. {

114. TIMSK=(1<<TOIE0); //Разрешить прерывания по переполнению таймера 0

115. TCCR0=(1<<CS00)|(1<<CS01)|(0<<CS02); //Делитель =/64

116. }

117.

118. //Программа обработки переменной меню

119. void menu(void)

120. {

121. if (mode==0)//Если переменная меню=0

122. {

123. if (flag==0)//Если флаг=0

124. {

125. lcd_com(0x80);//Чистим экран ЖКИ

126. lcd_string("<Menu1>");//Выводим название первого пункта меню 1

127. flag=1;//Переключаем флаг=1

128. }

129. }

130.

131. else //иначе

132.

133. if (mode==1)//Если переменная меню=1

134. {

135. if (flag==0)//Если флаг=0

136. {

137. lcd_com(0x80);//Чистим экран

138. lcd_string("<Menu2>");//Выводим название первого пункта меню 2

139. flag=1;//Переключаем флаг=1

140. }

141. }

142.

143. else //В любом другом случаи

144.

145. {

146. if (flag==0)//Если флаг=0

147. {

148. lcd_com(0x80);//Чистим экран ЖКИ

149. lcd_string("<Menu3>");//Выводим название первого пункта меню 3

150. flag=1;//Переключаем флаг=1

151. }

152. }

153. }

154.

155. //Основная программа

156. int main(void)

157. {

158. /////////////Конфигурируем порты МК////////////////

159. DDRD=0xFA; //PD0,PD2 как входа, остальные - выхода

160. PORTD=0x05;//Выводим на порт D = 000000101

161.

162. DDRC=0x00;//Весь порт C как вход

163. PORTC=0xFF;//Включаем подтягивающие резисторы

164. ///////////////////////////////////////////////////

165.

166. pause(3000); //Задержка для включения ЖКИ

167. lcd_init(); //Инициализация ЖКИ

168. pause(3000); //Задержка для включения ЖКИ

169.

170. init_timer();//Инициализация таймера 0

171.

172. sei();//Глобально разрешаем прерывания

173.

174. while(1)//Вечный цикл

175. {

176. menu();//Запуск обработки пунктов меню

177. }

178. }

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

1. if (mode==0)//Если переменная меню=02. { 3. if (flag==0)//Если флаг=04. {5. lcd_com(0x80);//Чистим экран ЖКИ6. lcd_string("<Menu1>");//Выводим название первого пункта меню 17. flag=1;//Переключаем флаг=18. /////////////////////////////////////9. Programm_1();//Программа которая выполняется в пункте меню 110. /////////////////////////////////////11. }12. }


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

Программа рассчитана на работу от внешнего кварцевого генератора на частоте 4МГц, в принципе по желанию можно свободно перевести МК на работу от внутреннего генератора.

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

Видео работы программы:

На момент написания статьи Я не знал о конструкции switch по сему придумывал велосипед.
На данный момент наилучший результат показало меню на конструкции switch, про него расскажу в одной из статей немного позже.

»

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

не читает АЦП в подразделе меню.

Опубликовано Anonymous в Чт., 09/08/2011 - 19:33.

Вот такая вот проблема. Переделал немного твой код - переключение меню по прерыванию от кнопки на INT2. Из кода видно что меню с вложенной программой находится в цикле while (1), но обновляться почему-то совсем не желает, однако если "прогнать" меню по кругу и вернуться к п. 1 то показания меняются.. Код выкладываю собсно...

1. void lcd_init (void) // инициализация ЖКИ2. {lcd_command(0x2c);3. delay (1000);4. lcd_command(0x0c);5. delay (1000);6. lcd_command(0x01);7. delay (1000);}8. 9. void clean_lcd (void) // очистка ЖКИ10. {lcd_command(0x01);}11. 12. ISR (INT2_vect) // обработчик прерывания по нажатию кнопки13. {if (mode++ == 2) mode=0; // инкремент индекса меню, если ==2, то сбрасываем в 014. flag=0; // разрешаем флаг записи15. GIFR=0x00; // сбрасываем флаг прерывания16. return;} 17. unsigned int ADC_read (void) // чтение регисра АЦП18. { unsigned int v;19. ADCSRA|=(1<<ADSC);20. while ((ADCSRA&_BV(ADIF))==0x00);21. v=(ADCL|ADCH<<8);22. return v;}23. 24. void write_adc (unsigned int u) // функция записи результата АЦП (пока)25. { lcd_command(0xC0); // перевод на 2ю строку26. unsigned int j; // переменная27. j=u/1000; // вычисляем тысячи28. if (j==0)29. {30. lcd_data(' '); // если 0 то пришем пусто31. } 32. else{33. lcd_data(0x30+j); // если нет, то 0+j34. }35. u=u-j*1000; // остаток сотен36. j=u/100; // вычисляем...37. lcd_data(0x30+j); // то же самое и так до едениц38. u=u-j*100;39. j=u/10;40. lcd_data(0x30+j);41. u=u-j*10;42. j=u;43. lcd_data(0x30+j);44. }45. void menu(void) // функция меню46.{47. if (mode==0) // если индекс == 048. {if (flag==0) // и запись разрешена49. {clean_lcd(); // чистим ЖКИ50. lcd_data('1'); // пишем "1."51. lcd_data('.'); 52. flag=1; // запрещяем инкремент индекса на всякий случай53. write_adc(u); // пишем в 1м разделе меню рез-т АЦП54. }55. }56. else57. if (mode==1) // тоже самое, но п. "2."58. {if (flag==0)59. {clean_lcd();60. lcd_data('2');61. lcd_data('.');62. flag=1;63. }64. }65. else66. if (mode==2) // тоже самое, но п. "3."67. {if (flag==0)68. {clean_lcd();69. lcd_data('3');70. lcd_data('.');71. flag=1;72. }73. 74. } 75. } 76. 77.int main(void)78.{79.DDRB&=~(1<<2); 80.PORTB=0x04;81.DDRC|=0xfc;82.delay(3000);83.lcd_init();84. 85.GICR|=(1<<INT2); // разрешить прерывания от INT286.ADCSRA=(1<<ADEN)|(1<<ADPS2)|(0<<ADPS1)|(1<<ADPS0); // ВКЛ АЦП87.ADMUX=(1<<REFS1)|(1<<REFS0)|(0<<MUX0)|(0<<MUX1)|(0<<MUX2)|(0<<MUX3); // настраиваем АЦП...88.sei();89. 90. while(1)91. { u=ADC_read(); // бесконечно преобразуем и пишем в меню92. menu();93. delay(6000);94. }95.}

»

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

Прошил программу, собрал

Опубликовано Anonymous в Ср, 05/18/2011 - 16:51.

Прошил программу, собрал схему, при включении запускается тест-программа ЖКИ (верхняя строка горит, нижняя нет) и все. Может подключил чего не так?
PC0 - кнопка +
PC1 - кнопка -
PD1 - RS
PD3 - E
PD4 - DB4
PD5 - DB5
PD6 - DB6
PD7 - DB7
Питание и контрастность ЖКИ подключены правильно, W/R - на землю.

»

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

А какой кварц стоит? Или

Опубликовано extremist в Ср, 05/18/2011 - 21:19.

А какой кварц стоит? Или какая частота внутреннего если от внутреннего генератора тактируешь?

»

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

Внутренний генератор,

Опубликовано Anonymous в Чт., 05/19/2011 - 07:09.

Внутренний генератор, прошивал как при 2,4 и 8 МГц.
ЖКИ у меня RC1602A.

»

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

Дело в том что программа

Опубликовано extremist в Чт., 05/19/2011 - 11:25.

Дело в том что программа написана под ЖКИ WH1602 я не знаю что там с твоим ЖКИ но возможной проблемой работы устрйоства может быть разное время инициализации и выполнения команд индикатором. Попробуй поиграться с задержками в библиотеке работы с ЖКИ, а именно с теми, что касаются инициализации и паузы после отправки команды в ЖКИ. Попробуй увеличить их!

»

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

Как вывести кириллицу?

Опубликовано Anonymous в Вт, 01/18/2011 - 00:15.

Как вывести кириллицу?

»

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

Вместо 'a','б','ф','ц' пиши

Опубликовано vakula в Вт, 01/18/2011 - 09:57.

Вместо 'a','б','ф','ц' пиши коды кириллических букв:
Таблица кодов

»



©2015- 2019 stydopedia.ru Все материалы защищены законодательством РФ.