|
|
View previous topic :: View next topic |
Author |
Message |
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
Text Based Menus |
Posted: Wed Sep 15, 2010 10:15 am |
|
|
Hello all,
I am developing a data logger and I want to present the setup functions
of the logger in a text based menu on hyperterminal.
Such menu should have options to set the time of the onboard RTC. The Measurment interval, and Dumping/erasing data from the onboard EEPROM... all this needs to be displayed properly formated and as clear as possible....and simple too...
For example something like this would suffice:
*****************MENU*************
*
* a) set time
* b) Dump Data
* c) Erase Data
* d) set Interval
*
***********************************
Every time it goes into an option another similar submenu is displayed - or the option is direcly executed....
The hyperterminal text box should only display the current menu / option.... not a new menu under the old one.... part of my question I guess is how to clear hyperterminal...I don't want to see the history of what has been previously displayed.
My question is purely on the display issues...
Has anybody coded a menu as such before?
Can you direct me to the nearest post on this issue?
my_search = Return(0x00);
Do you have any suggestions as to how could I do this without eating all my rom with printf()s and stored characters? An efficient printing loop?
I'm not looking for you to code this for me.....
Also, to see what I type/send to the PIC, should I echo from my ISR or once I exit the ISR? Or is the hyperterminal echo option a good choice?
I kinda know the answer to this... but I figured it can't help to ask.
You may wonder why hyperterminal? its common...
Sorry for the long post...
I'd appreciate any help...
gabriel. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
ECACE
Joined: 24 Jul 2006 Posts: 94
|
|
Posted: Wed Sep 15, 2010 11:51 am |
|
|
Per the Microsoft website, you can not clear the Hyperterminal screen.
http://support.microsoft.com/kb/123988
I had to do a similar type menu (For the same reason), and had to just do a bunch of line feeds.
Though it is not real clean code...it works though, this is how I did my menu. And as for using up memory, I wish there was a better way, but I don't know of one. One thing you could do is set up a loop to repeatdly put out the line feed instead of manually the way it is in my code below.
I have the first case statement, but you get the idea of what I was doing.
Code: |
While(1)
{
DisplayMenu();
ProcessMenu();
}
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Display Menu //
////////////////////////////////////////////////////////////////////////////////
void DisplayMenu()
{
int i; //Used in the COMMAND_TEMP conversion
printf("\r\n\r\n\r\n"); //Place a bunch of lines between 1 run and another
printf("Stepper motor controller ---\n\r\n\r");
printf("HT -- Holding Tq (1-10)\n\r");
printf("RT -- Running Tq (1-30)\n\r");
printf("DFT -- Default Tq (HT = 1 + RT = 10)\n\r");
printf("SPD -- Speed (RPM)(1-10K)\n\r");
printf("SPR -- Steps/Rev of motor (1-1K)\n\r\n\r");
printf("FWx -- FWD x steps(1-400)\r\n");
printf("RVx -- RVS x steps(1-400)\r\n");
printf("REVF -- FWD x revs (1-1K)\r\n");
printf("REVR -- RVS x revs (1-1K)\r\n\r\n");
printf("MD -- 1 = Full Step 2 Phase\r\n\t 2 = 1\\2 Step\r\n\t 3 = Full Step\r\n\r\n");
printf("STS -- Status\r\n\r\n");
printf("Enter command and press <ENTER>\r\n"); //Get command and attributes in string
gets(COMMAND);
for(i = 0 ; i <= 4 ; i++ ) //Convert COMMAND_TEMP to all uppercase
{
COMMAND[i] = toupper(COMMAND[i]);
}
printf("Attributes? <ENTER>\r\n"); //Get command and attributes in string
gets(ATTRIB);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Process Menu //
////////////////////////////////////////////////////////////////////////////////
void ProcessMenu()
{
/*
HT, //Holding Torque adjustment
RT, //Running Torque adjustment
DFT, //Loads both default torques
SPD, //Loads the user speed
FWx, //Forward x # of steps
RVx, //Reverse x # of steps
REVF, //Forward x # of Revolutions
REVR, //Reverse x # of Revolutions
MD, //Mode, sets 1/2 step, full step, or 2 phase full step
STS, //Status -- Gives back all of the parameters above
SPR, //Steps Per Revolution -- Allows user to set how many steps the stepper motor has
*/
if ((strcmp("HT", COMMAND)) == 0 )
cmd = 1;
else if ((strcmp("RT", COMMAND)) == 0 )
cmd = 2;
else if ((strcmp("DFT", COMMAND)) == 0)
cmd = 3;
else if ((strcmp("SPD", COMMAND)) == 0)
cmd = 4;
else if ((strcmp("FWX", COMMAND)) == 0)
cmd = 5;
else if ((strcmp("RVX", COMMAND)) == 0)
cmd = 6;
else if ((strcmp("REVF", COMMAND)) == 0)
cmd = 7;
else if ((strcmp("REVR", COMMAND)) == 0)
cmd = 8;
else if ((strcmp("MD", COMMAND)) == 0)
cmd = 9;
else if ((strcmp("STS", COMMAND)) == 0)
cmd = 10;
else if ((strcmp("SPR", COMMAND)) == 0)
cmd = 11;
else
cmd = 12;
// Now that all commands have been assigned an int #, we can control
// it with a switch statement below, but first we need to convert the
// ascii ATTRIBUTES to an integer
attribs32 = atoi32(ATTRIB); //Convert ascii to integer + gives attribs 32
attribs8 = make8(attribs32,0); //Strip off lower 8 bits to make attribs 8
attribsupper = make8(attribs32,1); //Strip off upper 8 bits of attrib 16
attribs16 = make16(attribsupper,attribs8); //Converted value of 16 bit attribs
switch(cmd)
{
///////////////////DONE////////////////////////////////////////////////////////
case(1): //Sets the Holding Torque level
{
HLD_TQ = attribs8; //Apply attribs to Holding Torque
//Takes just the lowest byte
if (HLD_TQ > HLD_TQ_LIMIT) //If attempted level is > than the Holding
HLD_TQ = HLD_TQ_LIMIT; //limit, then it is set to the
set_pwm1_duty(HLD_TQ); //Now set the Holding Torque Level
}
break; //Holding Torque Limit
|
_________________ A HW Engineer 'trying' to do SW !!! Run!!! |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Wed Sep 15, 2010 12:26 pm |
|
|
Hello ECACE,
Thanks for your reply.
i particularly like the use of the Gets() function... i had not thought of this... that solves one of my problems THANK YOU.
i was caught up inside my "box".... would have never remembered to use that....
now that raises another question which you might be able to answer..
i have never really used gets... will try tonight though!
i understand that Gets() saves the incoming chars into a string.
it exits once a return or new line is encountered....
now, my input is "time"... so i expect 2 chars before the \r.
for minutes, hours, etc...
what if by some reason the user inputs 3 chars before the \r?
typos do ocurr while trying to set up any machine...
does the string loop back? (circular buffer style)....i guess i could implement a check after the gets() call...
basically my question is how do you handle wrong inputs?
my original idea was:
Code: | prompt user for input
wait for incoming character
ISR fires + sets flag
check char to be limit1>char<limit2 (or some variation of this)
if check passed, continue to next char
else warn user
reset input string
request for new input
repeat till good.
on to next input field |
i guess that would be writing my custom Gets function.....thoughts?
i see for printing you do what i had hoped to avoid....alot of printfs
i guess simple is better.... or mabey faster?
i am willing to sacrifice space for speed.
i see you print to the user the expected values.... Good idea.
i shall do the same...
Regarding clearing hyperterminal:
Quote: | Try using Ctrl-L (0x0C). This may only work in TTY mode.
Otherwise, the ANSI sequence for clear screen is:
ESC, "[2J" |
i found this today..... on a microchip forum....
ill try this tonight aswell
any thoughts?
thank you for your time..
g _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
ECACE
Joined: 24 Jul 2006 Posts: 94
|
|
Posted: Wed Sep 15, 2010 12:36 pm |
|
|
I have defined the variables up front for the maximum size expected and gave the user the expected ranges. So if they were to put in a value that was too high, it would fail. For example if they were to put in 10,000 for the requested torque, it would only get the lower part of it as I only use the lower 8 bits.
If you go over the amount alloted, I think it only takes the first 5 chars for example in COMMAND.
Code: |
char COMMAND[5]; //Holds ascii response from user in menu
char ATTRIB[4]; //Holds ascii response from user in menu
static unsigned int cmd; //Becomes the integer equivalent of the COMMAND
static unsigned int32 attribs32; //Becomes the 32 bit integer equivalent of the ATTRIB
static unsigned int16 attribs16; //Becomes the 16 bit integer equivalent of the ATTRIB
static unsigned int8 attribs8; //Becomes the 8 bit integer equivalent of the ATTRIB
static unsigned int8 attribsupper; //Temp register to hold upper byte of attribs16 for conversion
|
I am not using interputs for the communications, so I just sit there till the user hits enter. _________________ A HW Engineer 'trying' to do SW !!! Run!!! |
|
|
John Morley
Joined: 09 Aug 2004 Posts: 97
|
|
Posted: Wed Sep 15, 2010 6:57 pm |
|
|
Hi,
Far be it from me to contradict Microsoft, but.....
If you use this code, you can clear the HyperTerminal display.....
Code: |
//Here we clear the HyperTerminal display screen
printf("\x1B[2J");
|
John _________________ John Morley |
|
|
Jerson
Joined: 31 Jul 2009 Posts: 125 Location: Bombay, India
|
|
Posted: Wed Sep 15, 2010 7:02 pm |
|
|
John, you are right when Hyperterm is set to VT100 emulation. That sequence does not work otherwise. |
|
|
ECACE
Joined: 24 Jul 2006 Posts: 94
|
|
Posted: Wed Sep 15, 2010 7:19 pm |
|
|
John,
Very cool. I was unaware about setting it to VT100. Thanks for the info. _________________ A HW Engineer 'trying' to do SW !!! Run!!! |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Wed Sep 15, 2010 9:45 pm |
|
|
yea, I have a whole VT100 based menu system on one project that's in color (on hyperterminal) and uses
Code: | void cls ( void ) {
fputc(27, COMM);
fputc('[', COMM);
fputc('2', COMM);
fputc('J', COMM);
fputc(27, COMM); // VT100 Home Cursor
fputc('[', COMM);
fputc('H', COMM);
}
|
_________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Thu Sep 16, 2010 2:02 am |
|
|
ECACE wrote: | I have defined the variables up front for the maximum size expected and gave the user the expected ranges. So if they were to put in a value that was too high, it would fail. For example if they were to put in 10,000 for the requested torque, it would only get the lower part of it as I only use the lower 8 bits.
If you go over the amount alloted, I think it only takes the first 5 chars for example in COMMAND.
Code: |
char COMMAND[5]; //Holds ascii response from user in menu
char ATTRIB[4]; //Holds ascii response from user in menu
static unsigned int cmd; //Becomes the integer equivalent of the COMMAND
static unsigned int32 attribs32; //Becomes the 32 bit integer equivalent of the ATTRIB
static unsigned int16 attribs16; //Becomes the 16 bit integer equivalent of the ATTRIB
static unsigned int8 attribs8; //Becomes the 8 bit integer equivalent of the ATTRIB
static unsigned int8 attribsupper; //Temp register to hold upper byte of attribs16 for conversion
|
I am not using interputs for the communications, so I just sit there till the user hits enter. |
It is worse than this.
Can hold 5 characters BUT the fith will allways be null, 0x00, '\0', 0 for a string, which is the string termination character, so you can only use 4 for your command or number!
IF you go over the 4 + null then you will overwrite the data in memory that follows this buffer, corrupting some other data or register depending on where the compiler puts your buffer!
gets does NOT know how big your buffer is so will just continue to overwrite data as more chars are entered. |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Thu Sep 16, 2010 6:28 am |
|
|
hi all,
i tried Gets() last night...
it didnt work with my code.... now... i think i figured out the answer on my way to work....
i have a size 4 array set as RS232 circular buffer...
the array loops back on the 3 item. ....
i use gets to receive 2 chars then <ENTER>.... i forgot that it also adds a 0 for the string termination... so i think that my problem could be any of the following...
so if i expect 2 values my string should hold 4 characters?
does Gets start filling up the array you provide it starting at position 0?
what if the target string already has \r from a previous run?
i know it stops when it gets 0x13... but does it actually store the 0x13 in the string?
if my input is '1' '5'
my string is "15\r0" ?
g _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
ECACE
Joined: 24 Jul 2006 Posts: 94
|
|
Posted: Thu Sep 16, 2010 6:39 am |
|
|
Wayne - Correct, the last char would be the null, so only the 4 would be accepted for command. Hence the last case is if the command did not match one of the defined ones listed in the menu.
Is this the most ideal way to do it? Probably not, but for an engineering tool (Which is what this was...stepper motor controller for motor qualifications), this worked fine. The user being an engineer who would enter the parameters.
Now exaclty what the compiler does with the others, is unknown to me. I did a test where I just held a key down and entered over a hundred chars, just to see what happened, it did not cause a crash. I would be curious to know what it does with the others.
Wayne_ wrote: | ECACE wrote: | I have defined the variables up front for the maximum size expected and gave the user the expected ranges. So if they were to put in a value that was too high, it would fail. For example if they were to put in 10,000 for the requested torque, it would only get the lower part of it as I only use the lower 8 bits.
If you go over the amount alloted, I think it only takes the first 5 chars for example in COMMAND.
Code: |
char COMMAND[5]; //Holds ascii response from user in menu
char ATTRIB[4]; //Holds ascii response from user in menu
static unsigned int cmd; //Becomes the integer equivalent of the COMMAND
static unsigned int32 attribs32; //Becomes the 32 bit integer equivalent of the ATTRIB
static unsigned int16 attribs16; //Becomes the 16 bit integer equivalent of the ATTRIB
static unsigned int8 attribs8; //Becomes the 8 bit integer equivalent of the ATTRIB
static unsigned int8 attribsupper; //Temp register to hold upper byte of attribs16 for conversion
|
I am not using interputs for the communications, so I just sit there till the user hits enter. |
It is worse than this.
Can hold 5 characters BUT the fith will allways be null, 0x00, '\0', 0 for a string, which is the string termination character, so you can only use 4 for your command or number!
IF you go over the 4 + null then you will overwrite the data in memory that follows this buffer, corrupting some other data or register depending on where the compiler puts your buffer!
gets does NOT know how big your buffer is so will just continue to overwrite data as more chars are entered. |
_________________ A HW Engineer 'trying' to do SW !!! Run!!! |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Thu Sep 16, 2010 7:05 am |
|
|
ECACE wrote: | Now exaclty what the compiler does with the others, is unknown to me. I did a test where I just held a key down and entered over a hundred chars, just to see what happened, it did not cause a crash. I would be curious to know what it does with the others.
|
The compiler itself does not do anything with the chars it just creates the code (program) that you run on the pic. What the program does, when using gets is it starts to write chars in the buffer you gave it BUT it doesn't know anything about the buffer except for the address of the first location you want to start saving the data.
What I mean by thi is, if you pass an array name
Code: |
char buf[10];
gets(buf);
|
It will start filling the memory at the address where buf starts, you can change the start point by:-
Code: |
char buf[10];
gets(&buf[5]);
|
But the routine does not know you are starting at position 5 or that there are only 5 spaces available.
Also, gets will not store the <cr> (return, char(13), 0x0D) char but replace it with the null.
The fact that your code did not fall over when you entered over 100 chars is because of the location of your array (in respect to other vars) or the usage of other vars that may have become corrupted in your code!
If you only have the one buffer and all other vars are created prior to this then a buffer overwrite will not affect any other vars, Also if you code does not then use any overwritten data in it's functionality you will not notice any corruption or experiance a crash.
With computer programming this is not as straight forward because your code is stored in ram so there is a possibility of code corruption as well as data corruption, also where stacks are used for storing data.
You were just lucky in your test routine. Mabey not so lucky if you tried the same test with you propper code?
Anyway, you need to be aware of possible consiquencies of using gets! mainly because you can not always control what a user will enter. |
|
|
ECACE
Joined: 24 Jul 2006 Posts: 94
|
|
Posted: Thu Sep 16, 2010 7:19 am |
|
|
Thanks for the detailed info. _________________ A HW Engineer 'trying' to do SW !!! Run!!! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|