Go Down

Topic: Help with basic LCD menu (Read 2 times) previous topic - next topic

SXRguyinMA

I've searched and searched and can't seem to find exactly what I'm looking for. I want to create a basic menu (if you can even call it that) for my LCD display with just a single button to change the menus, and up/down buttons for fan speeds (that'll be controlled only when that fan's menu is displayed). Here's how I want it to go:

Welcome screen
(on power-up)
     |
     |
Display 1
(coolant temp/flow rate)
     |
     |
Display 2
(Intake fan speed/voltage)
     |
     |
Display 3
(Exhaust fan 1 speed/voltage)
     |
     |
Display 5
(Exhaust fan 2 speed/voltage)
     |
     |
Back to display 1 and so on

There will also be a button-controlled servo to open and close a door but that will be independent of the menu system and not displayed.

Obviously I need 5 interrupts (flow meter, fan 1, fan 2, fan 3, servo button) and only have 2, which is why I'm going to use a ChipKIT MAX32 which has 5 interrupts and plenty of I/O for controlling fan speeds, etc. so that problem it solved.

I've got each system (except fan speed control) working independently with separate coding and each works fine (temp/flow works fine, fan speed display works fine). I just can't figure out how to merge them all together into a single working unit. I've seen several different menu libraries but they seem way more complex than what I need. I was thinking button state change or something but can't figure out how to get it all working properly.

What's the best way to go about that?
http://www.computersandcircuits.com

liudr

You just need a user interface to adjust parameters. For simplicity, such as maybe 3 lines per parameter adjustment, you can get the phi-panel:

http://www.inmojo.com/store/liudr-arduino-and-physics-gadgets/item/serial-lcd-back-pack---phi-panel/

Then the menu will be like

case 'U':
if (speed<max_speed) speed+=speed_increment;
//update serial lcd
break;

case 'D':
if (speed>minspeed) speed-=speed_increment;
//update serial lcd
break;

Khalid

#2
Dec 10, 2012, 03:56 pm Last Edit: Dec 10, 2012, 03:58 pm by Khalid Reason: 1
Look this thread and especially the end of pages  and you will find no menu easier than it.This is called MENWIZ by brunialti... Its brilliant, easy and cover almost all the things in a very easy way. Dont forget to read the pdf guide.:)
http://arduino.cc/forum/index.php/topic,99693.0.html
Simply...You can't afford me..

Author Of:
http://my-woodcarving.blogspot.com/
http://www.free3dscans.blogspot.com/
http://my-diysolarwind.blogspot.com/

Oops..some one gave me Karma...:)

liudr


Look this thread and especially the end of pages  and you will find no menu easier than it.This is called MENWIZ by brunialti... Its brilliant, easy and cover almost all the things in a very easy way. Dont forget to read the pdf guide.:)
http://arduino.cc/forum/index.php/topic,99693.0.html


Yes it is good but what you view as easy maybe hard to those beginners. If you have found my phi-panels, you will take back the "find no menu easier than it" statement.

Khalid

liudr,
I downloaded your phi library but it was difficult to understand, its not your fault, but i have less brain power.. I really like the videos you posted about your library but its difficult to find simple examples using Analoge button and 3wire lcds...
Is their any, pls point out.
Simply...You can't afford me..

Author Of:
http://my-woodcarving.blogspot.com/
http://www.free3dscans.blogspot.com/
http://my-diysolarwind.blogspot.com/

Oops..some one gave me Karma...:)

liudr


liudr,
I downloaded your phi library but it was difficult to understand, its not your fault, but i have less brain power.. I really like the videos you posted about your library but its difficult to find simple examples using Analoge button and 3wire lcds...
Is their any, pls point out.


Khalid, there are two things I provide that does menus:
1) phi_prompt library and its support library. They run with most types of inputs and HD44780 LCD. The setup part is a bit hard but my new version will provide simple setup functions.
2) phi-panel serial lcd panels or backpacks. These are hardware I designed and are already set up to run some of the phi_prompt menu functions. You simply send out a plain text to these panels through serial port with a command. The panels render the menu and interacts with users then return to you what the user selects.

I was referring to solution 2 for the OP.

Khalid

both the options require custom hardware which i have to purchase with the high shipment. ^_^
Simply...You can't afford me..

Author Of:
http://my-woodcarving.blogspot.com/
http://www.free3dscans.blogspot.com/
http://my-diysolarwind.blogspot.com/

Oops..some one gave me Karma...:)

dhenry

Quote
What's the best way to go about that?


It is fairly simple:

Code: [Select]

  button=read_button(button_pin); //read button on button_pin
  switch (button) {
  case 'U': //up button is pressed
     app_index = (app_index)?(app_index-1):MAX_APP; //update app_index
     break;
  case 'D': //down button is pressed
     app_index = (app_index==MAX_APP)?0:(app_index+1_; //update app_index
     break;
  default: do_something(); //illegal key press. do something / nothing
  }

  switch (app_index) {
  case 0: app0(); //run 1st application
             break;
  case 1: app1(); //run 2nd application
             break;
  ...
  }


You can start to fill the various boxes / functions. For example, if you use analog buttons, you just need to implement it in read_button(); and you can put your coolant / flowrate display in app0(); your fan speed/voltage in app1(); ...

It cannot be simpler than that, once you cut it down to logical blocks and implement those blocks one at a time.

liudr


both the options require custom hardware which i have to purchase with the high shipment. ^_^

Option one is free. just get an hd44780 display and a few buttons. If you think $6 is expensive for international shipping, FYI shipping to Australia or Europe is almost $6 plus bubble wrap and time.

SXRguyinMA


Quote
What's the best way to go about that?


It is fairly simple:

Code: [Select]

  button=read_button(button_pin); //read button on button_pin
  switch (button) {
  case 'U': //up button is pressed
     app_index = (app_index)?(app_index-1):MAX_APP; //update app_index
     break;
  case 'D': //down button is pressed
     app_index = (app_index==MAX_APP)?0:(app_index+1_; //update app_index
     break;
  default: do_something(); //illegal key press. do something / nothing
  }

  switch (app_index) {
  case 0: app0(); //run 1st application
             break;
  case 1: app1(); //run 2nd application
             break;
  ...
  }


You can start to fill the various boxes / functions. For example, if you use analog buttons, you just need to implement it in read_button(); and you can put your coolant / flowrate display in app0(); your fan speed/voltage in app1(); ...

It cannot be simpler than that, once you cut it down to logical blocks and implement those blocks one at a time.



ok so where exactly do I put my functions? do I put it in app0(xxxx);?
http://www.computersandcircuits.com

liudr

That code is a snippet, i.e. not complete. You complete it. Yes that was what dhenry meant.

SXRguyinMA


That code is a snippet, i.e. not complete. You complete it. Yes that was what dhenry meant.


I know it's just a snippet I'm just lost as to where to put my actual analogRead etc etc in the snippet
http://www.computersandcircuits.com

SXRguyinMA

Here's what I've got so far. It works as is with the commented-out lines (kinda - I can't get the % to display if it's showing 100). Am I on the right track?

Code: [Select]
#include <LiquidCrystal.h>
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);

const int buttonPin = 11;
const int potPin = A0;
const int tempPin = A1;
const int fan = 10;
const int buttonMin = 0;
const int buttonMax = 1;
int buttonState;
int lastButtonState = LOW;
long lastDebounceTime = 0;
long debounceDelay = 50;

void setup(){
  pinMode(buttonPin, INPUT);
  pinMode(potPin, INPUT);
  pinMode(tempPin, INPUT);
  pinMode(fan, OUTPUT);
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print(" Project:    ");
  lcd.setCursor(0, 1);
  lcd.print("    Circuit Box ");
  delay(5000);
  lcd.clear();
}

void loop(){
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    buttonState = reading;
  }
  //int range = map(reading, buttonMin, buttonMax, 0, 1); //Map the range to 2 options
//  switch (range) {
  //  case '0': // Manual Mode
      lcd.setCursor(0, 0);
      lcd.print("  Manual Mode   ");
      int fanSpeed = analogRead(potPin);
      fanSpeed = map(fanSpeed, 0, 1023, 120, 255);
      int  fanpct = map(fanSpeed, 120, 254, 40, 100);
      lcd.setCursor(0, 1);
      lcd.print("Fan Speed:");
      lcd.setCursor(11, 1);
      lcd.print(fanpct);
      if (fanpct < 100) lcd.print ('%');
  //    lcd.setCursor(14, 1);
//      lcd.print("%");
      analogWrite(fan, fanSpeed);
/*      break;
    case '1': // Automatic Mode
      lcd.setCursor(0, 0);
      lcd.print(" Automatic Mode ");
      int
      break;
    }
    delay(1);
}

  lcd.setCursor(0, 0);
  lcd.print("  Manual Mode   ");
  int fanSpeed = analogRead(potPin);
  fanSpeed = map(fanSpeed, 0, 1023, 120, 255);
  int  fanpct = map(fanSpeed, 120, 255, 40, 100);
  lcd.setCursor(0, 1);
  lcd.print("Fan Speed:");
  lcd.setCursor(14, 1);
  lcd.print("%");
  analogWrite(fan, fanSpeed); */
}
http://www.computersandcircuits.com

Nick Gammon

I'm confused by dhenry's answer.

Your original question was how to show 5 screens by pushing one button?

This shows the general idea. It outputs to serial so you can test by just grounding pin 8 (to act as your switch).

Code: [Select]

const byte mySwitch = 8; 

// these "states" are what screen is currently being displayed.
typedef enum
  {
  POWER_ON, COOLANT, INTAKE_SPEED, EXHAUST_FAN1, EXHAUST_FAN2,
  // add more here ...
 
  LAST_STATE  // have this last
  } states;

byte state = POWER_ON;

byte oldSwitch = HIGH;

void powerOn ()
  {
  Serial.println ("Welcome!");
  }

void showCoolant ()
  {
  Serial.println ("Coolant level = x");
  }
 
void showIntakeSpeed ()
  {
  Serial.println ("Intake speed = x");
  }
 
void showExhaustFan1 ()
  {
  Serial.println ("Exhaust Fan 1 = x");
  }
 
void showExhaustFan2 ()
  {
  Serial.println ("Exhaust Fan 2 = x");
  }
 
void setup ()
  {
  pinMode (mySwitch, INPUT_PULLUP);
  Serial.begin (115200);
  powerOn ();
  }  // end of setup
 
void loop ()
  {
  byte switchValue = digitalRead (mySwitch);
 
  // detect switch presses
  if (switchValue != oldSwitch)
    {
    delay (100);   // debounce

    // was it pressed?
    if (switchValue == LOW)
      {
      state++;      // next state
      if (state >= LAST_STATE)
        state = COOLANT; 
     
      switch (state)
        {
        case POWER_ON:     powerOn ();         break;
        case COOLANT:      showCoolant ();     break;
        case INTAKE_SPEED: showIntakeSpeed (); break;
        case EXHAUST_FAN1: showExhaustFan1 (); break;
        case EXHAUST_FAN2: showExhaustFan2 (); break;
        }  // end of switch
      }  // end of switch being pressed
     
    oldSwitch = switchValue; 
    } // end of switch changing state
   
  }  // end of loop
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

SXRguyinMA


I'm confused by dhenry's answer.

Your original question was how to show 5 screens by pushing one button?

This shows the general idea. It outputs to serial so you can test by just grounding pin 8 (to act as your switch).

Code: [Select]

const byte mySwitch = 8; 

// these "states" are what screen is currently being displayed.
typedef enum
  {
  POWER_ON, COOLANT, INTAKE_SPEED, EXHAUST_FAN1, EXHAUST_FAN2,
  // add more here ...
 
  LAST_STATE  // have this last
  } states;

byte state = POWER_ON;

byte oldSwitch = HIGH;

void powerOn ()
  {
  Serial.println ("Welcome!");
  }

void showCoolant ()
  {
  Serial.println ("Coolant level = x");
  }
 
void showIntakeSpeed ()
  {
  Serial.println ("Intake speed = x");
  }
 
void showExhaustFan1 ()
  {
  Serial.println ("Exhaust Fan 1 = x");
  }
 
void showExhaustFan2 ()
  {
  Serial.println ("Exhaust Fan 2 = x");
  }
 
void setup ()
  {
  pinMode (mySwitch, INPUT_PULLUP);
  Serial.begin (115200);
  powerOn ();
  }  // end of setup
 
void loop ()
  {
  byte switchValue = digitalRead (mySwitch);
 
  // detect switch presses
  if (switchValue != oldSwitch)
    {
    delay (100);   // debounce

    // was it pressed?
    if (switchValue == LOW)
      {
      state++;      // next state
      if (state >= LAST_STATE)
        state = COOLANT; 
     
      switch (state)
        {
        case POWER_ON:     powerOn ();         break;
        case COOLANT:      showCoolant ();     break;
        case INTAKE_SPEED: showIntakeSpeed (); break;
        case EXHAUST_FAN1: showExhaustFan1 (); break;
        case EXHAUST_FAN2: showExhaustFan2 (); break;
        }  // end of switch
      }  // end of switch being pressed
     
    oldSwitch = switchValue; 
    } // end of switch changing state
   
  }  // end of loop



OK that makes much more sense now that I see it laid out. I'm going much simpler than originally planned with only 2 options instead of 5 - automatic mode (temp-sensor controlled PWM fan speed) and manual mode (potentiometer-controlled PWM fan speed). I'll also be upgrading to a 20x4 LCD (when it arrives). The top 2 lines will display coolant temp and flow rate all the time with the bottom 2 lines switching between manual and auto modes with fan speed shown (which is what I'm trying to get working right now on the 16x2 I'm currently using)
http://www.computersandcircuits.com

Go Up