robowarner
Published © LGPL

Light Sync House

Just like the full size houses, only smaller! Has 31 EL wires and LEDs synced to music using an Arduino and Vixenlights.

IntermediateShowcase (no instructions)10 hours3,504
Light Sync House

Things used in this project

Story

Read more

Schematics

Light Control Schematic

Light control schematic, connections for Arduino are shown.

Code

LightHouseControl2016.ino

C/C++
Interfaces the house to the computer running VixenLights.
On VixenLights (free) I use the Renard plugin and select the serial port the Arduino is using.
//Light House Control 2016
//Warner King
//RoboWarner.com

//MM5450 code from l.e. hughes
// Date.....: 27 May 2011
// His Notes....: Basic, simple example of using shift registers to control the MM5450/5451
//            LED driver. This program was specifically written for the 5450, but should
//            also work with the 5451 and be easily modified for others. The 5450/5451
//            is latching and requires 36 signal databits to send all of the information
//            to control the LEDs (34 for the 5450; 35 for the 5451). There are minor
//            differences in the chip between the manufacturers, please read the appropriate
//            datasheet(s) before connecting power.
// 

#define BITSB 8                        // number of bits per byte, used for code clarity
#define DATABITS 36                    // what we must send to the chip in order to control the lights
#define STARTBIT 1                     // value of the starting bit;  

const int ledDim = 5;   //LED common pin, used with PWM for a dimming effect
const int ELpower = 3;  //EL power supply power, also used with PWM for dimming
const int ELblink = 2;  //Used to fix EL wires getting stuck on, is pulsed after each refresh to reset stuck triacs.
const int clockPin  = 4;               // connect Arduino pin 3 to clock pin (21) on the 5450
const int dataPin   = 6;               // connect Arduino pin 6 to data pin (22) on the 5450

const int numOfLightChannels = 32;
const int numDimChannels = 2;
const int startBytes = 2;

// The following line just computes the number of bytes we will need in the ledArray to hold all of
// bits of data for the signal; it could be declared statically.
//
const int arrayLen  = (int)((DATABITS-1)/BITSB) + 1;

// This is the actual array that will hold the signal bits. This program, for the 5450/5451, will
// need 5 bytes for a total of 40 bits.
//
byte ledArray[arrayLen];               // for this chip, length is 5 and that could hold 40 values  

int myInts[40];   //Holds the data received from Vixen
int errorReset = 0;       //Used to reset the serial input code if bad data is gathered.
bool ELpowerflag = false;   //Used to automatically turn off EL power supply if not in use.


typedef enum {                         // this exists primarily for code clarity
 OFF, ON
} ledState;

void setup() {
   Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(clockPin, OUTPUT);           // we don't need a latch pin since the 5450/5451 latched after
  pinMode(dataPin,  OUTPUT);          
  pinMode(ledDim,  OUTPUT);           
  pinMode(ELpower,  OUTPUT);           
  pinMode(ELblink,  OUTPUT);           
  digitalWrite(ledDim, LOW);
  digitalWrite(ELpower, LOW);
  digitalWrite(ELblink, LOW);
  
 allOff(); 
 sendDatabits();
// allOn();
// sendDatabits();
 delay(1000);
 }

// the loop function runs over and over again forever
void loop() { 

  if (Serial.available() >= (numOfLightChannels + startBytes + numDimChannels)) {
    for(int y = 0; y <= (numOfLightChannels + startBytes + numDimChannels); y++)
    {
      myInts[y]= Serial.read();    //Gather data and store it in the array  
    }
    if (myInts[0] == 126)     //First two bytes transmitted each refresh by the Renard Plugin version 1
    {
        if (myInts[1] == 128)
        {
          errorReset = 0;       //Valid signal, reset error counter
          ELpowerflag = false;  
          for (int p = 0; p <= (numOfLightChannels); p++)   //Translate data gathered from Vixen to the MM5450 array
          {
            if (myInts[p+1] == 255)     //255 is full intensity on in Vixen
            {
               setLight(p, ON);
               if(p <= (startBytes + 21))     //If any EL wire channels are on, let the EL power supply be activated
               {
                      ELpowerflag = true;
               }
            }
            else
            {
              setLight(p, OFF);
            }            
          }
          int ledMap = map(myInts[34], 0, 255, 255, 50);    //Mapping for dimming.
        
          int elMap = map(myInts[35], 0, 255, 40, 255);
          if (ELpowerflag == false || myInts[35] == 0)    //If no EL wire is turned on, turn off EL power supply
          {
            elMap = 0;
          }
          delay(90);    //Timing to get lights in sync with Vixen, as the program outputs data before the actual point it's needed in the song.
          analogWrite(ledDim, ledMap);  //PWM for the dimming on the LEDs and EL power supply
          analogWrite(ELpower, elMap );
          sendDatabits();  //Send data out to MM5450
            if (myInts[20] == 255)  //Activates built in LED, used for timing.
            {
               digitalWrite(LED_BUILTIN, ON);
            }
            else
            {
                digitalWrite(LED_BUILTIN, OFF);
            }            
          digitalWrite(ELblink, HIGH);   //Dirty fix for EL wire triacs getting stuck on, after each light refresh this will activate a transister to short out the EL AC output
          delayMicroseconds(250);        //thus allowing the stuck triacs to turn off. The delay is small enough it's not noticable to the eye.
          digitalWrite(ELblink, LOW);
        }
    } 
  }
  //Used to reset the serial input code if bad input is sent. 
  //Otherwise the above code will constantly loop and never find the proper data in the first 2 bytes.
  else if (Serial.available() > 1)
  {
    errorReset++;
    if (errorReset > 30)
    {
      while(Serial.available() > 0)
      {
        int trash = Serial.read();
      }
      errorReset = 0;
      
    }
  }
  delay(1); //Delay to prevent chaos
}



// Subroutine that sends all of the DATABITS to the chip. It begins by first sending the startbit, then it
// uses the Arduino shiftOut function to send the bits in each byte of the ledArray. I could have put the
// STARTBIT into the ledArray but decided that I liked it better outside of the array. Any time you want
// to turn lights on or off, this routine must be called after setting the appropriate bits in the ledArray.
//
void sendDatabits() {
 digitalWrite(clockPin, LOW);
 delay(2);
 digitalWrite(dataPin, STARTBIT);
 delay(2);
 digitalWrite(clockPin, HIGH);
 delay(5);
 digitalWrite(clockPin, LOW);
 delay(2);
 for(int i = 0; i < arrayLen; i++) {
   shiftOut(dataPin, clockPin, LSBFIRST, ledArray[i]);
 }

}

// Subroutine that takes a light (output pin) as a sole argument and sets the bit value for that pin
// to the opposite of its current setting (toggle).
//
void toggleLight(int pin) {
 byte arrayElem = int((pin-1)/BITSB);                     // which element of the ledArray is pin in
 byte byteElem  = (pin - (arrayElem * BITSB)) - 1;        // and which bit in that byte is the pin
 ledArray[arrayElem] ^= (1 << byteElem);                  // toggle byteElem
}


//This is modified from the original code, I added the bitWrite instead of using the original shift (<<) method.
//It sets the selected pin to ON or OFF
void setLight(int pin, byte val) {

 byte arrayElem = int((pin-1)/BITSB);                     // which element of the ledArray is pin in
 byte byteElem  = (pin - (arrayElem * BITSB)) - 1;        // and which bit in that byte is the pin
byte temp1 = ledArray[arrayElem];
 bitWrite(temp1,byteElem , val) ;
ledArray[arrayElem] = temp1;
}

// Subroutine that turns all lights on. Because the STARTBIT is 1 or ON, we don't want to set any
// bits above 35 to ON, lest it be interpreted as the start of another set of databits. Better error
// checking would be to make sure that no bit > 35 was ever set to 1.
//
void allOn() {
 for(int i = 1; i < DATABITS; i++) {
   setLight(i, ON);
 }
}
 
// Subroutine that turns all lights off
//
void allOff() {
 for(int i = 0; i < arrayLen; i++) {
   ledArray[i] = 0;
 }
}

Credits

robowarner

robowarner

1 project • 1 follower

Comments