Go Down

Topic: Save a string came from Serial (Read 8757 times) previous topic - next topic

crocoscore

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

PaulS

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.

crocoscore

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;

?

zoomkat

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

Google forum search: Use Google Search box in upper right side of this page.
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

crocoscore

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

marcello.romani

May I suggest

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

"Basics of C++" section.

nickgammon

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.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

crocoscore

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

guix

#8
Jan 03, 2013, 12:48 pm Last Edit: Jan 03, 2013, 12:53 pm by guix Reason: 1
Regarde ce post: http://arduino.cc/forum/index.php/topic,134402.msg1010837.html#msg1010837

PaulS

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?

crocoscore

#10
Jan 03, 2013, 01:53 pm Last Edit: Jan 03, 2013, 01:57 pm by crocoscore Reason: 1
Finally, I reorganized my code as in the example of the doc, 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 "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 ?

PaulS

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.

crocoscore

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

marcello.romani

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

crocoscore

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

Go Up