vvvv -> arduino using serial. LED cube control

This is my first arduino project and first time programing anything, it’s been really fun! The hardware here is nothing new but I’ve not seen much with vvvv or computer → arduino using serial.

I decided to make one of those 333 led cubes as a learning project then control it over serial using vvvv to turn it into a simple 3 channel spectrum analyser. Bass Mid and High are displayed on one face of the cube then cascade away from the viewer. I made my own multiplexing code.

Information is extracted from the audio using FFT module in vvvv, some simple processing done then sent over serial to arduino as 3 bytes, bass mid and treble. Each byte can have the values 0, 1, 2, 3. I had lots of problems with bytes end up in the wrong part of the array that contains the data. I tried to fix this by having vvvv send only one byte of data at a time and getting the arduino to send a byte down to vvvv to let it know when it’s ready for the next one. VVVV however did not like having data from the RS232 modules output being put anywhere back into the stream going into its input even if it was just toggling a switch. Strange.

I found that having “if (Serial.available() >= 3)” was necessary for the data to be inputted properly and also ‘Send Data’ on the RS232 module in vvvv musn’t be set to 1 constantly it must be triggered by an LFO.

Hope this helps someone… I found this forum very useful. Criticism appreciated.

int col[] = { 5, 6, 7, 8, 9, 10, 11, 12, 13 };       // an array of pin numbers to which LED columns are attached
int lev[] = { 2, 3, 4 };                             //pins for each level declared
int time = 5;                                        //refresh rate total delay is 3*this so 15ms
int x = 0;                                           //serial get loop
int itter = 5;

//array1 is the 'front' layer which takes the values from the serial port
//array2 is the second layer which takes values from array1
//array3 is the third layer which takes values from array2 and are then discarded

char array2[3] = { '0', '0', '0' };
char array3[3] = { '0', '0', '0' };
char array1[3] = { '0', '0', '0' };

void setup() {
  
  //turn on serial
  Serial.begin(9600);
  int thisPin;
  // pins are activated as outputs
  for (int thisPin = 0; thisPin < 9; thisPin++)  {
    pinMode(col[thisPin], OUTPUT);      
  }
  for (int thisPin = 0; thisPin < 3; thisPin++)  {
    pinMode(lev[thisPin], OUTPUT);      
  }
}

void loop() {
  
//if enough serial data is available the data is loaded into array1.
//data is an array of 3 strings 000 010 021 etc from vvvv
//the numbers show how many leds are turned on in each column of the front layer, bottom up

    if (Serial.available() >= 3)  {
 for ( int i = 0; i < 3; i++)
    array1[i]= Serial.read() ;
}


 x = x+1;                      //Here variable x is increased by 1 each itteration of the program
if (x == itter){                  //Can vary how often the arrays cascade down here

 int i = 0;
  while (i<3){

    array3[i]=array2[i];
    array2[i]=array1[i];
    i++;

  }
  x = 0;
}

//Bottom level is activated  
  
  digitalWrite(lev[0],HIGH);
  digitalWrite(lev[1],LOW );
  digitalWrite(lev[2],LOW);
  
 //the arrays are iterated though checking weather the leds on the bottom level need to be turned on or not
 
  int i = 0;
    while (i < 3) { 


      if (array1[i] != '0'){
        digitalWrite(col[i], HIGH);
      }
      if (array1[i] == '0'){
        digitalWrite(col[i], LOW);
      }
           
           
            if (array2[i] != '0'){
        digitalWrite(col[i+3], HIGH);
      }
      if (array2[i] == '0'){
        digitalWrite(col[i+3], LOW);
      }
      
            if (array3[i] != '0'){
        digitalWrite(col[i+6], HIGH);
      }
      if (array3[i] == '0'){
        digitalWrite(col[i+6], LOW);
      }
      
     
      i++;
  }
  
delay(time);

//Middle level is activated and the arrays iterated through.

  digitalWrite(lev[0],LOW);
  digitalWrite(lev[1],HIGH );
  digitalWrite(lev[2],LOW);
  

  i = 0;
    while (i < 3) { 

      if (array1[i] == '2'){
        digitalWrite(col[i], HIGH);
      }
      if (array1[i] == '3'){
        digitalWrite(col[i], HIGH);
      }
      if (array1[i] == '0'){
        digitalWrite(col[i], LOW);
      }
      if (array1[i] == '1'){
        digitalWrite(col[i], LOW);
      }
      
            if (array2[i] == '2'){
        digitalWrite(col[i+3], HIGH);
      }
      if (array2[i] == '3'){
        digitalWrite(col[i+3], HIGH);
      }
      if (array2[i] == '0'){
        digitalWrite(col[i+3], LOW);
      }
      if (array2[i] == '1'){
        digitalWrite(col[i+3], LOW);
      }
      
            if (array3[i] == '2'){
        digitalWrite(col[i+6], HIGH);
      }
      if (array3[i] == '3'){
        digitalWrite(col[i+6], HIGH);
      }
      if (array3[i] == '0'){
        digitalWrite(col[i+6], LOW);
      }
      if (array3[i] == '1'){
        digitalWrite(col[i+6], LOW);
      }

      i++;
      

  }
  
delay(time);

//top layer is activated. you know the drill here

  digitalWrite(lev[0],LOW);
  digitalWrite(lev[1],LOW );
  digitalWrite(lev[2],HIGH);
  

i = 0;
    while (i < 3) { 

      if (array1[i] == '3'){
        digitalWrite(col[i], HIGH);
      }
      if (array1[i] != '3'){
        digitalWrite(col[i], LOW);
      }
       if (array2[i] == '3'){
        digitalWrite(col[i+3], HIGH);
      }
      if (array2[i] != '3'){
        digitalWrite(col[i+3], LOW);
      }
      if (array3[i] == '3'){
        digitalWrite(col[i+6], HIGH);
      }
      if (array3[i] != '3'){
        digitalWrite(col[i+6], LOW);
      }      
      i++;
      

  }
delay(time);

//Fin!

}

VVVV patch:

www.sendspace.com/file/eqyylw

That is quite a first program there and a nice build in the cube.

I notice you are pulling three bytes, which only have a value from 0 to 3. Since you can fit those into 2 bits … you could combine all three values into a single byte using bitwise operations. This would make it so you could read one byte at a time and not have to wait for 3 to hit.

This may be a bit elementary … but I wished this was shown to me this way, so here it is (for you and/or anyone interested if you already had this down pat).

The easy part, just setup for the discussion:
Two Bits:
00 = 0, 01 = 1, 10 = 2, 11 = 3

In some code below I show the number format in B00000011 format to help show the bits in operation better.
So B00000011 is 3 as an example.

You can create a combined byte in this format …
BxxV3V2V1 in your app and then split it out when you get it.

  • see code for more details.

Here are some functions that may help in doing this and a sample application you can use as a sandbox to play with the idea some.

Just the combine and split functions … see the code below that for comments and details.

//=== This function should be passed values from 0 to 3 for each variable
//--- the return value will be a single byte with the combined value
byte getCombined(byte first, byte second, byte third){
  byte val1,val2,val3;
  
  val1 = (byte)(first & 3);
  val2 = (byte)(second & 3) << 2;
  val3 =(byte)(third & 3)<< 4;   
  return (val1) | (val2) | (val3);
}

//=== This function should be passed a combined value and 
//       the reference to store each variable
//--- Three 2 bit values will be extracted from the combined 
//    value and stored in the first,second and third variable locations  
void getSplit(byte combined, byte *first, byte *second, byte *third){
  *first = combined & 3;
  *second = (combined >> 2) & 3;
  *third =(combined >> 4) & 3;   
}

Complete application with verbose functions / comments.

/**************************************************************
 * Name    : Sample Compact and Expand using bitwise operations
 * By      : Joseph Francis
 * 
 * Date    : 07 Jul, 2010                                      
 * Version : 1.0                                               
 * Notes   : Code to combine three values 2 bit values (0-3) into 
 *           a single byte and then extract the three values
 *           Provided as a demo on the arduino forum
 * 
 *  Combined byte looks like this (xxV3V3V1)
 *    * xx = not used
 *    * V1 = Value 1
 *    * V2 = Value 2
 *    * V3 = Value 3
 * 
 ****************************************************************/

//=== This function should be passed values from 0 to 3 for each variable
//--- the return value will be a single byte with the combined value
byte getCombined(byte first, byte second, byte third){
  byte val1,val2,val3;
  
  //--- this example shows how to combine multiple values into a single byte
  //  the first value is pulled by using (&) to only use the right two bits
  val1 = (byte)(first & B00000011);
  //  the second value is trimed to use the right two bits only and shifted two bits
  // (eg. 3 becomes B00000011 then shifted to become B00001100)
 //    this is so the value needed (0 - 3) are in the correct position 
  val2 = (byte)(second & B00000011) << 2;
  // (eg. 3 becomes B00000011 then shifted to become B00110000) 
  val3 =(byte)(third & B00000011) << 4;   
  return (val1) | (val2) | (val3);
}

//=== This function should be passed a combined value and 
//       the reference to store each variable in.
//--- Three 2 bit values will be extracted from the combined ..
//    value and stored in the first,second and third variable locations  
void getSplit(byte combined, byte *first, byte *second, byte *third){
  //--- this example shows how to split a combined value
  //  the first value is pulled by using (&) to only use the right two bits
  *first = combined & B00000011;
  //  the second value is first shifted two bits, then the right two are used again
  // (eg. B00001100 becomes B00000011)
  *second = (combined >> 2) & B00000011; 
  //  the second value is first shifted four bits, then the right two are used again
  // (eg. B00110000 becomes B00000011)
  *third =(combined >> 4) & B00000011;   
}

//=== This function shows three values in the Serial monitor 
void showValues(byte v1, byte v2, byte v3){
  
  Serial.print("first ");
  Serial.print(v1,DEC);
  Serial.print(" - second ");
  Serial.print(v2,DEC);
  Serial.print(" - third ");
  Serial.print(v3,DEC);
  Serial.println(".");
 
}

//=== This demo creates some values and shows then
void loop(){
  byte val1,val2,val3;

  
  //--- Raw demo using bits for easy to see explanation on what
//  is going on bitwise  
  Serial.println("Set using B11111101");
  getSplit(B11111101,&val1,&val2,&val3);
  showValues(val1,val2,val3);

  Serial.println("Set using B11110111");
  getSplit(B11110111,&val1,&val2,&val3);
  showValues(val1,val2,val3);

  Serial.println("Set using B11011111");
  getSplit(B11011111,&val1,&val2,&val3);
  showValues(val1,val2,val3);
  
  byte combinedDemo;
  combinedDemo = getCombined(0,1,2);
  Serial.println("Set using combinedDemo(0,1,2)");
  getSplit(combinedDemo,&val1,&val2,&val3);
  showValues(val1,val2,val3);

  combinedDemo = getCombined(3,2,1);
  Serial.println("Set using combinedDemo(3,2,1)");
  getSplit(combinedDemo,&val1,&val2,&val3);
  showValues(val1,val2,val3);

  delay(10000);

}

void setup(){
  Serial.begin(9600);
}

The output of that application is:

Set using B11111101

first 1 - second 3 - third 3.

Set using B11110111

first 3 - second 1 - third 3.

Set using B11011111

first 3 - second 3 - third 1.

Set using combinedDemo(0,1,2)

first 0 - second 1 - third 2.

Set using combinedDemo(3,2,1)

first 3 - second 2 - third 1.

Thanks for feedback! Will update my code when I have a minute.