Please help with first project: controlling brightness and color on ShiftBrites

Hi everyone!

First post - I'm a complete noob at this. I have a decent knowledge of electronics, but no Arduino or programming experience. I want to learn! I would greatly appreciate your help with my first project. I have a chain of 8 ShiftBars with Satellite LED modules, connected to an Arduino Uno via the ShiftBrite shield. I would like to:

a) be able to control the brightness of all LEDs at once with a potentiometer
b) be able to vary the RGB colors of all LEDs at once with a second potentiometer
c) be able to turn the entire array on or off with a momentary switch button.

I've tested the chain using this code posted on the Macetech site:

#define clockpin 13 // CI
#define enablepin 10 // EI
#define latchpin 9 // LI
#define datapin 11 // DI

#define NumLEDs 3

int LEDChannels[NumLEDs][3] = {0};
int SB_CommandMode;
int SB_RedCommand;
int SB_GreenCommand;
int SB_BlueCommand;

void setup() {

pinMode(datapin, OUTPUT);
pinMode(latchpin, OUTPUT);
pinMode(enablepin, OUTPUT);
pinMode(clockpin, OUTPUT);
SPCR = (1<<SPE)|(1<<MSTR)|(0<<SPR1)|(0<<SPR0);
digitalWrite(latchpin, LOW);
digitalWrite(enablepin, LOW);

}

void SB_SendPacket() {

if (SB_CommandMode == B01) {
SB_RedCommand = 120;
SB_GreenCommand = 100;
SB_BlueCommand = 100;
}

SPDR = SB_CommandMode << 6 | SB_BlueCommand>>4;
while(!(SPSR & (1<<SPIF)));
SPDR = SB_BlueCommand<<4 | SB_RedCommand>>6;
while(!(SPSR & (1<<SPIF)));
SPDR = SB_RedCommand << 2 | SB_GreenCommand>>8;
while(!(SPSR & (1<<SPIF)));
SPDR = SB_GreenCommand;
while(!(SPSR & (1<<SPIF)));

}

void WriteLEDArray() {

SB_CommandMode = B00; // Write to PWM control registers
for (int h = 0;h<NumLEDs;h++) {

SB_RedCommand = LEDChannels[0];
SB_GreenCommand = LEDChannels[1];
SB_BlueCommand = LEDChannels[2];
SB_SendPacket();
}
delayMicroseconds(15);
digitalWrite(latchpin,HIGH); // latch data into registers
delayMicroseconds(15);
digitalWrite(latchpin,LOW);
SB_CommandMode = B01; // Write to current control registers
for (int z = 0; z < NumLEDs; z++) SB_SendPacket();
delayMicroseconds(15);
digitalWrite(latchpin,HIGH); // latch data into registers
delayMicroseconds(15);
digitalWrite(latchpin,LOW);
}
void loop() {

LEDChannels[0][0] = 1023;
LEDChannels[0][1] = 0;
LEDChannels[0][2] = 0;
LEDChannels[1][0] = 0;
LEDChannels[1][1] = 0;
LEDChannels[1][2] = 1023;
WriteLEDArray();
delay(200);
LEDChannels[0][0] = 0;
LEDChannels[0][1] = 0;
LEDChannels[0][2] = 1023;
LEDChannels[1][0] = 1023;
LEDChannels[1][1] = 0;
LEDChannels[1][2] = 0;
WriteLEDArray();
delay(200);
}
Everything checks out fine; I also did an experiment with a single RGB LED, without the ShiftBars, to see if I could write the code for the two potentiometers and the button:
// Will fade an RGB LED from warm to cool
// in relation to the pot value
// LED leads connected to PWM pins
const int RED_LED_PIN = 9; //Red LED pin
const int GREEN_LED_PIN = 10; //Green LED pin
const int BLUE_LED_PIN = 11; //Blue LED pin
const int Button_Pin = 2; // Pushbutton pin
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
void setup() {
// initialize the pushbutton pin as an input:
pinMode(Button_Pin, INPUT);
}
void loop() {
int color = analogRead(0);
//read the color temperature pot
//Range is 2000K to 5500K
//RGB 255,137,18 to 255,236,224
int brightness = analogRead(1);
//read the brightness pot
//Range is off to full on
int redValue = constrain(
map(color, 0, 1023, 0,255),255,255)*map(brightness, 0, 1023, 0, 255)/255;
//calculate the red Value (255-0
//over the range 0-1023)
int greenValue = constrain(
map(color, 0, 1023, 0, 255),137,236)*map(brightness, 0, 1023, 0, 255)/255;
//calculate the green value (0-255
//over 0-1023)
int blueValue = constrain(
map(color, 0, 1023, 0, 255),18,224)*map(brightness, 0, 1023, 0, 255)/255;
//calculate the blue value 0-255 over
//0-1023
// read the state of the pushbutton value
buttonState = digitalRead(Button_Pin);
// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// Display the requested color
analogWrite(RED_LED_PIN, redValue);
analogWrite(GREEN_LED_PIN, greenValue);
analogWrite(BLUE_LED_PIN, blueValue);
}
else {
// turn LEDs off:
analogWrite(RED_LED_PIN, 0);
analogWrite(GREEN_LED_PIN, 0);
analogWrite(BLUE_LED_PIN, 0);
}
}
I did not figure out how to get the momentary button to toggle, so I could use some help there, please! Otherwise, it seems to work fine.
The million-dollar question is: how do I combine these two sketches to allow me to control the ShiftBrite chain like I did with the single RGB LED? The two approaches seem very different. Is there a better way? I'm stuck here! Thanks a bunch for your help!

In your serial code it seems you are latching your registers too many times. You should take the latch pin LOW before sending data, and HIGH afterwards. Actually, your whole WriteLEDArray function needs reworking as it doesn't seem like the PWM data is getting latched properly. Do you really need to update the current-control registers more than once, in setup()?

On the hardware side, how are you powering your shiftbars?

EDIT: whoops, I see how you used the example code from macetech in your program :stuck_out_tongue: But the code from macetech is a bit hard to read, so maybe... I don't know. Perhaps your problem is in the hardware after all.

Thanks for the response!

Actually, there's no hardware problem - just my coding incompetence! :grin:

Both sketches work fine with their respective hardware connections; the pots work, the button works.

I need help figuring out how to integrate the pots and button into the macetech code. Thanks!

Haven't actually tested this, but it'll probably work...really, you just ignore all the ShiftBrite stuff and focus on the fact that if you put the right colors into LEDChannels[][] and call the WriteLEDArray() function, the ShiftBrites will display the colors you chose. I essentially pasted in your existing analogWrite code and changed very little, mostly to do button debouncing. You seem to have some specific values tuned in your map functions, so I didn't mess with them...instead multiplied the 0-255 output by 4 to get back to the 0-1023 range ShiftBrites need.

/* Ports and Pins
 
 Direct port access is much faster than digitalWrite.
 You must match the correct port and pin as shown in the table below.
 
 Arduino Pin        Port        Pin
 13 (SCK)           PORTB       5
 12 (MISO)          PORTB       4
 11 (MOSI)          PORTB       3
 10 (SS)            PORTB       2
 9                  PORTB       1
 8                  PORTB       0
 7                  PORTD       7
 6                  PORTD       6
 5                  PORTD       5
 4                  PORTD       4
 3                  PORTD       3
 2                  PORTD       2
 1 (TX)             PORTD       1
 0 (RX)             PORTD       0
 A5 (Analog)        PORTC       5
 A4 (Analog)        PORTC       4
 A3 (Analog)        PORTC       3
 A2 (Analog)        PORTC       2
 A1 (Analog)        PORTC       1
 A0 (Analog)        PORTC       0
 
 */
 
// Defines for use with Arduino functions
#define clockpin   13 // CI
#define enablepin  10 // EI
#define latchpin    9 // LI
#define datapin    11 // DI
 
#define Button_Pin 2

// Defines for direct port access
#define CLKPORT PORTB
#define ENAPORT PORTB
#define LATPORT PORTB
#define DATPORT PORTB
#define CLKPIN  5
#define ENAPIN  2
#define LATPIN  1
#define DATPIN  3
 
// Variables for communication
unsigned long SB_CommandPacket;
int SB_CommandMode;
int SB_BlueCommand;
int SB_RedCommand;
int SB_GreenCommand;
 
// Define number of ShiftBrite modules
#define NumLEDs 16
 
// Create LED value storage array
int LEDChannels[NumLEDs][3] = {0};
 
// Set pins to outputs and initial states
void setup() {
  pinMode(datapin, OUTPUT);
  pinMode(latchpin, OUTPUT);
  pinMode(enablepin, OUTPUT);
  pinMode(clockpin, OUTPUT);
  digitalWrite(latchpin, LOW);
  digitalWrite(enablepin, LOW);
  SPCR = (1<<SPE)|(1<<MSTR)|(0<<SPR1)|(0<<SPR0);

  pinMode(Button_Pin, INPUT);
}
 
// Load values into SPI register
void SB_SendPacket() {
 
    if (SB_CommandMode == B01) {
     SB_RedCommand = 127;
     SB_GreenCommand = 110;
     SB_BlueCommand = 110;
    }
 
    SPDR = SB_CommandMode << 6 | SB_BlueCommand>>4;
    while(!(SPSR & (1<<SPIF)));
    SPDR = SB_BlueCommand<<4 | SB_RedCommand>>6;
    while(!(SPSR & (1<<SPIF)));
    SPDR = SB_RedCommand << 2 | SB_GreenCommand>>8;
    while(!(SPSR & (1<<SPIF)));
    SPDR = SB_GreenCommand;
    while(!(SPSR & (1<<SPIF)));
 
}
 
// Latch values into PWM registers
void SB_Latch() {
 
  delayMicroseconds(1);
  LATPORT += (1 << LATPIN);
  //ENAPORT += (1 << ENAPIN);
  delayMicroseconds(1);
  //ENAPORT &= ~(1 << ENAPIN);
  LATPORT &= ~(1 << LATPIN);
 
}
 
// Send all array values to chain
void WriteLEDArray() {
 
  SB_CommandMode = B00; // Write to PWM control registers
 
  for (int i = 0; i<NumLEDs; i++) {
    SB_RedCommand = LEDChannels[i][0] & 1023;
    SB_GreenCommand = LEDChannels[i][1] & 1023;
    SB_BlueCommand = LEDChannels[i][2] & 1023;
    SB_SendPacket();
  }
 
  SB_Latch();
 
  SB_CommandMode = B01; // Write to current control registers
 
  for (int z = 0; z < NumLEDs; z++) SB_SendPacket();   
 
  SB_Latch();
 
}

void paintAll(int red, int green, int blue) {
  for (int i = 0; i < NumLEDs; i++) {
    LEDChannels[i][0] = red;
    LEDChannels[i][1] = green;
    LEDChannels[i][2] = blue;
  }

  WriteLEDArray();
}


boolean buttonNewState = false;
boolean buttonOldState = false;
boolean buttonState = false;
int dbTimer = 0;

void buttonDebounce() {

  if (digitalRead(Button_Pin) == HIGH) {
    dbTimer++;
    if (dbTimer > 10) {
      if (buttonOldState == false) {
        buttonNewState = true;
        buttonState = !buttonState;
      }
    }
  } else {
    dbTimer = 0;
    buttonNewState = false;
  }

  buttonOldState = buttonNewState;

} 

int actionTimer = 0;

void loop() {
 
  int color = analogRead(0);
  //read the color temperature pot
  //Range is 2000K to 5500K
  //RGB 255,137,18 to 255,236,224

  int brightness = analogRead(1);
  //read the brightness pot
  //Range is off to full on

  int redValue = constrain(
  map(color, 0, 1023, 0,255),255,255)*map(brightness, 0, 1023, 0, 255)/255;
  //calculate the red Value (255-0
  //over the range 0-1023)
  int greenValue = constrain(
  map(color, 0, 1023, 0, 255),137,236)*map(brightness, 0, 1023, 0, 255)/255;
  //calculate the green value (0-255
  //over 0-1023)
  int blueValue = constrain(
  map(color, 0, 1023, 0, 255),18,224)*map(brightness, 0, 1023, 0, 255)/255;
  //calculate the blue value 0-255 over
  //0-1023

  // read the state of the pushbutton value
  buttonDebounce();

  actionTimer++;
  if (actionTimer > 10) {

    actionTimer = 0;
    
    // check if the pushbutton is pressed.
    // if it is, the buttonState is HIGH:
    if (buttonState == true) {     
      // Display the requested color
      paintAll(redValue*4,greenValue*4,blueValue*4); 
    }
    else {
      // turn LEDs off:
      paintAll(0,0,0);
    }
  
  }
 
 delay(1);
  
}

Awesome! Thanks! I'll try it this weekend and report back to you.

Works flawlessly! Thanks again, Macegr!