Shift register to fade LED's on and keep them on until input

Hi,

I have been trailing around the net looking for a solution without any joy, so maybe you could help.

I have a shift register that I need to fade on 8 led's one after another, I have found the following, but for some reason the less only shine dimly, I need them to be on full brightness, also by removing the last part of the code this doesn't stop the fading out, it carries on in the loop, any ideas?

This isn't my code all credit goes to the author.

/************************************************************************************************************************************
Fade in LED's one by one using ShiftPWM with one shift register
 ************************************************************************************************************************************/

// You can choose the latch pin yourself.
const int ShiftPWM_latchPin=8;

#define SHIFTPWM_NOSPI
const int ShiftPWM_dataPin = 11;
const int ShiftPWM_clockPin = 12;


// If your LED's turn on if the pin is low, set this to true, otherwise set it to false.
const bool ShiftPWM_invertOutputs = false; 

// You can enable the option below to shift the PWM phase of each shift register by 8 compared to the previous.
// This will slightly increase the interrupt load, but will prevent all PWM signals from becoming high at the same time.
// This will be a bit easier on your power supply, because the current peaks are distributed.
const bool ShiftPWM_balanceLoad = false;

#include <ShiftPWM.h>   // include ShiftPWM.h after setting the pins!

// Here you set the number of brightness levels, the update frequency and the number of shift registers.
// These values affect the load of ShiftPWM.
// Choose them wisely and use the PrintInterruptLoad() function to verify your load.
// There is a calculator on my website to estimate the load.

unsigned char maxBrightness = 255;
unsigned char pwmFrequency = 75;
int numRegisters = 1;
int numRGBleds = numRegisters*8/3;

void setup(){

  // Sets the number of 8-bit registers that are used.
  ShiftPWM.SetAmountOfRegisters(numRegisters);

  // SetPinGrouping allows flexibility in LED setup. 
  // If your LED's are connected like this: RRRRGGGGBBBBRRRRGGGGBBBB, use SetPinGrouping(4).
  //ShiftPWM.SetPinGrouping(3); //This is the default, but I added here to demonstrate how to use the funtion
  
  ShiftPWM.Start(pwmFrequency,maxBrightness);
}


void loop()
{    
  // Turn all LED's off.
  ShiftPWM.SetAll(0);
  
  //ShiftPWM.SetOne(0, 255);
  
  // For every led
  for(int pin = 0; pin < 8; pin++){
    
    // Fade in
    for(unsigned char brightness = 0; brightness < 255; brightness++){
      ShiftPWM.SetOne(pin, brightness);
      delayMicroseconds(2000);
    }
    
    // Fade out
    for(unsigned char brightness = 255; brightness > 0; brightness--){
      ShiftPWM.SetOne(pin, brightness);
      delayMicroseconds(2000);
    }
        
  }

}

What shift register are you using ?

How is it wired up? What resistor values do you have?

Hi,

I am using the following setup, works dream apart from keeping the LEDs lit, I can put a long delay at then end but I need it to wait for input from say when another led is lit to carry on the rest of the sequence.

http://www.oomlout.com/oom.php/products/ardx/circ-05

Have you tied the code on that site?
The first thing I noticed about the code you posted is that you do not set up the pins as outputs in the setup function.

but I need it to wait for input from say when another led is lit to carry on the rest of the sequence.

I don't understand what you want to wait for, but o that at the end of the for loop:-

// Fade out
    for(unsigned char brightness = 255; brightness > 0; brightness--){
      ShiftPWM.SetOne(pin, brightness);
      delayMicroseconds(2000);
    }
// put the code that waits for something here

Ok let me explain,

I am showing how a micro controller works using LEDs.

So there will be 2 sets of LEDs, one set will be for one value and the other for the other set. Once you press a button a sequence is ran that fades on one led at a time, keeping the previous one lit until it reaches led 9, then holds and waits for the second sequence to finish, so it reaches the final led before the hold for example led 19, it then needs to allow the rest of the sequence to carry on finally ending with all the LEDs lit.

So it looks like this, led 1, 50, 2, 50...
Then waits at led 9, for led 19

So when led 19 lights up then the sequence will carry on with led 10 & 11 and 20 & 21

if (led 19 => 50){
Light led 10, led 11, led 20, led 21}

So in fact nothing remotely connected with the code you posted.

I can't see what it waits for, it just seems to be one sequence. To say it waits for an LED doesn't make sense because that LED is just part of the sequence isn't it?

Ok sorry, I'll explain more.

First off ignore the code a above, I've changed it somewhat but I need the delay as describe below,

I have a series of 10 LEDs in one tube and ten in another, when the 9th led is lit then the sequence stops so the final led is not lit, the LEDs in the next tube do the same, but when the 9th led is lit in 2nd tube then the 10th led is lit in both tubes, see diagram below

Tube 1

1 2 3 4 5 6 7 8 9 Wait till led 9 tube 2 is lit (ie pin 18) then light both 10 on tube 1 and 10
========================= on tube 2.

Tube 2

1 2 3 4 5 6 7 8 9

Yes but it is all just a simple sequence, there is no waiting for anything, it is simply a sequence. It could even be a linear one if you wire it up so that the physical LEDs are placed in the order you want them to come on.

I have a series of 10 LEDs in one tube and ten in another, when the 9th led is lit then the sequence stops so the final led is not lit

So you wire the first 9 LEDs to the first 9 shift register outputs you have.

the LEDs in the next tube do the same, but when the 9th led is lit in 2nd tube then the 10th led is lit in both tubes,

then the next 10 LEDs are wired in the second tube. The 10th LED in the first tube is wired to the 10th LED in the second tube or if they don't have to come on at the same time then the last of the shift register outputs.

If you don't like that then wire all 20 LEDs up one after the other in the shift register and write the code to do three things one after the other.

  1. light up the first 9 LEDs
  2. light up LEDs 11 to 19
  3. light up LEDs 10 and 20

There is no stopping or waiting it is just a sequence.

Ok thanks for that,

Can you explain how to get them to fade on one by one and stay on instead of fading off.

Can you explain how to get them to fade on one by one and stay on instead of fading off.

Simply do not include the fade out bit of the code:-

 // Fade out
    for(unsigned char brightness = 255; brightness > 0; brightness--){
      ShiftPWM.SetOne(pin, brightness);
      delayMicroseconds(2000);
    }

and just have the fade in bit:-

// Fade in
    for(unsigned char brightness = 0; brightness < 255; brightness++){
      ShiftPWM.SetOne(pin, brightness);
      delayMicroseconds(2000);
    }

Yeah I was thinking that was the solution and so tried it, but for some reason it carries on with the sequence, am I missing something?

Post the code of what you have, say what it does and say what you think it should do. Then we can tell you where you are going wrong.

Ok so here is what I have so far,

I am trying to get the loop to break on a double press of the button, so that the second shift register method is ran, Also I need the led's to go out once it runs the second method, currently they all come on instead of fading on one at a time.

here is my code.

#include <Button.h>

int latchPin = 5;
int clockPin = 6;
int dataPin = 4;
int outputEnablePin = 3;
//Button trigger = Button(2,LOW);

byte leds = 0;
byte button[] = {2};

#define NUMBUTTONS sizeof(button)
byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];

void setup() {
  //setBrightness(0);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  pinMode(outputEnablePin, OUTPUT); 
  //pinMode(2,INPUT); //Trigger switch sits on pin 2
  Serial.begin(9600);
  Serial.println("Welcome");
  byte i;
  
   for (i=0; i< NUMBUTTONS; i++) {
    pinMode(button[i], INPUT);
    digitalWrite(button[i], HIGH);
  }
    //Timer2 Overflow Interrupt Enable
  TIMSK2 |= 1<<TOIE2;
}
//byte pressCount1 = 0;


void check_switches()
{
  static byte previousstate[NUMBUTTONS];
  static byte currentstate[NUMBUTTONS];
  byte index;

  for (index = 0; index < NUMBUTTONS; index++) {
    currentstate[index] = digitalRead(button[index]);   // read the button
    /*     
    Serial.print(index, DEC);
    Serial.print(": cstate=");
    Serial.print(currentstate[index], DEC);
    Serial.print(", pstate=");
    Serial.print(previousstate[index], DEC);
    Serial.print(", press=");
    */
    
    if (currentstate[index] == previousstate[index]) {
      if ((pressed[index] == LOW) && (currentstate[index] == LOW)) {
          // just pressed
          justpressed[index] += 1;
      }
      else if ((pressed[index] == HIGH) && (currentstate[index] == HIGH)) {
          // just released
          justreleased[index] = 1;
      }
      pressed[index] = !currentstate[index];  // remember, digital HIGH means NOT pressed
    }
    //Serial.println(pressed[index], DEC);
    previousstate[index] = currentstate[index];   // keep a running tally of the buttons
  }
}

SIGNAL(TIMER2_OVF_vect) {
  check_switches();
}
void loop() {
  byte i;
 // check_switches();
  Serial.println(justpressed[0]);
//  delay(500);
  setBrightness(0);
if (justpressed[0]) {
  Serial.print("Single Pressed");
  for (int i = 0; i < 4; i++)
  {
    if (justpressed[0]==2){
      break;
    }
  //  check_switches();
    Serial.println(justpressed[0]);
    
    bitSet(leds, i);
    updateShiftRegister();
    delay(50);
    
    for (byte b = 255; b > 0; b--)
  {
    setBrightness(b);
    delay(20);
  }
  
  }
}
  //delay(1000);
  Serial.println(justpressed[0]);
if (justpressed[0]==2) {
  Serial.println("Double Pressed");
  for (int i = 0; i < 4; i++)
  {
    bitSet(leds, i);
    updateShiftRegister2();
    delay(50);
    for (byte b = 255; b > 0; b--)
    
  {
    setBrightness(b);
    delay(20);
  }
  //delay(1000);
  } 
}
justpressed[0] = 0;
setBrightness(0);
    }

void updateShiftRegister()
{
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, LSBFIRST, leds);// Change the start LED to 1
   digitalWrite(latchPin, HIGH);
}

void updateShiftRegister2()
{
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, MSBFIRST, leds);// Change the start LED to 8
   digitalWrite(latchPin, HIGH);
}


void setBrightness(byte brightness) // 0 to 255
{
  analogWrite(outputEnablePin, 255+brightness);
}

Some quick observations:-
Are the commented out lines meant to confuse? For clarity they should be removed.

void setBrightness(byte brightness) // 0 to 255
{ analogWrite(outputEnablePin, 255+brightness);
}

The analogue write only takes a number up to a maximum of 255, that code ensures that it is always 255 or greater, therefore it can never change the duty cycle of the PWM.

I am trying to get the loop to break on a double press of the button

I can't see the code doing that. A double press means you have to detect the edge, that is the transition from unpressed. Then you make a note of the time this happened using the millis() function. Then when you detect this transition again you again make a not of the time. Only if the interval between these two times is less that some threshold do you need to trigger the event.

I would have though there is no need for using interrupts to trigger reading the buttons. Do you know what speed you are doing this at. Buttons by computer standards change at a glacial slow rate there is no need to read them that often.

Ok so the loop break out is the following,

if (justpressed[0]==2){

Break;

}

I need the button to able be pressed at anytime during the loop. Which then jumps to the second if, but if the button is pressed three times it sets the value back to 0 hence starting the cycle again.

Can you simplify the code for a double press, I have re-engineered that code from one that I use to control buttons on a wave shield.

Thanks for your help mike :slight_smile:

I need the button to able be pressed at anytime during the loop.

If you need this then you need to be able to break out of a loop from a command in the interrupt service routine. You can not do this. You can only jump out of a loop when you check something and if you are going to check the state of the flag of the switches you might as well check the switches at the same time.

Now what you need to do is to write the whole program as a state machine, using the blink without delay technique. Look at that technique, it is as simple as it can get. Then grow it to cover your sequence.

So what you do it look at the milis timer and decide what you want to do next to advance the sequence, to look at the switches and so on.

As a final point you are altering the brightness of the LEDs by applying PWM to the shift register's output enable. This will always change the brightness of all the LEDs that are on, that is all the LEDs that have a one in the shift register. All the other LEDs will be off. So I think you can not get what you want with your current hardware setup. As I understand it you want one LED to fade up with some of the others being on and the rest being off.

That is correct, I have 4 LEDs which need lighting up one at a time, these stay on but once it receives the interrupt from the button it shifts to the opposite and starts the loop with the last 4 LEDs each one fading up at a time.

If this is not possible, can you send me a wiring diagram to achieve what I need.

You can do this with software by using the shiftpwm library:-
http://www.elcojacobs.com/shiftpwm/

If you want to do it with hardware then you need another chip. There are lots of chips you can use for this but it is extra expense and some of the chips are surface mount only so you need good soldering skills.

ok so an update, thanks for you advice, everything is running swimmingly although I do ask for your help once again.

So have two buttons that both need the option to be pressed twice, what I am after is setting a shift register to run the LSB outputs which produces 4 led's lit, then pressing the same button runs the method for MSB outputs to be lit, the things is I have set a boolean value to show when the button is pressed and when its not but can't for the life of me work out why its not doing what I want.

Do you have any ideas?

Heres my code so far.

Cheers :slight_smile:

#include <Button.h>

int latchPin = 5;
int clockPin = 6;
int dataPin = 4;
int outputEnablePin = 3;
//Button trigger = Button(2,LOW);

byte leds = 0;
byte button[] = {2, 8, 9};
byte switch_value = 0;
boolean btnOn;

#define NUMBUTTONS sizeof(button)
byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];

void setup() {
  setBrightness(0);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  pinMode(outputEnablePin, OUTPUT); 
  //pinMode(2,INPUT); //Trigger switch sits on pin 2
  Serial.begin(9600);
  Serial.println("Welcome");
  byte i;
  
   for (i=0; i< NUMBUTTONS; i++) {
    pinMode(button[i], INPUT);
    digitalWrite(button[i], HIGH);
  }
    //Timer2 Overflow Interrupt Enable
  TIMSK2 |= 1<<TOIE2;
}
//byte pressCount1 = 0;
SIGNAL(TIMER2_OVF_vect) {
  check_switches();
}

void check_switches()
{
  static byte previousstate[NUMBUTTONS];
  static byte currentstate[NUMBUTTONS];
  byte index;

  for (index = 0; index < NUMBUTTONS; index++) {
    currentstate[index] = digitalRead(button[index]);   // read the button
    /*    
    Serial.print(index, DEC);
    Serial.print(": cstate=");
    Serial.print(currentstate[index], DEC);
    Serial.print(", pstate=");
    Serial.print(previousstate[index], DEC);
    Serial.print(", press=");
    */
    
    if (currentstate[index] == previousstate[index]) {
      if ((pressed[index] == LOW) && (currentstate[index] == LOW)) {
          // just pressed
          justpressed[index] = 1;
          //switch_value = switch_value + 1;

      }
      else if ((pressed[index] == HIGH) && (currentstate[index] == HIGH)) {
          // just released
          justreleased[index] = 1;
      }
      pressed[index] = !currentstate[index];  // remember, digital HIGH means NOT pressed
    }
    //Serial.println(pressed[index], DEC);
    previousstate[index] = currentstate[index];   // keep a running tally of the buttons
  }
}


void loop() {

 /////////////////////////////////////////////////////
 //This is Button 1 Press
 /////////////////////////////////////////////////////
if (justpressed[0]) {
  button1();
  btnOn = true;
  justpressed[0] = 0;
  }
 /////////////////////////////////////////////////////
 //This is Button 2 Press
 /////////////////////////////////////////////////////
  
if (justpressed[1]) {
  button2();
  //btnOn = false;
 justpressed[1] = 0;
  }
  
 /////////////////////////////////////////////////////
 //This is Button 1 Pressed Twice
 ////////////////////////////////////////////////////
if (justpressed[0] && (btnOn == true)) {  
  button2();
 justpressed[0] = 0;
 switch_value = 0;
}
/////////////////////////////////////////////////////
 //This is Button 2 Pressed Twice
 ////////////////////////////////////////////////////
btnOn=false;
}
    

void updateShiftRegister()
{
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, LSBFIRST, leds);// Change the start LED to 1
   digitalWrite(latchPin, HIGH);
}

void updateShiftRegister2()
{
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, MSBFIRST, leds);// Change the start LED to 8
   digitalWrite(latchPin, HIGH);
}

void setBrightness(byte brightness) // 0 to 255
{
  analogWrite(outputEnablePin, 255-brightness);
}

void button1(){
  for (int i = 0; i < 4; i++)
  {
    bitSet(leds, i);
    updateShiftRegister();
    delay(50);
    for (byte b = 0; b < 255; b++)
  {
    setBrightness(b);
    delay(20);
  }
  if (justpressed[1]) {
  break;
  }
  }
  //bitSet(leds,0);
  //delay(1000); 
   
 leds = 0;
   //switch_value = 0;
  setBrightness(255);
}

void button2(){
for (int i = 0; i < 4; i++)
  {
    bitSet(leds, i);
    updateShiftRegister2();
    delay(50);
    for (byte b = 0; b < 255; b++)
  {
    setBrightness(b);
    delay(20);
  }
  if (justpressed[0]) {
  break;
  }
  }
  //bitSet(leds,0);
  //delay(1000); 
   
 leds = 0;
   //switch_value = 0;
  setBrightness(255);
}