Меню и Lcd шилд

vvadim
Offline
Зарегистрирован: 23.05.2012

Меню для дисплея 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;
    }
Как сделать, чтобы при нажатии кнопки выполнялось  только одно действие.
leshak
Offline
Зарегистрирован: 29.09.2011

прочитать прекрепленную тему про кнопки.

leshak
Offline
Зарегистрирован: 29.09.2011

И подумать чем отличаются состояния и события.

СОСТОЯНИЯ кнопки: нажата, не нажата
и СОБЫТИЯ кнопки: нажатие кнопки, отпускание кнопки

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

На примере.
Предположим ваша жена каждое утро заглядывает вам в кошелек.
И может наблюдать два два СОСТОЯНИЯ кошелька:
1. "бабла немерянно"
2. и "в кармане вошь на аркане".

Каждое утро глядя в кошелек, она может сделать выводы о наступлении двух событий кошелька:
1. Была "получка"
2. Вчера все пробухал.

Как она делает подобные выводы? Какой цепочкой рассуждений?

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

И, все-таки лучше с этим освоиться на основании одной кнопки. Цифровой. А уж потом браться за адаптацию под аналоговые кнопки.

 

 

 

vvadim
Offline
Зарегистрирован: 23.05.2012

Ввёл переменную для определения состояния кнопки - теперь работает как хотелось. 

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, спасибо.

leshak
Offline
Зарегистрирован: 29.09.2011

Честно говоря, хоть в теме про кнопки и показан пример про с "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: // а сейчас нажата "влево"
      .... другие кнопки.
    }
}

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

vvadim
Offline
Зарегистрирован: 23.05.2012

Ещё раз спасибо за толковый и познавательный комменарий