My Menu Object update speed is inconsistent
garyg
Posts: 420
Hi
I wrote an Object in which a menu is a forever loop.
Pressing a button#4 advances the menu selection.
When the proper menu is displayed on the LCD I tell the program to go to the selected menu using button#1.
I have 2 issues that are somewhat troubling to me.
Issue #1:
On power up of the Prop-Mini the proper menu screen is displayed.
Pressing and releasing Button#4 advances the menu to the next selection 1, 2, or 3.
If I keep pressing and releasing Button#4 about 10 or so times, 1sec on 1 sec off,
LCD display does not respond until I wait about 5 or 10 seconds.
Issue #2:
I'm thinking that maybe I do not have my Return to the Menue at the end of each minor method written correctly.
The structure of " return (Main_Menue) " is the only thing I tried to get back to the main menue after exiting the methods.
I'll try to display my code here:
The following should be the Archive file including the Full Duplex Serial that is needed.
When I'm using my Prop Mini and 2x16 Parallax LCD display set to 9600 baud, the Object starts working in
the manner I wanted.
I plan on using this in a larger project, but need to be sure it will work in a trouble free manner before attempting
to use it in my larger project.
Any words of wisdom, tips, would be greatly appreciated.
Garyg
I wrote an Object in which a menu is a forever loop.
Pressing a button#4 advances the menu selection.
When the proper menu is displayed on the LCD I tell the program to go to the selected menu using button#1.
I have 2 issues that are somewhat troubling to me.
Issue #1:
On power up of the Prop-Mini the proper menu screen is displayed.
Pressing and releasing Button#4 advances the menu to the next selection 1, 2, or 3.
If I keep pressing and releasing Button#4 about 10 or so times, 1sec on 1 sec off,
LCD display does not respond until I wait about 5 or 10 seconds.
Issue #2:
I'm thinking that maybe I do not have my Return to the Menue at the end of each minor method written correctly.
The structure of " return (Main_Menue) " is the only thing I tried to get back to the main menue after exiting the methods.
I'll try to display my code here:
'Menu_Driven_Object_GG-2016.spin {{ THIS WORKS!! BUT: When using BUTN4 to advance the menue selection more than about two iterations, the button response starts slowing down. Something is taking longer per iteration of the menue selections on BUTN4. I believe I have an error in my structure that I cannot find. More than likely, It's something I don't understand. }} {{ This is a simple Menu selection Object. On microcontroller boot-up the LCD is set to the menu display. Pressing BUTN4 will advance the selections to different Menu selections. After the proper Menu item is selected and showing on the display. Pressing BUTN1 will send the code to the proper method 1, 2, or 3. After the method is completed. Pressing BUTN1 should take the program back to the menue selection. }} CON ' Set Processor Speed @ 80mhz _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 ' Lcd Pin Assignment LCD_Pin = 18 ' Global Pin Assignments for Pushbuttons ' Pushbuttons start at the bottom of the board. BUTN1 = 8 BUTN2 = 9 BUTN3 = 10 BUTN4 = 11 VAR Long Flag1 'Flag for BUTN1 Long Flag2 'Flag for BUTN2 Long Flag3 'Flag for BUTN3 Long Flag4 'Flag for BUTN4 Long MENUE 'Variable used to reach the proper menu selection, 1,2 or 3. Long mask 'Used to set up the Waitpne instruction in MainMenue method OBJ ' FullDuplexSerial will be used to drive the Parallax 2 line LCD display LCD : "FullDuplexSerial" PUB Main waitcnt(clkfreq * 3 + cnt) ' 3sec Delay Before Starting Flag1:=0 'Flag for BUTN1 Flag2:=0 'Flag for BUTN2 Flag3:=0 'Flag for BUTN3 Flag4:=0 'Flag for BUTN4 MENUE:=1 'Sets MENUE variable to 1 which is the lowest menu number for this situation. 'Make BUTN1 through BUTN4 an input. dira[BUTN1] := 0 dira[BUTN2] := 0 ' dira[BUTN3] := 0 dira[BUTN4] := 0 mask := (|<BUTN1) | (|<BUTN4) 'OR the two button masks together into a single value. Used in the MainMenue method. LCD.start(LCD_Pin, LCD_Pin, %1000, 9_600) 'This is setting for LCD display. waitcnt(clkfreq / 10 + cnt) ' Pause for 100ms to initialize the LCD display. MAIN_MENUE ' Calls the next method pub MAIN_MENUE 'Set up and display initial MENUE LCD view. LCD.tx(12) ' Clear the LCD display waitcnt (60_000 + cnt) ' Pause for 5ms time for LCD display to clear LCD.str(string("MENU")) ' line 0 printed to LCD LCD.tx(13) ' Line feed LCD.str(string("BUTN4 = Select")) ' line 1 printed to LCD LCD.tx(212) ' Set quarter note LCD.tx(220) ' A tone repeat Waitpne (|<BUTN1, |<BUTN1, 0) 'Pause program execution until button BUTN1 is NOT pressed . If INA[BUTN1]==0 'BUTN1 must be released to enable BUTN1 again. Flag1:=0 'Flag1 says that the BUTN1 has been released. If INA[BUTN4]==0 'BUTN4 must be released to enable BUTN4 again. Flag4:=0 'Flag4 says that the BUTN4 has been released. waitpne( 0 , mask , 0 ) 'wait for either BUTN1 or BUTN4 to be set. mask is defined in the VAR section. {{ waitpne(0,(|<BUTN1) | (|<BUTN4), 0) 'This waits until either butn1 or butn4 have been pressed before moving on. 'It appears that this statement is quite a bit slower than waitpne( 0, mask, 0)}} IF INA[BUTN4]==1 and Flag4==0 Flag4:=1 MENUE:= MENUE+1 IF MENUE>3 MENUE:=1 if Flag4==1 Case MENUE 1 : '1 = Print to LCD, the 1st Menu LCD.TX(12) 'Clear the LCD screen. waitcnt(clkfreq / 200 + cnt) 'Wait 5ms for screen to clear. This is 1 / 0.005 seconds LCD.str(String("To 1st Menu?")) 2 : '2 = Print to LCD, the 2nd Menu LCD.TX(12) 'Clear the LCD screen. waitcnt(clkfreq / 200 + cnt) 'Wait 5ms for screen to clear. This is 1 / 0.005 seconds LCD.str(String("To 2nd Menu?")) 3 : '3 = Print to LCD, the 3rd Menu LCD.TX(12) 'Clear the LCD screen. waitcnt(clkfreq / 200 + cnt) 'Wait 5ms for screen to clear. This is 1 / 0.005 seconds LCD.str(String("To 3rd Menu?")) Flag4:=2 'Flag4:=2 is used so the Case MENU does not keep repeating. 'This stops the MENUE from updating if BUTN4 is staying pressed. If INA[BUTN1]==1 and Flag1==0 Flag1:=1 Case MENUE 1 : FirstMenue 'This is the method that drives the stepper motor to each gear position. 2 : SecondMenue 'This allows you to jog the stepper motor to the correct position for derailure position 'Then it saves the current StepCount to the Gear1 through Gear8 variables 3 : ThirdMenue 'This needs to be written in order to save the Gear1 through Gear8 data to EEPROM pub FirstMenue LCD.TX(128) 'Move cursor to Line0 position 0 LCD.str(String(" ")) 'Print 16 spaces to clear line 0 LCD.TX(128) 'Move cursor to Line0 position 0 waitcnt(clkfreq / 200 + cnt) 'Wait 5ms for screen to clear. This is 1 / 0.005 seconds LCD.str(String("In FirstMenue !!")) 'This proves I'm in the FirstMenue method. LCD.TX(148) 'Move cursor to Line1 position 0 LCD.str(String(" ")) 'Print 16 spaces to clear line 1 waitcnt(clkfreq / 200 + cnt) 'Wait 5ms for screen to clear. This is 1 / 0.005 seconds LCD.TX(148) 'Move cursor to Line1 position 0 LCD.str(String("Exit = BUTN1")) 'Instruction to leave this method Waitpne (|<BUTN1, |<BUTN1, 0) 'Pause program execution until button BUTN1 is NOT pressed . ' Waitpeq (|<BUTN1, |<BUTN1, 0) 'Pause program execution until button BUTN1 is pressed and held. repeat If INA[BUTN1]==1 return (MAIN_MENUE) pub SecondMenue LCD.TX(128) 'Move cursor to Line0 position 0 LCD.str(String(" ")) 'Print 16 spaces to clear line 0 LCD.TX(128) 'Move cursor to Line0 position 0 LCD.str(String("In SecondMenue !")) 'This proves I'm in the FirstMenue method. LCD.TX(148) 'Move cursor to Line1 position 0 LCD.str(String(" ")) 'Print 16 spaces to clear line 1 LCD.TX(148) 'Move cursor to Line1 position 0 LCD.str(String("Exit = BUTN1")) 'Instruction to leave this method Waitpne (|<BUTN1, |<BUTN1, 0) 'Pause program execution until button ina[8] is NOT pressed . ' Waitpeq (|<BUTN1, |<BUTN1, 0) 'Pause program execution until button ina[8] is pressed and held. repeat If INA[BUTN1]==1 return (MAIN_MENUE) pub ThirdMenue LCD.TX(128) 'Move cursor to Line0 position 0 LCD.str(String(" ")) 'Print 16 spaces to clear line 0 LCD.TX(128) 'Move cursor to Line0 position 0 LCD.str(String("In ThirdMenue !!")) 'This proves I'm in the FirstMenue method. LCD.TX(148) 'Move cursor to Line1 position 0 LCD.str(String(" ")) 'Print 16 spaces to clear line 1 LCD.TX(148) 'Move cursor to Line1 position 0 LCD.str(String("Exit = BUTN1")) 'Instruction to leave this method Waitpne (|<BUTN1, |<BUTN1, 0) 'Pause program execution until button ina[8] is NOT pressed . ' Waitpeq (|<BUTN1, |<BUTN1, 0) 'Pause program execution until button ina[8] is pressed and held. repeat If INA[BUTN1]==1 return (MAIN_MENUE)
The following should be the Archive file including the Full Duplex Serial that is needed.
When I'm using my Prop Mini and 2x16 Parallax LCD display set to 9600 baud, the Object starts working in
the manner I wanted.
I plan on using this in a larger project, but need to be sure it will work in a trouble free manner before attempting
to use it in my larger project.
Any words of wisdom, tips, would be greatly appreciated.
Garyg
Comments
That seems very strange - You don't need to do the return in a while loop. I actually don't know how the prop is going to deal with that, because it looks like that "return" function is trying to call your MAIN_MENUE method and returning the result.
What you probably want instead is the line you've commented out when you wait for the button to be pressed again.
Is there a reason you changed that?
Also, I noticed this comment in your code:
That's true, but you can make it the same speed by doing this:
constant() tells the compiler to evaluate what's in the braces and use that result, instead of computing it at runtime. Your original version would be performing two shifts and ORing the result together to produce the value.
I don't know if the weird repeat thing is the cause of your issues, but I'd start with that. It might also be worth outputting some "markers" to the debug terminal as you're going through your loops so you can see the code paths you're taking. If the code isn't doing what you expect, outputting where you are and what your current flag variables are might help you track down the issue.
I agree with your opinion that my code saying:
repeat
If INA[BUTN1]==1
return (MAIN_MENUE)
looks very strange.
The "repeat
If INA[BUTN1]==1
return (MAIN_MENUE)" actually does send the program back to the start of the MAIN_MENUE method.
If I just say MAIN_MENUE the program returns to the beginning of MAIN_MENUE and
all works ok.
I've been told that returning to a method by again calling that method is generally a very bad idea.
What I think may be happening is that when I exit FirstMenue via return statement or by just letting the FirstMenue
method run until it's end,
the program may be returning to the CASE which was the last statement causing FirstMenue to run.
Since the MENUE variable had not changed, program goes immediately back to the FirstMenue method.
Does that make any sense???
Your comments in your last post agree 100% with what the Propeller Manual says.
I think I just cannot figure out how to get back to the start of MAIN_MENUE Method.
I'll be trying your other suggestions also, but it's getting very late. Sometimes things make more sense in the Morning.
Thanks
Garyg
..
I edited my 1st post to get the code to display correctly the way it was written.
I found the clue to do this in Kwinn's spin attachment.
That should make things a bit easier to understand.
I put Kwinn's flow example as comments into my Object.
That helped and I was able to eliminate my peculiar return statements.
BUT
What happens,
when I run the updated object,
It starts out correctly I select the method I want to go to.
Push BUTN1 and program goes there.
I push BUTN1 again to exit and hopefully go back to Main_Menue
The LCD does not update the text in this part of the method.
I feel very close to getting this working.
I've tried a number of different things to get this to display again after leaving my
FirstMenue through ThirdMenue
I really don't understand why this text part of the code is being skipped.
Thanks to both of you guys
you are being very patient and helpful.
Garyg
I did not have any way to exit the loop in MAIN_MENUE.
I used Jason and Kwinns explanations to resolve my issues.
The Object now runs the way I intended from the start.
I'll be using this REV2 Object and lessons learned in a step motor control object I'm working on.
Thanks again for all your help on this
Comments and words of wisdom are always welcome
Garyg
I was making some changes to an old project that has a menu system similar to what you are working on and thought it might be of help. I copied the relevant parts into the code you posted and used your variable names as much as possible. Had to test it with PST (no lcd around). Hope it is of some use to you. If you decide to use it and have questions I will be happy to help.
While my Menue Object is working pretty good,
Yours appears to be more elegant.
I'll need to play with it for a while to be sure I understand exactly how it works.
and
Thanks Again for all your help on my Object Menu project.
Garyg
Thanks for you button press example.
I'll try this out to see if I can understand it.
Things like Modulus operators and statements like mode_select := ++pinflag//2 'change the mode
are difficult to wrap my head around.
For now, I need to change gears so to speak.
I changed my original menu selection routine based on information from this message thread.
I included the menu selection in my project and things are working good.
I'll attempt to attach a photo of my test bed and the end result of my spin code.
My next spin adventure will be concerning saving to eeprom.
I found a few threads that might get me going on that.
I need to do lots of reading to begin to understand what to do in the eeprom area.
More than likely, I'll be starting another thread on the EEprom thing.
Anyway, thanks again to everyone.
Garyg
You're welcome. If you want I could add some more comments and re-post it.
If you are willing I would appreciate it greatly.
Whenever I start on a project I always review my past message threads.
The ability to review my past message threads on this forum always helps with my projects.
garyg
I have been using PST for testing, no buttons or LCD handy. To test the get_buttons code you must press the PC's 1, 2, or 4 key 3 times to get to the appropriate sub menu. Once you switch to using the pushbuttons this will not be needed.
To switch to the buttons comment out the “ temp1 := LCD.rx “ line and uncomment the “temp1 := ina[butn1..butn4]” and “repeat until ina[butn1..butn4] == 0” lines. Change the “ repeat while loops < 2 ” from 2 to 8.
The get_buttons routine take care of debouncing the buttons and waiting for them to be released so no other button code should be needed elsewhere. A structure similar to that in the “pub MAIN_MENUE” in each of the sub menus would be a good start for that code.
PS, you may have to add in some of the LCD control code. I am guessing that writing two lines of 20 characters every time will work ok, but I could be wrong.
I've added your "Be aware of the following" info directly into
the LCD menu.spin file.
I now have a Kwinn subdirectory in my Propeller and Stamp projects directory.
I'm really not sure why I stopped using PST.
I think it had to do with the way PST worked differently from the Stamp programming software.
It appears that most people who post on the forum use PST when doing propeller things.
I will start using it again when reviewing and testing things related to LCD menu.spin.
Garyg