Go Down

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

Robin2

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
Two or three hours spent thinking and reading documentation solves most programming problems.

UKHeliBob

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

RustyShackleford

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

Code: [Select]
#!/usr/bin/perl
 
while ($line = <STDIN>) {

        # 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);

}



Robin2

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

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

RustyShackleford


Robin2

Adafruit Feather HUZZAH32.
I know that can be programmed with the Arduino IDE but I would not call it an Arduino board and it would have been nice to know what you were using right up front.

I know nothing about that board.

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

RustyShackleford

I know that can be programmed with the Arduino IDE but I would not call it an Arduino board and it would have been nice to know what you were using right up front.
I mentioned it in post #10, but should've earlier, sorry.

Maybe I should check Adafruit forums; but they don't have one specific to comms w/ computer like this one.

Anyhow, I'm fairly convinced the problem is on the computer side.  Seems the only potential issue at the Adafruit end is that the data comes a lot slower (with the closing/reopening of the pipe), but I've tried sleeping the Perlscript in between characters and it doesn't help.  Maybe I should be looking at an OSX forum.

MAS3

I don't understand a bit of Perl, but i'm curious if you are perhaps sending your data as null terminated arrays (strings).
If so, the null byte has to be handled too and the amount of data in your buffer would be larger than what you expect.
As pointed out before, you assumed that if the buffer size is larger than 1, it will be 2 (you even confirmed that in reply to my former reply).
Instead you could for example copy the result of Serial.available(), and use that to empty the buffer.
Someone also made a remark regarding a problem that may arise with that (that your buffer might get larger while you are still reading it).

That's why i suggested to add a display to your board, and have it display the buffer size and contents.
It visualises what your board sees coming in, instead of trying the serial comms which is the problem you seem to be experiencing.
But if you don't have the means to do so, this can't be used.
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

i'm curious if you are perhaps sending your data as null terminated arrays (strings).
I completely changed my sketch, after @Robin2 pointed out (post #12) that my code was not robust; I used the 3rd of the examples he linked, which encases the bytes of interest in angle brackets, and reads only one byte at a time.   And my Perl onto transmits one byte at a time.   I'll show my latest code below.
Quote
That's why i suggested to add a display to your board
Yeah, good idea, but I don't have such a display right now.

Code: [Select]

const byte numChars = 32;
char receivedChars[numChars];

boolean newData = false;

int num_on, num_off;

void setup() {
    Serial.begin(9600);
    Serial.println("<Arduino is ready>");
   
    // pulse the LED to show reset
    pinMode(LED_BUILTIN, OUTPUT);
    Serial.begin(9600);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(5000);
    digitalWrite(LED_BUILTIN, LOW);
    delay(2000);
   
    num_on = 100;
    num_off = 1000;
}

void loop() {
    recvWithStartEndMarkers();
    showNewData();

    // 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);

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


void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
 
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        num_on  = receivedChars[0] * 10;       
        num_off = receivedChars[1] * 10;
        newData = false;
    }
}



And the Perl is:

Code: [Select]
#!/usr/bin/perl
 
while ($line = <STDIN>) {

        # 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);

}


As is, it doesn't work.  Remove those 6 commented-out lines and it works.

Robin2

As is, it doesn't work.  Remove those 6 commented-out lines and it works.
I think you need to find a Forum where a Perl expert can help you.

I suspect it is possible to get Perl to send the whole message as one unit. It would be very strange if it could not.

...R

PS ... You could switch to Python :)
Two or three hours spent thinking and reading documentation solves most programming problems.

RustyShackleford

#25
Dec 14, 2017, 01:33 am Last Edit: Dec 14, 2017, 01:38 am by RustyShackleford
I think you need to find a Forum where a Perl expert can help you.

I suspect it is possible to get Perl to send the whole message as one unit. It would be very strange if it could not.
Strange indeed.
Quote
PS ... You could switch to Python :)
You know, several years ago at a contracting gig, just when I thought I'd finally achieved some basic mastery of Perl, someone clued me in that Python was the new "thing".   So it goes ...

Anyone know of a Perl to Python converter ?   :-)


sterretje

I guess we currently don't know if it's an Arduino issue or a perl issue. If so, use serial monitor to replace the perl side and test if the Arduino does what it is supposed to do; once that works, you can modify the perl side to match what the Arduino expects.
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.

Robin2

Anyone know of a Perl to Python converter ?   :-)
What use would that be if your Perl program does not work?  :)  :)

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

RustyShackleford

What use would that be if your Perl program does not work?  :)  :)
There's nothing wrong with my Perl program - it's so simple, just opens a filehandle and sends 4 characters to it.  The hypothesis would be that there's something generic about the way Perl does this.

But there's more data ...

A virtually-identical C program behaves exactly the same way as the Perl: closing and re-opening the file pointer fixes the problem.

It works fine with the serial monitor.

Seems to me it's gotta be something to do with the characters getting sent to the Arduino too quickly.   In Tools>UploadSpeed I have it set to 921600 as Adafruit recommends.   I changed FlashFrequency from 80MHz to 40MHz with no change.   Maybe the problem is in OSX ?!

Robin2

There's nothing wrong with my Perl program -
So why am I writing Reply #29 while you still have a problem?



Did you try my Python example?

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

Go Up