Synoptic 1 Posted January 3, 2017 Share Posted January 3, 2017 Hi ! I'm new and I did search a bit but with the millions of results, it was hard for me to check them all to see if one would answer my request. I would like to implement a simple 2 level menu using my MSP430. Something very simple to learn how it is done. I would like to display a variable value on the 16x2 LCD on the first row (easy part I can already do this) I would like to use 1 push button to scroll down options which are displayed on the second row all the time. I would like to use a second push button to select the option The selected option will go to the next menu level. I would like to then continue scrolling through the second level options wich will simply change the value of the variable so I can see it worked. I would like to start building a menu library so I can have 2 levels of menu depth. I will then build from this on. On my current setup I still have P1.4 and P1.5 free. The remaining pins are used to drive the LCD. I have a G2231 and a G2211 on a 1.4 Launchpad available (G2553 on order) Thank you very much ! Quote Link to post Share on other sites
Fmilburn 446 Posted January 4, 2017 Share Posted January 4, 2017 Hi @@Synoptic, That is definitely doable. As you said, there are lots of examples for doing similar things on the internet. You seem to have the problem fairly well defined. In your code, catch the button pushes in an interrupt or poll during the loop. Record the state of the buttons and act accordingly with a if... else control structure or with switch. There are examples for reading buttons and control structures on energia.nu: http://energia.nu/guide/ Try putting together the code and come back if you have an issue.... Quote Link to post Share on other sites
EdoNork 10 Posted January 4, 2017 Share Posted January 4, 2017 I don't think he is interested in a Energia solution, he hasn't ask in the related forum. See this as a guide https://www.youtube.com/watch?v=PFzNBtnfJ6Y Hope this helps. Quote Link to post Share on other sites
Synoptic 1 Posted January 4, 2017 Author Share Posted January 4, 2017 (edited) Hi ! So I got the interrupt working for the buttons. Now I would like to check which one was pressed in the interrupt routine. I read that I can use a Mask to determine which one was pressed, but it does not work. The two IF are always executed. #pragma vector = PORT1_VECTOR __interrupt void InterruptVectorPort1() { unsigned char flags = P1IFG & P1IE; if (flags & 0x10) { P1IFG &= ~0x10; message1++; } if (flags & 0x20) { P1IFG &= ~0x20; currentHours = 0; currentMinutes = 0; currentSeconds = 0; } } It works. my button wiring was not good. Edited January 4, 2017 by Synoptic Quote Link to post Share on other sites
Fmilburn 446 Posted January 5, 2017 Share Posted January 5, 2017 Glad you got it working. Using switch to control the program flow is a common way to do it and makes it easy to see what is going on or add new pins. For example, the following watches for the interrupt and toggles the LaunchPad LEDs (with a lot of bounce). /* Watch for interrupts on two buttons and toggle LEDs * Written for the G2553 on MSP-EXP430 G2 V1.5 LaunchPad */ #include <msp430.h> #define RED_LED BIT0 // LaunchPad LEDs #define GREEN_LED BIT6 #define S1 BIT3 // LaunchPad button #define EXT BIT4 // External switch int main(void) { WDTCTL = WDTPW | WDTHOLD; P1DIR |= RED_LED; P1OUT &= ~RED_LED; P1DIR |= GREEN_LED; P1OUT &= ~GREEN_LED; P1OUT = S1 | EXT; // Switches will be pull-up inputs P1REN = S1 | EXT; P1IE = S1 | EXT; // Enable interrupt for switches P1IES = S1 | EXT; // Interrupt occurs on HI --> LO P1IFG = 0x00; // Ensure no interrupts are pending on Port 1 _BIS_SR(GIE); // Global interrupt enable while(1){} // Loop forever } #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { switch(P1IFG & P1IE){ // Which pin was it? case BIT0: break; case BIT1: break; case BIT2: break; case BIT3: P1OUT ^= RED_LED; P1IFG &= ~ S1; // clear interrupt break; case BIT4: P1OUT ^= GREEN_LED; P1IFG &= ~EXT; // clear interrupt break; case BIT5: break; case BIT6: break; case BIT7: break; default: break; // should never get here } } Quote Link to post Share on other sites
chicken 630 Posted January 5, 2017 Share Posted January 5, 2017 I'd probably go with something along these lines:- pin IRQ sets an "event" variable according to key pressed (next, select, none).- main loop (or an event handler function within the main loop) with select/case state machine with a state for each menu entry.Variable state for the select, with each case section having roughly this structure: select(state) { [..] case menuX: if (event == select) do the action; //could be state=submenu else if (event == next) state = nextmenu; break; [..] } event = none; Also in the main loop, write/refresh the menu text according to current state. Quote Link to post Share on other sites
chicken 630 Posted January 5, 2017 Share Posted January 5, 2017 PS: If you want to get fancy/generic, you could implement the state/menu system with a structure. Something along these lines: struct { int menu_id, // continuous but not functional, helps to keep track of the menu id's int next_menu, // entry when pressing next void (*action) (void), // action when pressing select const char* label // displayed text } menu_t; int current_menu = 0; void do_select0(void) { current_menu = 2; // set to sub menu } void do_ select1(void) { // do main action 1 } void do_subaction1(void) { // do sub action 1 } void do_subaction2(void) { // do sub action 2 } void do_gotop(void) { current_menu = 0; // set to top menu } menu_t menu[] = { // Top level { 0, 1,"Sub Menu", do_select0 }, { 1, 0, "Action", do_select1 }, // Sub menu { 2, 3, "Sub action 1", do_subaction1 }, { 3, 4, "Sub action 2", do_subaction2 }, { 4, 2, "Up", do_gotop } }; and in the main loop / event handler: switch(event) { case next: current_menu = menu[current_menu].next_menu; write_text(menu[current_menu].label); break; case select: menu[current_menu].action(); write_text(menu[current_menu].label); break; default; // do nothing break; } event = none; // reset event variable Fmilburn, veryalive and LiviuM 3 Quote Link to post Share on other sites
Synoptic 1 Posted January 5, 2017 Author Share Posted January 5, 2017 PS: If you want to get fancy/generic, you could implement the state/menu system with a structure. Something along these lines: struct { int menu_id, // continuous but not functional, helps to keep track of the menu id's int next_menu, // entry when pressing next void (*action) (void), // action when pressing select const char* label // displayed text } menu_t; int current_menu = 0; void do_select0(void) { current_menu = 2; // set to sub menu } void do_ select1(void) { // do main action 1 } void do_subaction1(void) { // do sub action 1 } void do_subaction2(void) { // do sub action 2 } void do_gotop(void) { current_menu = 0; // set to top menu } menu_t menu[] = { // Top level { 0, 1,"Sub Menu", do_select0 }, { 1, 0, "Action", do_select1 }, // Sub menu { 2, 3, "Sub action 1", do_subaction1 }, { 3, 4, "Sub action 2", do_subaction2 }, { 4, 2, "Up", do_gotop } }; and in the main loop / event handler: switch(event) { case next: current_menu = menu[current_menu].next_menu; write_text(menu[current_menu].label); break; case select: menu[current_menu].action(); write_text(menu[current_menu].label); break; default; // do nothing break; } event = none; // reset event variable That is something in the like of what I want to do, thanks ! Quote Link to post Share on other sites
Rickta59 589 Posted January 6, 2017 Share Posted January 6, 2017 the example and use of menu_t seem to out of order... struct { int menu_id, // continuous but not functional, helps to keep track of the menu id's int next_menu, // entry when pressing next const char* label // displayed text void (*action) (void), // action when pressing select } menu_t;would match the example better Quote Link to post Share on other sites
Rickta59 589 Posted January 6, 2017 Share Posted January 6, 2017 i'd fix the , and make them ; however i'm editting on a tablet and it keeps running all the code lines together Quote Link to post Share on other sites
chicken 630 Posted January 6, 2017 Share Posted January 6, 2017 Hmm yes, I think it should be typedef struct { .. } menu_t. And semicolons! I always need the compiler to barf at me 3 times before I get these things right :-) Quote Link to post Share on other sites
Synoptic 1 Posted January 6, 2017 Author Share Posted January 6, 2017 Hmm yes, I think it should be typedef struct { .. } menu_t. And semicolons! I always need the compiler to barf at me 3 times before I get these things right :-) Me too, my C class is 20 years away from me. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.