Меню и Lcd шилд
- Войдите на сайт для отправки комментариев
Ср, 06/08/2014 - 13:11
Меню для дисплея 16х2 и кнопок на цифровых пинах работает.
Возникла необходимость сделать меню для кнопок на одном аналоговом пине. Пример работает.
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
int lcd_key = 0;
int adc_key_in = 0;
int adc_key_prev = 0;
void setup()
{
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print("Push A Button!");
lcd.setCursor(10,1);
lcd.print("A=");
}
void loop()
{
adc_key_prev = lcd_key ;
lcd_key = read_LCD_buttons();
if (adc_key_prev != lcd_key)
{
lcd.setCursor(12,1);
lcd.print(" ");
lcd.setCursor(12,1);
lcd.print(adc_key_in);
}
lcd.setCursor(0,1);
switch (lcd_key)
{
case btnRIGHT:
{
lcd.print("RIGHT ");
break;
}
case btnLEFT:
{
lcd.print("LEFT ");
break;
}
case btnUP:
{
lcd.print("UP ");
break;
}
case btnDOWN:
{
lcd.print("DOWN ");
break;
}
case btnSELECT:
{
lcd.print("SELECT");
break;
}
case btnNONE:
{
lcd.print("NONE ");
break;
}
}
}
int read_LCD_buttons()
{
adc_key_in = analogRead(0);
delay(5);
int k = (analogRead(0) - adc_key_in);
if (5 < abs(k)) return btnNONE;
if (adc_key_in > 1000) return btnNONE;
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE;
}
Зато теперь при попытке создать меню при нажатии кнопки (любой) сразу проскакивают все меню
case btnRIGHT:
{
if ( A == 10 || A == 15 || A == 20 )
A = A + 5;
break;
}
Как сделать, чтобы при нажатии кнопки выполнялось только одно действие.
прочитать прекрепленную тему про кнопки.
И подумать чем отличаются состояния и события.
СОСТОЯНИЯ кнопки: нажата, не нажата
и СОБЫТИЯ кнопки: нажатие кнопки, отпускание кнопки
Вналаче не на програмнном. Вначале на бытовом уровне нужно осозднать эту разницу. И как наблюдая за состояними, делать вывод о наступлении какого-то события.
На примере.
Предположим ваша жена каждое утро заглядывает вам в кошелек.
И может наблюдать два два СОСТОЯНИЯ кошелька:
1. "бабла немерянно"
2. и "в кармане вошь на аркане".
Каждое утро глядя в кошелек, она может сделать выводы о наступлении двух событий кошелька:
1. Была "получка"
2. Вчера все пробухал.
Как она делает подобные выводы? Какой цепочкой рассуждений?
Вот ваше read_lcd_button() - это чтение "состояний", а после вам "нужно подумать" и решить "какое событие наступило".
И бегать по меню, в соотвествии с событиями, а не состояними...
И, все-таки лучше с этим освоиться на основании одной кнопки. Цифровой. А уж потом браться за адаптацию под аналоговые кнопки.
Ввёл переменную для определения состояния кнопки - теперь работает как хотелось.
if (lcd_key == btnDOWN && flag == 0 ) { if ( A == 10 || A == 15 || A == 20 || A == 25) A = A + 5; flag = 1; } if (lcd_key == btnNONE ) { flag = 0; }leshak, спасибо.
Честно говоря, хоть в теме про кнопки и показан пример про с "flag" - мне не очень нравится он.
Вот когда читаешь такое код, то уследить за этими флагами (и не забыть их сбросить) - трудновато.
Да и вообще, само имя "flag" - слишком малоговорящие.
Вот если бы вы, все-таки с женой рассуждения привели, то у вас бы получилось что-то такое "если вчера (при прошлой проверке) кошелек был пустой, а сегодня - полный, то значит наступило событие "получка").
Значит нужно просто запоминать результаты проверки и тоже ими пользоваться при детектировании события.
Рассуждения вида "кнопка была не нажата, а теперь нажата" - IMHO как-то более органичны чем "кнопка нажата и флаг сброшен".
Все го-то и нужно, завести переменную prev_lcd_key и сохранять в нее, в конце loop() какай lcd_key был при этом проходе loop().
И тогда, сами "действия на события" не захламляются никакими flag=1, flag=0
Как так.... хотя. Стоп... вот хотел уже пример писать, но... у вас же изначально ужеть есть переменная adc_key_prev.
Только вот строчку
adc_key_prev=lcd_key; - я бы в конец loop() пихнул, как-то там оно "более интуитивно" (но с точки зрения работоспособности, и в начале, как у вас, все в порядке).
Значит переменная с "прошлым значением", у нас уже есть.
Значит осталось только условие "кнопка была не нажата, а теперь нажата" записать в виде кода. Практически дословно.
if(adc_key_prev== btnNONE && lcd_key==btnDOWN){ // была не нажата, а сейчас нажата вправо ..... что делать по нажатию кнопки.... }или, раз часть проверки adc_key_prev=btnNone у нас для всех кнопок одинакова, то можно "вынести ее за скобки", и воспользоваться вашим изначальным switch, просто обернув его в провеку, что "раньше кнопка была не нажата".
if(adc_key_prev==btnNONE){ // кнопка была не нажата) switch(lcd_key){ case btnRIGH: // а сейчас нажата "вправо" ...действие... break; case btnLEFT: // а сейчас нажата "влево" .... другие кнопки. } }Вообщем, как видите, размышления "на бытовом уровне", иногда, все-таки позволяет в итоге проще код писать.
Просто вначале "в голове уложить", а потом в код перевести.
Ещё раз спасибо за толковый и познавательный комменарий