Pages: [1]   Go Down
Author Topic: Strange behavior in char based switch/case  (Read 1237 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

before doing File I/O, i decided to see about sending text commands to the Uno.  The code is supposed to start counting at 'start', stop counting at 'stop', and reset the counter at 'zero'.  If already stopped, and you tell it to stop, it will send you a message saying "already stopped".  However, if i type in "st", it will start counting.  If i type in stop, hit will say "starting...", reset, then stop.  It never sends "Already stopped".  I then changed 'start' to 'begin'.  It now does "already stopped" and no longer displays "starting...", but still resets when stop is typed.

What am i doing wrong to make it behave this way?  Thanks in advance...

Code:
char inst;
int stat = 0;
int counter = 0;

void setup()
{
  Serial.begin(9600);
  Serial.println("Initializing");
}

void loop()
{
  if (stat == 1)
  {
    Serial.print(counter);
    Serial.println("...");
    counter++;
    delay(100);
  }
  if (Serial.available() )
  {
    inst = Serial.read();
  }
  switch (inst) {
    case 'begin':
      Serial.println("starting..");
      stat = 1;
      inst = ' ';
      break;
    case 'stop':
      if (stat == 0)
      {
        Serial.println("Already stopped");
        inst = ' ';
      }
      else
      {
        Serial.println("stopping...");
        stat = 0;
        inst = ' ';
      }
      break;
    case 'zero':
      Serial.println("resetting...");
      counter = 0;
      inst = ' ';
      break;
    default:
      stat = stat;
  }
}
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26522
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

A single char is never going to have the value 'begin'(or start or stop or zero), which is five chars.
What happens if there isn't a character available?
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

so should i do string? I found it interesting that it wouldn't start on "s", but would start on "st".

While nothing is there, it either keeps counting or stops counting depending on the value of stat (see first if statement).  each case resets inst.  If i didn't reset inst, it would keep the last value and run that condition.
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26522
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Unless you're going to expand the command set hugely, I'd stick to single letters.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Central MN, USA
Online Online
Tesla Member
***
Karma: 75
Posts: 7268
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Unless you're going to expand the command set hugely, I'd stick to single letters.

I second that. I've seen quite a few posts with OP trying to receive strings as commands where a single character is sufficient. Strings are for more complicated situations. Should it arise, you can come ask again. This situation could arise when you want to accomplish something like "start counting but not from zero and from 65535 and count down instead of count up". I'd be happy to share some of my code for such situations. For now, let's stick with single character commands and switch-case.
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, i'll stick to single letter commands.  I was probably going to have about 10-20 commands, but i suppose i can map them.  I just wanted to try a little "big boy programming" is all smiley.  I am interested in the code smiley.  Thanks again
Logged

South Texas
Offline Offline
Edison Member
*
Karma: 8
Posts: 1025
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You have 26 letters and 10 numbers to star with(yhat's more than I have fingers and toes...),so that should last a little while.
Logged

Offline Offline
Edison Member
*
Karma: 19
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

For a second character, you could nest the switch statements:
Code:
byte val1 = Serial.read();
switch(val1) {
case s:
  byte val2 = Serial.read();
  switch(val2) {
    case r:
    break;
  }
  break;
}
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 504
Posts: 19095
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You could buffer your input:

http://www.gammon.com.au/serial

Then when you get a newline you process the whole thing. But you can't use switch for strings. You could strcmp them. Or have a lookup table.
Logged


Global Moderator
Netherlands
Online Online
Shannon Member
*****
Karma: 224
Posts: 13917
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
You have 26 letters and 10 numbers to star with
26 char in lower and uppercase make 52
10 digits
32 other signs like `~!@#$%^&*()_+-={}|[]\:";'<>?,./
---
total of 94...

If you really want to use strings there are a few ways: (be sure to first build up the string!)

1) if then else ladder => simple and robust, slow, most used commands should be at top of the ladder of course
Code:
if (strcmp(s, "begin")==0) 
{
}
else if (strcmp(s, "next command")==0)
{
}
else if ....

2) perfect hash function followed by a switch => fast, but not trivial to find.
Code:
int cmd= phash(s);

switch(cmd)
{
  case 1: ..
  case 2: ..
  etc
}

A perfect hash is a hash function that (in this case) for every expected string of a set of commands generates an unique number by manipulating the string. It COULD look like the following:

Code:
int phash(char *s)
{
  return (s[0]-'a')*26 + (s[1]-'a');
}
This hash function assumes that the first two chars of a command string together form an unique number [and lowercase]. It will generate a number between 0 and 625.

A perfect hash function will generate a consecutive(?) number sequence { 1,2,3,4,5,...n } for a set of commands. This makes a perfect hash quite difficult to find. One advantage of a perfect hash is that the number can be used as the index for an array of functions. ==> func[phash(commandstring)](arguments_string);

Instead of the first 2 chars one can also take the first and the last, or 3,4,5 chars or the string length, the number of vowels etc.

Drawback of hash functions is that if you add a new command your hashfunction might need a redesign, so it is often good to elaborate the completeness of the commandset first.

Hope this helps,
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

0
Offline Offline
God Member
*****
Karma: 2
Posts: 596
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Haven't used it (yet), but seems interesting:

http://arduino.cc/playground/Code/CmdMessenger

This library should ease the implementation of a string-based command set.
Logged

Central MN, USA
Online Online
Tesla Member
***
Karma: 75
Posts: 7268
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

My multi-character command code looks like Nick's code. There has to be a special character to indicate the end of the command, often end of line or something you don't use inside your command, such as a back slash or '#' etc. I chose mine to be '~' since it is the firmware for serial LCDs. The '~' is the last character on the ASCII table that can be typed from a keyboard and is not used in messages. You create a buffer (char array) to store all characters until you get to the end of command character, then interpret the command with a set of syntax. Say your command always comes with

command_identifer [parameter1],[parameter2] end_of_command

Then you can do strcmp on command_identifier, and you can use sscanf to extract parameters (that is, in form of numbers).

I'll have to pretty up my code a bit before I can show it publicly.  smiley-grin
Logged


Global Moderator
Netherlands
Online Online
Shannon Member
*****
Karma: 224
Posts: 13917
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
You have 26 letters and 10 numbers to star with
26 char in lower and uppercase make 52
10 digits
32 other signs like `~!@#$%^&*()_+-={}|[]\:";'<>?,./
---
total of 94...

If you really want to use strings there are a few ways: (be sure to first build up the string!)

1) if then else ladder => simple and robust, slow, most used commands should be at top of the ladder of course
Code:
if (strcmp(s, "begin")==0) 
{
}
else if (strcmp(s, "next command")==0)
{
}
else if ....

2) perfect hash function followed by a switch => fast, but not trivial to find.
Code:
int cmd= phash(s);

switch(cmd)
{
  case 1: ..
  case 2: ..
  etc
}

A perfect hash is a hash function that (in this case) for every expected string of a set of commands generates an unique number by manipulating the string. It COULD look like the following:

Code:
int phash(char *s)
{
  return (s[0]-'a')*26 + (s[1]-'a');
}
This hash function assumes that the first two chars of a command string together form an unique number [and lowercase]. It will generate a number between 0 and 625.

A perfect hash function will generate a consecutive(?) number sequence { 1,2,3,4,5,...n } for a set of commands. This makes a perfect hash quite difficult to find. One advantage of a perfect hash is that the number can be used as the index for an array of functions. ==> func[phash(commandstring)](arguments_string);

Instead of the first 2 chars one can also take the first and the last, or 3,4,5 chars or the string length, the number of vowels etc.

Drawback of hash functions is that if you add a new command your hashfunction might need a redesign, so it is often good to elaborate the completeness of the commandset first.

Hope this helps,
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

West Des Moines, Iowa USA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 428
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

From the C Language Standard, ISO/IEC 9899:1999(E) 6.8.4.2:

1) The controlling expression of a switch statement shall have integer type.

3) The expression of each case label shall be an integer constant expression and no two of the case constant expressions in the same switch statement shall have the same value after conversion.
Logged

There's always a better way!

Pages: [1]   Go Up
Jump to: