General Question about Serial

I have what should be a simple question about Serial, but I can't seem to find anything helpful. I have a program that uses

if(!Serial.available())

What's the difference between using that and using

if(Serial.available())

I know the latter waits for Serial to reach the Arduino before processing, but I'm not sure what's happening when you tell the Arduino to wait until Serial is not available.

The first one is wrong. It will work, but it is not okay.
The '!' is for a boolean operation and is a 'not'.

For example

boolean sunlight = true;

if(sunlight)
  Serial.println("The sun is shining");

if(!sunlight)
  Serial.println("The sun is not shining");

The Serial.available() returns the number of bytes that are received and are waiting in the receive-buffer inside the Serial library.
To test if no bytes are waiting, it can be done like this:

if(Wire.available() == 0)
{
  // no Serial bytes are waiting, there is some time to blink a led.
  blink_a_led();
}

Serial.available() returns the number of bytes available to read. Neither constructor is anything I like. I prefer to be explicit about what the function is waiting for.

The if(!Serial.available()) statement says that if not 0, that is if there is serial data to read, do something.

The if(Serial.available()) statement says if 1 or more, that is there is serial data to read, do something.

The first can be though of as "if not nothing to do, do it". The second can be thought of as "if something to do, do it". Obviously, the second is easier to understand. For English speakers, anyway.

PaulS:
The if(!Serial.available()) statement says that if not 0, that is if there is serial data to read, do something.

The first can be though of as "if not nothing to do, do it".

Care to re-word that? You've managed to describe it exactly backwards.... Twice...

Regards,
Ray L.

You've managed to describe it exactly backwards.... Twice...

Care to elaborate? Since Serial.available() returns 0 when there is nothing to do, the if(!0) result says that if there is not 0 characters (not nothing to do), do something.

So then if I send data to the Arduino, say for example >>150<<, and I use:

if(Serial.available()) {
Serial.println(Serial.read());
}

will it print

>>150<<

or

>
>
1
5
0
<
<

And if I use:

if(!Serial.available()) {
Serial.println(Serial.read());
}

which one of the above will the output look like?

So I guess I'm going to get more specific here and see if I can get a question answered that's related to what I'm working on. I am using a program called VixenLights that controls an LED strip. When Vixen begins sending data, it sends out a header, >>150<<. After which I believe it sends one byte at a time with the LED number and the color. I'm not exactly positive on how the serial data is structured, all I know is it works :). I'm trying to make the project wireless now with two nrf24l01+ modules and I'm not sure how I should transmit the incoming data from Vixen... Here is the code I have now that works with the Vixen software. Notice the

while(!Serial.available());

lines. I'm not real sure what's going on here...

#include <FastLED.h>

#define NUM_LEDS 150
#define DATA_PIN 3

CRGB leds[NUM_LEDS];

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

void loop() {
    int cnt;
    unsigned int num_leds;
    unsigned int d1, d2, d3;
    
    for(;;) {
        cnt = 0;
        while(!Serial.available());
        if(Serial.read() != '>') {
            continue;
        }
        while(!Serial.available());
        if(Serial.read() != '>') {
            continue;
        }
        while(!Serial.available());
        d1 = Serial.read();
        while(!Serial.available());
        d2 = Serial.read();
        while(!Serial.available());
        d3 = Serial.read();
        while(!Serial.available());
        if(Serial.read() != '<') {
            continue;
        }
        while(!Serial.available());
        if(Serial.read() != '<') {
            continue;
        }
        num_leds = (d1-'0')*100+(d2-'0')*10+(d3-'0');
        if(num_leds > NUM_LEDS) {
            continue;
        }
        FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, num_leds);
        do {
            while(!Serial.available());
            leds[cnt].r = Serial.read();
            while(!Serial.available());
            leds[cnt].g = Serial.read();
            while(!Serial.available());
            leds[cnt++].b = Serial.read();
        }
        while(--num_leds);
        FastLED.show();
    }
}
while(!Serial.available());

This means "While not serial [data is] available, do [nothing];", although I prefer

while(!Serial.available())
   ; // wait

as it can't be confused with a single-line statement.

if/while (Serial.available()) reads pretty nicely, I thought, and so does

if/while (!Serial.available())

So that sketch waits for each character to come in, then reads it. Not the best structure if you have other things to do. :frowning:

Cheers,
/dev

Notice the

Yeah, I did. But, as has been pointed out, Serial.available() does not return a boolean saying that there is, or is not data to be read. So, that statement REALLY should be:
while(Serial.available() == 0); // Do nothing while there is nothing to read.

Then, it is crystal clear what is meant and what will happen.

I'm not real sure what's going on here...

Probably because that code is crap. The loop() function is called in an infinite loop. There is no reason to add an infinite loop inside it.

The loop() function should have a while(Serial.available() > 0) block, that handles all incoming serial data.

Inside that block, it should read and possibly store data. After reading an available character, it should decide whether it is a start marker. If not, and two start markers have not been received, ignore it.

If it is, it should increment the count of start markers.

If it is not a start marker and two start markers have arrived, then it should store the data in the next array, based on how many bytes have been read since the second start marker arrived.

Obviously, dealing with the end markers has to happen, too.

But, if it works, you don't have to make it better.

What data, exactly, do you want to send by radio? And, when? One byte at a time? Three bytes at a time? All n bytes for all p LEDs?

I'm cool with you calling it crap code since I didn't write it. :slight_smile:

As far as how I plan to send the data, that's still unknown. Since I do have working code, I was going to first try to send it a byte at a time, the same way it's received from Vixen. The issue right now is that I don't really know exactly how the data is being structured in Vixen when it's sent and if it is really necessary to read it a byte at a time or if, like you said, I can store the data.

As for the endless loop... I believe I tried to remove that, but it didn't work when I did. Not sure why. Maybe I'll clean this code up and in the process learn more about how the data is coming in.

The examples in Serial Input Basics are simple reliable ways to receive data.

The NRF24 is somewhat different because the devices themselves carry out a great deal of invisible error checking. I think you can take it that if the data is received it is what was sent.

Assuming your Arduino receives the data over a serial connection you can send it onwards via wireless in any format that is convenient - including just passing it on unchanged. I believe there is a not-very-big maximum packet size for the NRF24 but I can't immediately remeber what it is. The data in my project is far below the limit. Obviously you can send longer data as multiple packets, but it would probably be simpler if you can avoid that.

I used this tutorial to get my NRF24s working.

...R

The issue right now is that I don't really know exactly how the data is being structured in Vixen when it's sent and if it is really necessary to read it a byte at a time

All serial data is read a byte at a time. You could have this code use a simple function:

void loop()
{
   while(Serial.available() > 0)
   {
      byte b = Serial.read();

      // Send the byte via the radio to the other device
   }
}

Then, most of the code in this function is going to move to the Arduino on the other end of the radio link.

There, you create a function to replace Serial.available() that determines how much radio data is available, and call in instead of Serial.available(). You create a function that gets a byte from the radio, and call it in place of Serial.read().

PaulS:
All serial data is read a byte at a time. You could have this code use a simple function:

Paul, the NRF24 sends a packet of data (which could be several bytes - up to 32?) as a unit surrounded by its own invisible error checking.

If radio.available() is true it means the packet has arrived.

...R

Robin2:
Paul, the NRF24 sends a packet of data (which could be several bytes - up to 32?) as a unit surrounded by its own invisible error checking.

If radio.available() is true it means the packet has arrived.

...R

I know that the packet can contain more than one byte. But, it doesn't have to, does it? Aren't packets kept in order?

PaulS:
I know that the packet can contain more than one byte. But, it doesn't have to, does it? Aren't packets kept in order?

I'm not sure, but I'd be very surprised if receive packets are buffered at all. In other words, there will only ever be zero or one available. Whether the decoder responds to new packets at all once a packet is recognized, is also an interesting question. I would venture a guess that it expects the packet to be read before it will resume decoding.

PaulS:
I know that the packet can contain more than one byte. But, it doesn't have to, does it? Aren't packets kept in order?

I don't understand the context behind your question "Aren't packets kept in order?"

All I was trying to say is that radio.available() returns true or false, not the length of the data in the packet.

If you have enabled dynamic payloads there is a getDynamicPayloadSize(). Otherwise the packet size is fixed.

...R

All I was trying to say is that radio.available() returns true or false, not the length of the data in the packet.

I got that. I was wrong.

What I want to know, since I don't have those radios, is, if I send 10 packets, are they going to be received in the order sent? It wouldn't matter if I sent a packet containing several values, then paused until I got an acknowledgement. But, If I send a bunch of tiny packets, will they be received in order? What happens if one is garbled, and needs to be re-sent? What does that do to the packets that I sent after the one that got garbled?

XBees handle all this for you.

PaulS:
if I send 10 packets, are they going to be received in the order sent? It wouldn't matter if I sent a packet containing several values, then paused until I got an acknowledgement.

The normal use of the device includes an acknowledgment. And, in fact the "receiver" can send useful data as part of the acknowledgment which can save the two devices from having to switch roles. I have been developing an application in which the transmitted data is irrelevant - the actual value is in the acknowledgment.

I can't see myself using the device in a style where several packets are sent "blindly" - although that is certainly possible.

In any case I'm pretty sure there is no possibility of the packets being received in the wrong order, although some might get lost.

...R