Kind of Multitasking

Hi, guys,

I have a small problem, and I need your support. I'm also not sure if this is the right place for my question, if not it would be nice if you could tell me where the right place is.

I have a project where I want to use an Arduino to read sensor data and send it via USB to a Raspberry PI which then processes it. In addition, the raspberry Pi should send messages via USB to the Arduino in order to make it move motors.

My problem is that the Arduino has to read the sensors all the time, and I can't send a message to the PI at the end of each loop to ask if the motors need to be moved. That would cost way to much Time.

Is there a way to let the Arduino run a program, and when it receives a message via USB, run a function after which it continues with the normal program?

Would be nice if you could help me.

isi_ko

Kinda vague.

What I want is for the Arduino to run a program, and when it receives a message via USB, it should perform a function and then return to the "main program". So it should look all the time if a message has come, and independently of that, it should read the sensor data all the time and send it to the Raspberry PI

What's the problem?

It might help if you showed a concrete example.

This is my Code

In the commented out part I tried to send a message to the PI to ask him to send a message back, but that took way to much time.

Most people won't follow a link to code. Please include the code in your post.

immediately after "void loop() {" put something like:

if (Serial.available()) {
  DOSOMETHING();
}

That way the code will check every cycle if the RPi has sent back data. If yes, then do something like "Send back serial data".

Do note though that if your baudrate is 9600 as shown in your code, any Serial communications is gonna be slow regardless. I highly recommend bumping it up to 115200 for extremely quick communications that won't bog down your code.

you have to explain this as well

My problem is that the Arduino has to read the sensors all the time, and I can't send a message to the PI at the end of each loop to ask if the motors need to be moved. That would cost way to much Time.

if you need to send the sensor data, you keep the Serial port busy one way. nothing prevents you from receiving too...

move the Serial line to 1,000,000 bauds that won't be a problem between an Arduino and a RPi and you'll see a slight :smiley: :wink: speed increase compared to your 9600 bauds...

Although what @Technokid2000 proposed would work

 if (Serial.available()) {
  DOSOMETHING();
}

if time is of the essence, I would suggest to directly read the Serial line at test against -1

int incoming = Serial.read();
if (incoming != -1) { // read returns -1 if there is nothing to read
  // we have received something
}

The reason is that available() does actually take time to do some counting (with modulo which is a costly operation) and if you don't care about how many bytes are available, then no need to ask for the count, just if data is really there or not — which is what read() will tell you.

available() gives a false sense that it is a boolean answer and not a count - I don't like that name much...

J-M-L:
The reason is that available() does actually take time to do some counting and if you don't care about how many bytes are available, then no need to ask for the count, just if data is really there or not — which is what read() will tell you.

In the good old days of DOS/ASM based UART Port programming of IBMPC, we had to check first that the port had really received data and then read the arrived data.

ASM Codes to Read RHB-register by Polling the RxRDY-bit:
L11:	mov		dx, 2002h		; pointing at SR-register
	in		al, dx
L12:	test		al, 02h		; checking if al1-bit (RxRDY-bit) is 1
	jz		L11			; RxRDY-bit is not LH

L13:	mov		dx, 2000h		; pointing at Rx-register
	in		al, dx		; reading ASCII code from Rx-register
L14:	nop					; reading from Rx-register is done

I think, the available() and read() methods have the similar reasoning.

GolamMostafa:
I think, the available() and read() methods have the similar reasoning.

Well I see how the idea that you would first check if there is something to read before reading but as you say

we had to check first that the port had really received data

--> this is a boolean information, the code should read

bool HardwareSerial::available(void)
{
  return (_rx_buffer_head != _rx_buffer_tail);
}

and we should have a different method rxBufferSize() that would return the actual number of bytes ready to be read.

int HardwareSerial::rxBufferSize(void)
{
  return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
}

but hey, that's how they've done it... so best way to work around this (small) cost is to use either read() or peek() which will return -1 (and remove or not the byte if there is one).

I reckon that at 9600 bauds it does not matter much anyway, the time penalty is not there... At 2,000,000 bauds it's somewhat (a bit) more visible

1. When I don't include the available() method in the sketch, I have a noisy Serial Monitor (Fig-1).


Figure-1:

Executed sketch:

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

void loop()
{
  //byte n = Serial.available();
  //if (n != 0)
  //{
    char x = Serial.read();
    Serial.println(x);
    delay(1000);
  //}
}

2. When I do include the available() method in the sketch, I get a quiet Serial Monitor (Fig-2).


Figure-2:

Executed sketch:

void setup()
{
  Serial.begin(9600);

}

void loop()
{
  byte n = Serial.available();
  if (n != 0)
  {
    char x = Serial.read();
    Serial.println(x);
    delay(1000);
  }
}

3. Any interpretation for the above results?

4. If I don't include the available() method, then should I include the following codes in the sketch to get a quiet Monitor?

char x = Serial.read();
if(x != -1)
{
   Serial.println(x);
}

    char x = Serial.read();
    Serial.println(x);

as I said, you need to have x as an integer (because that's what read returns) and test it against -1 to see if something was read. here you print 0xFF which gives you the weird output

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

void loop()
{
    int x = Serial.read();
    if (x != -1) Serial.println(x);
}

the whole point is not to avoid testing if something was there to read, the point is to do so in an "efficient" way (probably save ~20 clock cycles so probably 1.25µs :slight_smile: ...)

I only mentioned it here as OP seemed to imply that timing was critical

So to get a quiet Serial Monitor, we have to include in the sketch either of the following two code blocks--
1. Option-1

byte n = Serial.available();
If(n != 0)
{
    char x = Serial.read();
    Serial.println(x);
}

2. Option-2

char x = Serial.read();
if(x != -1)     //0xFF
{
    Serial.println(x);
}

As I understand, you are recommending Option-2.

I suggest option 2 (with a modification from char to int as otherwise you could not receive binary 0xFF byte correctly, -1 will be coded 0xFFFF (on AVR) whereas 0xFF will be checked as 0x00FF) if you don't care about how many bytes are in the incoming buffer.

So I would suggest

int x = Serial.read();
if(x != -1)     // 0xFFFF on AVR, 0xFFFFFFFF on MKR or ESP
{
    Serial.println(x);
}

or even faster as most of the time the buffer is empty probably

if(Serial.peek() != -1)     // 0xFFFF on AVR, 0xFFFFFFFF on MKR or ESP
{
    Serial.println(Serial.read());
}

That's only if you really care about micro-second level efficiency, there are so many example out there with available() that this could confuse beginners for whom it's OK to say "test if something is available before reading it". So when teaching, I would still recommend the "slow" approach, it's easier to grasp and does not require understanding of what's happening in the background.

isi_ko:
Is there a way to let the Arduino run a program, and when it receives a message via USB, run a function after which it continues with the normal program?

Yes, a few of my own projects do that.

Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable. It is what I use for Arduino to Arduino and Arduino to PC communication.

You can send data in a compatible format with code like this (or the equivalent in any other programming language)

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

You should be able to see how those examples can work alongside other functions that you call from loop().

If you want to see a more general multi-tasking example have a look at how the code is organized in Several Things at a Time. Note how each function runs very briefly and returns to loop() so the next one can be called. None of the functions tries to complete a task in one call. And there may be dozens of calls to a function before it is actually time for it to do anything.

...R