Go Down

Topic: Split Serial Port Character Data to EEPROM (Read 2465 times) previous topic - next topic

Abhisheik

Hello,

I am making a controller for switching of and off a relay . The other part is working fine but am stuck at something . I need to receive data from serial port and split is into two variable. like @a,500000/. First is a string and the second is a long integer. @ is to tell arduino to read new command and / is command termination character

After reading the data from the string i need to store the value 500000 to EEPROM. "a" is the command string which needs to tell arduino to store variable to a particular address. If arduino  receive @b,500000/ the data needs to be stored in other address to EEPROM. Address of eeproms can be configured to anything. Data value will be six digits always.

I have been searching and googling for hours and hours trying various example but cant get anything to work. Can anyone  suggest a simple solution.


PaulS

Quote
I have been searching and googling for hours and hours trying various example but cant get anything to work.

Reading serial data and storing it is easy, when the data is properly delimited, as yours is.

Parsing the data into command and value tokens is trivial, using strtok().

Comparing the command against a known set of commands is trivial, using strcmp().

Storing the value token in EEPROM is trivial. Converting the value token to a value is trivial, if that is what you want to do. Storing the value in EEPROM is trivial

So, it's hard to imagine what part you have problems with. Nothing in your code looks wrong.

Of course, nothing looks right, either, seeing as how you didn't post any.

Quote
Can anyone  suggest a simple solution.

Sure. As soon as you've suggested a simple problem. "I want to read serial data, parse it, and store something in EEPROM at some undefined address" isn't a simple problem. Complex problems do not have simple solutions, until you break the problem down.

Abhisheik

Hello Paul,

Thanks for your reply and suggestion. And yes you are right nothing is simple if u get too deep into it .

Sorry i didnt post it earlier . Here is the code i am trying.

Code: [Select]
#include <string.h>

#define MAX_STRING_LEN  10

char *record1;
char *p, *i;

void setup()
{

 Serial.begin(9600);
}

void loop () {
 if(Serial.available());
 {

   while (Serial.available() > 0)
   {
     char string = Serial.read();

     *record1 = string;
     Serial.println(subStr(record1, " ", 1));
     Serial.println(subStr(record1, " ", 2));
   }
   
 }
}



// Function to return a substring defined by a delimiter at an index
char* subStr (char* str, char *delim, int index) {
 char *act, *sub, *ptr;
 static char copy[MAX_STRING_LEN];
 int i;

 // Since strtok consumes the first arg, make a copy
 strcpy(copy, str);

 for (i = 1, act = copy; i <= index; i++, act = NULL) {
   sub = strtok_r(act, delim, &ptr);
   if (sub == NULL) break;
 }
 return sub;

}


if i put @a,500000/ is input, I get all the characters in different lines. One more thing. I am not writing anything to eeprom right now as it can be done once i split the strings completely. Thanks again

PaulS

Code: [Select]
      char string = Serial.read();
Do you have floats named int? Or ints named double?

The Serial.read() function returns ONE character.
You can't then treat that one character as an array. At least not usefully.

This code:
Code: [Select]

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

will read the packet, storing everything after the start of packet (< in this case) up to, but not including, the end of packet (> in this case). Change them to whatever you like.

Where it says "Process the packet" is where you put code to parse the packet, which is in inData.

Abhisheik

Hello Paul....

Thanks a lot for your help. Moving forward to your suggestion here is my final code.. Its heavily amateurish on my part cause i am not a programmer..  Seems to be working now somehow.. please suggest what more can be done to optimize this.

Code: [Select]
/*
Example to receive data from serial port in format <a,123456> and parse it to store in three eeprom location 10,11,12 by receiving as string then converting to integer.
Maximum number size to be received from serial port is six digits. for longer number add mode Cyclesint , epri and eprs.
 
*/

#define SOP '<'
#define EOP '>'
#include <EEPROM.h>

bool started = false;
bool ended = false;

int     commaPosition;
String  text;
char inData[10]; //Complete data recieved from Serial port
byte index;
String cyclesStr; // Value part of the recieved string
String command;  // Command part of the recieved string
int Cyclesint; //First two characters of value integer to be stored in EEPROM location 10
int Cyclesint1;//First two characters of value integer to be stored in EEPROM location 11
int Cyclesint2;//First two characters of value integer to be stored in EEPROM location 12
long int epri1;//EEPROM location 10 Value
long int epri2;//EEPROM location 11 Value
long int epri3;//EEPROM location 12 Value
long int eepr; //Concatinated integer from 10~12 EEPROM locations
String eprs1; //First two characters of value string
String eprs2; //Next two characters of value string
String eprs3; //Last two characters of value string


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

  epri1 = EEPROM.read(10);
  epri2 = EEPROM.read(11);
  epri3 = EEPROM.read(12);
  eepr = epri1*10000+epri2*100+epri3; // Numbers Concatenation

  Serial.println(eepr); //Print final number to be read from eeprom after concatenation of integers
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read(); //RAW serial DATA
    if(inChar == SOP)
    {
      index = 0;
      inData[index] = '\0';
      started = true;
      ended = false;
    }
    else if(inChar == EOP)
    {
      ended = true;
      break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }


  if(started && ended) // The end of packet marker arrived. Process the packet
  {
    text = inData;
    String  message = text; // holds text not yet split
    // the position of the next comma in the string


    do
    {
      commaPosition = message.indexOf(',');
      if(commaPosition != -1)
      {
        command = message.substring(0,commaPosition) ;
        message = message.substring(commaPosition+1, message.length());
      }
      else
      {  // here after the last comma is found
        if(message.length() > 0)
          cyclesStr = message ;

      }
    }
    while(commaPosition >=0);


    eprs1 = cyclesStr.substring(0,2) ; //parse first two charachters
    eprs2 = cyclesStr.substring(2,4) ; //parse next two charachters
    eprs3 = cyclesStr.substring(4,6) ; // parse last two charachters

    Serial.println(command);
    Serial.println(cyclesStr);

    char tarray[3];
    eprs1.toCharArray(tarray, sizeof(tarray));
    Cyclesint = atoi(tarray); 

    char tarray1[3];
    eprs2.toCharArray(tarray1, sizeof(tarray));
    Cyclesint1 = atoi(tarray1); 

    char tarray2[3];
    eprs3.toCharArray(tarray2, sizeof(tarray));
    Cyclesint2 = atoi(tarray2); 

    EEPROM.write(10,Cyclesint); //Write first two characters to location 10
    EEPROM.write(11,Cyclesint1); //Write next two characters to location 11
    EEPROM.write(12,Cyclesint2); //Write last two characters to location 12

      delay(100); //delay for EEPROM write

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}



Data needs to be sent as <command,123456>

PaulS

Quote
please suggest what more can be done to optimize this.

Since you asked...

Code: [Select]
/*
Example to receive data from serial port in format <a,123456> and parse it to store in three eeprom location 10,11,12 by receiving as string then converting to integer.
Maximum number size to be received from serial port is six digits. for longer number add mode Cyclesint , epri and eprs.
 
*/

There is no extra charge for using the enter key. So, use it!

Code: [Select]
String cyclesStr; // Value part of the recieved string
String command;  // Command part of the recieved string

No! There is no reason to use this resource wasting class.

Code: [Select]
    text = inData;
    String  message = text; // holds text not yet split

No! No! No! The strtok() function is far better. There is no reason to copy the character data into a String object and then copy it into another String object.

Code: [Select]
int Cyclesint; //First two characters of value integer to be stored in EEPROM location 10
int Cyclesint1;//First two characters of value integer to be stored in EEPROM location 11
int Cyclesint2;//First two characters of value integer to be stored in EEPROM location 12
long int epri1;//EEPROM location 10 Value
long int epri2;//EEPROM location 11 Value
long int epri3;//EEPROM location 12 Value

If the data fits in an int when being stored, it's fit in an int when being read back.

Go Up