Pages: [1]   Go Down
Author Topic: Arduino 1.0 new Serial commands  (Read 1282 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Full Member
***
Karma: 1
Posts: 137
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey everyone,
So for a new project of mine I am trying to use the new Arduino 1.0 system.  But I seem to be having a bit of trouble with the new serial commands.  Basically what I am trying to do is send 6 bytes to the arduino and have the arduino parse out those bytes and act accordingly.  The byte is structured as such:
1) negotiator, such as '!"
2) motor/command selection '0-6'
3)motor speed, byte1
4)motor speed, byte2
5)motor speed, byte 3
6)terminator, such as '~'
The motor speed is made up of three bytes because I would like to send values '000' through '255' through the three bytes.

Does anyone have a good idea as to how i can receive the bytes, look for the negotiator, parse the next four bytes, and wrap/end everything up with the terminator??
I think I should be using the Serial.findUntil() and the Serial.parseint() commands but I can't get everything to work properly together.
I have the following code:
Code:
void useSerial()
{
//This function is for commanding the qik only through Serial
while(Serial.available() > 0)
{
  Serial.println(Serial.available());
  boolean ready = Serial.findUntil("!","~");
  if(ready)
  {
    Serial.println(Serial.available());
    if (Serial.available() == 4)
    {
      byte1 = Serial.read();
      byte2 = Serial.read();
      byte3 = Serial.read();
      byte4 = Serial.read();
      Debug();
    }
  }
}
}
and basically Serial.available seems to always be either 1 or 0, no matter how much info i send through.
Any help would be greatly appreciated.
Logged

0
Offline Offline
Shannon Member
****
Karma: 199
Posts: 11639
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Don't use == for the result of available - if more is available you will hang forever - the correct test would be
Code:
  if (Serial.available () >= 4)
  {
    // now read the bytes.
  }

This way the code won't lock up if its too slow and 5 or more bytes are in the buffer.
Logged

[ I won't respond to messages, use the forum please ]

0
Offline Offline
Full Member
***
Karma: 1
Posts: 137
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

well i only want the bytes after the '!' byte.
i think the bigger issue is that when I run input something like '!0100~'  i get a response of:
'1
1
2'
since the only serial.print commands are for the printing of available bytes, i think there may be some issue with the new serial commands, such as the serial.findUntil.  i cant get it to work quite right
Logged

0
Offline Offline
Tesla Member
***
Karma: 141
Posts: 9470
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you are sending a string like !0100~ then you probably need to capture the string and then use the string functions to parse it. I tweeked the below code to use the ~ as the end of string delimiter. Not sure if you really need the ! to signal the start of the string in your setup.

Code:
//zoomkat 3-5-12 simple delimited ',' string parce
//from serial port input (via serial monitor)
//and print result out serial port
// CR/LF could also be a delimiter

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like wer,qwe rty,123 456,hyre kjhg,
  //or like hello world,who are you?,bye!,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == '~') {
      if (readString.length() >1) {
        Serial.println(readString); //prints string to serial port out
        //do stuff with the captured readString
        readString=""; //clears variable for new input
      }
    } 
    else {     
      readString += c; //makes the string readString
    }
  }
}


Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

New Zealand
Online Online
Jr. Member
**
Karma: 4
Posts: 91
View Profile
~
 Bigger Bigger  Smaller Smaller  Reset Reset

Your program works (by fluke) at a high baud rate (e.g. 115200), but not at a low baud rate. The reason for this is that the findUtil() function reads and discards any communication that is not in the right format (e.g. !...~). At a high baud rate, the buffer can fill up before the findutil has time to process it, meaning that it finds the start character and the terminal character successfully.

At a low baud rate, however, it gets called before the buffer has enough information in, e.g. !xx, and because it does not comply to the format, this gets discarded. Then the rest of the string comes in as xx~, and once again, it does not comply, and gets discarded, so you have lost your entire packet.

The fix is simple. In addition to MarkT's fix, your while loop should also check the length of the available buffer, and it should contain enough characters to hold your whole packet.
I also suggest prefixing some of the information before printing it. Having a bunch of numbers and not knowing which print statement wrote it, is difficult to debug.
So the code should be something like this:
Code:
while(Serial.available() >= 6)
{
  Serial.print(F("raw: "));
  Serial.println(Serial.available());
  boolean ready = Serial.findUntil("!","~");
  if(ready)
  {
    Serial.print(F("processed: "));
    Serial.println(Serial.available());
    if (Serial.available() >= 4)
    {
       ...
    }
  }
}
Logged

0
Offline Offline
Full Member
***
Karma: 1
Posts: 137
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thanks for the sample code and explanation.  with your help it seems to be working well now
although i do have one question, what does the F() do in
Code:
F("raw: ")
my code is now:
Code:
void useSerial()
{
//This function is for commanding the qik only through Serial
while(Serial.available() >= 6)
{
  Serial.print(F("raw: "));
  Serial.println(Serial.available());
  boolean ready = Serial.findUntil("!","~");
  if(ready)
  {
    Serial.print(F("processed: "));
    Serial.println(Serial.available());
    if (Serial.available() >= 4)
    {
       command = Serial.read();
       Serial.print("Command is:  ");
       Serial.println(command);
       byte3 = Serial.read();
       Serial.print("Byte3 is:  ");
       Serial.println(byte3);
       byte4 = Serial.read();
       Serial.print("Byte4 is:  ");
       Serial.println(byte3);
       byte5 = Serial.read();
       Serial.print("Byte5 is:  ");
       Serial.println(byte5);
    }
  }
}
}
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 72
Posts: 7171
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I am a bit old-fashion. I will use the below logic if I need to make sure I receive the right content:

1. if serial.available(), serial.read()
2. if read!='!' return to step 1 else go to step 3
3. start a timer now by storing the millis in a variable called start.
4. if millis()-start>=threshold, report time out while receiving command else go to 5.
5. if serial.available () serial.read()
6. if length of received string == length expected go to step 7 else go to step 4.
7. if read=='~' then process the command in step 8, else report wrong format received, discard received content and go to 1.
8. process the result with old-fashion sscanf or motor=bytes[1]-'0' to get motor number from ASCII to int, then speed=(bytes[2]-'0')*100+(bytes[3]-'0')*10+(bytes[4]-'0').
9. operate the motor at the requested speed.

It's a bit long but it makes sure what it reads conforms with the expected format. You can also just keep buffering incoming characters until you find '~' and then check the buffer for a valid complete entry to process.
Logged


New Zealand
Online Online
Jr. Member
**
Karma: 4
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

although i do have one question, what does the F() do in
Code:
F("raw: ")

It is a macro that ensures that constant strings are kept in flash memory (32 KBytes), and not loaded into SRAM. you only have 2048 bytes of SRAM, and every character takes up a byte. the F() macro ensures that only 1 character at a time is loaded from flash into RAM before being passed to the UART.
Logged

Enschede - The Netherlands
Offline Offline
Jr. Member
**
Karma: 0
Posts: 75
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can do this much simpler now with the parseInt and parseFloat commands.
If you use newline as terminator (/n) you can just type the command in your serial monitor and press enter.

The example online.
http://arduino.cc/en/Tutorial/ReadASCIIString

Just put commas, spaces or other characters in between the numbers, it works all.
Logged

Pages: [1]   Go Up
Jump to: