Arduino can only read from serial one character at a time

I’m working on making an LED matrix display, using a 576 LED strip (18x32), and eventually I will want to use serial communication in order to get weather information to show on the display. I’m learning how serial communication works at the moment, and came across Serial Input Basics - updated which was very helpful. I believe I have the basic concept down, but when I take the third example and use it in my own code, I can only get the Arduino to return the string if I send it one character at a time. For instance, sending “” gives me nothing, but if I send that same thing one letter at a time, it returns properly.

I’ve narrowed this down to running the led_Strip.write() during the loop of my sketch. Because of this, I believe that my issue is because of the arduino taking too long to write 576 LED lights and not being available for the entire string. That doesn’t make too much sense to me though, because as I understand it the arduino has a buffer to hold the information sent over serial, which would then still be available for the arduino when it is finished with the led_Strip.write().

I’ve included the relevant code. I did not write the recWithStartEnd() or the printNewData() functions, I took them straight from the page linked above.

#include <PololuLedStrip.h>
PololuLedStrip<12> ledStrip;
#define LED_COUNT 576
rgb_color colors[LED_COUNT];
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Doing something");
}

void loop() {
  // put your main code here, to run repeatedly:
  ledStrip.write(colors, LED_COUNT); //If this line is commented out, the program runs as expected
  recvWithStartEndMarkers();
  printNewData();
}

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

 // if (Serial.available() > 0) {
    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 printNewData(){
  if (newData == true){
    Serial.println("This just in: ");
    Serial.println(receivedChars);
    newData = false;
  }
}

Since I think I have found the problem, can anyone say why the buffer is not saving the information until the arduino is ready for it? Is there any way to have the arduino get the information from serial while it is writing to the LED strip? I’m not overly concerned about the refresh rate on the LEDs, but I would like it to update at least a few times per second. Thank you for any help, and if there’s any questions I can answer to make it easier to help me, please let me know.

I’m using an Arduino Due, WS2812b LED strips, and nothing else at the moment. I’m connecting to the programming USB port on the arduino, and I’m running Linux mint on my computer, if any of that helps.

The code looks okay at first glance. I'm suspicious about your sending instead. Are you sure you are sending end markers in both cases, for example?

haltermak:
For instance, sending “” gives me nothing, but if I send that same thing one letter at a time, it returns properly.

I don’t understand. What are you using to send the data?

ALL serial data is sent one character after the other - that’s what serial means.

…R

aarg:
The code looks okay at first glance. I’m suspicious about your sending instead. Are you sure you are sending end markers in both cases, for example?

I have tried it many times, I’m quite sure. To test I send “”, to which the arduino sends nothing in return. I think it is only getting one character at a time. For instance, if I send “”, then “world”, then “hello>”, the arduino prints “w” as it’s response. That made me believe it was only getting one character at a time. So I tried entering “<”, “h”, “e”, “l”, “l”, “o”, “>”, each time as a separate press of send on the serial monitor. The arduino returns “hello” as soon as I send the end character, ‘>’. But if I remove the led_Strip.write(), I can just send and the arduino returns “hello.”

Robin2:
I don’t understand. What are you using to send the data?

ALL serial data is sent one character after the other - that’s what serial means.

…R

I understand that much. However, the example from the page I linked allows you to send many characters at a time, by using the start character and end ciharacter. When I run my program without the led_Strip.write() in the loop, it functions as I’d expect. The serial monitor sends the data to the buffer, then the arduino reads it one character at a time. When I run it with that line in, it functions as I detailed in the paragraph above.

the library you are using…

#include <PololuLedStrip.h>

uses interrupts?

haltermak:
When I run my program without the led_Strip.write() in the loop, it functions as I'd expect.

Then the problem is due to that led_Strip.write() function.

I have no idea what is going on inside it.

...R

look here in loop():

void loop() {
  // put your main code here, to run repeatedly:
  ledStrip.write(colors, LED_COUNT); //If this line is commented out, the program runs as expected
  recvWithStartEndMarkers();
  printNewData();
}

you are CONSTANTLY writing the array to the strip…

the function 1) blocks and 2) disables interrupts. So, interrupts are largely disabled all of the time.

you have to change the logic to update the strip if and only if arduino receives new values.

EDIT:

Example below eliminates this nonsense:

recvWithStartEndMarkers();
printNewData();

in favor of a function that will tell you that you’ve received something (basically conditionally calling both the printNewData() function and the write to the ledStrip). I’ve re-factored your recvWithStartEndMarkers() function as you don’t need start and end markers for Serial transmission. This code only needs a newline character (i.e. ‘\n’ in the code that follows). So, rather than bracketing your data in those sideways carats (<>) just send the data with a newline behind it. Or, as you can see from the function, select any char to end the message.

#include <PololuLedStrip.h>
#define MAX_MESSAGE_LENGTH 32

PololuLedStrip<12> ledStrip;
#define LED_COUNT 576
rgb_color colors[LED_COUNT];

void setup() 
{
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println(F("Doing something"));
}

void loop()
{
  if(char* newMessage = checkForNewMessage(Serial, '\n'))
  {
    Serial.println(newMessage);
    // De-Code your message here, then write to the ledStrip
    ledStrip.write(colors, LED_COUNT); //If this line is commented out, the program runs as expected
  }
}

const char* checkForNewMessage(Stream& stream, const char endMarker)
{
  static char incomingMessage[MAX_MESSAGE_LENGTH] = "";
  static byte idx = 0;
  if(stream.available())
  {
    incomingMessage[idx] = stream.read();
    if(incomingMessage[idx] == endMarker)
    {
      incomingMessage[idx] = '\0';
      idx = 0;
      return incomingMessage;
    }
    else
    {
      idx++;
      if(idx > MAX_MESSAGE_LENGTH - 1)
      {
        //stream.print(F("{\"error\":\"message too long\"}\n"));  //you can send an error to sender here
        idx = 0;
        incomingMessage[idx] = '\0';
      }
    }
  }
  return NULL;
}

I’ll leave it to you to parse the message…

BulldogLowell:
Example below eliminates this nonsense:

recvWithStartEndMarkers();

printNewData();




in favor of a function that will tell you that you've received something

Why is my stuff "nonsense"?

My code provides an indicator when something is received.

I am not saying mine is the only way to do it - but I don't think it is fundamentally different to yours. And my code was written to work with the Arduino functions that less experienced users are likely to be familiar with.

...R

Although I prefer to test the newData flag in loop(), I agree that Robin's code works because it checks the flag in the printNwData() function.

The only thing OP has to do is to move ledStrip.write() into the printNewData() function at thr right place and it should work. As printNewData now does not only print, a more sensible name should be appropriate.

Robin2:
Why is my stuff "nonsense"?

My code provides an indicator when something is received.

I am not saying mine is the only way to do it - but I don't think it is fundamentally different to yours. And my code was written to work with the Arduino functions that less experienced users are likely to be familiar with.

...R

In the context of your tutorial, it is great. The approach is yours and I tried to stay as close to your tutorial as possible. However, in the context of this program, the function names are meaningless and they don't indicate in any way that there are dependancies. In your tutorial it's fine because there is nothing else happening.

Again, as I've mentioned, you stopped short of taking the tutorial all the way through the basics of functional programming. I feel that folks would benefit greatly by paying attention for one more module. They's leave way more prepared (i.e. this post).

sterretje:
Although I prefer to test the newData flag in loop(), I agree that Robin's code works because it checks the flag in the printNwData() function.

Of course its your prerogative, but why not tell the story as you write the code?

  if (thisHappens(toThis))
 {
    doThis();
  }