Save a string came from Serial

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:

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 :)

    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.

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*;* ?

very simple code to turn the arduino LED on and off. Type on or off in the serial monitor then send.

// 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="";
  } 
}

Thanks you so much zoomkat, now I understand ! I will adapt it :)

May I suggest

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

"Basics of C++" section.

  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.

I took the code this morning, here is what I did :

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:

//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 ;)

Regarde ce post: http://arduino.cc/forum/index.php/topic,134402.msg1010837.html#msg1010837

    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?

Finally, I reorganized my code as in the example of the doc, it seems cleaner:

//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 "numberWanted = (readString - '0');" to convert readString in a number. That's not possible ?

Also, I tried

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

but it didn't work, why ?

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.

// 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 :~

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

#ifndef _SERIAL_RECEIVER_H
#define _SERIAL_RECEIVER_H

#if ARDUINO >= 100
#include 
#else
#include 
#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

#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

#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();
}

I don't understand much... Plus, I have an error :

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 :)

Oh god, I didn't see :sweat_smile: 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 ?

crocoscore: 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).

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.

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