Menu and Timer/threaded functions

Hi All

I am working on an assingment for uni and would like to implement some “advanced” features to get some bonus marks. What i was wondering was if it was possible to do some sort of “seeming” threaded applications (the term might not be right).

What i needs to do is read data from some sensors and send data via serial at regular intervals (e.g. 100ms to read date and 1000ms to send data), what i would like to do is implement a menu system to change application settings, but not sure what the best way to approach this would be.

I have been playing with some code and have some rudimentary menu items working, but it is all in the “main” loop. some of this has been adapted from various sources on the net.
My questions are:

  1. Is it possible to do a timer based function to read/send data which isn’t in the main loop? if so can anyone point to some resources?
  2. What is the best way to implement the menu and checking if a button has been pressed?

I am using arduino Mega and a linksprite 16x2 LCD keypad shield for arduino…

Code below, thanks
Stephen

#include <LiquidCrystal.h>
#include <LCDkeypad.h>
LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7);
int lcd_adc_key_val[5] ={
  50, 200, 400, 600, 800 };
int lcd_NUM_keyS = 5;
int lcd_adc_key_in;
int lcd_key=-1;
int lcd_oldkey=-1;
int lcd_analogue_pin = 0;

//Application Variables
int is_in_menu = 0;
int menupage = 1;        //Variable to store the current menu page in
int max_menu_pages = 5; //Variable to store the number of menu pages available    
int selected_menu_item = 0;
void setup()
{
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("     helle! ");
  lcd.print("      welcome!");
  lcd.setCursor(0,1);
  lcd.print("   LinkSprite");
  lcd.print("    LCD Shield");
  delay(100);

  lcd.clear();
  lcd.setCursor(0,0); 
  lcd.print("Select to enter Menu"); 
}
void loop()
{
  get_LCD_KeyPress();
  //if we aren't in the menu, display running stats, 
  //else if we are in menu, display menu
  if (is_in_menu == 0)
  {
    lcd.clear();
    lcd.print("Running details");
    //Now check if the LCD key has been pressed
    if (lcd_key != lcd_oldkey)    
    {   
      lcd_oldkey = lcd_key;
      //If the key pressed is "select", enter the menu
      if (lcd_key == 4) //If we aren't in the menu, and the select button is pressed, open the menu
      {
        is_in_menu=1;                      //set the menu flag
      } 
    }

  } 
  else if (is_in_menu == 1)
  {
    application_Menu();
    if (lcd_key != lcd_oldkey)    
    {
      lcd.print(lcd_key);
      switch (lcd_key)
      {
      case 0: //RIGHT BUTTON
        if (menupage < max_menu_pages) {
          menupage=menupage+1;
        }
        break;
      case 1:  //UP BUTTON
        if (menupage >1) {
          menupage=menupage-1;
        }
        break;
      case 2: //DOWN BUTTON
        if (menupage < max_menu_pages) {
          menupage=menupage+1;
        }
        break;
      case 3: //LEFT BUTTON
        if (menupage >1) {
          menupage=menupage-1;
        }
        break;
      }
    }
  }


  delay(200);
}


void application_Menu()
{ 
  lcd.clear();
  lcd.setCursor(0,0);    
  lcd.print("Menu");
  lcd.setCursor(0,1);
  switch (menupage)
  {
  case 1: 
    lcd.print("1.item1");
    break;
  case 2: 
    lcd.print("2.item2");
    break;
  case 3: 
    lcd.print("3.item3");
    break;
  case 4: 
    lcd.print("4.item4");
    break;
  case 5: 
    lcd.print("5.exit");
    break;
  }
}

void get_user_menu_input()
{
  menupage = 1;
  lcd.print("Exiting");
  is_in_menu = 0;
  delay(1000);
}

void get_LCD_KeyPress()
{
  lcd_adc_key_in = analogRead(lcd_analogue_pin);    // read the value from the sensor 
  lcd_key = get_key(lcd_adc_key_in);  // convert into lcd_key press
  if (lcd_key != lcd_oldkey)   // if lcd_keypress is detected
  {
    delay(40);  // wait for debounce time
    lcd_adc_key_in = analogRead(lcd_analogue_pin);    // read the value from the sensor 
    lcd_key = get_key(lcd_adc_key_in);    // convert into lcd_key press

  }
}
// Convert ADC value to lcd_key number
int get_key(unsigned int input)
{
  int k;
  for (k = 0; k < lcd_NUM_keyS; k++)
  {
    if (input < lcd_adc_key_val[k])
    {
      return k;
    }
  }   
  if (k >= lcd_NUM_keyS)k = -1;  // No valid lcd_key pressed
  return k;
}
lcd.print(F("     helle! "));

You may get bonus marks for not wasting precious RAM on a memory-constrained architecture.

As mentioned, this is code that has been used from various sources, this ISN'T a final product as i am still working on how i want to achieve my end goal.

What is in here isn't meant to represent the final product, but more as to how to achieve it. There will still be cleaning and optimising as i go.

You may find that unless you adopt the habit early, your code will fail in strange and unexpected ways. The usual clues are forum posts with titles like "weird crash" or "sketch keeps repeating setup". Menus often grow quickly, and what seemed to work a couple of iterations ago now fails, in seemingly unrelated areas.

To your question 1), the answer is, as always, look at the blink without delay example in the IDE.

You can use the technique in the Blink Without Delay example sketch to manage timing. I wrote a more extended example in the first post of this Thread.

Personally I would take marks off you for having all that junk within loop() rather than in relevant functions. You will see in my example that there is very little in loop() and, hopefully, the intent of everything is clear.

...R

AWOL - Thanks for the feedback. At this stage i am just playing around. Definitely will look at cleaning that up. It was the original code for the LCD that i found on-line that i am developing. Also thanks for the link

Robin2 - Thanks for that, will look at cleaning up the loop. I’m still learning programming in C as majority of my programming is from a VB.NET environment without loops

Will look at the posted example to see how that’s implemented and see how it goes.
The assignment isn’t due for a few more months, but really want to get on top of it early.