Search code examples
serializationarduinopixelled

Arduino - Reading Serial Data


I am trying to send information to an Arduino Mega 2560 using serial data in order to control both LED Pixel Strips and conventional christmas light strings. I am also using VIXEN lighting software.

I can control one strip of LED pixels from Vixen using this code in the Arduino loop() function;

          Serial.readBytes((char*)leds, NUM_LEDS * 3);//buffer to store things in, length (number of bytes to read)
          FastLED.show();//refresh the pixel LED's

I can also control a relay (or multiple relays) for the conventional lights using this code;

#define CHANNEL_01 7 //Pin #7 on the Arduino Mega board

   void setup()
    {
      // Begin serial communication
      Serial.begin(BAUD_RATE);
      #define CHANNEL_COUNT 1 

    int channels[] = {CHANNEL_01}
    int incomingByte[16];
    // Define baud rate. This figure must match that of your profile configuration in Vixen!
    #define BAUD_RATE 9600 


      // Set up each channel as an output
      for(int i = 0; i < CHANNEL_COUNT; i++)
      {
        pinMode(channels[i], OUTPUT);
      }
    }

void loop()
{
  if (Serial.available() >= CHANNEL_COUNT)
  {
    // Read data from Vixen, store in array
    for (int i = 0; i < CHANNEL_COUNT; i++)
    {
      incomingByte[i] = Serial.read();
    }
    // Write data from array to a pin on Arduino
    for (int i = 0; i < CHANNEL_COUNT; i++)
    {
      digitalWrite(channels[i], incomingByte[i]);
    }
  }
}

The problem is that I cannot do both of these things. I can either assign the 150 bytes of LED data to the LED strip and it works fine, OR, I can run the relays and they work fine. I have not been able to figure out how to chop up the bytes from the serial data and send it to the appropriate pin. For example, maybe I want to control a relay using pin 7 and a strip of LED pixels using pin 6.

The strip of pixel LED's consumes the first 150 bytes of data from the serial data. But how can I get the next one byte that controls a relay that turns on and off the conventional christmas light string? The byte that controls the light string would be the 151'st in the serial data. Is there a way to specify the 151'st byte? Serial.read() does nothing more than read the first byte (I think). How can a user iterate through the bytes of serial data and select only the ones they want?


Solution

  • To solve this problem I bought an Arduino Uno to run the standard (non-LED) lights separate from the LED lights which run off an Arduino MEGA 2560. The non-LED lights are run on one controller in the Vixen Lights software. The controller has 4 outputs (channels), one for each of the non-LED light sets. Each channel will control one line on a solid state relay. The Arduino Uno runs the relays using this code;

    #define PIN1 7 //Pin number seven
    #define PIN2 6 //Pin number six
    #define PIN3 5 //Pin number five
    #define PIN4 4 //Pin number four
    
    #define BAUD_RATE 9600 //just running 4 relay switches so we don't need much speed
    #define CHANNEL_COUNT 4 //there are 4 channels coming from the Vixen controller
    
    int bt[4]; //a variable we will use in the loop section of code
    int x; //another variable we will use in the loop section of code
    
    void setup() {
        delay(1000); //a little delay to give Uno some time on startup
        Serial.begin(BAUD_RATE); //set the baud rate of the serial stream
        pinMode(PIN1, OUTPUT); //set the four pins on the Arduino Uno to output
        pinMode(PIN2, OUTPUT);
        pinMode(PIN3, OUTPUT);
        pinMode(PIN4, OUTPUT);
    
    }
    
    void loop() {
        if (Serial.available() >= CHANNEL_COUNT) { 
            for (X = 0; x < CHANNEL_COUNT; x++) { //for every channel...
                bt[x] = Serial.read(); //we read a byte from the serial stream buffer and store it in an array for later use
            }
    
            digitalWrite(PIN1, bt[0]);  //we tell the pins on the arduino what to do... 
            digitalWrite(PIN2, bt[1]);  //using the array of integers that holds the byte values from the serial stream...
            digitalWrite(PIN3, bt[2]); 
            digitalWrite(PIN4, bt[3]);
    
        }   
    
    }
    

    The LED's run off a second controller in the Vixen Lights software. I have two 12 volt, 50 pixel LED strips of type WS2811. The Arduino uses the FastLED library that can be downloaded for free from FastLED.io. What I found was that there is one byte of garbage data that comes in the serial stream for the LED strips and I had to move past that byte of data in order for the LED's to receive the correct bytes of data to control their color, position etc. I use this code to run my LED's off the Arduino MEGA 2560;

    #include <FastLED.h> //include the FastLED library in the Arduino project
    #define LED_PIN1 7 //I am going to run one strip of 50 LEDs off of pin 7 on the MEGA
    #define LED_PIN2 6 //I am going to run a second strip of 50 LEDs off of pin 6 on the MEGA
    #define BAUD_RATE 115200 
    #define NUM_LEDS 50
    
    //It took me some time to figure out that my two pixel strips are set 
    //to different color codes. Why? I don't know, but they are.  
    #define RGB_ORDER RGB //one of my pixel strips is set to use RGB color codes
    #define BRG_ORDER BRG //the second strip came from the factory with BRG color codes
    
    #define LED_TYPE WS2811 //what type of LEDs are they? Mine are WS2811, yours may be different.
    
    //create an array to hold the FastLED CRBG code for each of the 50 pixels in the 
    //first strip.
    CRGB leds1[NUM_LEDS]; 
    
    //create another array to hold the FastLED CRBG codes for each of the 50 pixels in 
    //the second strip.
    CRGB leds2[NUM_LEDS]; 
    
    int g; //a variable we will use in the loop section
    
    int bufferGarbage[1]; //THIS IS THE KEY TO MAKING THIS WHOLE THING WORK. WE NEED TO 
     //GET PAST THE FIRST MYSTERY BYTE THAT IS SENT TO THE ARDUINO MEGA FROM THE VIXEN 
     //LIGHTS SOFTWARE. So we create a variable we will use in the loop section of code. 
    
    void setup() {
        delay(1000);
        Serial.begin(BAUD_RATE);
        pinMode(LED_PIN1, OUTPUT); //set our pins to output. PIN1 is pin 6 on the Arduino board.
        pinMode(LED_PIN2, OUTPUT); //set our pins to output. PIN2 is pin 7 on the Arduino board.
    
         //This line sets up the first pixel strip to run using FastLED
        FastLED<LED_TYPE, LED_PIN1, RGB_ORDER>(leds1, NUM_LEDS).setCorrection(TypicalLEDStrip); 
    
        //This line sets up the second pixel strip to run using FastLED
        FastLED<LED_TYPE, LED_PIN2, BRG_ORDER>(leds2, NUM_LEDS).setCorrection(TypicalLEDStrip); 
    }
    
    void loop() {
        if (Serial.available() >= 0) { //if there is data in the serial stream
               //bufferGarbage is to capture the first byte of garbage that comes across.
               //Without this the LED's are out of sync. 
               //In my case if I didn't capture this byte the first pixel on my 
               //second LED strip would match the color code that should be on the last 
               //pixel of the first strip. We don't do anything with this byte.
               //but we need to read it from the serial stream so we can move to the 
               //next byte in the stream.
               bufferGarbage[0] = Serial.read();  
    
            //then we need to populate the leds1 array so FastLED can tell the pixels what to do.
            //We have 50 pixels in the strip and each pixel has a CRGB property that uses 
            //a red, green, and blue attribute. So for each LED we need to capture 3
            //bytes from the serial stream. 50 LEDs * 3 bytes each means we need to read
            //150 bytes of data from the serial stream.
            for (g = 0; g < NUM_LEDS; g++) {
                Serial.readBytes( ( char*)(&leds1[g], 3);
            }
            for (g = 0; g < NUM_LEDS; g++) {//then we read the next 150 bytes for the second strip of LEDs
                Serial.readBytes( ( char*)(&leds2[g], 3);
            }
    
            FastLED.show(); //then we tell FastLED to show the pixels!
    
        }
    }