Go Down

Topic: why do I have to close & re-open port between bytes (Read 1 time) previous topic - next topic

RustyShackleford

Dec 11, 2017, 08:34 pm Last Edit: Dec 11, 2017, 10:20 pm by RustyShackleford
[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.

Delta_G

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. 
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

UKHeliBob

Guess what ?

We will need to see the Arduino code so that we know what you are doing.
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

sterretje

#3
Dec 11, 2017, 08:40 pm Last Edit: Dec 11, 2017, 08:41 pm by sterretje
Post your code, Arduino side and the Perl side as well.

Don't forget to use code tags [code]and [/code]
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

Delta_G

Quote
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. 
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

RustyShackleford

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

Sketch:

Code: [Select]

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:

Code: [Select]

#!/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.

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.

RustyShackleford

#7
Dec 11, 2017, 11:32 pm Last Edit: Dec 11, 2017, 11:40 pm by RustyShackleford
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].



RustyShackleford

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.

Code: [Select]

#include <stdio.h>
 
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);
}

MAS3

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.



Have a look at "blink without delay".
Did you connect the grounds ?
Je kunt hier ook in het Nederlands terecht: http://arduino.cc/forum/index.php/board,77.0.html

RustyShackleford

#10
Dec 12, 2017, 06:13 am Last Edit: Dec 12, 2017, 06:36 am by RustyShackleford
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) ?



UKHeliBob

Quote
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.
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Robin2

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

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

RustyShackleford

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'.

RustyShackleford

#14
Dec 12, 2017, 07:15 pm Last Edit: Dec 12, 2017, 07:24 pm by RustyShackleford
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).


Quote
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.


Go Up