Pages: [1]   Go Down
Author Topic: serial variable  (Read 684 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

So i'm still messing with the code and getting stuff figured out. What i am doing is making my arduino micro into a command interpreter, so that by using a serial monitor i can send a message and have the board do something in real time. like i could tell it to make a certain pin high or low or perhaps run short pieces of pre-made code. let's say i wanted to say hello to the arduino and have it say hello back on an lcd display.

// i send hello over serial
// arduino checks if my command equals hello
// arduino says "Hi, how are you?"

so how do i compare a serial input to an existing word like hello
i have this but it doesn't work

Code:

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int prompt = 0;

void setup(){

  lcd.begin(16, 2);

  Serial.begin(9600);
}

void loop()
{
                                       // when characters arrive over the serial port...
  if (Serial.available()) {
                                       // wait a bit for the entire message to arrive
    delay(100);
                                       // clear the screen
    lcd.clear();
                                       // read all the available characters
    while (Serial.available() > 0) {
                                       // ?? set the variable "prompt" to what is coming in over serial
prompt = (Serial.read());
                                       // ?? does prompt equal hello
     if (prompt == "hello") {
                                       // since it does, print "hi how are you" to lcd
        lcd.print("Hi, how are you?");
       
      }
    }
  }
}

now i know there is a proper and/or shorter way of doing this, how would I?
Logged

Melbourne Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 42
There are only 10 types of people in the world: those who understand binary, and those who don't.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I've needed to do something similar myself recently.

I didn't want to rely on a new line to delimit the lines, so I used a tilde (~) instead.  As each char is read (Serial.read() only reads one char at a time), I build up a string until the delimiter is reached, then work out what do do based on the word/phrase received.

All you need to do is append a tilde to the end of the phrase ie hello~

Here's the code - I hope it helps.

Code:
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

static String command;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  checkSerialPort();
  delay(500);
 
}

void checkSerialPort()
{
  int incomingData;

  while (Serial.available() > 0)
  {
    //get the sent data
    incomingData = Serial.read();
    if((String) char(incomingData)=="~")
    {
      //It's the end of a command. go ahead and execute
      Serial.print("We received : ");
      Serial.println((String) command);
      if(command=="hello")
      {
        setLCD("hi how are you");     
      }
      command="";
    }else{
      command+=(String) char(incomingData);       
    }
  }


void setLCD(String chars)
{
  lcd.setCursor(0,0);
  lcd.print(chars); 
}
Logged

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

thank you, this is exactly what i was looking for. I have a couple other questions, where would i add a second command (like i say bye and it says goodbye back) so that it always loops back to the beginning, upon completion of a command. Also would it be possible to split a command into certain parts, like "digitalhigh/5~" it could use the slash to stop one string and start another, so within one command i could specify that i want to turn digital pin 5 high. then I suppose I could just make digitalhigh/1 through digitalhigh/13 as separate commands, anyway. but creating two or three strings from one command might be useful for other things, like programming something where the interpreter knows part of the command but not another. like you could say "name: chris~" and it knows the name command, but has no idea what your name might actually be. in this instance the colon would be the string seperator. Thanks again for that code and thanks in advance for any help you could give me on this.
Logged

California
Offline Offline
Faraday Member
**
Karma: 82
Posts: 3123
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

http://gammon.com.au/serial

Using this tecnique, you can use a series of if/elseif and strcmp() to process commands
« Last Edit: June 21, 2013, 11:20:29 pm by Arrch » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    if((String) char(incomingData)=="~")

It is completely unnecessary to use String here.

Please note that in versions of the IDE up to and including 1.0.3, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.), as described here for example.

Alternatively, install the fix described here:  Fixing String Crashes

Preferably upgrade your IDE to version 1.0.4 or above at: http://arduino.cc/en/Main/Software



Change it to:

Code:
    if (incomingData == '~')

That is much simpler and avoids memory fragmentation, in addition to the bugs mentioned above.
Logged

Melbourne Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 42
There are only 10 types of people in the world: those who understand binary, and those who don't.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thank you, this is exactly what i was looking for. I have a couple other questions, where would i add a second command (like i say bye and it says goodbye back) so that it always loops back to the beginning, upon completion of a command. Also would it be possible to split a command into certain parts, like "digitalhigh/5~" it could use the slash to stop one string and start another, so within one command i could specify that i want to turn digital pin 5 high. then I suppose I could just make digitalhigh/1 through digitalhigh/13 as separate commands, anyway. but creating two or three strings from one command might be useful for other things, like programming something where the interpreter knows part of the command but not another. like you could say "name: chris~" and it knows the name command, but has no idea what your name might actually be. in this instance the colon would be the string seperator. Thanks again for that code and thanks in advance for any help you could give me on this.

No problems, pleased I could help.

As Nick points out, there are issues with the String library in IDEs lower than 1.0.4, so please do go ahead and upgrade to 1.0.4 or 1.0.5 if you're not there already.  I'm using 1.0.5 and it seems to work fine.

In answer your other questions, perhaps this will help :

I use a 3 character 'command' to work out what it is I want to do, then associate a value to it, delimited by a colon.
The four examples I've included in the code would be accessed with strings constructed like this :
hel:0~                            //Just blindly calls a function (0 won't be used).
lcd:hi how are you~          //Writes the string 'hi how are you' to the LCD  
dhi:5~                           //Sets digital pin 5 high
dlo:5~                           //Sets digital pin 5 low

The string is parsed out and a series of if/else if statements decide what it needs to do.

The full version is below - hopefully it does what you need.

Cheers,

Doug.



Code:

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

static String command;

void setup()
{
   pinMode(5,OUTPUT);
}

void loop()
{
  checkSerialPort();
  delay(500);
}



void checkSerialPort()
{
    /*
    **Command format :
    <command>:<commandValue>~
    ie
    ABC:123~
    
    */
  String commandChars;
  String commandValue;
  int incomingData;
  
  
  while (Serial.available() > 0)
  {
    //get the sent data
    incomingData = Serial.read();
     if(incomingData=='~')
    {
      //It's the end of a command. go ahead and execute
      Serial.print("We received : ");
      Serial.println(command);
      commandChars = command.substring(0,3);
      commandValue = command.substring(4,command.length());

      Serial.print("commandChars : ");
      Serial.println(commandChars);  
      Serial.print("commandValue : ");
      Serial.println(commandValue);
      command="";
    }else{
      command+=(String) char(incomingData);        
    }
    
    if(commandChars=="hel")
    {
      setLCD("hi how are you");
    }
    else if(commandChars=="lcd")
    {
      setLCD(commandValue);
    }
    else if(commandChars="dhi")
    {
      writeHiLo(stringToNumber(commandValue),HIGH);
    }
    else if(commandChars="dlo")
    {
     writeHiLo(stringToNumber(commandValue),LOW);
    }
  }
}

void writeHiLo(int pin,int value)
{
  digitalWrite(pin,value);
}


void setLCD(String chars)
{
  lcd.setCursor(0,0);
  lcd.print(chars);  
}

int stringToNumber(String thisString)
{
int i;
int value;
int length;
  
  length = thisString.length();
  char blah[(length+1)];
  for(i=0; i<length; i++) {
    blah[i] = thisString.charAt(i);
  }
  blah[i]=0;
  value = atoi(blah);
  return value;
}

« Last Edit: June 22, 2013, 07:42:46 pm by Melbfella » Logged

Melbourne Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 42
There are only 10 types of people in the world: those who understand binary, and those who don't.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    if((String) char(incomingData)=="~")

It is completely unnecessary to use String here.

Please note that in versions of the IDE up to and including 1.0.3, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.), as described here for example.

Alternatively, install the fix described here:  Fixing String Crashes

Preferably upgrade your IDE to version 1.0.4 or above at: http://arduino.cc/en/Main/Software



Change it to:

Code:
    if (incomingData == '~')

That is much simpler and avoids memory fragmentation, in addition to the bugs mentioned above.

Hi Nick,

I did try without the cast when I first wrote this function, but it produces this error :

'ISO C++ forbids comparison between pointer and integer'

My past is in the C#/Visual Basic world, so pointers are a bit of a black art to me - is there something else I need to do?

Cheers,

Doug.
Logged

New Jersey
Offline Offline
Faraday Member
**
Karma: 49
Posts: 3420
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I suspect it's a quote/double quote issue. You likely did this:
Code:
     if(incomingData=="~")

Whereas Nick suggested:
Code:
     if(incomingData=='~')
Logged

Melbourne Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 42
There are only 10 types of people in the world: those who understand binary, and those who don't.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I suspect it's a quote/double quote issue. You likely did this:
Code:
    if(incomingData=="~")

Whereas Nick suggested:
Code:
    if(incomingData=='~')

Well spotted wildbill - thanks for that smiley

It does indeed work with single quotes.

The code example provided above has been modified to include this change.

Cheers,

Doug.
« Last Edit: June 22, 2013, 06:40:09 am by Melbfella » Logged

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

thank you all for the help- i've got lots of useful code to play with now.

when compiling your three letter code, i get the following terminal error:

core.a(main.cpp.o): In function `main':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.3\hardware\arduino\cores\arduino/main.cpp:11: undefined reference to `setup'
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.3\hardware\arduino\cores\arduino/main.cpp:14: undefined reference to `loop'

i'll update to 1.0.4 or 1.0.5 now and see if it fixes things.
Logged

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

Quote
when compiling your three letter code, i get the following terminal error
Do you mean the code in reply #5?
It's incomplete, it doesn't have a setup or loop, you'll have to provide your own.
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

I figured that, after the 1.0.5 install i'll add the setup and loop.
Logged

Melbourne Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 42
There are only 10 types of people in the world: those who understand binary, and those who don't.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thank you all for the help- i've got lots of useful code to play with now.

when compiling your three letter code, i get the following terminal error:

core.a(main.cpp.o): In function `main':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.3\hardware\arduino\cores\arduino/main.cpp:11: undefined reference to `setup'
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.3\hardware\arduino\cores\arduino/main.cpp:14: undefined reference to `loop'

i'll update to 1.0.4 or 1.0.5 now and see if it fixes things.

I've added setup() and loop() to the code example.
Logged

0
Offline Offline
Tesla Member
***
Karma: 116
Posts: 8944
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
So i'm still messing with the code and getting stuff figured out. What i am doing is making my arduino micro into a command interpreter, so that by using a serial monitor i can send a message and have the board do something in real time. like i could tell it to make a certain pin high or low or perhaps run short pieces of pre-made code. let's say i wanted to say hello to the arduino and have it say hello back on an lcd display.

Simple serial test code to have the board do something.

Code:
//zoomkat 3-5-12 simple delimited ',' string parse
//from serial port input (via serial monitor)
//and print result out serial port
// CR/LF could also be a delimiter
//send on, or off, from the serial monitor

int ledPin = 13;
String readString;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  Serial.println("serial LED on/off test with , delimiter"); // so I can keep track
}

void loop() {

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      //if (readString.length() >0) {
        Serial.println(readString); //prints string to serial port out
        //do stuff with the captured readString
        if(readString.indexOf("on") >=0)
        {
          digitalWrite(ledPin, HIGH);
          Serial.println("LED ON");
        }
        if(readString.indexOf("off") >=0)
        {
          digitalWrite(ledPin, LOW);
          Serial.println("LED OFF");
        }       
        readString=""; //clears variable for new input
      //}
    } 
    else {     
      readString += c; //makes the string readString
    }
  }
}

Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Pages: [1]   Go Up
Jump to: