Go Down

Topic: New Arduino library: MenuSystem (Read 30422 times) previous topic - next topic

iddqd

One more stupid question.
How can I get value that have been settled for NumericMenuItem ?

Brad Burleson

I don't know if it really helps anyone, but I was playing with this library (to replace my home-grown mess) and I took the lcd_nav example and modified it to use an OLED display and a rotary encoder for input.

Since I didn't think about using a long press of the encoder for the "back" function, I simply added an extra menu item (in each submenu) with the text "back" and a callback that does a back() call (looks like I should have used a BackMenuItem instead?)

(Regarding the "back" function, one thing I wanted to do was reset the submenu when it was re-entered so the user starts at the first menu selection, not the last.  To do this I needed to call reset() for Menu and not MenuSystem, so I moved reset() from protected to public for the Menu class.  Not sure if this is something anyone else would want though)

I wrote this on a Teensy 3.2 (so I use the PJRC Encoder library) using a el-cheapo SH1106 OLED display on eBay (which is why I ended up using mfGFX and not the stock Adafruit GFX library - Tomash's SH1106 library seems to depend upon mfGFX) and a rotary encoder from Sparkfun.

If you have an SSD1306 display you should be able to use the stock Adafruit libraries instead.

Since I'm using oddball hardware I'm just going to post the example here

Code: [Select]
/*
 * oled_nav.ino - Example code using the menu system library
 *
 * This example shows using the menu system with a el cheepo
 * SH1106 OLED display from eBay and a Sparkfun rotary encoder
 *
 * Hardware used is:
 *
 * - Teensy 3.2 (https://www.pjrc.com/store/teensy32.html)
 * - Sparkfun Rotary Encoder (https://www.sparkfun.com/products/10982)
 * - Cheap eBay SH1106 OLED Display (Adafruit's SSD1306 should also work)
 *
 * Software used is:
 *
 * - Adafruit mfGFX Graphics Library (https://forums.adafruit.com/viewtopic.php?f=47&t=61388)
 * - SH1106 display library (see http://tomashg.com/?p=1263)
 * - Teensy Encoder Library (https://www.pjrc.com/teensy/td_libs_Encoder.html)
 *
 * Copyright (c) 2016 arduino-menusystem
 * Licensed under the MIT license (see LICENSE)
 */

#include <Arduino.h>
#include <MenuSystem.h>

// Need these libraries for the OLED and Rotary Encoder
#include <SPI.h>
#include <Wire.h>
#include <Encoder.h>
#include <Adafruit_mfGFX.h>
#include <Adafruit_SH1106.h>

const byte ENC_LEFT_PIN             = 24;
const byte ENC_RIGHT_PIN            = 25;
const byte PUSH_BUTTON_PIN          = 26;
const byte OLED_RESET               = 33;

Encoder myEnc(ENC_LEFT_PIN, ENC_RIGHT_PIN);

Adafruit_SH1106  lcd(-1);
//Adafruit_SSD1306 lcd(OLED_RESET);

// renderer
class MyRenderer : public MenuComponentRenderer {
public:
    virtual void render(Menu const& menu) const {
        lcd.clearDisplay();
        lcd.setTextColor(WHITE);
        lcd.setCursor(0,0);
        lcd.print(menu.get_name());
        lcd.setCursor(0,20);
        menu.get_current_component()->render(*this);
        lcd.display();
    }

    virtual void render_menu_item(MenuItem const& menu_item) const {
        lcd.print(menu_item.get_name());
        lcd.display();
    }

    virtual void render_back_menu_item(BackMenuItem const& menu_item) const {
        lcd.print(menu_item.get_name());
        lcd.display();
    }

    virtual void render_numeric_menu_item(NumericMenuItem const& menu_item) const {
        lcd.print(menu_item.get_name());
        lcd.display();
    }

    virtual void render_menu(Menu const& menu) const {
        lcd.print(menu.get_name());
        lcd.display();
    }
};
MyRenderer my_renderer;

// Forward declarations
void on_item1_selected(MenuItem* p_menu_item);
void on_item2_selected(MenuItem* p_menu_item);
void on_item3_selected(MenuItem* p_menu_item);
void on_back_selected(MenuItem* p_menu_item);

int readEncoder(void);

// Menu variables

MenuSystem ms(my_renderer);
MenuItem mm_mi1("Level 1 - Item 1 (Item)",  &on_item1_selected);
MenuItem mm_mi2("Level 1 - Item 2 (Item)",  &on_item2_selected);
Menu mu1("Level 1 - Item 3 (Menu)");
MenuItem mu1_mi1("Level 2 - Item 1 (Item)", &on_item3_selected);
MenuItem mu1_mi2("Level 2 - Back",          &on_back_selected);


// Helper function(s) for OLED display

// Display (or erase) text on the OLED
void showIt(const char * text, boolean erase) {
   if (erase)
      lcd.setTextColor(BLACK);  
    else
      lcd.setTextColor(WHITE);
  
    lcd.setCursor(0,30);
    lcd.print(text);
    lcd.display();
}

// Main display routine for selection handling
void showSelected(const char * text) {
    showIt(text, false);               // Show the text
    delay(1500);                       // Wait for a moment
    showIt(text, true);                // Erase text
}

// Menu callback functions

void on_item1_selected(MenuItem* p_menu_item) {
  showSelected("Item1 Selected  ");
}

void on_item2_selected(MenuItem* p_menu_item) {
  showSelected("Item2 Selected  ");
}

void on_item3_selected(MenuItem* p_menu_item) {
  showSelected("Item3 Selected  ");
}

// This callback should be used any time a "back" selection is needed
void on_back_selected(MenuItem* p_menu_item) {
  ms.back();
}

// Get input from the Rotary Encoder
void rotaryHandler() {
  short command = readEncoder();
  switch (command) {
    case -1:             // LEFT
      ms.prev();
      ms.display();

      break;
    case 1:              // RIGHT
      ms.next();
      ms.display();

      break;
    case 0:              // SELECT
      ms.select();
      ms.display();
      delay(100);        // Crude debounce attempt

      break;        
  }
}

// Read the Rotary encoder and wait for a button press or movement
//
// Based on code from
//(https://simelectronics.wordpress.com/2012/11/10/using-encoders-with-x-plane/)
int readEncoder(void) {
  while (1) {
    // Has a button been pressed?
    if (digitalRead(PUSH_BUTTON_PIN) == HIGH) {
      // Yes.  Make sure it's been released
      while (digitalRead(PUSH_BUTTON_PIN) == HIGH) {}

      return 0;
     } else {
      // divide by 4 to find how many 'clicks' the encoder's gone through
      short myEncDiff = myEnc.read() / 4;
 
      if (myEncDiff) {
        // only done when we've reached a detent!
        myEnc.write(0);

        return myEncDiff;
       }
     }
  }
  
  return 0;     // Just to keep the compiler happy
}

// Standard arduino functions
void setup() {
  pinMode(PUSH_BUTTON_PIN, INPUT);
  
  lcd.begin(SH1106_SWITCHCAPVCC,  0x3C); // Default I2C Address
//lcd.begin(SSD1306_SWITCHCAPVCC, 0x3D); // Use I2C addr 0x3D

  lcd.clearDisplay();  
  lcd.drawPixel(0,0,BLACK);            // Remove stray pixel on screen??
  lcd.setTextColor(WHITE);  
  lcd.display();
  
  ms.get_root_menu().add_item(&mm_mi1);
  ms.get_root_menu().add_item(&mm_mi2);
  ms.get_root_menu().add_menu(&mu1);
  mu1.add_item(&mu1_mi1);
  mu1.add_item(&mu1_mi2);

  ms.display();
}

void loop() {
  rotaryHandler();
}


The example will print the menu name at the top line of the display (root menu is simply blank), then the menu item below that.  Selecting an item will cause the text "Selected" to appear below the menu item for 1.5 seconds.

Strictly FWIW (Your mileage may vary, objects in mirror are closer than they appear, do not taunt happy fun ball)
 
Regards,

Brad
KF7FER

RobiGo

One more stupid question.
How can I get value that have been settled for NumericMenuItem ?
Are you figured out how to get that value? I'm struggling with the same problem.


Any help much appreciated!

Thanks

Willie---

Did anyone save this menu library (and his examples to use it), so I download and try it? His site has long since died, and not even the "Wayback Machine" has a copy. :(

Or, if there is something better, please let me know. :)

I just want a VERY SIMPLE menu to store or recall "presets" for a radio project I'm working on. I have the Arduino controlling the radio for "up" and "down" tuning as well as AM/FM. Now, I want to add memory presets using the EEPROM... and a working menu would be nice. :)

I'm still a Noob, so I have a lot to learn... but why reinvent the wheel, when I'm sure there's something out there I can use? :)

Willie...

Bitsfromitaly

Hi, i take a look at this menu system. The link you wrote as new point to chat doesn't work (http://blog.humblecoder.com/arduino-menu-system-library/).

Is your project still alive?


zahraaghabagheri

Hi
I am zari;
i am  learninig ARDUINO now; I want design a menu,  I searched MenuSystem library very much, but I cant find way of using this library, please help me. :)  :)  :)  :)  :)
best regards.
 :)

Andron

Hi.
Help how to work with the library.
I'm compiling a standard example and throwing an error.

#include <MenuSystem.h>

MenuSystem ms; 
Menu mm(""); 
MenuItem mi_time("TIME"); 
MenuItem mi_date("DATE"); 
MenuItem mi_alarm("ALARM"); 
Menu mu_disp("DISP"); 
MenuItem mi_disp_brightness("BRTNS");

void setup() {
  // put your setup code here, to run once:
// Menus
  mm.add_item(&mi_time, &on_menu_set_time);
  mm.add_item(&mi_date, &on_menu_set_date);
  mm.add_item(&mi_alarm, &on_menu_set_alarm);
  mm.add_menu(&mu_disp);
  mu_disp.add_item(&mi_disp_brightness, &on_menu_set_brightness);
  ms.set_root_menu(&mm);
}

void loop() {
  // put your main code here, to run repeatedly:

}


Test_Mainmenu:3: error: no matching function for call to 'MenuSystem::MenuSystem()'

 MenuSystem ms; 

            ^

D:\Arduino\Scatch\Test_Mainmenu\Test_Mainmenu.ino:3:12: note: candidates are:

In file included from D:\Arduino\Scatch\Test_Mainmenu\Test_Mainmenu.ino:1:0:

D:\Arduino\Scatch\libraries\arduino-menusystem-master/MenuSystem.h:339:5: note: MenuSystem::MenuSystem(const MenuComponentRenderer&)

     MenuSystem(MenuComponentRenderer const& renderer);

     ^

D:\Arduino\Scatch\libraries\arduino-menusystem-master/MenuSystem.h:339:5: note:   candidate expects 1 argument, 0 provided

D:\Arduino\Scatch\libraries\arduino-menusystem-master/MenuSystem.h:336:7: note: constexpr MenuSystem::MenuSystem(const MenuSystem&)

 class MenuSystem

       ^

D:\Arduino\Scatch\libraries\arduino-menusystem-master/MenuSystem.h:336:7: note:   candidate expects 1 argument, 0 provided

D:\Arduino\Scatch\libraries\arduino-menusystem-master/MenuSystem.h:336:7: note: constexpr MenuSystem::MenuSystem(MenuSystem&&)

D:\Arduino\Scatch\libraries\arduino-menusystem-master/MenuSystem.h:336:7: note:   candidate expects 1 argument, 0 provided

Test_Mainmenu:5: error: no matching function for call to 'MenuItem::MenuItem(const char [5])'

 MenuItem mi_time("TIME"); 

                        ^
Test_Mainmenu:18: error: 'on_menu_set_brightness' was not declared in this scope

   mu_disp.add_item(&mi_disp_brightness, &on_menu_set_brightness);

                                          ^

Test_Mainmenu:19: error: 'class MenuSystem' has no member named 'set_root_menu'

   ms.set_root_menu(&mm);
exit status 1
no matching function for call to 'MenuSystem::MenuSystem()'



What am I doing wrong?

CrossRoads

Do you have Mainmenu.h in your /libraries folder? The errors would indicate you do not.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Andron

Thanks for the answer.
I downloaded and added Mainmenu.h to the folder with the library.
At compilation again produces an error.

In file included from D:\Arduino\Scatch\Test_Mainmenu\Test_Mainmenu.ino:2:0:

D:\Arduino\Scatch\libraries\arduino-menusystem-master/MainMenu.h:4:26: fatal error: states/State.h: No such file or directory

 #include "states/State.h"

                          ^

compilation terminated.

bidoowee

Hi all,

Sorry for the very basic question, but I have been struggling to find a menu library that I can actually get to compile on and off for the last couple of weeks without success. I'm beginning to wonder if it is something regarding compiling cpp code that I'm doing wrong as opposed to trying to use libraries that are no longer maintained. I've installed the current arduino-menusystem library 2.1.1 (it shows as "installed" in library manager) and am using Arduino IDE 1.8.3. When I compile the lcd_nav example, I get errors from the second line of code after the includes and then a whole whack of others.

Any help would be greatly appreciated. First few errors below.

Many thanks,

bidoowee



lcd_nav:27: error: expected class-name before '{' token

 {

 ^

lcd_nav:43: error: 'BackMenuItem' has not been declared

     virtual void render_back_menu_item(BackMenuItem const& menu_item) const

                                        ^

lcd_nav:48: error: 'NumericMenuItem' has not been declared

phreaknes

I'm at the end of my mental rope. I like the menu library you've got, but I've tried 20 different approaches with no luck.

I'm trying do do a 'simple' menu with a 16x2 and a (interrupt) rotary encoder with button. The menu has 6 cases (Menu) and one of the case has a submenu with menuitem with a select() and back() with 2 options.

Can the developer or some kind library supporting soul create a barebones example? I think the community would greatly benefit from an example like this as these rotary encoders are very popular and of course 16x2 lcd are pretty much universal.  

Spaceman98

Does this library work for the teensy 3.5?

Spaceman98

Alright, I've determined that it works with the teensy 3.5 itself (at least serial_nav does) but I haven't been able to get it to work with my screen library, which is Adafruit_SSD1306. Does it work with that library?

Spaceman98

alright with some touching up it did in fact work with Adafruit_SSD1306

Go Up