Go Down

Topic: Serial communication "protocol" with Raspberry (Read 727 times) previous topic - next topic

sotomaior

Hy guys,

i found some problems in reading correctly messages sent from my raspberry pi thoward the serial port to my dear 2009:

for the purpose of my domotic system i would like to read messages in the form "l00:99" (light number 0 is on) "t05:26" (temperature sensor number 6 says 26 degrees).

I wont post the whole messy domotic code but just only the "matter" part:
Code: [Select]
char command[6], inChar;
int i = 0;
void setup() {
  Serial.begin(9600);
  Serial.flush();
  pinMode(13, OUTPUT);
}


void loop() {
  if ((Serial.available() > 0))
  {
  for (i = 0; i<=7; i++)
  {
    inChar = Serial.read();
    command[i] = inChar;
  }
  }
 
  if (command == "l00:99") {digitalWrite(13, HIGH);}
}


the problem is that even if i type the command (l00:99), it does not turn the led on, probably it is a \n \r matter, but i cant get it, anyone can help?

thanks

UKHeliBob

#1
Apr 25, 2013, 12:57 pm Last Edit: Apr 25, 2013, 01:02 pm by UKHeliBob Reason: 1
Code: [Select]
 for (i = 0; i<=7; i++)reads 8 characters into the command array, whether or not there are 8 characters available and doesn't terminate it, then you test the array against a literal that has only got 6 characters.  Will that work ?

As a first step try printing your command array before doing the test.  Print a delimiter immediately before and after so that can see how many characters are in the array.

Code: [Select]
Serial.print(">";
Serial.print(command);
Serial.println("<";


http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=11425&page=1 would be a good page for you to read
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

tobyb121

Code: [Select]
if (command == "l00:99") {digitalWrite(13, HIGH);}
That is not how to check if strings are equal. "l00:99" creates the char array {'l','0','0',':','9','9','\0'} and then returns a pointer to it. When you type command=="l00:99" you are checking if the address of command is equal to the address of that array, which it definitely will not. The way to check strings is to either use a for loop checking your command variable character by character, or use a built in function like strcmp, which does this same process for you.
The other problem, as UKHeliBob mentioned, is that you try and read 8 characters from the Serial port but only check if there are 1 or more available, the rate at which this loop will run you'll read each character in a separate loop iteration

sotomaior


Code: [Select]
  for (i = 0; i<=7; i++)reads 8 characters into the command array, whether or not there are 8 characters available and doesn't terminate it, then you test the array against a literal that has only got 6 characters.  Will that work ?

no, i tried 5, 6 7 and 8 in order to avoid those problems but none worked


Code: [Select]
if (command == "l00:99") {digitalWrite(13, HIGH);}
That is not how to check if strings are equal. "l00:99" creates the char array {'l','0','0',':','9','9','\0'} and then returns a pointer to it. When you type command=="l00:99" you are checking if the address of command is equal to the address of that array, which it definitely will not. The way to check strings is to either use a for loop checking your command variable character by character, or use a built in function like strcmp, which does this same process for you.

actually i have also tried before strcmp(command, "l00:99") == 0, but it did not worked too


The other problem, as UKHeliBob mentioned, is that you try and read 8 characters from the Serial port but only check if there are 1 or more available, the rate at which this loop will run you'll read each character in a separate loop iteration

should i say
Code: [Select]
if Serial.available == 6?

PaulS

Why doesn't the Raspberry send data intelligently? That is, with start and end of packet marker, and delimiters between the values? That would make parsing a lot easier.

The code you have now is not creating strings. It is simply populating char arrays, so none of the string functions, like strcmp(), can be used.

Each time you store a character in the array, you need to store a NULL in the array, too.

If you get the Raspberry whipped into shape, some code like this will read all the serial data, as fast (or slow) as it arrives:
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';
  }
}


Where it says "Process the packet" is where you would use strcmp() (or, more intelligently strtok() and atoi()) to deal with what was in the packet.

sotomaior

paul, thanks a lot your posts are always full of infos!

i tried to test your program but i am probably missing something in sending the command via serial:

Code: [Select]
#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(9600);
   pinMode(13, OUTPUT);
   // 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';
      }
    }
  }
  if (strcmp(inData, "loo:99" ) == 0) {digitalWrite(13, HIGH);}
  // 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';
  }
}


i typed <l00:99> and nothing happend, what's the deal?

PaulS

You need to move the code to compare the string to INTO the if(started && ended) block.

sotomaior

thanks a lot, u solved my "deal of the day", now i can continue my domotic software  XD

Go Up