Reading from Serial1 requires that I write to Serial. Solved

Hi,

I'm sure I'm doing something silly, but I don't know what.

I have a Mega and I am periodically reading single characters from Serial1. I have noticed that the character I read is often junk unless I first write at least about 5 characters to Serial (i.e. the programming port). Any idea why this would be, please?

i.e. This works
Serial.print("You entered: ");
char ch = Serial1.read();

This usually fails:
char ch = Serial1.read();

I'm perplexed...

Thanks!

Are you checking to make sure there is something to read first?

if (Serial1.available())
char ch = Serial1.read();

Read this before posting a programming question

All your code, not just two lines.

Besides, what James C4S says is correct.

I didn't post the code because there's too much of it and it's spread over multiple files. I am checking if there is something to read, but the check is in a different function. I'll try adding it also to the same function. I can see how that could be causing the issue.

Your code is not synchronized with serial comm. Your serial reading is not matching with data available with your reading.

raacampbell:
I didn't post the code because there's too much of it and it's spread over multiple files.

Serial port handling is usually simple and only involves a few lines of code. I suggest you write a test sketch that demonstrates your problem in the simplest possible way, and then post it here.

PeterH:
Serial port handling is usually simple and only involves a few lines of code. I suggest you write a test sketch that demonstrates your problem in the simplest possible way, and then post it here.

You're right, I should have done that. You guys have provided valuable suggestions, though. It does looks like I need an extra check that characters are available. I try that today and see what happens.

raacampbell:

PeterH:
Serial port handling is usually simple and only involves a few lines of code. I suggest you write a test sketch that demonstrates your problem in the simplest possible way, and then post it here.

You're right, I should have done that. You guys have provided valuable suggestions, though. It does looks like I need an extra check that characters are available. I try that today and see what happens.

Could you just explain one thing?

Why make a program so big it can't be posted that includes parts you do not have working, practiced understanding of?

I'm not poking at you to make fun or anything. I just see so much of this that the question of "Why?" comes ever more clearly to mind.

I've seen that going back to 1980 when I had to fix piece by piece a PhD thesis business package in line number basic while I was still learning basic and had no degree myself.

What is the view of programming that leads to writing a pile of errors before checking let alone fixing any of them? I would truly like to understand because perhaps somewhere in the knowing of that there might be a simple way to get people to stop doing that.

Years could be saved in which to waste in other less productive ways!

What is the view of programming that leads to writing a pile of errors before checking let alone fixing any of them?

I rather suspect that it's what you do before learning the hard way that stepwise refinement makes your life easier.

If you call Serial.read() without first checking Serial.available(), your code is by definition broken.

read() does not test if a character is available to read and does not block. (Its a known gotcha
in the Serial library)

Try defining your own blocking read() it thats what you want:

char mySerial1Read()
{
  while (Serial1.available() == 0)
  {}
  return Serial1.read ();
}

[ the reason the call to Serial.print() makes things appear to work is that it takes time and by luck the Serial1
interface has received a valid byte by then ]

Ok, it seems I need a 1 ms delay (as shown below). I apologize for not initially supplying a stripped down example.

In the code below, the idea is that the user supplies a string such as "m3". The first character leads to a call of the doM() function, which then reads the second character and does something with it. I know that looks pointless in the example below, but in the real implementation it makes more sense because a variety of different commands can come in and these are of more than two characters in length, etc. The doM() function needs a 1 ms delay in order to work. I guess to make sure the buffer is full.

void setup(){
  Serial.begin(115200);
  Serial1.begin(115200);
}


void loop(){
  if (Serial1.available()){
    char ch=Serial1.read(); //read first character
       if (ch=='m')
          doM();
     //Other starter characters that lead to different function calls would follow 
    }
}


void doM(){
 delay(1); //THIS IS NEEDED
 while (Serial1.available()){
    char ch=Serial1.read();
    Serial.println(ch);
    //do other stuff with ch
    }
}

GoForSmoke:
Could you just explain one thing?

Why make a program so big it can't be posted that includes parts you do not have working, practiced understanding of?

I must say, I'm perplexed at how you know that my code is over-long, poorly understood by me, and riddled with errors. :slight_smile: Regardless, I will answer your question. What I meant by "too big to post" is that there's no point posting the whole program because it is 1000 lines long (including comments) and virtually all of it is irrelevant to the issue I'm having. My code was already near this size, fully functional, and without errors before I added the serial port reading stuff and ran into this problem. Hence this thread. Does that answer your question, or would you like more information about what I'm doing?

No, the delay() isn't necessary. Waiting until a character is available is...

Instead you could call:
while(Serial1.avaialble() == 0 ); // this will block until the next character arrives.

Thanks, I can see how that should be the more elegant solution. I assume you mean me to replace the delay with the blocking while? Oddly, however, this doesn’t work properly. If you’re interested here’s what I see: I send to Serial1 the message: “m12345” and see if it is read correctly using the code above, except that I modify doM() and test the delay vs the while by commenting out the lines as appropriate.

void doM(){
 //while(Serial1.available() == 0 ){}//block until char arrives
 delay(1);

 while (Serial1.available()){
   char ch=Serial1.read();
   Serial.print(ch);
 }
}

With only the delay uncommented (as shown above) I see the string “12345” displayed on the terminal listening to Serial. So that’s correct. However, with only the while uncommented, I get back only the character “1”. I don’t understand why this would be. Whilst the 1ms delay feels like a hack, I think I will stick to it for now because it behaves as I expect and has no negative consequences. It would be nice to know why your solution isn’t working for me. Probably I’m doing something silly: I’ve been programming for a good while but I’m new to C, mics, and a lot of this hardware stuff.

The code is working fine, your assumptions are flawed.

The code, as written, will stop receiving characters as soon as the buffer is empty. Unfortunately, not all of the characters you send will arrive at the same time. So either you do the unreliable method of blocking (like with delay()) for extended periods of time, you count the number of characters you receive, or wait for an "end of packet" delimiter to know when your "send" is finished.

Ah, yes, it's not behaving as I thought it was. So basically you're saying that my while loop executes faster than the characters can come into the Serial port. Makes sense now that you say it! I think you've told me enough for me to now get rid of the delay. Thanks!

raacampbell:
So basically you’re saying that my while loop executes faster than the characters can come into the Serial port.

Exactly.


GoForSmoke:
Could you just explain one thing?

Why make a program so big it can't be posted that includes parts you do not have working, practiced understanding of?

I often wonder that, however I suspect that in many cases people copy large chunks of code from other examples, and bang them together. This will tend to lead to this effect. The smaller batches work on their own, but the large conglomerate doesn't.

In principle I totally agree with you, GoForSmoke. Let's say I am making a temperature sensor that reads the temperature and shows it on some LEDs, I will always test the sensor (via serial prints), the LEDs (with dummy data), and then once I am sure the "black boxes" work on their own, start connecting them together.

raacampbell:

[quote author=James C4S link=topic=182885.msg1355591#msg1355591 date=1376673771]
No, the delay() isn't necessary. Waiting until a character is available is...

Instead you could call:
while(Serial1.avaialble() == 0 ); // this will block until the next character arrives.

Thanks, I can see how that should be the more elegant solution. I assume you mean me to replace the delay with the blocking while? Oddly, however, this doesn't work properly. If you're interested here's what I see: I send to Serial1 the message: "m12345" and see if it is read correctly using the code above, except that I modify doM() and test the delay vs the while by commenting out the lines as appropriate.

void doM(){
 //while(Serial1.available() == 0 ){}//block until char arrives
 delay(1);

 while (Serial1.available()){
   char ch=Serial1.read();
   Serial.print(ch);
 }
}

With only the delay uncommented (as shown above) I see the string "12345" displayed on the terminal listening to Serial. So that's correct. However, with only the while uncommented, I get back only the character "1". I don't understand why this would be. Whilst the 1ms delay feels like a hack, I think I will stick to it for now because it behaves as I expect and has no negative consequences. It would be nice to know why your solution isn't working for me. Probably I'm doing something silly: I've been programming for a good while but I'm new to C, mics, and a lot of this hardware stuff.
[/quote]

Go back and look at this and the post before it. Notice the difference in the while statements? ~~You have the serial read inside the while loop, and that loop stops going as soon as the character arrives. You've said, keep reading this character until it actually gets here, then ignore it and move on. What you want to say is, hang up on this line until the serial character gets here, then move on to reading it. ~~ See next post.

In the example in the post before the statement is:

while(Serial.available == 0);
char c = Serial.read();
Serial.println(c);

In this example, notice that there is a semicolon behind the while statement and the serial stuff isn't in curly braces. This while loop says, while Serial.available == 0 do nothing and keeps doing nothing over and over again until that character arrives.

Notice

Ooops, read that first code wrong. The code the OP wrote doesn't say keep reading until it gets there, it says keep reading as long as something is there.

In this case, if the thing isn't there right at the beginning, then the while loop never gets executed because the condition fails the first time. Leaves you in the same boat as if you hadn't changed anything.