Saturday, February 7, 2015

A Rose by Pretty Much Any Color You'd Like...

Got the RGB led's to working with three functions:
  • Sparkle (fire random colors)
  • Fade multiple Led's to a single color
  • Fade multiple Led's to a to complimentary colors

While I could have written the code to handle an array of Led's, I'm only really going to use two for the main dress (run in series of 8 each for the panels of the dress and 2-4 for the hair,) so decided to keep it simple.

Code follows.

Shiftcolors.ino


#include <RGBColor.h>

#include <LED.h>
Led * c2;
Led * c1;
void setup()
{
  c1=new Led(3,5,6);
  c2=new Led(9,10,11);
  Serial.begin(9600);
}

void loop() 
{
  do {
    Serial.println("Flashing");
    RGBFlash(*c1,*c2,100);
    Serial.println("Fading");
  RGBColor * color=new RGBColor();
  shiftTogether(*c1, *c2, *color, random(10,50));
  Serial.println("FadingComplete");
  delay(5000);
  RGBColor * color2=new RGBColor();
  Serial.println("Fading compliments");
  shiftCompliments(*c1,*c2, *color2,30);
  Serial.println("Fading complete");
  delay(5000);
  }
  while (true);
  delay(5000);
  
}


void ShiftRandomColor()
  RGBColor * color=new RGBColor();
  shiftCompliments(*c1,*c2, *color,30);
}

void RGBFlash (Led &led1, Led &led2, int times)
{
    int count=0;
    do {
      RGBColor * color=new RGBColor();
      RGBColor * color2=new RGBColor();
      led1.SetRGB(color->Red(),color->Green(),color->Blue());
      led2.SetRGB(color2->Red(),color2->Green(),color2->Blue());
      
     fireLed(led1);
     fireLed(led2);

      delay(random(30,100));     
            
      count++;
      
    } while (count<times);

}

void shiftTogether (Led &led1, Led &led2, RGBColor color, byte pause)
{
  bool halt=false;
   do {
   if (matchColors(led1,color)==true&&matchColors(led2,color)==true)
    {
      halt=true;
    }
   
     fireLed(led1);
     fireLed(led2);
     
     delay(pause);
     
  } while(halt==false);
}

void shiftCompliments(Led &led1, Led &led2, RGBColor color, byte pause)
{
  RGBColor * color2=new RGBColor(color.ID(),true);
  bool halt=false;
  do {
    if (matchColors(led1,color)==true&&matchColors(led2,*color2)==true)
    {
      halt=true;
    }
     
     fireLed(led1);
     fireLed(led2);
     
     delay(pause);
     
  } while(halt==false);

}

bool matchColors(Led &led,RGBColor &color)
{
  bool r=0;
  bool g=0;
  bool b=0;
  
  if (led.Blue()==color.Blue())
  {
    b=1;
  }
  else {
    if (led.Blue()>color.Blue()) led.SetBlue(led.Blue()-1);
    else led.SetBlue(led.Blue()+1); 
  }
  
  
  if (led.Red()==color.Red())
  {
    r=1;
  }
  else {
    if (led.Red()>color.Red()) led.SetRed(led.Red()-1);
    else led.SetRed(led.Red()+1); 
  }
  
  
  if (led.Green()==color.Green())
  {
    g=1;
  }
  else {
    if (led.Green()>color.Green()) led.SetGreen(led.Green()-1);
    else led.SetGreen(led.Green()+1); 
  }
  if (r==1)
  {
    if (g==1) {
      if (b==1) {
    Serial.print(led.RPin());
    Serial.print(" ");
    Serial.print(led.GPin());
    Serial.print(" ");
    Serial.print(led.BPin());
    Serial.print(" ");
    Serial.print(color.Red());
    Serial.print(",");
    Serial.print(color.Green());
    Serial.print(",");
    Serial.print(color.Blue());
    Serial.print("=");
    Serial.print(led.Red());
    Serial.print(",");
    Serial.print(led.Green());
    Serial.print(",");
    Serial.println(led.Blue());
    return true;
      }
    }
  }
  
  return false;
  
}

void shiftColors(Led &led, RGBColor color, int pause)
{
  
bool halt=0;

  do {
      // fade to black until colors match
    if (matchColors(led,color)==true)
    {
      halt=true;
    }
     
     fireLed(led);
     
     delay(pause);
     
  } while(halt==false);
  
  
}


void fadeLed(Led led, int pause)
{
  // Create a color of 0,0,0 (black)
  RGBColor * color=new RGBColor(0,0,0);
  bool halt=false;
    do {
      // fade to black until colors match
    if (matchColors(led,*color)==true)
    {
      halt=true;
    }
     
     fireLed(led);
     
     delay(pause);
     
  } while(halt==false);

}

void fireLed(Led led)
{
  if (led.IsRGB())
  {
    analogWrite(led.RPin(),led.Red());
    analogWrite(led.GPin(),led.Green());
    analogWrite(led.BPin(),led.Blue());
  }
}

Led.h

#ifndef LED_h
#define LED_h
#include <Arduino.h>
#include <WProgram.h>

/*
  LED.h - Library for standard and RGB LED's
  Beau Bureau, 2014
  Released into the public domain.
*/

class Led {
private:
// sets the colors red, green, and blue, and the RGB pins.  Red is the power pin for standard LED's.
byte red, green, blue, rPin, gPin, bPin;

public:
Led() {};
~Led() {};
// Standard static constructor
Led(byte);
// standard RGB constructor
Led(byte,byte,byte);
// Public members for red, green and blue.
byte Blue() {return blue;}
byte Green() {return green;}
byte Red() {return red;}
//Pins for RGB.  RPin is also the power pin.
byte RPin() {return rPin;}
byte GPin() {return gPin;}
byte BPin() {return bPin;}
// Public member for power.
byte Power() {return rPin;}
// checks whether the bPin has been set to -1.  If it is set to -1 in the constructor, it is not an RGB LED.
bool IsRGB() {return bPin!=255;}
// public methods to set RGB
void SetRed(byte);
void SetGreen(byte);
void SetBlue(byte);
void SetRGB(byte,byte,byte);
// public method to set a random color
void SetRandomColor();
};


#endif


Led.cpp

#include<LED.h>
#include <Arduino.h>
#include <WProgram.h>
Led::Led(byte p) {
  //Initiates a standard LED.  the rPin is power.
  rPin=p;
  // Either g or b can bee tested against to see if this is an RGB.  They will be equal to -1 if a standard RGB.
  gPin=-1;
  bPin=-1;
  red=0;
  green=0;
  blue=0;
}


Led::Led(byte r,byte g,byte b) {
// Initiates an RGB LED, sets color to white. 
rPin=r;
gPin=g;
bPin=b;
red=255;
green=255;
blue=255;
}



void Led::SetRandomColor() {

  // Randomize, choose a color of 0-6. 0=red, 1=green, 2=blue, 3=purple, 4=yellow, 5=orange
  
  int color=random(0,5);

switch (color) {
   case 0: 
   red=255;
   green=0;
   blue=0;
   break;
   case 1:
   green=255;
   red=0;
   blue=0;
   break;
   case 2: 
   blue=255;
   red=0;
   blue=0;
   break;
   case 3:
   red=255;
   blue=255;
   green=0;
   break;
   case 4:
   red=255;
   green=255;
   blue=0;
   break;
   default:
   red=255;
   green=128;
   blue=0;
   break;
 }

}

void Led::SetRGB(byte r, byte g, byte b) {
red=r;
green=g;
blue=b;
}

void Led::SetRed(byte val) {


  red=val;

}

void Led::SetBlue(byte val) {

  blue=val;

}

void Led::SetGreen(byte val) {

  green=val;

}


RGBColor.h


#ifndef RGBColor_h
#define RGBColor_h
#include <Arduino.h>
#include <WProgram.h>

/*
  RGBColor.h - Library for standard and RGB LED's
  Beau Bureau, 2014
  Released into the public domain.
*/

class RGBColor {
private:
// sets the colors red, green, and blue, and the RGB pins.  Red is the power pin for standard LED's.
byte red, green, blue, id, compliment;
void setColors(byte);
void setCompliment();

public:
RGBColor();
~RGBColor(){Serial.println("Destructor called");}
RGBColor(byte);
RGBColor(byte, bool);
RGBColor(byte,byte,byte);
// Standard static constructor
byte Red() {return red;}
byte Blue() {return blue;}
byte Green() {return green;}
byte ID(){return id;}

};


#endif


RGBColor.cpp

#include<RGBColor.h>
#include <Arduino.h>
#include <WProgram.h>

RGBColor::RGBColor() {
      byte input=random(1,9);
setColors(input);
}
RGBColor::RGBColor(byte input) {

setColors(input);
  
}

RGBColor::RGBColor(byte input, bool comp) {
setColors(input);
setCompliment();
  
}

RGBColor::RGBColor(byte r, byte g, byte b) {
  //Initiates a standard LED.  the rPin is power.
  red=r;
  green=g;
  blue=b;
  id=255;
  compliment=255;
}

void RGBColor::setCompliment() {
  setColors(compliment);

}

void RGBColor::setColors(byte input) {
if (input>0&&input<12) {}
else input=random(1,9);
switch (input)
  {
    // red
    case 1:
      red=255;
      green=0;
      blue=0;
      id=1;
      compliment=2;
      break;
    //green
    case 2:
      red=0;
      green=255;
      blue=0;
      id=2;
      compliment=1;
      break;
    // blue
    case 3:
      red=0;
      green=0;
      blue=255;
id=3;
compliment=4;
      break;
    // orange
    case 4:
      red=255;
      green=102;
      blue=0;
id=4;
compliment=3;
      break;
    // crimson
    case 5:
      red=255;
      green=0;
      blue=71;
id=5;
compliment=6;
      break;
   // lemon
    case 6:
      red=255;
      green=255;
      blue=102;
id=6;
compliment=7;
      break; 
   // purple
    case 7:
       red=102;
       green=0;
       blue=204;
id=7;
compliment=6;
       break;
    // Different purple
    case 8:
      red=204;
      green=0;
      blue=102;
id=8;
compliment=6;
      break;
    // Yet another purple
    case 9:
      red=215;
      green=30;
      blue=172;
id=9;
compliment=4;
break;
    case 10:
      red=0;
      green=255;
      blue=255;
id=10;
compliment=11;
      break;
    case 11:
      red=255;
      green=127;
      blue=80;
id=11;
compliment=10;
      break;
  }
}

Sunday, February 1, 2015

Using the RGBColor Class

Just created a bit of code to feed off my RGBColor class.  Main functions include:

  • shiftColors: takes an LED, an RGBColor, and an int.  Runs matchColors against both pins until both match.  The passed int represents the # of milliseconds to delay after each iteration of matchColors.
  • shiftCompliments: takes two LED's, an RGBColor, and an int.  Shifts two LED's, one to a color, and another to a color-wheel compliment of that color.  Runs matchColors against both pins until both match. The passed int represents the # of milliseconds to delay after each iteration of matchColors.
  • matchColors: tales an LED and an RGBColor.  Checks each of the three colors on the LED against the values of the color; increments or decrements by 1 as needed.  Passes true if all values match, otherwise passes false.
  • fadeLed: takes an LED and an int.  Runs matchColors against both pins until both match. The passed int represents the # of milliseconds to delay after each iteration of matchColors.
  • fireLed: takes an LED.  AnalogWrites to the RGB pins of the LED.


Code follows

#include <RGBColor.h>

#include <LED.h>
Led * c2;
Led * c1;
void setup()
{
  c1=new Led(3,5,6);
  c2=new Led(9,10,11);
  Serial.begin(9600);
}

void loop() 
{
  RGBColor * color=new RGBColor();
  shiftCompliments(*c1,*c2, *color,30);
  Serial.println("Reached!");
  delay(5000);
  
}


void ShiftRandomColor()

  RGBColor * color=new RGBColor();
  shiftCompliments(*c1,*c2, *color,30);
}

void shiftCompliments(Led &led1, Led &led2, RGBColor color, byte pause)
{
  RGBColor * color2=new RGBColor(color.ID(),true);
  bool halt=false;
  do {
    if (matchColors(led1,color)==true&&matchColors(led2,*color2)==true)
    {
      halt=true;
    }
     
     fireLed(led1);
     fireLed(led2);
     
     delay(pause);
     
  } while(halt==false);

}

bool matchColors(Led &led,RGBColor &color)
{
  bool r=0;
  bool g=0;
  bool b=0;
  
  if (led.Blue()==color.Blue())
  {
    b=1;
  }
  else {
    if (led.Blue()>color.Blue()) led.SetBlue(led.Blue()-1);
    else led.SetBlue(led.Blue()+1); 
  }
  
  
  if (led.Red()==color.Red())
  {
    r=1;
  }
  else {
    if (led.Red()>color.Red()) led.SetRed(led.Red()-1);
    else led.SetRed(led.Red()+1); 
  }
  
  
  if (led.Green()==color.Green())
  {
    g=1;
  }
  else {
    if (led.Green()>color.Green()) led.SetGreen(led.Green()-1);
    else led.SetGreen(led.Green()+1); 
  }

  if (r==1)
  {
    if (g==1) {
      if (b==1) {
    Serial.print(led.RPin());
    Serial.print(" ");
    Serial.print(led.GPin());
    Serial.print(" ");
    Serial.print(led.BPin());
    Serial.print(" ");
    Serial.print(color.Red());
    Serial.print(",");
    Serial.print(color.Green());
    Serial.print(",");
    Serial.print(color.Blue());
    Serial.print("=");
    Serial.print(led.Red());
    Serial.print(",");
    Serial.print(led.Green());
    Serial.print(",");
    Serial.println(led.Blue());
    return true;
      }
    }
  }
  
  return false;
  
}

void shiftColors(Led &led, RGBColor color, int pause)
{
  
bool halt=0;

  do {
      // fade to black until colors match
    if (matchColors(led,color)==true)
    {
      halt=true;
    }
     
     fireLed(led);
     
     delay(pause);
     
  } while(halt==false);
  
  
}


void fadeLed(Led led, int pause)
{
  // Create a color of 0,0,0 (black)
  RGBColor * color=new RGBColor(0,0,0);
  bool halt=false;
    do {
      // fade to black until colors match
    if (matchColors(led,*color)==true)
    {
      halt=true;
    }
     
     fireLed(led);
     
     delay(pause);
     
  } while(halt==false);

}

void fireLed(Led led)
{
  if (led.IsRGB())
  {
    analogWrite(led.RPin(),led.Red());
    analogWrite(led.GPin(),led.Green());
    analogWrite(led.BPin(),led.Blue());
  }
}

The RGB Color Class

Working with RGB LED's, I wanted a simple way to phase from one predefined color to another.  At first, I thought of adding "target" RGB values to each pin.  It would then be a simple matter of comparing the current RGB values to the target ones, and either incrementing or decrementing as needed.  

As RGB colors may come in useful for other C++ projects, I decided to shift my tack and write into their own class.  The member variables are pretty simple; it has:
  • R, G, and B (all bytes.)
  • An ID (also a byte.)  This correlates to a list of 9 possible colors. (The current color load out is very purple-heavy to match my wife's dress.)  
  • Compliment (also of type byte.)  This allows users to choose the compliment of a passed color ID.
All of these are broadcast publicly with the exception of compliment.

There are only two private members:
  • setColors: this sets the RGB value to one the 9 "preset" colors.
  • setCompliment: this sets the color to the color-wheel compliment of the passed color ID.

RGBColor includes three constructors,
  • The standard constructor, which will randomly choose from one of 9 established colors.
  • One that takes a byte from 1-9, setting the instantiated color to the chosen color. 
  • One that takes a byte and a bool, setting the instantiated color to the color compliment of the chosen color.
  • One that will set a color to its color-wheel compliment (useful for having two complimentary RGB LED's.)
  • One that takes three bytes and manually sets the R, G, and B values to this.  If a color is manually set, ID and Compliment are both set to 255.
Will likely add more colors as time goes on and try to find a logical way to mathematically pass the compliment. 

Code follows.

RGBColor.h

#ifndef RGBColor_h
#define RGBColor_h
#include <Arduino.h>
#include <WProgram.h>

/*
  RGBColor.h - Library for standard and RGB LED's
  Beau Bureau, 2014
  Released into the public domain.
*/

class RGBColor {
private:
// sets the colors red, green, and blue, and the RGB pins.  Red is the power pin for standard LED's.
byte red, green, blue, id, compliment;
void setColors(byte);
void setCompliment();

public:
RGBColor();
RGBColor(byte);
RGBColor(byte, bool);
RGBColor(byte,byte,byte);
// Standard static constructor
byte Red(){return red;}
byte Blue() {return blue;}
byte Green() {return green;}
byte ID(){return id;}

};


#endif


#include<RGBColor.h>
#include <Arduino.h>
#include <WProgram.h>

RGBColor::RGBColor() {
      byte input=random(1,9);
setColors(input);
}
RGBColor::RGBColor(byte input) {
if (input>0&&input<10) {}
else input=random(1,9);
setColors(input);
  
}

RGBColor::RGBColor(byte input, bool comp) {
setColors(input);
setCompliment();
  
}

RGBColor::RGBColor(byte r, byte g, byte b) {
  //Initiates a standard LED.  the rPin is power.
  red=r;
  green=g;
  blue=b;
  id=255;
  compliment=255;
}

void RGBColor::setCompliment() {
Serial.println("compliment");
  setColors(compliment);

}

void RGBColor::setColors(byte input) {

switch (input)
  {
    // red
    case 1:
      red=255;
      green=0;
      blue=0;
      id=1;
      compliment=2;
        Serial.println("red");
      break;
    //green
    case 2:
      red=0;
      green=255;
      blue=0;
      id=2;
      compliment=1;
              Serial.println("green");
      break;
    // blue
    case 3:
      red=0;
      green=0;
      blue=255;
id=3;
compliment=4;
              Serial.println("blue");
      break;
    // orange
    case 4:
      red=255;
      green=102;
      blue=0;
id=4;
compliment=3;
              Serial.println("orange");
      break;
    // crimson
    case 5:
      red=255;
      green=0;
      blue=71;
id=5;
compliment=6;
              Serial.println("crimson");
      break;
   // lemon
    case 6:
      red=255;
      green=255;
      blue=102;
id=6;
compliment=7;
              Serial.println("lemon");
      break; 
   // purple
    case 7:
       red=102;
       green=0;
       blue=204;
id=7;
compliment=6;
               Serial.println("purple");
       break;
    // Different purple
    case 8:
      red=204;
      green=0;
      blue=102;
id=8;
compliment=6;
              Serial.println("purple2");
      break;
    // Yet another purple
    case 9:
      red=215;
      green=30;
      blue=172;
id=9;
compliment=4;
              Serial.println("purple3");
      break;
  }
}

Saturday, January 31, 2015

Steampunk Light Dress Part Four: Progress Thus Far

A basic video showing the progress of the shift register and 16 LED's.  Have ended up cutting corners and not using the ShiftRegister class in all functions; while being a little bit heavier from a documentation standpoint, I managed to trim about 2000 bytes of pointless variables from the wave and pulse functions.

So  

Monday, January 26, 2015

Shift Registers Have Class

Have been working on adapting my standard pin functions to work with a shift register.  First worked on a class for the shift registers.

First step was declaring the basics; bytes for my clock, latch, and data pins, and an int to declare the total number of pins used on the shift register.  Next big concern was tracking the state of each of the eight pins; as the state can only be off or on, this was done with a simple array of booleans. As I would like to incorporate 24 total LED's into the project, so I added two extra arrays to keep track of the two additional shift registers I will have daisy chained to the first.  Next created a constant, static array of bytes to represent each of the pins values (from B1 to B10000000, or 1 to 255 in decimal.)  We want it static because these values can be shared among all shift registers, and we want it constant because binary math should never change within the scope of this program.

As the array of pins matches up with the array of pin values (pin 0 is 1, pin 2 is 01 etc,) all we have to do to activate a pin is pass an int to the void ActivatePin, which sets the appropriate boolean to true.  To get a value for our ShiftOut function, all we have to do now is add up the values for each pin that is set to true - these are stored in an array of 3 bytes; one to hold the value for each shift register we intend to use.

All that remained was to add a few maintenance functions; ShiftClear() to clear the shift register values and ClearPins() to clear the boolean value of each of the pins.  Also added a RandomPin() function to allow it to output a random pin.
Header and cpp file to follow.




ShiftRegister.h
#ifndef LED_h
#define LED_h
#include <Arduino.h>
#include <WProgram.h>

/*
  ShiftRegister.h - Library for standard and RGB LED's
  Beau Bureau, 2014
  Released into the public domain.
*/

class ShiftRegister{
private:
// Gets the binary equivalent of a given pin
int ReturnPin(int);
// sets the clock and data pins
byte clockPin,latchPin,dataPin;
// sets the number of pins
int noPins;
// Stores the values of our shift registers
byte rArray[3];
// gives all the available numbers
static const byte Pins[8];
// Tells the system which pins have been turned on
bool firstPinsActive[8];
bool secondPinsActive[8];
bool thirdPinsActive[8];
// adds the values of the pins.
void CountPins();


public:
ShiftRegister();
// standard shift register constructor
ShiftRegister(byte,byte,byte, int);
// Public members for red, green and blue.
byte ClockPin() {return clockPin;}
byte LatchPin() {return latchPin;}
byte DataPin() {return dataPin;}
int NoPins() {return noPins;}
byte ShiftNum(int);
void ClearShift();
void ActivatePin(int);
void ClearPins();
byte RandomPin();

};


#endif



ShiftRegister.cpp
#include<ShiftRegister.h>
#include <Arduino.h>
#include <WProgram.h>
const byte ShiftRegister::Pins[]={B00000001,B00000010,B00000100,B00001000,B00010000,B00100000,B01000000,B10000000};


ShiftRegister::ShiftRegister() { 
ClearShift();
ClearPins();
}



ShiftRegister::ShiftRegister(byte c, byte l,byte d, int p) { 
clockPin=c;
latchPin=l;
dataPin=d;
noPins=p;
ClearShift();
ClearPins();
}




void ShiftRegister::CountPins() {
ClearShift();
for (int i=0; i<8;i++)
{
if (firstPinsActive[i]==1)
{
rArray[0]=rArray[0]+Pins[i];
}
if (secondPinsActive[i]==1)
{
rArray[1]=rArray[1]+Pins[i];
}

if (firstPinsActive[i]==2)
{
rArray[2]=rArray[2]+Pins[i];
}
}
}


void ShiftRegister::ClearShift() 
{
for (int i=0;i<3;i++)
{
rArray[i]=0;
}
}
void ShiftRegister::ClearPins() {
for (int i=0; i<8;i++)
{
firstPinsActive[i]=0;
secondPinsActive[i]=0;
thirdPinsActive[i]=0;
}
}

// returns the boolean-equivalent integer of the specified register (can be up to 3)
byte ShiftRegister::ShiftNum(int i)
{
if (i<3)
{
return rArray[i];
}
}

void ShiftRegister::ActivatePin(int input)
{
if (input>24)
{
return;
}
if (input>16)
{
input=input-16;
// this pin stops you from counting the same pin twice
if (thirdPinsActive[input-1]==0)
{
// Activate the pin
thirdPinsActive[input-1]=1;
}
}
if (input>8)
{
input=input-8;
if (secondPinsActive[input-1]==0)
{
secondPinsActive[input-1]=1;
}
}
if (input <=8)
{
if (firstPinsActive[input-1]==0)
{
Serial.print("activating pin ");
Serial.println(input);
     
firstPinsActive[input-1]=1;
}
}
CountPins();

}

byte ShiftRegister::RandomPin() {

  // return a random pin number
  
  int output=random(0,noPins-1);
return output;

}

Saturday, January 17, 2015

Figuring out Shift Registers

Shift registers are handy and inexpensive.  Using just three pins on your Arduino, you can control hundreds of others.  I've already gone over the rote basics of how the work from a wiring standpoint, but how does it pan out logically?

Here's a (very rough) sketch of a 74HC595 8-bit register.
So, assuming the shift register is properly connected to the Arduino, each of the outputs from 0-7 (8 total) are treated as bits, which, for those of you who don't know, are the protons and electrons of the information world.  Bits are the fundamental building block of all data from the simple byte (8 bits) all the way  up to the highest definition video file.  They're pretty easy to understand as they can only be 1 or 0, which is handy if you want to store something that only has two possible values; a check box on a form for example (which can be either YES or NO,) or in our case whether a pin has power or not (HIGH or LOW.)  Bits have been with us since the dawn of computer logic; since the early Jacquard Looms which took punch cards embedded with rows bits that told the loom what action to perform next.

You'll notice the shift register above is an 8-bit registers, and as almost anyone familiar with computer networking and IP addresses knows, 8 bits make up a byte.  A byte can have 256 possible values from 0 to 255.  Why 256?  Because instead of counting in the decimal we were taught in grade school (which goes in sets from 0 to 10,) you're counting in binary, which goes in sets of 0 or 1.

This is so simple it's deceptively confusing.  From the right, the first value in a line is the 1's place.  It can be either 0 or 1.  The second value is the 2's place.  It can be either 0 or 2.  It basically doubles from here; 4,8,16,32,64,128 etc.  So if you had a value of 10, you'd add 0 in the 1's place to 1 in the 2's place, giving you 2.  this would make 11 3, 110 6, and it goes on and on.

Apply this to our shift register above.  After passing the clock and latchpin and the way we want it to process the data, we give the shiftout function a number representing the pins we want to toggle.  So let's say we wanted to turn output pins 0 and 2 on, but leave 1 off.  

Imagine it like this:

Pin 0: 1 (1=ON)
Pin 1: 0 (0=OFF)
Pin 2: 1

101 in decimal would be 5 (1 in the 4+0 in the 2+1 in the 1.)  Likewise if we wanted to turn 0-2 on we'd have 111, which would be decimal 7 (4+2+1.)   If you're a bit confused as to why we start with pin 0, it's relatively simple; computers start counting at 0 instead of 1 as it is actually the first value in our number system.

So let's say we wanted to hook up another shift register.  Do we need to take up another 3 pins on the Arduino?  Not at all; we just hook the data pin of Register 2 to the overflow pin of register 1, hook the power and ground of register 2 to the proper rails, and connect the clock and latch pins of Register 2 in parallel with Register 1.  It's all diagrammed here.

The wiring seems simple enough, so what about the logic?  Before I read up on it, I confess that I assumed it was as simple as passing it a larger number.  Each register is an 8-bit address space with 256 possible values, so I assumed that if I passed the register the number 511 it would automatically overflow, lighting up all 8 of Register 1's LED's and the first LED of Register 2.

How naive I was.

Turns out you have to pass the shiftout to the register twice (there's no sense showing the code here, as this blog, again, demonstrates it quite well.)  The first shiftout will pass the value to register 1 and the second will overflow to register 2.  Each shiftout must contain a value between 0 and 256, indicating which bits you want to turn on or off.  I edited the above blog's code (as I only had room for two additional LED's on my breadboard,) and eureka; it worked perfectly.

Hopefully this will provide some basic help understanding both the shiftout function and the broader topic of shift registers in general.