Arduino Forum

Using Arduino => Programming Questions => Topic started by: crocoscore on Jan 03, 2013, 12:17 am

Title: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 12:17 am
Hello !
I'm a new french Arduino adept therefore please forget my mistakes  ;)

I'm working for a system which will be control by Serial commands. I must retrieve the command that I entered on the console.
Example :
I write "on" and Arduino light the led.

But it is a real headache...
That's what I've done and that doesn't work:

Code: [Select]

int character_available = 0;
char character;

int i = 0;

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


void serialEvent() //declaration of interrupt function on the serial port
{
  character_available = Serial.available(); // variable containing the number of characters available in the buffer
 
  char messageString[character_available]; //array will contain this message
 
  i = 0;
 
  while(character_available > 0) // so long there are characters to read
  {
    character = Serial.read();
    messageString[i] = character;
    character_available = Serial.available();
    i++;
   
    message = message, messageString[i]; //this must register the string and if we do Serial.print(message); it show "Hello" for example
  }
}


It's getting later in France. Maybe I made ??a mistake beast... But thanks you and see you soon  :)
Title: Re: Save a string came from Serial
Post by: PaulS on Jan 03, 2013, 12:26 am
Code: [Select]
    message = message, messageString[i]; //this must register the string and if we do Serial.print(message); it show "Hello" for example
What is this nonsense? message is not even defined. , is NOT a concatenation operator, despite any amount of wishful thinking.
Title: Re: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 12:40 am
I don't really know how string works, it's true. But this mistakes comes from my copy / paste.

I add
char* message;

but I don't know how I can correct
message = message, messageString;

it is
message = message + messageString;

or
message = message . messageString;

?
Title: Re: Save a string came from Serial
Post by: zoomkat on Jan 03, 2013, 12:58 am
very simple code to turn the arduino LED on and off. Type on or off in the serial monitor then send.

Code: [Select]

// zoomkat 8-6-10 serial I/O string test
// type a string in serial monitor. then send or enter
// for IDE 0019 and later

int ledPin = 13;
String readString;

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

void loop() {

  while (Serial.available()) {
    delay(10); 
    char c = Serial.read();
    readString += c;
  }

  if (readString.length() >0) {
    Serial.println(readString);

    if(readString.indexOf("on") >=0)
    {
      digitalWrite(ledPin, HIGH);
    }

    if(readString.indexOf("off") >=0)
    {
      digitalWrite(ledPin, LOW);
    }

    readString="";
  }
}

Title: Re: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 01:08 am
Thanks you so much zoomkat, now I understand ! I will adapt it :)
Title: Re: Save a string came from Serial
Post by: marcello.romani on Jan 03, 2013, 02:36 am
May I suggest

http://www.cplusplus.com/doc/tutorial/

"Basics of C++" section.
Title: Re: Save a string came from Serial
Post by: nickgammon on Jan 03, 2013, 03:42 am
Code: [Select]

  character_available = Serial.available(); // variable containing the number of characters available in the buffer
 
  char messageString[character_available]; //array will contain this message


That part is flawed. You are making a dynamic array to hold the "available" number of characters, however more may arrive while you are reading them. That is the subsequent loop may well overflow the array. Plus you haven't allowed room for a terminator.
Title: Re: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 12:44 pm
I took the code this morning, here is what I did :
Code: [Select]
void serialEvent()
{

  while (Serial.available()) {
    delay(10); 
    char c = Serial.read();
    readString += c;
  }
  Serial.println("");
  Serial.println("-----");
  if (isDigit(readString))
  {
    numberWanted = (readString - '0');
   
    Serial.print("Pushes number of the day ");
    Serial.print(numberWanted);
    Serial.print(" is : ");
    Serial.println(round(counterByDay[numberWanted]));
  }
  else
  {
    Serial.println("This is not a number.");
  }
  Serial.println("-----");
  Serial.println("");
 
  readString = 0;
}


But now, I realize that I have errors in the rest of the program, and I doubt that it comes from this last piece.
Every day I record the number of pulses and I stock it all in a table, here is my method of storage:
Code: [Select]
//actualise time
  time = millis();
 
  //preparing time to verify that is a multiple of one day, a day = 15000 ms (to test
  time = time/(round(time / 15000));
 
  //if time = one day, save the number
  if ((time >= 15000) && (time <= 15100) && (numberSaving == 0) && (millis() > 3000))
  {
    //operations to save the number with the date in an array:
    day++;
    counterByDay[day] = buttonPushCounter;
   
    //initialise counter
    buttonPushCounter = 0;
   
    numberSaving = 1;
  }
  //If the number have been saved, and if won't be save a second time, we initialise numberSaving
  else if (((time < 15000) || (time > 15100)) && (numberSaving == 1))
  {
    numberSaving = 0;
  }


If I don't have problem on that 2 parts, I'll show you how I write on the screen.

See you and thank you  ;)
Title: Re: Save a string came from Serial
Post by: guix on Jan 03, 2013, 12:48 pm
Regarde ce post: http://arduino.cc/forum/index.php/topic,134402.msg1010837.html#msg1010837
Title: Re: Save a string came from Serial
Post by: PaulS on Jan 03, 2013, 01:39 pm
Code: [Select]
    numberWanted = (readString - '0');
You can NOT subtract a character from a String.

How many times do you need to be told to ditch the String class?
Title: Re: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 01:53 pm
Finally, I reorganized my code as in the example of the doc (http://arduino.cc/en/Tutorial/SerialEvent), it seems cleaner:
Code: [Select]

//Prepare control by console
int numberWanted;
char readString;
boolean stringComplete = false;
int charAvailable;


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

void loop()
{
 [......]
 if (stringComplete)
 {
   //if readString is a number, show the counter of this day
   if (isDigit(readString))
   {
     numberWanted = (readString - '0');
     
     Serial.print("Le nombre de basculement du jour ");
     Serial.print(numberWanted);
     Serial.print(" est : ");
     Serial.println(round(counterByDay[numberWanted]));
   }
   else //command unknow
   {
     Serial.println("Ceci n'est as un nombre.");
   }
   
   //inizialise string;
   readString = 0;
   stringComplete = false;
 }
}

//Now, what prog must do if commands are sent
void serialEvent()
{
 //creation of the string
 while (Serial.available())
 {
   delay(10);  
   char c = Serial.read();
   readString += c;
   
   charAvailable = Serial.available();
   if (charAvailable == 0)
   {
     stringComplete = true;
   }
 }
}


I show the trick (http://my.safaribooksonline.com/book/hardware/arduino/9781449321185/4dot3dot-receiving-serial-data-in-arduino/id4110355) "numberWanted = (readString - '0');" to convert readString in a number. That's not possible ?

Also, I tried
Code: [Select]

   charAvailable = Serial.available();
   if (c == \0)
   {
     stringComplete = true;
   }

but it didn't work, why ?
Title: Re: Save a string came from Serial
Post by: PaulS on Jan 03, 2013, 02:03 pm
Quote
but it didn't work, why ?

Who knows? Snippets-R-Us.com is down the internet a ways. Perhaps you could take your snippets there and ask.

Or, post ALL of your code.
Title: Re: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 02:10 pm
Code: [Select]

// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to
const int  buttonPin2 = 3;   // second button to know the numbers of everydays
const int ledPin2 = 8;

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int buttonState2 = 0;
int lastButtonState = 0;     // previous state of the button
int lastButtonState2 = 0;

double time = 0; // will contain the hour

int numberSaving = 0; //permite to know if the number have been already saved

int i; //to explore the array

//Array which will contain de number of the push by day
int day = 0; //not one because the programm will automatically increment
float counterByDay[] = {}; //this array will begin on 1, not on 0

//Prepare control by console
int numberWanted;
char readString;
boolean stringComplete = false;
int charAvailable;


void setup()
{
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  pinMode(buttonPin2, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  // initialize serial communication:
  Serial.begin(9600);
 
  // little home message
  Serial.println("------COMPTEUR D'IMPULSIONS-------");
  Serial.println("Nb: appuyer sur le bouton pour obternir les resultats des derniers jours.");
  Serial.println("");
}


void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  // turns on the LED when button pushed
  digitalWrite(ledPin, buttonState);
 
  // compare the buttonState to its previous state
  if ((buttonState != lastButtonState) && (millis() > 3000)) //"millis() > 3000" permite to avoid the inconvenience of starting
  {
    // if the state has changed, increment the counter
    if (buttonState == HIGH)
    {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
      Serial.print("Compteur:  ");
      Serial.println(buttonPushCounter);
      Serial.println("");
    }
    else {
      // if the current state is LOW then the button
      // wend from on to off:
      Serial.println("+1");
    }
  }
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;
 
  //actualise time
  time = millis();
 
  //preparing time to verify that is a multiple of one day
  time = time/(round(time / 15000));
 
  //if time = one day, save the number
  if ((time >= 15000) && (time <= 15100) && (numberSaving == 0) && (millis() > 3000)) //REAL: if(time >= 86400000 && time <= 86402000)
  {
    //operations to save the number with the date in an array:
    day++;
    counterByDay[day] = buttonPushCounter;
   
    //initialise counter
    buttonPushCounter = 0;
   
    //write it on the sreen
    Serial.println("");
    Serial.println("-----");
    Serial.print("Jour ");
    Serial.print(day);
    Serial.print(", nombre de basculement:  ");
    Serial.println(round(counterByDay[day]));
    Serial.println("-----");
    Serial.println("");
   
    numberSaving = 1;
  }
  //If the number have been saved, and if won't be save a second time, we initialise numberSaving
  else if (((time < 15000) || (time > 15100)) && (numberSaving == 1))
  {
    numberSaving = 0;
  }
 
  //This part must show all the array when button 2 is pressed
  // read the pushbutton2 input pin:
  buttonState2 = digitalRead(buttonPin2);
  // turns on the LED 2 when button pushed
  digitalWrite(ledPin2, buttonState2);
 
  // compare the buttonState2 to its previous state
  if ((buttonState2 != lastButtonState2)  && (millis() > 3000))
  {
    // if the state has changed,
    if (buttonState2 == HIGH)
    {
      // if the current state is HIGH then the button
      // wend from off to on
     
      //Here the programm personnalise the announcement for 3 category : the first day, the second, more than 2
      Serial.println("");
      Serial.println("-----");
      if (day == 0)
      {
        Serial.print("Compteur du premier jour (jour actuel):  ");
        Serial.print(buttonPushCounter);
        Serial.println("");
      }
      else if (day == 1)
      {
        Serial.println("Compteur d'hier et d'aujourd'hui :  ");
        Serial.print("- Hier :  ");
        Serial.println(round(counterByDay[1]));
        Serial.print("- Depuis ce matin :  ");
        Serial.println(buttonPushCounter);
      }
      else //this explains that there are a lot of day
      {
        Serial.print("Compteur ");
        Serial.print(day);
        Serial.println(" derniers jours: ");
       
        //listing all days with an array
        for (i = 1; i < (day+1); i = i + 1)
        {
          Serial.print("- Jour ");
          Serial.print(i);
          Serial.print(" :  ");
          Serial.println(round(counterByDay[i])); //round could be delete
        }
       
        Serial.print("- Depuis ce matin :  ");
        Serial.println(buttonPushCounter);
      }
      Serial.println("-----");
      Serial.println("");
    }
  }
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState2 = buttonState2;
 
 
  if (stringComplete)
  {
    //if readString is a number, show the counter of this day
    Serial.println("");
    Serial.println("-----");
    if (isDigit(readString))
    {
      numberWanted = (readString - '0');
     
      Serial.print("Le nombre de basculement du jour ");
      Serial.print(numberWanted);
      Serial.print(" est : ");
      Serial.println(round(counterByDay[numberWanted]));
    }
    else //command unknow
    {
      Serial.println("Ceci n'est as un nombre.");
    }
    Serial.println("-----");
    Serial.println("");
   
    //inizialise string;
    readString = 0;
    stringComplete = false;
  }
}

//Now, what prog must do if commands are sent
void serialEvent()
{
  //creation of the string
  while (Serial.available())
  {
    delay(10); 
    char c = Serial.read();
    readString += c;
   
    charAvailable = Serial.available();
    if (charAvailable == 0)
    {
      stringComplete = true;
    }
  }
}


I'm a new user and I must learn quickly because I'm working on a project baccalaureate, sorry if I made strange mistakes  :~
Title: Re: Save a string came from Serial
Post by: marcello.romani on Jan 03, 2013, 02:39 pm
I hope this code can be useful to you.

Copy SerialReceiver.h and SerialReceiver.cpp in your sketch folder.
Change processMessage() function to suit your needs.
Make sure you call run() in loop().

SerialReceiver.h
Code: [Select]
#ifndef _SERIAL_RECEIVER_H
#define _SERIAL_RECEIVER_H

#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

// ASCII codes - see http://www.asciitable.com/
#define CR 0x0D
#define LF 0x0A

// type of receive error
typedef enum {
    ERR_NONE,            // there was no error
    ERR_TIMEOUT,         // the next byte took too long to arrive
    ERR_BUFFERFULL       // the receive buffer was too small to store all the incoming bytes
} SerialRecvError;

typedef void (*receiveHandler)(const char* buf, SerialRecvError err);

class SerialReceiver {
public:
    SerialReceiver(receiveHandler f, unsigned long receiveTimeout);

    // receive buffer size (including null terminator)
    static const byte RECV_BUF_SIZE = 30;

    // is the specified char an end-of-message marker ?
    boolean isEndOfMessage(char ch);

    // to be called in loop()
    void run();

private:
    // receive buffer
    char _recvBuf[RECV_BUF_SIZE];
   
    // number of bytes currently storedn in the receive buffer
    byte _recvBufCnt;

    // whan was the last byte received ?
    unsigned long _lastRecvTimeMs;

    // max delay between two consecutive bytes in the serial stream
    unsigned long _receiveTimeout;

    // poiter to message processing function
    receiveHandler _receiveHandler;
};

#endif



SerialReceiver.cpp
Code: [Select]
#include "SerialReceiver.h"


SerialReceiver::SerialReceiver(receiveHandler f, unsigned long receiveTimeout) {
    _receiveHandler = f;
    _receiveTimeout = receiveTimeout;
    _recvBufCnt = 0;
}


boolean SerialReceiver::isEndOfMessage(char ch) {
    return (ch == CR) || (ch == LF);
}


void SerialReceiver::run() {
    if (Serial.available()) {
        char ch = Serial.read();
   
        if (isEndOfMessage(ch)) {
            if (_recvBufCnt > 0) {
                _recvBuf[_recvBufCnt] = 0;
                if (_receiveHandler != NULL) {
                    (*_receiveHandler)(_recvBuf, ERR_NONE);
                }
                _recvBufCnt = 0;
            }
        }
        else if (_recvBufCnt < (RECV_BUF_SIZE - 1)) {    // notice - 1 to leave room for the NULL terminator
            _recvBuf[_recvBufCnt] = ch;
            _recvBufCnt++;
            _lastRecvTimeMs = millis();
        }
        else {
            // buffer full - byte lost
            _recvBuf[_recvBufCnt] = 0;
            if (_receiveHandler != NULL) {
                (*_receiveHandler)(_recvBuf, ERR_BUFFERFULL);
            }
            _recvBufCnt = 0;
        }
    }
   
    if (_recvBufCnt > 0) {
       if (millis() - _lastRecvTimeMs > _receiveTimeout) {
            _recvBuf[_recvBufCnt] = 0;
            if (_receiveHandler != NULL) {
                (*_receiveHandler)(_recvBuf, ERR_TIMEOUT);
            }
            _recvBufCnt = 0;
       }
    }
}



Example sketch
Code: [Select]
#include "SerialReceiver.h"


// called when a full messages has been received
void processMessage(const char* buf, SerialRecvError err) {
   
    // do something with the received string
    Serial.print("Received: ");
    Serial.println(buf);
   
    switch(err) {
        case ERR_NONE:
            break;
           
        case ERR_TIMEOUT:
            Serial.println("Timeout detected.");
            break;
           
        case ERR_BUFFERFULL:
            Serial.println("Buffer full.");
            break;
    }
}


SerialReceiver rec(processMessage, 10);


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


void loop() {
    rec.run();
}
Title: Re: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 02:56 pm
I don't understand much... Plus, I have an error :
(http://img11.hostingpics.net/pics/335682error.png)
Title: Re: Save a string came from Serial
Post by: marcello.romani on Jan 03, 2013, 03:03 pm
Did you actually copy all of the code from my post ? It seems to me you started to copy from "private:" downwards, but there's more before that line :)
Title: Re: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 03:52 pm
Oh god, I didn't see  :smiley-sweat:
That's work but it's not what I wan't...

But I think the last code I have posted is good but I have a just a problem with my array or with string. I was testing it on Gobetwino when I see "is not a well formed command string" for all I wrote on my program... Can you help me ?
Title: Re: Save a string came from Serial
Post by: PeterH on Jan 03, 2013, 03:58 pm

Can you help me ?


If you want help with Gobetwino, then you need to enable logging within Gobetwino so that you can see what strings it received from the Arduino and what messages it displayed, and post the actual log output from Gobetwino (in its entirety).
Title: Re: Save a string came from Serial
Post by: PaulS on Jan 03, 2013, 04:01 pm
Quote
If you want help with Gobetwino, then you need to enable logging within Gobetwino so that you can see what strings it received from the Arduino and what messages it displayed, and post the actual log output from Gobetwino (in its entirety).

The serial data sent to GoBetwino IS displayed, with no need to enable logging it.
Title: Re: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 04:30 pm
I was just saying that my problem is probably either my table or value chains of nature, or display on the console. Finally it is revealed that Gobetwino, I think.

In this code, what is not good?
http://arduino.cc/forum/index.php/topic,140381.msg1055282.html#msg1055282 (http://arduino.cc/forum/index.php/topic,140381.msg1055282.html#msg1055282)
Title: Re: Save a string came from Serial
Post by: Arrch on Jan 03, 2013, 05:05 pm
Code: [Select]

char readString;
...
void serialEvent()
{
  //creation of the string
  while (Serial.available())
  {
    ...
    readString += c;
   
  }
}


Based on the fact that you're calling it readString, I assume you think the += is concatanating c in your code? It's not. += works as concatenation for String objects, but not for chars. What you are doing is summing the characters into a single character. So if you were to send it '2' and '2', the result in readString will be 'd'.

What you need to an array of chars:

Code: [Select]
const int maxLength = 50;
char readString[maxLength];


You also need an index variable (either global or static) that will keep track of where in the array you are.

Code: [Select]
int strIndex = 0;

And lastly, you need a character that will signal that you are done transmitting your string. This will depend on what program is sending you the string. The Arduino's Serial Monitor, for example can append '\r' and/or '\n' to the end of each transmission.

Code: [Select]
#define END_OF_STRING '\n'

From there you just need to read a character as you receive it and decide whether to parse the data and reset the array (if it's the END_OF_STRING marker):

Code: [Select]

// Do Something with the string
readString[0] = '\0'; // clear the array
strIndex = 0; // reset the index to 0


or add it to the array:

Code: [Select]
readString[strIndex] = inChar; // put the new char in the array
strIndex++; // increment our index for the next char
readString[strIndex] = '\0'; // null terminate our array to make it a proper string
Title: Re: Save a string came from Serial
Post by: marcello.romani on Jan 03, 2013, 05:15 pm
Arrch thanks for explaining my code :)
Title: Re: Save a string came from Serial
Post by: marcello.romani on Jan 03, 2013, 05:18 pm
Quote
Based on the fact that you're calling it readString, I assume you think the += is concatanating c in your code? It's not. += works as concatenation for String objects, but not for chars


Wrong. Operator += is overloaded and has a version that takes a char:

Code: [Select]
String & operator += (char c)

/hardware/arduino/cores/arduino/WString.h
Title: Re: Save a string came from Serial
Post by: PaulS on Jan 03, 2013, 05:20 pm
Quote
Wrong. Operator += is overloaded and has a version that takes a char:

No. You are wrong. The String class has a += operator. The char type does NOT.
Title: Re: Save a string came from Serial
Post by: marcello.romani on Jan 03, 2013, 05:22 pm
I'm sorry, I didn't notice he declared readString as char.  :smiley-roll-sweat:
Title: Re: Save a string came from Serial
Post by: marcello.romani on Jan 03, 2013, 05:26 pm
Code: [Select]
[quote author=crocoscore link=topic=140381.msg1055398#msg1055398 date=1357224754]
Oh god, I didn't see  :smiley-sweat:
That's work but it's not what I wan't...


I guess it does. But I admit understanding other people's code is not as fun as rolling your own.
Title: Re: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 05:26 pm
Thank you all ! But if my command is a number, how can I convert the string ?
Title: Re: Save a string came from Serial
Post by: Arrch on Jan 03, 2013, 05:29 pm

Thank you all ! But if my command is a number, how can I convert the string ?

atoi()
Title: Re: Save a string came from Serial
Post by: crocoscore on Jan 03, 2013, 05:30 pm
Ok I will try. I'm back in a few houres  :P