Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Building a menu system with 3 buttons (guidance)


  • Please log in to reply
11 replies to this topic

#1 JerseyTechGuy

JerseyTechGuy

    Advanced Member

  • Members
  • PipPipPip
  • 870 posts

Posted 18 January 2012 - 10:37 PM

I have spent some time Googling around to see if anyone has build a simple menu system for the Netduino and haven't found much of anything. I have a few ideas but wanted to throw out my rough architecture and see if anyone has any thoughts on best approach. So, I will have a basic menu that comes up on start... Will have selections like "Start Logging" which will run a continuous logging loop from sensors, "Erase SD" to clear the SD card for new logging, "Set time" to allow setting of the time and date if the DS1307 is blank. I will have 3 buttons (Up, Down, Enter) and all this will happen on an LCD screen. So I guess my concerns / questions for best approach are: 1) How to start in a loop that looks for the button presses on D0, D1 and D2. Only when the "Start Logging" choice has been made will this menu process stop and start logging loop. Should these be loops? Threaded? Event Driven? 2) Is there a better way to handle the buttons than use 3 Inputs? Any thoughts, guidance or opinions are welcomed. Meanwhile I'll be working on some ideas.

#2 Stefan

Stefan

    Moderator

  • Members
  • PipPipPip
  • 1965 posts
  • LocationBreda, the Netherlands

Posted 19 January 2012 - 07:49 AM

1) How to start in a loop that looks for the button presses on D0, D1 and D2. Only when the "Start Logging" choice has been made will this menu process stop and start logging loop. Should these be loops? Threaded? Event Driven?

I would use the interruptport class. So event driven.

2) Is there a better way to handle the buttons than use 3 Inputs?

It's the simplest way. As long as it's just 3 buttons, you'll be fine :)
"Fact that I'm a moderator doesn't make me an expert in things." Stefan, the eternal newb!
My .NETMF projects: .NETMF Toolbox / Gadgeteer Light / Some PCB designs

#3 JerseyTechGuy

JerseyTechGuy

    Advanced Member

  • Members
  • PipPipPip
  • 870 posts

Posted 19 January 2012 - 12:35 PM

I did get an event driven prototype working last night. Used some code I found here for the menu items array. Got it working fine. The only issue I am running into is having the program stop looking at those interrupts when you choose the menu item "Start Logging". Maybe I am misunderstanding the purpose of the DisableInterrupt. I'll play a little more and If I do / don't get it working, I'll post the code to share or critique.

#4 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 19 January 2012 - 01:00 PM

Are you in a hurry? I've almost finished a demo of a LCD display, and the items displayed are selected via pushbuttons. Which kind of display are you using? Cheers
Biggest fault of Netduino? It runs by electricity.

#5 JerseyTechGuy

JerseyTechGuy

    Advanced Member

  • Members
  • PipPipPip
  • 870 posts

Posted 19 January 2012 - 01:24 PM

Are you in a hurry?
I've almost finished a demo of a LCD display, and the items displayed are selected via pushbuttons.
Which kind of display are you using?
Cheers


I am in the prototype stages, so I'm not in an extreme hurry. I am using a 16x2 LCD with an I2C LCD backpack..

#6 Darrin

Darrin

    Advanced Member

  • Members
  • PipPipPip
  • 96 posts

Posted 19 January 2012 - 04:23 PM

I did get an event driven prototype working last night. Used some code I found here for the menu items array. Got it working fine.

The only issue I am running into is having the program stop looking at those interrupts when you choose the menu item "Start Logging". Maybe I am misunderstanding the purpose of the DisableInterrupt. I'll play a little more and If I do / don't get it working, I'll post the code to share or critique.


It sounds like you simply need to call the ClearInterrupt() method after handling the OnInterrupt() event.

If you upload your code we can take a look at it and help you out.

Cheers!

#7 JerseyTechGuy

JerseyTechGuy

    Advanced Member

  • Members
  • PipPipPip
  • 870 posts

Posted 19 January 2012 - 04:44 PM

It sounds like you simply need to call the ClearInterrupt() method after handling the OnInterrupt() event.

If you upload your code we can take a look at it and help you out.

Cheers!


You were right on the money Darrin. Forgot the ClearInterrupt call. I have it working perfectly now. You can scroll up and down and when you select an item, it either does a sub menu or runs another block of code and in this case the buttons are disabled until needed again.

#8 djhampson

djhampson

    New Member

  • Members
  • Pip
  • 1 posts

Posted 14 April 2012 - 10:34 PM

Hi Mario,

How did your LCD display demo end up? Is it available somewhere?

Thanks,

Are you in a hurry?
I've almost finished a demo of a LCD display, and the items displayed are selected via pushbuttons.
Which kind of display are you using?
Cheers



#9 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 15 April 2012 - 04:22 AM

Hi Mario,

How did your LCD display demo end up? Is it available somewhere?

Thanks,



Oh, sure! It's a been that I've posted the LCD library and the related circuit:
http://highfieldtale...y-for-netduino/
Cheers
Biggest fault of Netduino? It runs by electricity.

#10 MegaOhm

MegaOhm

    New Member

  • Members
  • Pip
  • 8 posts

Posted 24 October 2012 - 09:14 AM

You were right on the money Darrin. Forgot the ClearInterrupt call. I have it working perfectly now. You can scroll up and down and when you select an item, it either does a sub menu or runs another block of code and in this case the buttons are disabled until needed again.


Is the code you developed form the Menu screen available anywhere? thanks!

#11 JerseyTechGuy

JerseyTechGuy

    Advanced Member

  • Members
  • PipPipPip
  • 870 posts

Posted 24 October 2012 - 09:57 AM

Is the code you developed form the Menu screen available anywhere? thanks!


I can work on posting it. I'll have to pull out the the menu specific code from my program. I'll try to get it posted today.

#12 JerseyTechGuy

JerseyTechGuy

    Advanced Member

  • Members
  • PipPipPip
  • 870 posts

Posted 24 October 2012 - 11:53 AM

I tried to clean out any code specific to my product. There are still lines for the LCD display in there but you'll need to change those to work with whatever display you are using.

There may also be a few variable specific to the modes my product runs in like IsRunning, IsScanning, etc. You can remove those but thought they would be good to see as they are used to disable the buttons in certain cases.

using System;
using System.Threading;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
using Toolbox.NETMF.Hardware;

namespace Netduino.MenuExample
{
	/// <summary>
	/// Menu Example
	/// </summary>
	public class Program
	{

    	#region Constants

    	// 5 Way Button Constants
    	const Cpu.Pin BUTTON_ENTER = Pins.GPIO_PIN_D2;
    	const Cpu.Pin BUTTON_UP = Pins.GPIO_PIN_D3;
    	const Cpu.Pin BUTTON_DOWN = Pins.GPIO_PIN_D4;
    	const Port.ResistorMode BUTTON_RESISTOR_MODE = Port.ResistorMode.PullUp;
    	const bool BUTTON_ACTIVE_LEVEL = false;

    	#endregion

    	#region Static Members

    	// The input port(s) for the 5 way button(s)
    	AutoRepeatInputPort incEnterButton = new AutoRepeatInputPort(BUTTON_ENTER, BUTTON_RESISTOR_MODE, BUTTON_ACTIVE_LEVEL);
    	AutoRepeatInputPort incUpButton = new AutoRepeatInputPort(BUTTON_UP, BUTTON_RESISTOR_MODE, BUTTON_ACTIVE_LEVEL);
    	AutoRepeatInputPort incDownButton = new AutoRepeatInputPort(BUTTON_DOWN, BUTTON_RESISTOR_MODE, BUTTON_ACTIVE_LEVEL);

    	// Menu Items
    	private static menu[] myMenu = new menu[] {
                                                	new menu() { menuTag = "StartProcess", menuText = "Start Process", parentTag="MyMenuSystem" }, 
                                                	new menu() { menuTag = "LightanLED", menuText = "Light an LED", parentTag="MyMenuSystem" },
                                                	new menu() { menuTag = "RunDiagnostics", menuText = "Run Diagnostics", parentTag="MyMenuSystem" },
                                                	new menu() { menuTag = "Reboot", menuText = "Reboot", parentTag="MyMenuSystem" },
                                              	};

    	// Set the current menu to the top element
    	public menu currentMenu = myMenu[0];

    	// Application Variables
    	// IsRunning is used when the program is running a dedicated function that shouldn't be interrupted.
    	private bool IsRunning = false;

    	private bool IsScanning = false;

    	private bool IsDiagnosing = false;

    	#endregion

    	#region Structures

    	// Menu elements: create the structure
    	public struct menu
    	{
        	public menu(string menuTag, string menuText, string parentTag)
        	{
            	this.menuTag = menuTag;
            	this.menuText = menuText;
            	this.parentTag = parentTag;
        	}

        	public string menuTag;
        	public string menuText;
        	public string parentTag;
    	}

    	#endregion

    	#region Public Methods

    	public static void Main()
    	{
        	new Program().run();
    	}

    	#endregion

    	#region Private Methods

    	private void run()
    	{

        	try
        	{

            	// Display the welcome splash screen
            	DisplayWelcome();

            	// Give it some time to catch up
            	Thread.Sleep(250);

            	// Display the Menu
            	DisplayMenu(currentMenu);

            	// Start the wait loop
            	WaitForInteractions();
        	}
        	catch (Exception ex)
        	{

        	}

    	}

    	private void rerun()
    	{

        	try
        	{
            	// Clear the LCD
            	LCD.Clear();
            	// Display the welcome splash screen
            	DisplayWelcome();
            	// Display the Menu
            	DisplayMenu(currentMenu);
            	// Start the wait loop

            	WaitForInteractions();
        	}
        	catch (Exception ex)
        	{

        	}

    	}

    	private void WaitForInteractions()
    	{

        	while (true)
        	{
            	try
            	{
                	// Wait indefinitely or until button states have changed
                	Thread.Sleep(Timeout.Infinite);
            	}
            	catch (Exception ex)
            	{

            	}
        	}

    	}

    	private void DisplayWelcome()
    	{

        	try
        	{
            	// Clear LCD
            	LCD.Clear();

            	// Write out messages
            	LCD.Print(Lcd.Position.ROW_1, Lcd.Position.COLUMN_1, "My Menu System");
            	LCD.Print(Lcd.Position.ROW_2, Lcd.Position.COLUMN_1, "Starting Up...  ");
        	}
        	catch (Exception ex)
        	{

        	}

    	}

    	#region Menu Methods

    	private void getNextMenu()
    	{
        	bool foundFlag = false;
        	bool endFlag = true;

        	// Set current Position
        	foreach (menu tempMenu in myMenu)
        	{
            	// Loop to the current item
            	if (tempMenu.menuTag == currentMenu.menuTag)
            	{
                	foundFlag = true;
                	continue;  // jump to next item
            	}
            	if (foundFlag)
            	{
                	if (tempMenu.parentTag == currentMenu.parentTag)
                	{
                    	// If next item is same parent, set as current
                    	currentMenu = tempMenu;
                    	endFlag = false;
                    	break; // stop looking
                	}
            	}
        	}

        	// If we get to the end, loop back to the top
        	if (!endFlag)
        	{
            	DisplayMenu(currentMenu);
        	}
        	else
        	{
            	// Couldn't find next menu so loop back to top
            	foreach (menu tempMenu in myMenu)
            	{
                	if (tempMenu.parentTag == currentMenu.parentTag)
                	{
                    	currentMenu = tempMenu;
                    	break;
                	}
            	}
            	DisplayMenu(currentMenu);
        	}
    	}

    	private void getPriorMenu()
    	{
        	menu priorMenu = currentMenu;

        	// Set current Position
        	foreach (menu tempMenu in myMenu)
        	{
            	if (tempMenu.parentTag == currentMenu.parentTag)
            	{
                	// If next item is same parent and not the current item, set as current
                	if (tempMenu.menuTag != currentMenu.menuTag)
                	{
                    	priorMenu = tempMenu;
                	}
            	}

            	// Loop to the current item
            	if (tempMenu.menuTag == currentMenu.menuTag)
            	{
                	currentMenu = priorMenu;
                	break;
            	}
        	}

        	DisplayMenu(currentMenu);
    	}

    	private void selectMenu()
    	{
        	bool isMenu = false;

        	// Check if this is a menu or option
        	foreach (menu tempMenu in myMenu)
        	{
            	if (tempMenu.parentTag == currentMenu.menuTag)
            	{
                	currentMenu = tempMenu;
                	isMenu = true;
                	break;
            	}
        	}

        	// If menu item then display
        	if (isMenu)
        	{
            	DisplayMenu(currentMenu);

        	}
        	else
        	{
            	RunThisOption(currentMenu.menuTag);
        	}
    	}

    	private void cancelMenu()
    	{
        	// Go back up one level
        	foreach (menu tempMenu in myMenu)
        	{
            	if (tempMenu.menuTag == currentMenu.parentTag)
            	{
                	currentMenu = tempMenu;
                	break;
            	}
        	}
        	// Display
        	DisplayMenu(currentMenu);
    	}

    	private void DisplayMenu(menu thisMenu)
    	{

        	try
        	{
            	LCD.Print(Lcd.Position.ROW_1, Lcd.Position.COLUMN_1, "My Menu System");
            	String str = new string((char)32, (19 - (thisMenu.menuText.Length)));
            	LCD.Print(Lcd.Position.ROW_2, Lcd.Position.COLUMN_1, ">" + thisMenu.menuText + str);
        	}
        	catch (Exception ex)
        	{

        	}

    	}

    	private void RunThisOption(string selectedItem)
    	{
        	try
        	{
            	switch (selectedItem)
            	{
                	case "StartLogging":
                    	IsRunning = true;
                    	StartLogging();
                    	break;
                	case "EraseSDCard":
                    	IsRunning = true;
                    	EraseSDCard();
                    	break;
                	case "RunDiagnostics":
                    	IsRunning = true;
                    	RunDiagnostics();
                    	break;
                	case "Reboot":
                    	IsRunning = true;
                    	Reboot(false);
                    	break;
                	default:
                    	break;
            	}
        	}
        	catch (Exception ex)
        	{

        	}

    	}

    	#endregion

    	#endregion

    	#region Event Handlers

    	void incButton_OnStateChange(object sender, AutoRepeatEventArgs e)
    	{

        	try
        	{
            	AutoRepeatInputPort button = (AutoRepeatInputPort)sender;

            	// up pressed
            	if ((button.Id == Pins.GPIO_PIN_D4) && (IsRunning == false))
            	{
                	switch (e.State)
                	{
                    	case AutoRepeatInputPort.AutoRepeatState.Press:
                        	getPriorMenu();
                        	return;
                    	case AutoRepeatInputPort.AutoRepeatState.Tick:
                        	if (IsRunning == true)
                        	{
                            	IsScanning = false;
                        	}
                        	return;
                    	case AutoRepeatInputPort.AutoRepeatState.Release:
                        	// ...
                        	return;
                	}
            	}

            	// up special case of tick
            	if ((button.Id == Pins.GPIO_PIN_D4) && (IsRunning == true) && (IsScanning == true))
            	{
                	switch (e.State)
                	{
                    	case AutoRepeatInputPort.AutoRepeatState.Tick:
                        	if (IsRunning == true)
                        	{
                            	IsScanning = false;
                        	}
                        	return;
                	}
            	}

            	// up special case of tick
            	if ((button.Id == Pins.GPIO_PIN_D4) && (IsRunning == true) && (IsDiagnosing == true))
            	{
                	switch (e.State)
                	{
                    	case AutoRepeatInputPort.AutoRepeatState.Tick:
                        	if (IsRunning == true)
                        	{
                            	IsDiagnosing = false;
                        	}
                        	return;
                	}
            	}

            	// down pressed
            	if ((button.Id == Pins.GPIO_PIN_D3) && (IsRunning == false))
            	{
                	switch (e.State)
                	{
                    	case AutoRepeatInputPort.AutoRepeatState.Press:
                        	getNextMenu();
                        	return;
                    	case AutoRepeatInputPort.AutoRepeatState.Tick:
                        	// ...
                        	return;
                    	case AutoRepeatInputPort.AutoRepeatState.Release:
                        	// ...
                        	return;
                	}
            	}

            	// enter pressed
            	if (button.Id == Pins.GPIO_PIN_D2)
            	{
                	switch (e.State)
                	{
                    	case AutoRepeatInputPort.AutoRepeatState.Press:
                        	selectMenu();
                        	return;
                    	case AutoRepeatInputPort.AutoRepeatState.Tick:
                        	if (IsRunning == true)
                        	{
                            	IsScanning = false;
                        	}
                        	return;
                    	case AutoRepeatInputPort.AutoRepeatState.Release:
                        	// ...
                        	return;
                	}
            	}
        	}
        	catch (Exception ex)
        	{

        	}

    	}

    	#endregion

	}
}






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.