LEDs and shift registers

I'm trying to run random light patterns on 8 LEDs through a shift register. In simple terms, I'm going to have a list of light patterns and have some code to select at random a pattern to send to the shift register. I'm completely new to arduino coding and have no idea what script tools to use to make this work. I was told to make an array list or something, but I have no idea how to do this. I have honestly been all over google and youtube, but I can't find a thing about doing random arrays. If you need anymore information just let me know.

Other info.
Arduino Uno R3
Shift register 74hc595

I'm trying to run random light patterns on 8 LEDs

Before coding, what type of patterns you what to display ?

The 595 display only 8 output. From 00000000 to 11111111 or 0 to 255.

So just random a number between 0 to 255. When I think about random numbers, I think about a lotery like 6/49, a number between 1 to 49. But select 6 time a number between 1 to 49. So in your application ( I don't know yet ) just generated a number between 0 to 255, send the number to the 595 to be display.

for a few examples.

the plain shift,
10000000
01000000
00100000
00010000
00001000
00000100
00000010
00000001(and then reverse the patern)
Also doing a double shift where two LEDs are on side by side

Grow,
00000000
00011000
00111100
01111110
11111111
11100111
11000011
10000001
00000000(and then reverse the pattern)

Chaser,
10000000
01000000
00100000
00010000
00001000
00000100
00000010
00000001
10000001
01000001
00100001
00010001
00001001
00000101
00000011.... and continue till all of the LEDs are lit. I also what an inverted version where the LEDs start all on and get turned off.

And lastly a random strobe, where random one to all of the LEDs turn on and off at random to create a strobe effect..

I'm going to have these set up where the shift register is going to activate a NPN transistor as a switch and have the LEDs plugged right into power.

PWR -> LEDs -> Transistor -> GND

DIGI Out -> Transistor Base -> GND

This way the LEDs will get max power without worrying about frying the 74hc595

PWR -> LEDs -> Transistor -> GND

DIGI Out -> Transistor Base -> GND

This way the LEDs will get max power without worrying about frying the 74hc595

And don't forget the limiting resistors. For base limiting : 4.7 K ohms, for LED limiting : 470 ohms

To send a data to be display. I will use this bare-bone code and do a little modification.

const byte latchpin = 12; // <-- you can select another pins if you want
const byte clockpin = 11;
const byte datapin = 10;  

const byte array_size = 14;

byte send_byte;
 
int stay_on = 1000; // stay for 1 second - number is in milli Second - 10 exp -3 

byte my_array[14] = { b10000000, b01000000, b00100000, b00010000, b00001000, b00000100, b00000010, b00000001,
                             b00000010, b00000100, b00001000, b00010000, b00100000, b01000000 };

void setup()
{
   // setup section
    pinMode(latchpin, OUTPUT);
    pinMode(clockpin, OUTPUT);
    pinMode(datapin, OUTPUT);
}

void loop()
{

// my main program code here
// display my patern 
for ( int i=0;i< array_size;i++)
  {
     send_byte = my_array[i];
     display_my_data ( send_byte );
     delay ( stay_on ); // set the time to stay on
  }

}

// Display Routine
void display_my_data( byte my_data )
{
   digitalWrite( latchpin, LOW);
   shiftOut( datapin, clockpin,LSBFIRST, my_data);
   digittalWrite( latchpin, HIGH);
}

I'm having a hell of a time trying to reverse engineer this stuff. Back when I was doing HTML, all I had to do was look at a web page source to figure out how to use a piece of code or copy an effect/layout. I thank you for all your help though. Here's all of the patterns I'm wanted to do. I know there's got to be a way to code these without putting in every single frame by hand :*

Shift

10000000
01000000
00100000
00010000
00001000
00000100
00000010
00000001
00000010
00000100
00001000
00010000
00100000
01000000
10000000

Shift Invert

01111111
10111111
11011111
11101111
11110111
11111011
11111101
11111110
11111101
11111011
11110111
11101111
11011111
10111111
01111111

Grow

00000000
00011000
00111100
01111110
11111111
11100111
11000011
10000001

Grow Reverse

00000000
10000001
11000011
11100111
11111111
01111110
00111100
00011000

Chase

10000000
01000000
00100000
00010000
00001000
00000100
00000010
00000001
10000001
01000001
00100001
00010001
00001001
00000101
00000011
10000011
01000011
00100011
00010011
00001011
00000111
10000111
01000111
00100111
00010111
00001111
10001111
01001111
00101111
00011111
10011111
01011111
00111111
10111111
01111111
11111111

Chase Invert Reverse

11111110
11111101
11111011
11110111
11101111
11011111
10111111
01111111
01111110
01111101
01111011
01110111
01101111
01011111
00111111
00111110
00111101
00111011
00110111
00101111
00011111
00011110
00011101
00011011
00010111
00001111
00001110
00001101
00001011
00000111
00000110
00000101
00000011
00000010
00000001
00000000

Sure, shift left, shift right, and invert should do it. Simple loop, easy.

@Nick Gammon

Sure, shift left, shift right, and invert should do it. Simple loop, easy

Easy for you. Not for me. :wink:

@bdvs

If you want to do all those display, first you will need a mode selector and do the pattern.

Like :

-Select Patern

  • A circuit - a button you press to select the patern
    -Play Patern
  • A section in the program to play the patern

An idea

Techone:
Easy for you. Not for me. :wink:

Here are some examples, I'll let you do the rest ...

void showbin (const byte c)
  {
  for (int i = 7; i >= 0; i--)
    Serial.write ((c >> i) & 1 | '0');
  Serial.println ();
  }
  
void setup()
{
  Serial.begin(115200);
  
  byte leds, a, b;
  
  // shift
  Serial.println ("Shift");
  leds = 0x80;
  for (int i = 0; i < 8; i++)
    {
    showbin (leds);  
    leds >>= 1;
    }
  Serial.println ();
    
  // shift invert
  Serial.println ("Shift invert");
  leds = 0x80;
  for (int i = 0; i < 8; i++)
    {
    showbin (~leds);  
    leds >>= 1;
    }
  Serial.println ();
   
  // grow
  Serial.println ("Grow");
  leds = 0x00;
  a = 0b00010000;
  b = 0b00001000;
  for (int i = 0; i < 5; i++)
    {
    showbin (leds);  
    leds |= a | b;
    a <<= 1;
    b >>= 1;
    }
  a = 0b00010000;
  b = 0b00001000;
  for (int i = 0; i < 3; i++)
    {
    leds &= ~ (a | b);
    showbin (leds);  
    a <<= 1;
    b >>= 1;
    }    
  Serial.println ();
    
}

void loop(){}

Output:

Shift
10000000
01000000
00100000
00010000
00001000
00000100
00000010
00000001

Shift invert
01111111
10111111
11011111
11101111
11110111
11111011
11111101
11111110

Grow
00000000
00011000
00111100
01111110
11111111
11100111
11000011
10000001

@Nick Gammon

Thanks Nick for the example. I will study it. And you are right, it matter of using << or >> bitwise operators. And a few tricks.

Thanks. :slight_smile:

I was thinking today about it, and I think it is possible to use the MAX7219 instead of using 74HC595. And instead of using 8 leds, why not a lots more leds... I will try to figure this out and have a go at it. I do need practice in programing the Arduino.

I will do is :

  • Init the MAX7219
  • Set for a patern
  • Select a patern ( up or down )
  • set scrolling speed
  • select the speed ( up or down )
  • go the the patern section
  • Display the patern, the selection number and the scrolling speed.
  • loop to Set for a patern

Here a picture of the leds I might use. ( the 8 is for the numbers display ( speed and selection number ) and the Leds bar is for the led's scrolling. ( 40 leds = 5 set of 8 leds ) And the 4 push buttons. 2 for the speed select and 2 for the patern select.

I just give myself a challange. With your example, it will help. As for the selection routine, I did a code for a Gear Selection, the switch code should work. I bit of a modifications, my calculator code for display with modification, I might have a go at it.

I have a page about the 7219 here:

It's pretty straightforward (you need to wire the LEDs in a matrix). I have bit patterns for a font on that page, but you could use any pattern you like.

Thanks Nick. I add to "My Favorites/microcontrollers" folder, your link. It will help a lot. I will try to understand your code and use it as an example.

I will breadboard my little project. I will code it and will post it in this tread.

I wonder if the OP understand the example code in post #8.

Very helpful advice - now I know why my LEDs dim so much when more are turned on. The Arduino 5v pin is obviously not supplying enough current. Can someone explain the transistor approach in a little more detail? (I'm a programmer but an electronics newbie). I'm using a Uno and a couple of 74HC595 serially linked (to drive 32 LEDs). The LEDs are rated at 30mA so I'm using 180ohm resistors - but I guess I need some oomph to light the whole lot at the same time? More than one batterry in parallel?

@garthn

The LEDs are rated at 30mA so I'm using 180ohm resistors - but I guess I need some oomph to light the whole lot at the same time? More than one batterry in parallel

Why you are using 180 ohms ? 470 ohms is much safer. A LED rated at 30 mA is only the max value. It is the voltage drop of a LED is more important than the current rated. A diode have a constant voltage drop. A LED is a kind of diode. Work like a diode, ack like a diode, therefore it is a diode, except it got a bigger voltage drop.

Current limiting formula : R limiting = ( V supply - V diode drop ) / Limiting current

The supply of the Arduino is max about 500 mA. So to keep it safe, let use 400 mA - a 100 mA safe marging.

Take 400 mA / 32 = 12 mA each . The 74HC595 is I source about 5 mA - safe operation. So I use a 470 ohms.

Let re-calculate : ( 5 V - 2.2 V ) / 470 ohms = 6 mA <--- safe for the 74HC595 to use directely Assuming the voltage drop of your LED is 2.2 V

About using transistors : here a link : Transistor Circuits

To quote myself :

I was thinking today about it, and I think it is possible to use the MAX7219 instead of using 74HC595. And instead of using 8 leds, why not a lots more leds... I will try to figure this out and have a go at it. I do need practice in programing the Arduino.

I did build it. It work... so far. I did a test program to tested my MAX7219 setup. During the programming, I did have a problem to display properly. I taught the MAX was mal-function, but it was not.

I did this :

for (byte i = 0 ; i < 256; i++)
{
    display_number[j]= i ; // j is the digit to be display - like : Digit 1 =  1
    display_the_max();
    delay(25);
}

Well, that did not work. It keep repeating, the same loop !!!

I fix it that part of the code. I change byte for int. That work better. 256 was never going to be execute. A byte is max 255.

Anyway , here the complete test code. I use pin 13 for a debug/test monitor.

const byte datapin = 12;
const byte latchpin = 11;
const byte clockpin = 10;

byte display_number[8] = {0,0,0,0,0,0,0,0};

void setup()
{
 pinMode(datapin, OUTPUT);
 pinMode(latchpin, OUTPUT);
 pinMode(clockpin, OUTPUT);
 pinMode(13, OUTPUT);
 digitalWrite(13, LOW);
 // set : Normal Mode
 digitalWrite(latchpin, LOW);
 shiftOut(datapin, clockpin, MSBFIRST, 0x0C );
 shiftOut(datapin, clockpin, MSBFIRST, 0x01 );
 digitalWrite(latchpin, HIGH);
 delay(5);
 // set : Normal Operation
 digitalWrite(latchpin, LOW);
 shiftOut(datapin, clockpin, MSBFIRST, 0x0F );
 shiftOut(datapin, clockpin, MSBFIRST, 0x00 );
 digitalWrite(latchpin, HIGH);
 delay(5);
 // set : Intensity 
 digitalWrite(latchpin, LOW);
 shiftOut(datapin, clockpin, MSBFIRST, 0x0A );
 shiftOut(datapin, clockpin, MSBFIRST, 0x0B );
 digitalWrite(latchpin, HIGH);
 delay(5);
 // set : Numbers of digits 
 digitalWrite(latchpin, LOW);
 shiftOut(datapin, clockpin, MSBFIRST, 0x0B );
 shiftOut(datapin, clockpin, MSBFIRST, 0x07 );
 digitalWrite(latchpin, HIGH);
 delay(5); 
 // set : Decode Mode Register
 digitalWrite(latchpin, LOW);
 shiftOut(datapin, clockpin, MSBFIRST, 0x09 );
 shiftOut(datapin, clockpin, MSBFIRST, 0x00 ); // I set the MAX7219 for No Decode Mode.
 digitalWrite(latchpin, HIGH);
 delay(5);
 // set display to zero
 display_the_max();
}

void loop()
{
 for (int j=0;j<8;j++)
 {
   for (int i=0;i<256;i++)
   {
     display_number[j]=lowByte(i);
     display_the_max();
     delay(25);
   }  
   display_number[j]=0;
   display_the_max();
   digitalWrite(13, HIGH);
   delay(5000); 
   digitalWrite(13, LOW);
 }
 digitalWrite(13, HIGH);
 delay(2000);
 digitalWrite(13, LOW);
}

void display_the_max()
{
 for (int k=0; k<8;k++)
 {
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, MSBFIRST, (k+1));
    shiftOut(datapin, clockpin, MSBFIRST, display_number[k]);
    digitalWrite(latchpin, HIGH);
    delay(5); 
 }   
}

I forgot : The R set for the MAX7219 current segment limiting is 68 K. A bit higher than the datasheet. I just want the segments to be under 10 mA. During a power-up test ( no Arduino connected ), all leds was light up, so I measured the I total going into the circuit. It was around 100 mA, it is well bellow the Arduino voltage regulator current rating.

I did a code to display a basic patern, ( I am planning to display multi-paterns ), the code is not complete, but it work so far. It miss : mode selection, scrolling speed selection, more paterns and a random patern. The random patern will use an open analog pin value for a random seed value. I will build a noise generator circuit see site : http://www.sentex.ca/~mec1995/tutorial/xtor/xtor6/xtor6.html and check the noise circuit. I breadboard it and I will need to amplify the signal, remove the high frequency component, and use the clean amplify signal for a random voltage to be use by the analog pin. I will post my final circuit. I included a picture of the noise signal. +12 V is use to power the circuit. Any lower, no noise signal. My scope setting is : 50 mV / div , 5 mS / div.

For now, here the code I will use ( tested OK so far ) to display leds chaser paterns using a MAX7219. Some parts is missing. It is not complete yet.

// Output Pins - Data In, Latch pulse and Clock pulse
const byte datapin = 12;
const byte latchpin = 11;
const byte clockpin = 10;
// Input Pins
const byte inpin[4] = {4,5,6,7};
// Analog Pin
const byte anapin = 1;

// Load up the display buffer
byte display_data[8] = {0,0,0,0,0,0,0,0};
// Numbers to Display Code
byte display_number[10] = {0b01111110,0b00110000,0b01101101,0b01111001,0b00110011,0b01011011,0b01011111,0b01110000,0b01111111,0b01110011}; 

int analog_value = 512;
int delay_rate = 500;

byte the_rate = 50;
byte the_mode = 1;

void setup()
{
 // set analog voltage reference origin  
 analogReference(EXTERNAL); 
 // Set Output pins 
 pinMode(datapin, OUTPUT);
 pinMode(latchpin, OUTPUT);
 pinMode(clockpin, OUTPUT);
 // Set Input pins
 for (byte i=0;i<4;i++)
 {
   pinMode(inpin[i], INPUT); 
 }  
 // set MAX7219 : Normal Mode
 digitalWrite(latchpin, LOW);
 shiftOut(datapin, clockpin, MSBFIRST, 0x0C );
 shiftOut(datapin, clockpin, MSBFIRST, 0x01 );
 digitalWrite(latchpin, HIGH);
 delay(5);
 // set MAX7219 : Normal Operation
 digitalWrite(latchpin, LOW);
 shiftOut(datapin, clockpin, MSBFIRST, 0x0F );
 shiftOut(datapin, clockpin, MSBFIRST, 0x00 );
 digitalWrite(latchpin, HIGH);
 delay(5);
 // set MAX7219 : Intensity 
 digitalWrite(latchpin, LOW);
 shiftOut(datapin, clockpin, MSBFIRST, 0x0A );
 shiftOut(datapin, clockpin, MSBFIRST, 0x0B );
 digitalWrite(latchpin, HIGH);
 delay(5);
 // set MAX7219 : Numbers of digits 
 digitalWrite(latchpin, LOW);
 shiftOut(datapin, clockpin, MSBFIRST, 0x0B );
 shiftOut(datapin, clockpin, MSBFIRST, 0x07 );
 digitalWrite(latchpin, HIGH);
 delay(5); 
 // set MAX7219 : Decode Mode Register
 digitalWrite(latchpin, LOW);
 shiftOut(datapin, clockpin, MSBFIRST, 0x09 );
 shiftOut(datapin, clockpin, MSBFIRST, 0x00 );
 digitalWrite(latchpin, HIGH);
 delay(5);
 // set display to zero
 display_the_max();
}

void loop()
{
  get_the_rate();
  the_mode = 1;
  mode_1_2();
  delay(3000);
  the_mode = 2;
  mode_1_2();
  delay(3000);
  
} 

void display_the_max()
{
  for (byte i=0; i<8;i++)
 {
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, MSBFIRST, (i+1));
    shiftOut(datapin, clockpin, MSBFIRST, display_data[i]);
    digitalWrite(latchpin, HIGH);
    delay(5); 
 }  
}

void get_the_rate()
{
  byte High_nibble;
  byte Low_nibble;
  
  delay_rate = int(the_rate) * 10;
  High_nibble = the_rate / 10;
  Low_nibble = the_rate % 10;
  display_data[6] = display_number[High_nibble];
  display_data[5] = display_number[Low_nibble];
}  

// Shift
void mode_1_2()
{
  byte shift_data = 0b10000000;
  
  if (the_mode == 1 )
  {
    display_data[7] = display_number[1];
    for (byte i=0;i<5;i++)
    {
      display_data[i]=0b00000000;
    }  
  }
  if (the_mode == 2 )
  {
    display_data[7] = display_number[2];
    for (byte i=0;i<5;i++)
    {
      display_data[i]=0b11111111;
    }  
  }  
  for (int k=4;k>=0;k--)
  {
   shift_data = 0b10000000; 
   for(byte j=0;j<8;j++)
   {
     if (the_mode == 1)
     {
        display_data[k] = shift_data;        
     }
     if (the_mode == 2)
     {
        display_data[k] = ~shift_data;
     }   
     display_the_max();
     delay(delay_rate);
     shift_data = shift_data >> 1;     
   }
   if (the_mode == 1 )
   { 
     display_data[k] = 0b00000000;
   }
   if (the_mode == 2 )
   {
     display_data[k] = 0b11111111;
   }  
  }
  for (int k=0;k<5;k++)
  {
   shift_data = 0b00000001; 
   for(byte j=0;j<8;j++)
   {
     if (the_mode == 1)
     {
        display_data[k] = shift_data;
     }
     if (the_mode == 2)
     {
        display_data[k] = ~shift_data;
     }   
     display_the_max();
     delay(delay_rate);
     shift_data = shift_data << 1;     
   }
   if (the_mode == 1)
   {   
     display_data[k] = 0b00000000;
   }
   if (the_mode == 2)
   {
     display_data[k] = 0b11111111;
   }   
  }  
}

// Grow
void mode_3()
{
  display_data[7] = display_number[3]; 
  
} 
// Grow Invert
void mode_4()
{
  display_data[7] = display_number[4];
}
//Chase
void mode_5()
{
  display_data[7] = display_number[5];
}
// Chase Invert
void mode_6()
{
  display_data[7] = display_number[6];
  
}
// Random
void mode_7()
{
  display_data[7] = display_number[7];
  
}