shift registers ,LED's ,timer

Arduino Project

Hello, I have in my mind a project like below.

1 Connect the arduino with 6 LED's controlled with a Shift register

2 Read from a text file the light sequence and put into the register (1,2,4,8,16,32,16,8,4,2)
So this would light each LED in sequence like the KITT sweep example.

3 Connect a timer to the project which would control when to perform the next LED lighting event from reading another text file, example 1,0,1,0,1,0

4 So if the clock was set to 60 BPM, the first value is "1" so light up the first LED. The next value on the clock is "0" so do nothing ,the next is "1" so light up the second LED etc etc.

so after the circuit is working correctly I could change the light sequence and the timer sequence to whatever I want, ie Light sequence (1,2,4,16,8,32,16,8,16,2) and the timer to (1,0,0,1,1,0,1)

Does this make sense :slight_smile:

Any pointers here?

Regards

Geoff

Any pointers here?

First thing, why do you need a shift register?


Rob

Shift register like a TPIC6B595 would let him control strings of 12V LEDs.
It also gets one away from the current/port limits of the '328P.
74HC595 still stinks for that (70mA total), but hey, gotta start somewhere!

Ref - First thing, why do you need a shift register

I'm basically starting out using the "Shift Out" tutorial which uses shift registers and LED's. That's 50% of my project I think.

I want to modify it so I can specify the lighting sequence and the timing of the lighting events using text files.

Thanks for the info about TPIC6B595's that will be useful.

Regards

Geoff

True, but he hasn't mentioned 12v or LED strings or that he's pin bound. Is that the case JimiH?

Also where is this "text file" residing, do you have an SD card or getting the data from a PC?

EDIT:

I'm basically starting out using the "Shift Out" tutorial which uses shift registers and LED's.

Ok, that explains the shift reg, what about the text file?


Rob

Ref - Also where is this "text file" residing, do you have an SD card or getting the data from a PC?

The files will reside on a PC.

Ref - True, but he hasn't mentioned 12v or LED strings or that he's pin bound. Is that the case JimiH?

First of all I will user basic low power LED's connected to a breadboard to prove the concept ,after that I'm toying with the idea of using
other devices instead of the LED's, Motors, Solenoids etc etc. But to keep it as simple as possible I plan
to use LED's first of all.

Geoff

I think to simplify things further I will hard code the light sequence and timer sequence. After I have proved the concept
i will try to read the sequences via a file on the PC.

After I have set the BPM via the 555 timer, if that possible? its a simple matter of feeding that into the clock on the register right?

Regards

Geoff

Using a 555 actually complicates matters IMO because now you have to sync the CPU with the timer whereas the CPU can easily do all the work in code.

Is that a requirement as well?


Rob

Thats good to know as its not a requirement I just assumed I needed a timer. If I can do it all in the code that would be great.

As a basic example of how I see it working is as follows.

I have timer pulsing 120 BPM so counting that out would be, 1 AND 2 AND 3 AND 4 AND 5 AND 6 AND 7 AND 8 etc etc.
Lets say we have a tune, twinkle twinkle little star (Main beat are in CAPS)

TWIN-kle-TWIN-kle-LITT-le-STAR.

So the timer sequence would be

1-1-1-1-1-1-1-0

The 1's would cause the LED's to flash and the 0's would not flash. After I have that situation sorted then I can use the second Light sequence
to determine which LED light's

Does that make sense :~

thanks

Geoff

Oh, so you want to modulate a 120Hz signal, that's a different story.

That could be done all in software as well but it would be harder, in that case maybe going back to the 555 is the best thing for you.

You could run the 555 output to an AND gate and on the other input of the gate connect your data stream.

Then write a simple shiftout() function that shifts the bits in an array of bytes out one at a time with a delay between them.

I cannot see this sounding even vaguely like Twinkle... though, more like Morse code although with LEDs I guess you won't hear anything :slight_smile:


Rob

:slight_smile:

Thanks for AND gate idea.

One problem I will have is I have two data streams.

Timer Stream - 1,1,1,1,1,0
Light Stream - 1,2,4,16,32,64

So with the above data i light the 1st ,2nd, 3rd ,4th ,5th LED then the 64 doesn't light.

Thanks

Geoff

Sorry, I'm sure this is simple but I'm not following it, in the above example wouldn't you just send the value 0x1F to shiftOut()? But then that doesn't give you a 120Hz modulated signal unless you feed that signal into the AND gate with the 120Hz on the other input.

How about a drawing of the required waveform or something.


Rob

Sorry Rob I'm not making myself clear. I'm only a newb at this stuff although I've done many
of the examples on this site so not that newb.

I'll put it another way.

Lets say I have 4 coloured LEDs Red, Blue, Green and White.

I choose the lighting sequence of, Red, Blue, Red, White, Blue, Green, Red.

Then I have a timing sequence to control when each light will come on.
So with a timing sequence of 1,1,1,1,1,1 each light will come on in the specified sequence.
At 120 bpm that's 1 light every half a second.

However if I change the timing sequence to 1,1,1,0,0,0,1,1,1 the first three will come on in sequence at 0.5 sec intervals.
Then we have a pause for three beats 1.5 sec, then the remaining lights will come on in sequence.

So when the circuit is completed I can change the Lighting and Timing sequence to what ever I choose.

Is that a better description?

Thanks

Geoff

Ok I think I've got it, I was reading your 120bps as 120Hz, big difference :slight_smile:

There are probably a 1000 ways to do this but here's my first thought.

If the number of sequences is not large (say < 500) you could have an array of bytes that holds bit patterns for your 4 LEDs.

Every .5 secs you read the next value from the array and write the value to the 4 pins controlling the LEDs.

byte seq_array[] =

//      RBGW
   B00001000,  // first pattern
   B00000100,
   B00001000,
   B00000001,
   B00000100,
   B00000010,
   B00001000,
   B00000001,  // first 3 in seq for 3 beats
   B00000010,
   B00000100,
   B00000000,  // all off for 3 beats
   B00000000,
   B00000000,
   B00000010,  // last 3 in seq for 3 beats
   B00000100,
   B00001000
};

I still don't know if I got the sequence you described but the above should be able to do any sequence.

If you think this is on the right track we can fill in the blanks.


Rob

Thanks Rob that's something to think about. We are 50% there :slight_smile:

This is the first array with the sequence of lights required

//      RBGW
   B00001000,  // This is the sequence of lights required
   B00000100,
   B00001000,
   B00000001,
   B00000100,
   B00000010,
   B00001000,
   B00000001,  
   B00000010,
   B00000100,
   B00000010,  
   B00000100,
   B00001000
};

Notice I have taken out the 3 pauses as this will controlled by a second aaray to control what happens on every beat.

An array like this would fire each line of the first array.

(1,1,1,1,1,1,1,1,1,1,1,1,1)

ie, if its a "1" then execute the first line of the first aaray, when we get the next "1" execute the second line etc etc
However if we get a "0" then do nothing, then if we get a "1" execute the third line of the first aaray.

So an aaray like this (1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0) would make the lights flash in the same sequence but
we would have a pause between them. An array like this (1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1) would light the first half of
the first aaray straight away then we have a pause for 6 beats, then we complete the sequence.

So essentially we have two arrays the second of which controls when we read the first.

You ready to give up yet :slight_smile:

Thanks

Geoff

When I'm doing bit/pattern shfiting, I create a buffer to hold the pattern. I'll try to describe the concept in words:

If I want to "shift-in" a pattern (or shift a pattern from left-to-right and then right-to-left) I create a "buffer" variable (with 6 LEDs I'd use a byte) and an output variable.

The basic right-shift sequence would be like this:
Load the pattern into the buffer.
Copy buffer bit-0* into output bit-5. Diaplay data/pattern to LEDs.
Shift both bytes right.

Loop-back and copy buffer bit-0 into output bit-5, Display data/pattern to LEDs ....etc.

Assuming you want to shift the entire sequence through ('till you are back to zeros) you can add a step:
Copy output bit-0 into buffer bit-6 before shifting, so that you don't loose the bit zero value/state. Note that you are copying into an "extra" bit-6 of the buffer (the 7th bit) so that you don't over-write the pattern before shifting.

This creates a "rotating circle" with half of the data/pattern showing on the LEDs and the the other half of the data saved in the buffer. Of course you can rotate both directions. It usually helps to draw a picture to keep track of when to copy and shift, so that you don't over-write and mess-up your pattern.

You can also create something called a Johnson Counter, which rotates the pattern in a circle (without hiding it in a buffer) but it inverts the data before feeding it back in the other side. So if LED 6 is off, that data is inverted before rotating back-in, turning LED 1 on. (Again, this does require an extra "buffer bit" to save the bit that's getting rotated out of the pattern and back-in the other side.)

With 4 bits, the Johnson Counter pattern looks like this when rotated left:
0000
0001
0011
0111
1111
1110
1100
1000
0000
0001
0011
0111
1111
1110
1100
1000
0000 ...etc.

If you reverse the pattern at the right time, you can get something like the "KITT effect".

  • Bit zero is the least significant (rightmost) bit. With 6 LEDs, you are using bits 0 - 5.

I think I'm following, how many steps will there be, that will affect how it's done.

EDIT: I didn't notice the extra post by DVDdoug, I'll read that now.


Rob

Thanks guys

Braking it down to its simplest form I would say this.

LED Pattern =

0001
0010
0100
1000

Sequence pattern =

1,3,4,2

So when I read the first sequence pattern value "1" that means do LED pattern 0001. Next sequence pattern ="3" now do LED pattern 0100 etc etc.

So in essence I could change the order of when the LED's flash by using the second sequence pattern.

Regards

Geoff

I think this should do what you want

byte patterns[] = {
  //  RBGW
     B0001,  
     B0010,
     B1100,
     B0011,
     B1000
};

byte sequence[] = {1,3,0,4,2};  // as many as you like

//             W  B   G  R
byte pins[] = {3, 6, 10, 4}; // logical pin numbers, WBGR order

int curr_seq = 0;

const int N_LEDS = 4;
const int N_SEQS = sizeof(sequence) / sizeof (sequence[0]);

void setup() {
  for (int i = 0; i < N_LEDS; i++) {
    pinMode (pins[i], OUTPUT);
  }
}

void loop () {

  if ((millis() % 500) == 0) {
    every_500_ms ();
  }

}

void every_500_ms () {

  byte pattern = patterns[sequence[curr_seq]];

  for (int i = 0; i < N_LEDS; i++) {
    digitalWrite (pins[i], (pattern & 1) ? HIGH : LOW);
    pattern >>= 1;
  }

  if (++curr_seq > N_SEQS) curr_seq = 0;

}

You may need more but this compiles and should run although I can't test it.


Rob

Cheers Rob :slight_smile:

I'll give that a go over the weekend

I did write this up in c# today hoping it would give you the heads up as what I'm trying to do but you beat me to it.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace AarayTest1

{

    class Program

    {

        static void Main(SEQ[] args)

        {


            string[] arr = new SEQ[7]; // Initialize

            arr[0] = "6";               // Element 1

            arr[1] = "5";               // Element 2

            arr[2] = "4";             // Element 3

            arr[3] = "3";              // Element 4

            arr[4] = "2";             // Element 5

            arr[5] = "1";              // Element 6

            arr[6] = "0";              // Element 7

 

            // Loop over SEQ

            foreach (SEQ s in arr)

          

            {

 

                switch (s)

                {

                    case "0":

 

                        Console.WriteLine("Hit the sixth LED");

                        break;

 

                    case "1":

 

                        Console.WriteLine("Hit the Fifth LED");

                        break;

 

                    case "2":

 

                        Console.WriteLine("Hit the Fouth LED");

                        break;

 

                    case "3":

 

                        Console.WriteLine("Hit the Third LED");

                        break;

 

                    case "4":

 

                        Console.WriteLine("Hit the Second LED");

                        break;

 

                    case "5":

 

                        Console.WriteLine("Hit the First LED");

                        break;

 

                    case "6":

 

                        Console.WriteLine("Pause ,do nothing");

                        break;

                }


                Console.ReadLine(); //Pause

         
            }  

        }
        }

    }

Thanks again

Geoff