Menu Design For LCD

Hello, There !

In one of the my project i am trying to design Menu for Alphanumeric LCD 16x4 with 4-Push Button (NEXT,ENTER,PREVIOUS &BACK) using arduino mega-2560. Initially When I use +5V Logic At input of push button in circuit with same program everything is fine but now i want to change the logic according to project (Push button connected to --Ve logic) in that case Whenever I pressed NEXT button it perform PREVIOUS Button function and vice-versa for logic -ve at push button in circuit. can anyone suggest which changes required to get output correct? cicuit diagram

Source code:

#include <LiquidCrystal.h>

#define LCD_ROWS 4
#define LCD_COLS 16

void buf_locate(int, int);
void buf_char(char);
void buf_clear(void);
void lcd_refresh(void);
void buf_str(char *);
void buf_str_XY(int, int, char *);
void buf_int(int);
void buf_clear_menu(void);

char lcd_buf[LCD_ROWS][LCD_COLS];
char lcd_buf_old[LCD_ROWS][LCD_COLS];
int  lcd_buf_x, lcd_buf_y;

typedef struct menu_t
{
  const char * name;
  menu_t * next;
  menu_t * prev;
  menu_t * child;
  menu_t * parent;
  void (*menu_function)(void);
};

  menu_t menu1;
    menu_t sub_menu1_1;
    menu_t sub_menu1_2;
  
  menu_t menu2;
    menu_t sub_menu2_1; 
    menu_t sub_menu2_2;
  
  menu_t menu3;
    menu_t sub_menu3_1; 
  
  menu_t *currentPointer=&menu1;

  void menu_refresh(void);
  void menu_next(void);
  void menu_prev(void);
  void menu_enter(void);
  void menu_back(void);

  void key_next_press(void);
  void key_prev_press(void);
  void key_enter_press(void);
  void key_back_press(void);

  void (*key_next_func)(void) = &menu_next;
  void (*key_prev_func)(void) = &menu_prev;
  void (*key_enter_func)(void)= &menu_enter;
  void (*key_back_func)(void) = &menu_back;

  int menu_index=0;
  int lcd_row_pos=0;
  int lcd_row_pos_level_1=0, lcd_row_pos_level_2=0;

  void offset(void);void datum(void);
  void dateset(void);void timeset(void);
  void burst(void);

LiquidCrystal lcd(38,37,36,35,34,33);

void setup()
{
  menu1={ "CONFIGRATION", &menu2, &menu3, &sub_menu1_1, NULL, NULL }; // definition of menu components: (*name, *next, *prev, *child, *parent, (*menu_function))
    sub_menu1_1={ "Offset", &sub_menu1_2, &sub_menu1_2,NULL, &menu1, offset };
    sub_menu1_2= { "Data", NULL, &sub_menu1_1, NULL, &menu1,datum};
    
  menu2={ "DATE AND TIME", &menu3, &menu1, &sub_menu2_1, NULL, NULL };
    sub_menu2_1={ "Date", &sub_menu2_2, &sub_menu2_2, NULL, &menu2, dateset};
    sub_menu2_2={ "Time", NULL, &sub_menu2_1, NULL, &menu2, timeset};
    
  menu3={ "LOGGING", &menu1, &menu2, &sub_menu3_1, NULL,NULL};
    sub_menu3_1={ "Burst", NULL,&sub_menu3_1, NULL, &menu3,burst};
   

  lcd.begin(16, 4);
  lcd.setCursor(0,0);
  
  pinMode(47,INPUT);
  pinMode(46,INPUT);
  pinMode(45,INPUT);
  pinMode(44,INPUT);
  menu_refresh();
}

void loop() 
{
  key_next_press();
  delay(50);
  key_prev_press();
  delay(50);
  key_enter_press();
  delay(50);
  key_back_press();
  delay(50);
  lcd_refresh();
}

void menu_refresh(void) 
{
  menu_t *temp=NULL;
  int i;
  int center;
  for(int i=0;i<LCD_COLS;i++)
  {
    lcd_buf[0][i]='-';
  }
  
  if ((currentPointer->parent)!=NULL) 
  {
    temp = (currentPointer->parent)->child;
    center = ( LCD_COLS - (strlen((temp->parent)->name)) )>>1;
    buf_locate(center-1,0);
    buf_char(' ');
    buf_str((temp->parent)->name);
    buf_char(' ');
  }
  
  else 
  {
    temp = &menu1;
    center = (LCD_COLS - 4)>>1;
    buf_str_XY(center-1,0," MENU ");
  }
  
  for (i = 0; i != menu_index - lcd_row_pos; i++) 
  {
    temp = temp->next;
  }
  buf_clear_menu();
  
  for (i = 1; i < LCD_ROWS; i++) 
  {
    buf_locate(0, i);
    if (temp == currentPointer) 
      buf_char(62);
    else 
      buf_char(' ');
    buf_locate(2, i);
    buf_str(temp->name);
    temp = temp->next;
    if (!temp) 
      break;
  }
  // lcd_refresh();
}

int menu_get_index(menu_t *q) 
{
  menu_t *temp;
  int i = 0;
  if (q->parent) temp = (q->parent)->child;
  else temp = &menu1;
  while (temp != q) 
  {
  temp = temp->next;
  i++;
  }
  return i;
}

int menu_get_level(menu_t *q) 
{
  menu_t *temp = q;
  int i = 0;
  if (!q->parent) return 0;
  while (temp->parent != NULL) 
  {
    temp = temp->parent;
    i++;
  }
  return i;
}

void menu_next(void) 
{
  if (currentPointer->next)
  {
    currentPointer = currentPointer->next;
    menu_index++;
    if (++lcd_row_pos > LCD_ROWS - 2) 
      lcd_row_pos = LCD_ROWS - 2;
  }
  else
  {
    menu_index = 0;
    lcd_row_pos = 0;
    if (currentPointer->parent) currentPointer = (currentPointer->parent)->child;
    else currentPointer = &menu1;
  }
  menu_refresh();
}

void menu_prev(void) 
{
  currentPointer = currentPointer->prev;
  if (menu_index)
  {
    menu_index--;
    if (lcd_row_pos > 0) lcd_row_pos--;
  }
  else
  {
    menu_index = menu_get_index(currentPointer);
    if (menu_index >= LCD_ROWS - 2) lcd_row_pos = LCD_ROWS - 2;
    else lcd_row_pos = menu_index;
  }
  menu_refresh();
}

void menu_enter(void) 
{
  if (currentPointer->menu_function)
    currentPointer->menu_function();
  if (currentPointer->child)
  {
    switch (menu_get_level(currentPointer)) 
    {
      case 0:
        lcd_row_pos_level_1 = lcd_row_pos;
        break;
      case 1:
        lcd_row_pos_level_2 = lcd_row_pos;
        break;
    }
    // switch...case can be replaced by:
    // lcd_row_pos_level[ menu_get_level(currentPointer) ] = lcd_row_pos;
    menu_index = 0;
    lcd_row_pos = 0;
    currentPointer = currentPointer->child;
    menu_refresh();
  }
}

void menu_back(void) 
{
  if (currentPointer->parent) 
  {
    switch (menu_get_level(currentPointer)) 
    {
      case 1:
        lcd_row_pos = lcd_row_pos_level_1;
        break;
      case 2:
        lcd_row_pos = lcd_row_pos_level_2;
        break;
      }
    currentPointer = currentPointer->parent;
    menu_index = menu_get_index(currentPointer);
    menu_refresh();
  }
}

void buf_locate(int x, int y)
{
  lcd_buf_x = x;
  lcd_buf_y = y;
}

void buf_char(char c)
{
if (lcd_buf_x < LCD_COLS && lcd_buf_y < LCD_ROWS)
  {
    lcd_buf[lcd_buf_y][lcd_buf_x] = c;
    lcd_buf_x++;
    if (lcd_buf_x == LCD_COLS) 
    {
      lcd_buf_x = 0;
      lcd_buf_y++;
      if (lcd_buf_y == LCD_ROWS)
      lcd_buf_y = 0;
    }
  }
}

void buf_clear(void)
{
  for(int y=0; y<LCD_ROWS; y++)
  {
    for(int x=0; x<LCD_COLS; x++)
    {
      lcd_buf[y][x]=' ';
    }
  }
  lcd_buf_x=0; lcd_buf_y=0;
}

void buf_clear_menu(void)
{
  for(int y=1; y<LCD_ROWS; y++)
  {
    for(int x=0; x<LCD_COLS; x++)
    {
      lcd_buf[y][x]=' ';
    }
  }
  lcd_buf_x=0; lcd_buf_y=0;
}

void lcd_refresh(void)
{
  static int locate_flag = 0; // informs when lcd cursor position have to be changed
  for(int y=0; y<LCD_ROWS; y++)
  {
     lcd.setCursor( 0, y );
    for(int x=0; x<LCD_COLS; x++)
    {
      if( lcd_buf[y][x] != lcd_buf_old[y][x] )
      {
        if( !locate_flag )
        lcd.setCursor( x, y );
        lcd.print( lcd_buf[y][x] );
        lcd_buf_old[y][x] = lcd_buf[y][x];
        locate_flag = 1;
      }
      else
        locate_flag = 0;
    }
  }
}

// Additional function 
void buf_str(char *text)
{
  while(*text)
  buf_char(*text++);
}

void buf_str_XY(int x, int y, char *text)
{
  buf_locate(x,y);
  while(*text)
  buf_char(*text++);
}

void buf_int(int value)
{
  char string[5];
  itoa(value, string, 10);
  buf_str(string);
}

void key_next_press(void){
  int key_next_lock=0;
  if( !key_next_lock && (digitalRead(46)))
  {
   key_next_lock=1;
   if(key_next_func) 
   (*key_next_func)();
  } 
  else if(key_next_lock && !(digitalRead(46))) 
      key_next_lock++;
}

void key_prev_press(void)
{
  int key_prev_lock=0;
  if( !key_prev_lock && (digitalRead(45)))
  {
    key_prev_lock=1;
    if(key_prev_func) 
    (*key_prev_func)();
  } 
  else if( key_prev_lock && !(digitalRead(45))) 
       key_prev_lock++;
}

void key_enter_press(void)
{
  int key_enter_lock=0;
  if( !key_enter_lock && (digitalRead(47)))
  {
    key_enter_lock=1;
    if(key_enter_func) 
    (*key_enter_func)();
  } 
  else if( key_enter_lock && !(digitalRead(47))) 
      key_enter_lock++;
}

void key_back_press(void)
{
  int key_back_lock=0;
  if( !key_back_lock && (digitalRead(44)))
  {
    key_back_lock=1;
    if(key_back_func) 
    (*key_back_func)();
  } 
  else if( key_back_lock && !(digitalRead(44)))
      key_back_lock++;
}

void offset(void)
{
  buf_clear_menu(); 
}

void datum(void){}

void dateset(void){}

void timeset(void){}

void burst(void){}

now i want to change the logic according to project (Push button connected to --Ve logic)

Have you got pullup resistors on the inputs to hold them HIGH when not pressed ? If not, then consider using INPUT_PULLUP in pinMode() to activate the internal pullup resistors

You will, of course, need to change your wiring to take the inputs LOW (to GND) when the buttons are pressed and to reverse the logic of the tests for button presses to test for LOW to detect button presses

Something like this

  if ( !key_next_lock && (digitalRead(46) == LOW))

Already used pull-up resistor in circuit (as shown in attachment)

Which attachment ?

Print the values that you are testing. Are they what you expect ?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.