Go Down

Topic: Serial Input Basics (Read 351835 times) previous topic - next topic

Robin2

Code: [Select]
strtokIndx = strtok(receivedBytes,",");
 saying that it's an invalid conversion from byte to char. What should I do?
In my examples the data is put into a char array - receivedChars[]. I'm guessing that is what strtok() is intended for. I don't know whether a cast would be suitable.

I don't understand your question about clearing the input buffer - what exactly do you not understand.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Qiking

In my examples the data is put into a char array - receivedChars[]. I'm guessing that is what strtok() is intended for. I don't know whether a cast would be suitable.

I don't understand your question about clearing the input buffer - what exactly do you not understand.

...R
I don't understand where to put the while loop. Do I put it after all my other functions, before all my other functions, or put all my functions inside the while loop?

Robin2

I don't understand where to put the while loop. Do I put it after all my other functions, before all my other functions, or put all my functions inside the while loop?
Put it at the place in your code where you want to empty the input buffer. You could put the code into a function and just call the function from the appropriate location,

Code: [Select]
void clearInputBuffer() {
   while (Serial.available() > 0) {
        Serial.read();
   }
}

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

mmunic194

Hi,
first of all this was very usefull for me. Now I have one question. Is it possible to use markers to separate string into variables? For example: if I send "<1><2><3>" over serial monitor, how could I store that in to variables like x=1, y=2, z=3? I need that to controll the pins on my arduino so I can send instruction using PLC over the serialc conection. My plan is tu create swich statement wich will use that data to go trough. I want to make it in the way that when the instruction is over (after i send <1><2><3>, it should store it like x=1, y=2, z=3, go trough few swich statements that use variable x,y and z and than stop and wait for next instruction) I hope I made my question clear anough and I'm really looking foward to your reply.
Regards!

Robin2

For example: if I send "<1><2><3>" over serial monitor, how could I store that in to variables like x=1, y=2, z=3?
It would be possible, but not so easy because the code will treat each value as the start of a new set of data.
But the demo code does the same thing using <1,2,3> so why not use that system?

Perhaps I don't understand what you want to do?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

RayLivingston

Why not simply send clear, unambiguous commands like: "x=1,y=5,z=3"?  Parse that using strtok(), and you can do whatever you want.

Regards,
Ray L.

Robin2

@mmunic194,

Please continue the discussion about your project in your own Thread so as not to confuse readers of this one.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Robin2

#22
Feb 04, 2015, 04:40 pm Last Edit: Feb 05, 2015, 11:33 am by Robin2
EDIT 05 Feb 2015
Following the very helpful comment in Reply #23 I have updated the code and posted it in Reply #25


The examples in my original Post and in Reply #1 take a single character from the input buffer on each iteration of loop(). However in this Thread the problem arose that loop() did not repeat fast enough to keep up with the incoming characters, the buffer overflowed and data was lost.

This following version which has two extra lines in the function recvWithStartEndMarkers() deals with that problem by taking all the available bytes from the buffer on every iteration.

To illustrate this I have added a demonstration function doOtherStuff() which simply has a short 20 millisecond delay() as a crude way to simulate other calculations (or whatever) that might be taking place in a bigger program and preventing loop() from repeating fast enough.

I think the two extra lines I have added to recvWithStartEndMarkers() could be added to any of the examples.

Code: [Select]

const byte numChars = 90;
char receivedChars[numChars];

boolean newData = false;

void setup() {
Serial.begin(9600);
Serial.println("<Arduino is ready -->");
}

void loop() {
recvWithStartEndMarkers();
showNewData();
doOtherStuff(); // <<=== NEW  --- This just simulates time spent elsewhere in a big program
}

void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;

if (Serial.available() > 0) {
while (Serial.available() > 0 && newData == false) { // <<== NEW - get all bytes from buffer
rc = Serial.read();

if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}

else if (rc == startMarker) {
recvInProgress = true;
}
} // <<=== NEW
}
}

void showNewData() {
if (newData == true) {
Serial.print("This just in ... ");
Serial.println(receivedChars);
newData = false;
}
}

void doOtherStuff() {
delay(20); // <<===NEW - This just simulates time spent elsewhere in a big program
}


...R
Two or three hours spent thinking and reading documentation solves most programming problems.

ShapeShifter

That is a good addition!

One possible optimization:
Code: [Select]
if (Serial.available() > 0) {
 while (Serial.available() > 0 && newData == false) { // <<== NEW - get all bytes from buffer
I think the IF test is redundant here, and can be eliminated without affecting the operation, as you will be covered by the new while loop:
  • If there IS data available when you enter, the while loop will spin as necessary to receive all data
  • If there is NO data available when you enter, the while condition will not be satisfied and the loop will not execute

It's a minor nit, but it saves a few bytes of precious PROGMEM without affecting operation and readability. If you feel the IF statement helps to show that nothing is done if no data is available, then put it in a comment?

Robin2

#24
Feb 04, 2015, 08:02 pm Last Edit: Feb 04, 2015, 08:03 pm by Robin2
One possible optimization:I think the IF test is redundant here,
Thanks, I have not tested but I think you are correct and I had overlooked that.

I will test it and probably change it - but I need to change the text as well so it may be tomorrow. It may actually make the explanation simpler.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Robin2

Having considered @ShapeShifter's comment in Reply #23 I have decided that it would be most useful to users of the original examples to incorporate his change in them. That way people who only read the original post and Reply #1 will get the benefit.

The updated version of the code I posted in Reply #22 is as follows.
Code: [Select]

const byte numChars = 90;
char receivedChars[numChars];

boolean newData = false;

void setup() {
Serial.begin(9600);
Serial.println("<Arduino is ready -->");
}

void loop() {
recvWithStartEndMarkers();
showNewData();
doOtherStuff(); // <<=== NEW  --- This just simulates time spent elsewhere in a big program
}

void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;

// if (Serial.available() > 0) {
while (Serial.available() > 0 && newData == false) { // <<== NEW - get all bytes from buffer
rc = Serial.read();

if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}

else if (rc == startMarker) {
recvInProgress = true;
}
}
}

void showNewData() {
if (newData == true) {
Serial.print("This just in ... ");
Serial.println(receivedChars);
newData = false;
}
}

void doOtherStuff() {
delay(20); // <<===NEW - This just simulates time spent elsewhere in a big program
}


I have edited the earlier posts so that, hopefully, the whole Thread makes sense.

A big thank-you to @ShapeShifter.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

larryd

Good work as usual.
Thanks for giving your time to this.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

halfdome

#27
Feb 14, 2015, 09:10 pm Last Edit: Feb 15, 2015, 04:08 pm by halfdome
<EDIT 15.02.2015> Previously I made a statement in this post about saving quite a bit of memory by using the void serialEvent() function instead of having the watch_serial_port() function inside the main loop.

Unfortunately that observation was all based on a typo in my program code :-(

Apart from saving maybe a few bytes by omitting some duplicate "if (Serial.available())" statements, no further savings can be made.


ShapeShifter

Code: [Select]
void SerialEvent(){
    while(Serial.available(){
         do_something();
}
Interesting. But keep in mind the note on the SerialEvent() Reference page:
Quote
NB : Currently, serialEvent() is not compatible with the Esplora, Leonardo, or Micro
I'm sure this caveat also applies to the Yun, which has the same processor as a Leonardo.

Also, I think you have a typo in your code sample: Shouldn't serialEvent() start with a lower case 's'?

Robin2

In case one runs out of (flash) memory:
I have deliberately not used serialEvent() in order to keep my examples simple and tranparent.

I would be very interested to see the two code examples you used to determine the saving of 400 bytes.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Go Up