Question

I have an arduino taking serial input and will turn on the leds. The code is below.

I have a strange problem that when I send multiples of 120x bytes e.g., 240, 480 the last 120 bytes never get read completely.

I see on the serial monitor 120 120 120 81 if I send 480 bytes of data. Could anyone point out the mistake?

#include "FastLED.h"
#define DATA_PIN 6
#define NUM_LEDS 40

byte colors[120];

CRGB leds[NUM_LEDS];

void setup(){
  FastLED.addLeds<NEOPIXEL, DATA_PIN, RGB>(leds, NUM_LEDS);
  Serial.begin(115200);
}

void loop(){
  if (Serial.available()){
    int i =0;
    char incomingByte;

    while(1) {  
      incomingByte = Serial.readBytes((char *)colors,120);
      break;
    }
    Serial.print(incomingByte);
    for(i=0;i<NUM_LEDS ;i++){
      leds[i].green = colors[i];
      leds[i].red = colors[i+1];
      leds[i].blue = colors[i+2];
    }
    if(incomingByte==0x78){
      FastLED.show();
    }
  }
}
Was it helpful?

Solution

your code is flawed in different ways.

First, please remove the useless use of while(1) {…; break;}, it's just adding an overhead and adds nothing to your algorithm.

Otherwise, your code is not working well because, I guess, at some point there's a lag happening in the serial communication that causes the read to timeout. Let's have a look at source code.

First, you take the readBytes() function. All it does is:

size_t Stream::readBytes(char *buffer, size_t length)
{
  size_t count = 0;
  while (count < length) {
    int c = timedRead();
    if (c < 0) break;
    *buffer++ = (char)c;
    count++;
  }
  return count;
}

i.e. it iterates length times over the blocking read function. But it breaks if that function's return value is less than zero, returning less than length bytes. So that what's happening to get less than length, so let's have a look at timedRead():

int Stream::timedRead()
{
  int c;
  _startMillis = millis();
  do {
    c = read();
    if (c >= 0) return c;
  } while(millis() - _startMillis < _timeout);
  return -1; // -1 indicates timeout
}

what happens here, is that if the read succeeds, it returns the read value, otherwise it loops until timeout has passed, and returns -1, which will end readBytes immediately. The default value for the timeout is 1000ms, though you can make that value higher by using Serial.setTimeout(5000); in your setup() function.

Though you have nothing to earn by using the blocking readBytes() function. So you'd better instead write your loop so you read the values, and trigger an event only once all values have been read:

#define NB_COLORS 120

void loop() {
    static byte colors[NB_COLORS];
    static int colors_index=0;
    if (colors_index < NB_COLORS) {
        // let's read only one byte
        colors[colors_index] = Serial.read();
        // if a byte has been read, increment the index
        if (colors[colors_index] != -1)
            ++colors_index;
    } else {
        // reset the index to start over
        colors_index = 0;
        // should'nt you iterate 3 by 3, i.e. having i=i+3 instead of i++ ?
        for(i=0;i<NUM_LEDS ;i++){
          leds[i].green = colors[i];
          leds[i].red = colors[i+1];
          leds[i].blue = colors[i+2];
        }
        FastLED.show();
    } 
}

HTH

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top