Shipley, West Yorkshire
Offline
Newbie
Karma: 0
Posts: 17
|
 |
« on: January 13, 2013, 05:17:02 pm » |
I am trying to write a menu system to integrate with my home automation system but I have run across a problem with nested switch...case switches used to perform the menu routines. The menu is driven off one keypad and needs to be multi-level. This is the menu code so far: void loop() { char key = keypad.getKey(); switch (key) { case '*': menuActive = true; //Allows access to the menu GLCD.ClearArea(); GLCD.println("1. LED On"); GLCD.println("2. LED Off"); GLCD.println("3. LED Blink"); GLCD.println("4. Master config"); GLCD.println("5. MenuItem5"); GLCD.println("6. MenuItem6"); GLCD.println("7. MenuItem7"); GLCD.println("# To exit menu"); break; case '#': //Disables menu access menuActive = false; HomeScreen(); //Basic home screen presenting user with some basic options break; case '1': if (menuActive == true) { digitalWrite(ledPin, HIGH); //For testing only ActionCompleted(); } break; case '2': if (menuActive == true) { digitalWrite(ledPin, LOW); ActionCompleted(); //Generic screen to show user action performed sucessfully } break; case '3': if (menuActive == true) { ActionCompleted(); digitalWrite(ledPin, HIGH); delay(100); digitalWrite(ledPin, LOW); delay(100); digitalWrite(ledPin, HIGH); delay(100); digitalWrite(ledPin, LOW); } break; case '4': if (menuActive == true) { GLCD.ClearArea(); GLCD.println("Master Configuration"); GLCD.println("# To exit menu"); GLCD.println("1. Device ID"); case '1': //Error is given on this line because the number 1 is used twice... GLCD.ClearArea(); GLCD.println("Device ID menu"); break; } break; } }
The error says: VOSHA_UCP.ino: In function 'void loop()': VOSHA_UCP:116: error: duplicate case value VOSHA_UCP:66: error: previously used here But I need that to work to provide me with a multi level menu. Is there any workarounds to this problem? uber
|
|
|
|
|
Logged
|
|
|
|
|
SE USA
Online
Faraday Member
Karma: 33
Posts: 3621
@ssh0le
|
 |
« Reply #1 on: January 13, 2013, 05:23:43 pm » |
use if elseif else
|
|
|
|
|
Logged
|
http://arduino.cc/forum/index.php?action=unread;boards=2,3,4,5,67,6,7,8,9,10,11,66,12,13,15,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,86,87,89,1;ALL
|
|
|
|
Shipley, West Yorkshire
Offline
Newbie
Karma: 0
Posts: 17
|
 |
« Reply #2 on: January 13, 2013, 05:28:07 pm » |
Just tried throwing this in on the end: case '4': if (menuActive == true) { GLCD.ClearArea(); GLCD.println("Master Configuration"); GLCD.println("# To exit menu"); GLCD.println("1. Device ID"); if(key == '1') { //This toggles the function to enable LED instead of entering menu GLCD.ClearArea(); GLCD.println("Device ID menu"); } }
And it just enabled the other function with the same key that it was assigned to... I'm thinking about toggling the main menu lock once I get into a lower menu... uber
|
|
|
|
|
Logged
|
|
|
|
|
East Anglia (UK)
Offline
Edison Member
Karma: 48
Posts: 1408
May all of your blinks be without delay
|
 |
« Reply #3 on: January 13, 2013, 05:30:05 pm » |
OK, I give up, where is the second switch hiding ? Presumably it should be in your case '4' somewhere
|
|
|
|
|
Logged
|
|
|
|
|
Shipley, West Yorkshire
Offline
Newbie
Karma: 0
Posts: 17
|
 |
« Reply #4 on: January 13, 2013, 05:31:39 pm » |
I did try that earlier before I posted and it didn't seem to like nested switches, I'll try again now...
uber
|
|
|
|
|
Logged
|
|
|
|
|
Shipley, West Yorkshire
Offline
Newbie
Karma: 0
Posts: 17
|
 |
« Reply #5 on: January 13, 2013, 05:36:40 pm » |
Just tried this. Again, to no avail... case '4': if (menuActive == true) { menuActive = false; GLCD.ClearArea(); GLCD.println("Master Configuration"); GLCD.println("# To exit menu"); GLCD.println("1. Device ID"); switch (key) { case '1': //if(key == '1') GLCD.ClearArea(); GLCD.println("Device ID menu"); break; } break;
I tried disabling access to the menu system but that seems to lock me out entirely and if I remove the menuActive = false line I'm back to the problem of it turning the LED on again... :S uber
|
|
|
|
|
Logged
|
|
|
|
|
East Anglia (UK)
Offline
Edison Member
Karma: 48
Posts: 1408
May all of your blinks be without delay
|
 |
« Reply #6 on: January 13, 2013, 05:45:06 pm » |
If I understand correctly you want a new switch...case after displaying a sub menu in your case '4'. Is that right ?
If so then you will need to read the keyboard again in case '4' and assign the input to a different variable. You currently have only one keypad.getKey in your code.
|
|
|
|
|
Logged
|
|
|
|
|
Shipley, West Yorkshire
Offline
Newbie
Karma: 0
Posts: 17
|
 |
« Reply #7 on: January 13, 2013, 05:49:48 pm » |
Just tried this now as you suggested: case '4': if(menuActive == true){ GLCD.ClearArea(); GLCD.println("Master Configuration"); GLCD.println("# To exit menu"); GLCD.println("1. Device ID"); char key2 = keypad.getKey(); //Used for this sub menu only switch (key2) { case '1': GLCD.ClearArea(); GLCD.println("Device ID menu"); break; }
And it still toggles the LED, this is infuriating... uber
|
|
|
|
|
Logged
|
|
|
|
|
UK
Offline
Tesla Member
Karma: 89
Posts: 6388
-
|
 |
« Reply #8 on: January 13, 2013, 05:51:26 pm » |
Is this menu supposed to be blocking (the code does not leave the switch case until the user has left the nested menu)?
In your original code it looks as if you were going to introduce a nested switch statement, but you omitted the switch statement itself - you only included the case statements. Hence it was considered as a (mangled) part of the outer switch, causing the error.
In a later copy of your code you added the switch statement but did not include the code to read the user input used to navigate within the menu or anything to cause the sketch to wait until that input arrived or cope if it did not arrive.
|
|
|
|
|
Logged
|
|
|
|
|
Shipley, West Yorkshire
Offline
Newbie
Karma: 0
Posts: 17
|
 |
« Reply #9 on: January 13, 2013, 05:54:06 pm » |
Yes, the menu system is supposed to be blocking as the actions are performed in the root menu itself. I am trying to get the user input to this one sub menu but it keeps triggering the second function (To turn on the LED) in the menu above the main configuration menu which isn't what I want and the only way I could see this possible is to put the menu in a routine and then call it and just pass it user input from the loop :/
uber
|
|
|
|
|
Logged
|
|
|
|
|
Queens, New York
Offline
Edison Member
Karma: 29
Posts: 1568
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
|
 |
« Reply #10 on: January 13, 2013, 06:06:15 pm » |
That is a lot of stuff crammed into your loop() function, just put the case statements in there with calls to the stuff inside your case statements.
Case 0: Function1(); Break;
Case 1: Function2(); Break;
Etc...
It is easier to isolate the problems.
|
|
|
|
|
Logged
|
UNO, MEGA, NANO, 4x4 keypad, micro servos, RF transceivers, bluetooth, ultrasonic sensor, 20x4 I2C LCD, 3.2 TFT touch screen, L298N Dual motor driver, Voice Recognition 15W, Gameduino
Arduino Tutorials, coming soon.
"If your doing nothing, it does not mean your lazy, it just means your open for anything that suits you" - Unknown
|
|
|
|
Shipley, West Yorkshire
Offline
Newbie
Karma: 0
Posts: 17
|
 |
« Reply #11 on: January 13, 2013, 06:11:38 pm » |
I'll have to try that tomorrow, I've switched my laptop off for the night now
uber
|
|
|
|
|
Logged
|
|
|
|
|
Poole, Dorset, UK
Offline
God Member
Karma: 8
Posts: 671
|
 |
« Reply #12 on: January 13, 2013, 06:13:19 pm » |
But the problems with you as this compiles int i;
void setup(){ }
void loop(){ switch (i){ case 1: break; case 2: switch (i){ case 1:break; case 2:break; } break; } } Mark PS try auto formatting your code then post it ALL with the current error message. M
|
|
|
|
|
Logged
|
|
|
|
|
Shipley, West Yorkshire
Offline
Newbie
Karma: 0
Posts: 17
|
 |
« Reply #13 on: January 14, 2013, 01:58:37 am » |
I tried adding a function and I couldn't give it user input properly, I could only back out of the menu... Here is my entire code at the moment: #include <Keypad.h>
#include <glcd.h> #include <glcd_Buildinfo.h> #include <glcd_Config.h>
#include "fonts/allFonts.h"
int ledPin = 13;
boolean menuActive = false; //
const byte ROWS = 4; //four rows const byte COLS = 3; //three columns char keys[ROWS][COLS] = { { '1','2','3' } , { '4','5','6' } , { '7','8','9' } , { '*','0','#' } }; byte rowPins[ROWS] = { 40, 41, 42, 43}; //connect to the row pinouts of the keypad byte colPins[COLS] = { 44, 45, 46}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup() { pinMode(ledPin, OUTPUT); GLCD.Init(); GLCD.SelectFont(System5x7); GLCD.println("VOSHA UCP"); GLCD.println("Press * for menu"); GLCD.println("1. Lamp toggle"); GLCD.println("2. Alarm silence"); GLCD.println("3. Alarm sound"); GLCD.println("4. LED value set"); }
void loop() { char key = keypad.getKey(); switch (key) { case '*': menuActive = true; GLCD.ClearArea(); GLCD.println("1. LED On"); GLCD.println("2. LED Off"); GLCD.println("3. LED Blink"); GLCD.println("4. Master Config"); GLCD.println("5. MenuItem5"); GLCD.println("6. MenuItem6"); GLCD.println("7. MenuItem7"); GLCD.println("# To exit menu"); break;
case '#': menuActive = false; HomeScreen(); break;
case '1': if (menuActive == true) { digitalWrite(ledPin, HIGH); ActionCompleted(); } break;
case '2': if (menuActive == true) { digitalWrite(ledPin, LOW); ActionCompleted(); } break;
case '3': if (menuActive == true) { ActionCompleted(); digitalWrite(ledPin, HIGH); delay(100); digitalWrite(ledPin, LOW); delay(100); digitalWrite(ledPin, HIGH); delay(100); digitalWrite(ledPin, LOW); delay(100); digitalWrite(ledPin, HIGH); delay(100); digitalWrite(ledPin, LOW); delay(100); digitalWrite(ledPin, HIGH); delay(100); digitalWrite(ledPin, LOW); delay(100); digitalWrite(ledPin, HIGH); delay(100); digitalWrite(ledPin, LOW); delay(100); digitalWrite(ledPin, HIGH); delay(100); digitalWrite(ledPin, LOW); delay(100); } break;
case '4': if (menuActive == true) { MasterConfig(); break;
default: break; } } }
void HomeScreen() { //Routine to display home screen and provide updates GLCD.ClearArea(); GLCD.println("VOSHA UCP"); GLCD.println("Press * for menu"); GLCD.println("1. Lamp toggle"); GLCD.println("2. Alarm silence"); GLCD.println("3. Alarm sound"); GLCD.println("4. LED value set"); }
void ActionCompleted() { GLCD.ClearArea(); GLCD.CursorTo(0,0); GLCD.print("Action completed!"); delay(500); menuActive = false; HomeScreen(); }
void MasterConfig() { menuActive = false; GLCD.ClearArea(); GLCD.println("Master Configuration"); GLCD.println("# To exit menu"); GLCD.println("1. Device ID"); char key2 = keypad.getKey(); switch (key2) { case '1': GLCD.ClearArea(); GLCD.println("Device ID menu"); break; default: break; } }
MasterConfig is where I have moved that menu to try out Hazards suggestion and I can't give it input... uber
|
|
|
|
|
Logged
|
|
|
|
|
East Anglia (UK)
Offline
Edison Member
Karma: 48
Posts: 1408
May all of your blinks be without delay
|
 |
« Reply #14 on: January 14, 2013, 02:40:29 am » |
You need to add code so that the inner switch..case is not exited until the user releases the key. Otherwise it will be picked up as a keypress and interpreted by the outer switch..case.
At the moment, when the user triggers the sub menu the MasterConfig menu appears. They then press 1 and see the message "Device ID menu". The inner switch..case then exits and we are back in the outer switch but the user still has their finger on the 1 key, hence the LED lights.
|
|
|
|
|
Logged
|
|
|
|
|
|