0

Lesson 5 sketch
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Lesson 5 sketch

by dodotopia on Sun Dec 30, 2007 4:35 pm

I've made little mods to lesson 5's sketch and thought I'd post it...here it is.

Code: Select all | TOGGLE FULL SIZE
/*
 *  Orb mockup.  Cycle through 8 modes (Crossfade through 3 primary & 3 secondary colors, Red, Green, Blue,
 *  Yellow, Cyan, Magenta and Off).  Works best with a difuser i.e. ladyada's paper cube
 *  (http://ladyada.net/learn/arduino/lesson3.html) or Ambient's glass Orb (http://www.ambientdevices.com).
 * 
 *  Credits for the code go to ladyada & Clay Shirky
 */

int switchPin = 2;              // switch is connected to pin 2

int bluePin = 11;               // Blue LED connected to pin 11
int greenPin = 10;              // Green LED connected to pin 11
int redPin = 9;                 // Red LED connected to pin 11


int val;                        // variable for reading the pin status
int val2;                       // variable for reading the delayed status
int buttonState;                // variable to hold the button state

int lightMode = 0;              // What mode is the light in?

// Program variables
int redVal   = 255;             // Variables to store the values to send to the pins
int greenVal = 1;               // Initial values are Red full, Green and Blue off
int blueVal  = 1;

int i = 0;                      // Loop counter   
int wait = 25;                  // 25ms (.025 second) delay; shorten for faster fades

void setup() {
  pinMode(switchPin, INPUT);    // Set the switch pin as input

  pinMode(bluePin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(redPin, OUTPUT);
 
  Serial.begin(9600);                     // Set up serial communication at 9600bps
  buttonState = digitalRead(switchPin);   // read the initial state
}

void loop(){
  val = digitalRead(switchPin);                   // read input value and store it in val
  delay(20);                                      // 10 milliseconds is a good amount of time
  val2 = digitalRead(switchPin);                  // read the input again to check for bounces
  if (val == val2) {                              // make sure we got 2 consistant readings!
    if (val != buttonState) {                     // the button state has changed!
      if (val == LOW) {                           // check if the button is pressed
        if (lightMode == 0) {                     // if its off
          lightMode = 1;                          // Crossfade!
        } else {
          if (lightMode == 1) {                   // if its crossfade
            lightMode = 2;                        // make it red!
          } else {
            if (lightMode == 2) {                 // if its red
              lightMode = 3;                      // make it green!
            }   else {
              if (lightMode == 3) {               // if its green
                lightMode = 4;                    // make it blue!
              }   else {
                if (lightMode == 4) {             // if its blue
                  lightMode = 5;                  // make it yellow!
                }  else {
                  if (lightMode == 5) {           // if its yellow
                    lightMode = 6;                // make it cyan!
                  } else {
                    if (lightMode == 6) {         // if its cyan
                      lightMode = 7;              // make it magenta!
                    } else {
            if (lightMode == 7) {       //  if its magenta,
                        lightMode = 0;            // turn light off!
                      }
         } 
                         }
                        }
                       }
                      }
                     }
                    }
                   }
                  }
                   
    buttonState = val;                 // save the new state in our variable
  }

  // Now do whatever the lightMode indicates
  if (lightMode == 0) { // all-off
    digitalWrite(bluePin, LOW);
    digitalWrite(greenPin, LOW);
    digitalWrite(redPin, LOW);
  }

  if (lightMode == 1) { // crossfade
     i += 1;      // Increment counter
  if (i < 255) // First phase of fades
  {
    redVal   -= 1; // Red down
    greenVal += 1; // Green up
    blueVal   = 1; // Blue low
  }
  else if (i < 509) // Second phase of fades
  {
    redVal    = 1; // Red low
    greenVal -= 1; // Green down
    blueVal  += 1; // Blue up
  }
  else if (i < 763) // Third phase of fades
  {
    redVal  += 1; // Red up
    greenVal = 1; // Green low
    blueVal -= 1; // Blue down
  }
  else // Re-set the counter, and start the fades again
  {
    i = 1;
  } 

  analogWrite(redPin,   redVal);   // Write current values to LED pins
  analogWrite(greenPin, greenVal);
  analogWrite(bluePin,  blueVal); 

  delay(wait); // Pause for 'wait' milliseconds before resuming the loop
  }

  if (lightMode == 2) { // Red
    digitalWrite(bluePin, LOW);
    digitalWrite(greenPin, LOW);
    digitalWrite(redPin, HIGH);
  }
  if (lightMode == 3) { // Green
    digitalWrite(bluePin, LOW);
    digitalWrite(greenPin, HIGH);
    digitalWrite(redPin, LOW);
  }   
    if (lightMode == 4) { // Blue
    digitalWrite(bluePin, HIGH);
    digitalWrite(greenPin, LOW);
    digitalWrite(redPin, LOW);
  }
      if (lightMode == 5) { // Yellow
    digitalWrite(bluePin, LOW);
    digitalWrite(greenPin, HIGH);
    digitalWrite(redPin, HIGH);
  }
        if (lightMode == 6) { // Cyan
    digitalWrite(bluePin, HIGH);
    digitalWrite(greenPin, HIGH);
    digitalWrite(redPin, LOW);
  }
      if (lightMode == 7) { // Magenta
    digitalWrite(bluePin, HIGH);
    digitalWrite(greenPin, LOW);
    digitalWrite(redPin, HIGH);
  }
}

dodotopia
 
Posts: 5
Joined: Sun Dec 30, 2007 4:31 pm

by A. Square on Thu Jan 03, 2008 3:47 am

If you're interested, here are a couple of suggestions to tighten up your code.

You don't need that whole series of nested if statements to change your "lightMode" variable. You could simply use:


Code: Select all | TOGGLE FULL SIZE
if(lightMode == 7) {        // if it's magenta
      lightMode = 0;          // turn it off
} else {
       ++lightMode;          // otherwise, move it to the next mode
}



You could also use the modulo function, but then your lightMode variable would overflow eventually, so it might not be the best idea.

The second suggestion is for tightening up the series of "else ifs" at the end. Instead, you might want to consider reading up on switch/case statements, which does essentially the same thing, but is a little easier to read and work with, I think.

Good luck!
A. Square
 
Posts: 41
Joined: Mon Dec 17, 2007 12:51 pm

by rglenn on Fri Jan 04, 2008 12:05 am

Using the modulo function:
Code: Select all | TOGGLE FULL SIZE
lightMode = ++lightMode % 8;


Putting the ++ in front of lightMode there is crucial - if it goes after (as in lightMode++) then lightMode will vary from 1 to 8, not from 0 to 7. This is the important difference between pre- and post-incrementing.

rglenn
 
Posts: 20
Joined: Thu Oct 04, 2007 10:36 pm

by mtbf0 on Fri Jan 04, 2008 9:22 am

a couple of things.

the mega168 does not have hardware division so the modulus function is kind of expensive in terms of cpu cycles. fortunately the modulus of a number by a power of 2 can be had by bitwise anding the number with the power of 2 minus one. so

lightMode = ++lightMode % 8;

is equivalent to

lightMode = ++lightMode & 7;

which not only runs faster, but saves code space since the division library need not be loaded.

secondly, the mega168 is an 8 bit processor so it's best to declare variables to be 8 bits where possible. unfortunately an int is 16 bits, so declaring lightMode and anything else that fits in 8 bits as an char, (values from -128 to 127), or as a unsigned char, (values from 0 to 255), saves space and time.

thirdly, declaring things like bluePin, greenPin and redPin as variables leaves you open to accidentally altering them in code. it is therefore considered prudent to declare such things as constants as follows

#define bluePin 11
#define greenPin 10
#define redPin 9

by convention, though, constants in c are usually named in upper case.

last but not least, your collection of if statements to select the color to display could be greatly simplified by associating each led with a bit of lightMode which, since it only varies from 0 to 7, uses three bits. so

digitalWrite (bluePin, (lightMode & 1) ? HIGH : LOW);
digitalWrite (greenPin, (lightMode & 2) ? HIGH : LOW);
digitalWrite (redPin, (lightMode & 4) ? HIGH : LOW);

this code will give the colors blue, green, cyan, red, magenta, yellow, and white as lightMode varies from 1 to 7 and will cause all leds to be off when lightMode is 0.

?: is a conditional operator in c and c++. basically, a statement, a ? b : c, will have the value b if a is true, (non-zero), or c if a is false, (zero). (lightMode & 1) is true when lightMode is 1, 3, 5 or 7, so for these cases the blue led is on. (lightMode & 2) is true when lightMode is 2, 3, 6 or 7. and (lightMode & 4) is true when lightMode is 4, 5, 6 or 7.

if you assign cross fading mode to lightMode 7 you can wrap the three digitalWrite calls in an if statement.

hope you find this helpful. i had to type it twice, since i timed out the first time. ^*&&#@!
Last edited by mtbf0 on Sat Jan 05, 2008 8:50 am, edited 1 time in total.
User avatar
mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am
Location: oakland ca

by A. Square on Fri Jan 04, 2008 10:35 am

mtbf0 wrote:hope you find this helpful. i had to type it twice, since i timed out the first time. ^*&&#@!


Thanks for the info, mtbf0; whether or not the original poster finds it helpful, I certainly learned a few things.

However, you might know more about coding than I do, but apparently I know more about message boards: always copy a long comment to the clipboard before posting, just in case! ;)
A. Square
 
Posts: 41
Joined: Mon Dec 17, 2007 12:51 pm

by mtbf0 on Sat Jan 05, 2008 8:47 am

oops. turns out that the arduino environment does not recognize the keywords int8 and uint8. use types char and unsigned char instead.

here is a brief sketch illustrating the bits i outlined in my earlier post. it compiles in the arduino environment. i'll see if it actually runs tomorrow

Code: Select all | TOGGLE FULL SIZE
/*

   color switch sketch

   assumes n.o. switch with pullup on digital pin 2 and common cathode
   rgb led with red connected to digital pin 9, green to 10 and blue to
   11.

   colors will cycle with each button press

*/
#define SWITCHPIN 2
#define BLUEPIN 11
#define GREENPIN 10
#define REDPIN 9

unsigned char buttonVal1;
unsigned char buttonVal2;
unsigned char buttonState;
unsigned char lightMode = 0;

void setup() {
  pinMode(SWITCHPIN, INPUT);

  pinMode(BLUEPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(REDPIN, OUTPUT);
 
  buttonState = digitalRead(SWITCHPIN);   // get initial state of switch
}

void loop(){
//
// first debounce switch input
//
  buttonVal1 = digitalRead(SWITCHPIN);   // read switch
  delay(20);            // dum-de-dum
  buttonVal2 = digitalRead(SWITCHPIN);   // reread switch
  if (buttonVal1 == buttonVal2) {   // not bouncing?
    if (buttonVal1 != buttonState) {   // new state?
      buttonState = buttonVal1;      // set new button state
      if (buttonState == LOW)      // switch is pressed ?
   lightMode = ++lightMode & 7;   // increment lightMode
    }
  }
//
// set leds according to value of lightMode
//
//   bit 0 controls blue led
//   bit 1 controls green
//   bit 2 controls red
//
//   so colors according to value of lightMode are ...
//
//   lightMode == 0 --> all leds off
//   lightMode == 1 --> blue
//   lightMode == 2 --> green
//   lightMode == 3 --> cyan (blue and green)
//   lightMode == 4 --> red
//   lightMode == 5 --> magenta (blue and red)
//   lightMode == 6 --> yellow (red and green)
//   lightMode == 7 --> white (all leds on)
//
  digitalWrite (BLUEPIN, (lightMode & 1) ? HIGH : LOW);
  digitalWrite (GREENPIN, (lightMode & 2) ? HIGH : LOW);
  digitalWrite (REDPIN, (lightMode & 4) ? HIGH : LOW);
}
User avatar
mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am
Location: oakland ca

by mtbf0 on Thu Jan 10, 2008 3:14 pm

this works.

when cross fading one color is full on, one is dimming and one is getting brighter. the debug code is in there because although my concept was good, my execution, as usual was a little sloppy. it can be turned on by uncommenting the "#define debug" line. to turn in back off put the pair of slashes back at the beginning if the line.

you may notice that i only increase the intensity halfway. this is because as you approach a 100% duty cycle on the pwm, the apparent change in brightness gets less. on the other hand 50% is still a little dim.

change the line fadecount = 1; to fadecount = 0; to see why i had to add in the debug stuff. arrrrgh.


Code: Select all | TOGGLE FULL SIZE
/*

   color switch sketch

   assumes n.o. switch with pullup on digital pin 2 and common cathode
   rgb led with red connected to digital pin 9, green to 10 and blue to
   11.

   colors will cycle with each button press

*/
//#define debug
#define SWITCHPIN 2
#define BLUEPIN 11
#define GREENPIN 10
#define REDPIN 9

unsigned char buttonVal1;
unsigned char buttonVal2;
unsigned char buttonState;
char blueVal;
char greenVal;
char redVal;
char blueInc;
char greenInc;
char redInc;
unsigned char fadeCount;
unsigned char lightMode = 0;

#ifdef debug
void dump (void) {
  Serial.print (fadeCount, DEC);  Serial.println ();
  Serial.print (blueVal, DEC); Serial.print (",");
  Serial.print (blueInc, DEC); Serial.print (" - ");
  Serial.print (greenVal, DEC); Serial.print (",");
  Serial.print (greenInc, DEC); Serial.print (" - ");
  Serial.print (redVal, DEC); Serial.print (",");
  Serial.print (redInc, DEC); Serial.println ();
}
#endif

void setup() {
  pinMode(SWITCHPIN, INPUT);
  pinMode(BLUEPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(REDPIN, OUTPUT);
 
  blueVal = 127;
  blueInc = 0;
  greenVal = 0;
  greenInc = 1;
  redVal = 127;
  redInc = -1;
  fadeCount = 0;
#ifdef debug
  Serial.begin (9600);
  dump ();
#endif
  buttonState = digitalRead(SWITCHPIN);   // get initial state of switch
}

void loop(){
//
// first debounce switch input
//
  buttonVal1 = digitalRead(SWITCHPIN);   // read switch
  delay(20);            // dum-de-dum
  buttonVal2 = digitalRead(SWITCHPIN);   // reread switch
  if (buttonVal1 == buttonVal2) {   // not bouncing?
    if (buttonVal1 != buttonState) {   // new state?
      buttonState = buttonVal1;      // set new button state
      if (buttonState == LOW)      // switch is pressed ?
   lightMode = ++lightMode & 7;   // increment lightMode
    }
  }
//
// set leds according to value of lightMode
//
//   bit 0 controls blue led
//   bit 1 controls green
//   bit 2 controls red
//
//   so colors according to value of lightMode are ...
//
//   lightMode == 0 --> cross fade colors
//   lightMode == 1 --> blue
//   lightMode == 2 --> green
//   lightMode == 3 --> cyan (blue and green)
//   lightMode == 4 --> red
//   lightMode == 5 --> magenta (blue and red)
//   lightMode == 6 --> yellow (red and green)
//   lightMode == 7 --> white (all leds on)
//
  if (lightMode) {                        // if nonzero, show color
    digitalWrite (BLUEPIN, (lightMode & 1) ? HIGH : LOW);
    digitalWrite (GREENPIN, (lightMode & 2) ? HIGH : LOW);
    digitalWrite (REDPIN, (lightMode & 4) ? HIGH : LOW);
  }
  else {                                  // else cross fade
    if (++fadeCount > 127) {
#ifdef Debug
      dump ();
#endif
      blueInc += (blueInc & 0x80) ? 2 : -1;
      greenInc += (greenInc & 0x80) ? 2 : -1;
      redInc += (redInc & 0x80) ? 2 : -1;
      fadeCount = 1;
#ifdef debug
      dump ();
#endif
    }
    blueVal += blueInc;
    greenVal += greenInc;
    redVal += redInc;
    analogWrite (BLUEPIN, blueVal);
    analogWrite (GREENPIN, greenVal);
    analogWrite (REDPIN, redVal);
  }
}
//  ad nauseum
User avatar
mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am
Location: oakland ca

Please be positive and constructive with your questions and comments.


cron