why do I have to close & re-open port between bytes

[See the code several posts later].

Hi, I am completely new to Arduino, though not to programming and hardware ... I am having a problem that I think can be described in a couple of sentences and answered simply (if I'm wrong, I'll post my code):

My sketch is trying to read 2 bytes at a time from the USB to UART serial port. I am sending the two bytes using a Perlscript (under OSX Unix terminal). Unless the Perlscript closes and re-opens the serial port between writing the 2 bytes, the sketch does not see any but the first byte. I have added a 100ms delay between sending the 2 bytes.

Bewildered. TIA.

The behavior of a program is dictated by the code you have written for it. I don't know what you think anyone can do without the code.

Guess what ?

We will need to see the Arduino code so that we know what you are doing.

Post your code, Arduino side and the Perl side as well.

Don't forget to use code tags [code]and [/code]

Here is the sketch (sorry, I do not see the button for code-tags):

And couldn't be bothered to read "How to use this forum". That refusal to read before acting may be at the heart of your problem. It's kind of a critical thing to do in the programming world.

Uh, wrong duplicate thread deleted. Oh well. For the 4th or 5th time, here is my code.

Sketch:

int num_on, num_off, br;
char str[10];

void setup()
{
    // pulse the LED to show reset
    pinMode(LED_BUILTIN, OUTPUT);
    Serial.begin(9600);
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(5000);
    digitalWrite(LED_BUILTIN, LOW);
    delay(2000);
    
    Serial.setTimeout (100);
    
    num_on = 100;
    num_off = 1000;
}



void loop()
{
    // pulse the LED on/off for the specified number of ms
    digitalWrite(LED_BUILTIN, HIGH);
    delay(num_on);
    digitalWrite(LED_BUILTIN, LOW);
    delay(num_off);
    
    // check to see if new on/off times have been sent
    if (Serial.available()>1) {
      br = Serial.readBytes (str,2);
      num_on = str[0] * 10;
      num_off = str[1] *10;
    }

    // for debug 
    Serial.println ("on");
    Serial.println (num_on);
    Serial.println ("off");
    Serial.println (num_off);
    Serial.println ("bytes read");
    Serial.println (br);
}

Perl:

#!/usr/bin/perl
  
$f0 = $ARGV[0];
$f1 = $ARGV[1];

open(my $ard, ">","/dev/cu.SLAB_USBtoUART");
printf $ard  "%c", $f0;

#close ($ard);
#open(my $ard, ">","/dev/cu.SLAB_USBtoUART");

printf $ard  "%c", $f1;
close ($ard);

Works as expected with the two commented-out lines in the middle put back in. But with them commented out, the sketch never succeeds at the Serial.available>1. So 'br' is 0, and num_on and num_off never get updated.

Perl output is buffered and won't be sent until the buffer is full or the file handle is closed or flushed manually.

Add $ard->flush() in a suitable place.

oqibidipo: Perl output is buffered and won't be sent until the buffer is full or the file handle is closed or flushed manually.

Add $ard->flush() in a suitable place.

Thanks. But the 'flush' doesn't seem to work; nor does binmode $ard;

Anyhow, since I printf the two bytes and then close the filehandle, seems like both bytes should get sent. I'm not looking for just the first byte in my sketch; I'm waiting for Serial.available to return "greater than 1"and it never happens (unless I run the Perlscript more than once).

The first time I run the perlscript, neither byte gets read (the 'if (Serial.available)' never succeeds). The second time, the first byte I sent ends up in str[0] and str[1].

Using compiled C on the computer side, I get similar behavior. Remove the two commented-out lines, and it doesn't work properly. Make me suspect my sketch.

#include 
  
int main()
{
        FILE *ard;
        char str[2] = {121,223};

        ard=fopen("/dev/cu.SLAB_USBtoUART", "w");
        fprintf (ard, "%c\n", str[0]);
        //fclose (ard);

        //ard=fopen("/dev/cu.SLAB_USBtoUART", "w");
        fprintf (ard, "%c\n", str[1]);
        fclose (ard);
}

Hi.

You're waiting for the buffer to be larger than 1 byte, right ? Do you have any means to display the buffer size (the return of Serial.available()) in your sketch ? That's what i'd be looking for in an attempt to debug code, because it seems the terms in your if.. statement is never met, or something is / has been coming in, in addition to what you are looking for.

Because of the trouble is suspected to be in your serial comms, i'd add a 1602 display (perhaps using I2C) to do this. But that's because i have tons of stuff like that laying around here.

I would also dump the contents of the serial buffer to that screen, to see what is coming in and whether that is exactly what you expected or not. We're debugging now after all, and any data you can get your hands on might get you some clues.

Yeah, I'm waiting for Serial.available to return a value larger than 1 (e.g. 2).

Part of my problem is I can't see the serial output (from my Serial.println calls), until I fire up Tools->SerialMonitor in the IDE. I have to wait to do that until after I run the Perl, because otherwise the Perl can't access the Filehandle. Is there some work around for that, so I can see the very first Serial.println outputs after the Perl runs ? Copying into a buffer, I suppose.

Passing 2-byte chunks of data from my computer to my sketch seems like a pretty basic and straightforward thing. I gotta figure I'm doing something really stupid.

Could it be some effect of using an ESP32-based board (Adafruit Feather HUZZAH32) ?

Part of my problem is I can't see the serial output (from my Serial.println calls), until I fire up Tools->SerialMonitor in the IDE.

Starting the Serial monitor resets the Arduino.

RustyShackleford: For the 4th or 5th time, here is my code.

Your code for reading Serial is not robust. You are checking if there are 2 or more bytes and then you assume that the bytes you read are in the right order without doing any checking.

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. The system in the 3rd example will be the most reliable and is very easily implemented in a PC program.

...R

UKHeliBob: Starting the Serial monitor resets the Arduino.

I don't think this is true. I do not see the 5-sec LED blink that my sketch performs in 'setup'.

Robin2: Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

This is very helpful. Thank you. I had looked at some of the examples under File->Examples in the IDE, but this is much better. I didn't realize so much "robustifying" was necessary. I assumed if I sent two bytes that eventually Serial.available would return 2.

This paragraph confuses me:

And because data arrives relatively slowly it is easy for the Arduino to empty the serial input buffer even though all of the data has not yet arrived. Many newcomers make the mistake of assuming that something like while (Serial.available() > 0) { will pick up all the data that is sent. But it is far more likely that the WHILE will empty the buffer even though only part of the data has arrived.

How does WHILE empty the buffer ? All it (Serial.available) does is ask how many bytes are in the buffer, it doesn't read any of them. Is this saying that when Serial.available tells you there's one byte in the buffer, that the next time it's called it will say 0 if no additional bytes arrived, or 1 (instead of 2) if a second byte arrived ? This might explain my difficulty, though not why closing and re-opening the filehandle fixes it (seems like the opposite would be the case).

The system in the 3rd example will be the most reliable and is very easily implemented in a PC program.

I plan to do the computer end with a Perlscript (in Unix Terminal window on OSX). And eventually over Wifi from Android.

RustyShackleford: How does WHILE empty the buffer ?

The Serial.read() in the WHILE loop() will repeat so fast that it can take (say) 11 characters out of the buffer and report the buffer empty before the 12th character arrives.

...R

RustyShackleford: I don't think this is true. I do not see the 5-sec LED blink that my sketch performs in 'setup'.

What type of Arduino board are you using ?

Even using those examples of sketches to receive serial comms, the same behavior. I have to close and reopen the filehandle between every character, or it receives them unreliably.

The Perl code couldn't be simpler; as shown here, it doesn't work, but remove those commented-out closing/reopenings of 'ard' and it works perfectly. Seems the problem is in pushing the characters out the pipe (at the computer end). (Oh, I should've mentioned, I'm using this to send a pair of 8-bit values, not characters per se).

#!/usr/bin/perl
  
while ($line = ) {

        # grab the two values from standard input
        ($a,$b) = split(' ', $line);
        printf "values are: %d %d\n", $a, $b;

        # write the two values (as characters) to Arduino, enclosed in angle brackets
        open(my $ard, ">","/dev/cu.SLAB_USBtoUART");
        printf $ard "<";
#       close ($ard);
#       open(my $ard, ">","/dev/cu.SLAB_USBtoUART");
        printf $ard "%c", $a;
#       close ($ard);
#       open(my $ard, ">","/dev/cu.SLAB_USBtoUART");
        printf $ard "%c", $b;
#       close ($ard);
#       open(my $ard, ">","/dev/cu.SLAB_USBtoUART");
        printf $ard ">";
        close ($ard);

}

I am not familiar with Perl. Maybe this Python - Arduino demo will give you some ideas.

...R

UKHeliBob: What type of Arduino board are you using ?

Adafruit Feather HUZZAH32.