fake PWMing three 74hc595 shift registers

hey guy/girls,

i was wondering if you could please help me alter this code so that i can fade 24 leds. i want the device they go into to look as though it is breathing, through light. so i would like the leds to fade up to 255 in about 1000ms and then fade down to 0 in say 2000ms.

this is the code so far.

//Pin connected to ST_CP of 74HC595
int latchPin = 6;
//Pin connected to SH_CP of 74HC595
int clockPin = 4;
////Pin connected to DS of 74HC595
int dataPin = 5;

void setup() {

pinMode(latchPin, OUTPUT);
Serial.begin(9600);

}

void loop() {
int z=0;
for (z=0; z<=255; z++) {
digitalWrite(latchPin, 0); // ground the latchpin
shiftOut(dataPin, clockPin, z);
shiftOut(dataPin, clockPin, 0);
shiftOut(dataPin, clockPin, 0);
digitalWrite(latchPin, 1); // return the latch pin high

digitalWrite(latchPin, 0); // ground the latchpin
shiftOut(dataPin, clockPin, 0);
shiftOut(dataPin, clockPin, z);
shiftOut(dataPin, clockPin, 0);
// 2nd register ignite all 8 LEDs
digitalWrite(latchPin, 1); // return the latch pin high

digitalWrite(latchPin, 0); // ground the latchpin
shiftOut(dataPin, clockPin, 0);
shiftOut(dataPin, clockPin, 0);
shiftOut(dataPin, clockPin, z);
digitalWrite(latchPin, 1); // return the latch pin high

}
}

// the heart of the program
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
// This shifts 8 bits out MSB first,
//on the rising edge of the clock,
//clock idles low

//internal function setup
int i=0;
int pinState;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, OUTPUT);

//clear everything out just in case to
//prepare shift register for bit shifting
digitalWrite(myDataPin, 0);
digitalWrite(myClockPin, 0);

//for each bit in the byte myDataOut?
//NOTICE THAT WE ARE COUNTING DOWN in our for loop
//This means that %00000001 or "1" will go through such
//that it will be pin Q0 that lights.
for (i=7; i>=0; i--) {
digitalWrite(myClockPin, 0);

//if the value passed to myDataOut and a bitmask result
// true then... so if we are at i=6 and our value is
// %11010100 it would the code compares it to %01000000
// and proceeds to set pinState to 1.
if ( myDataOut & (1<<i) ) {
pinState= 1;
}
else {
pinState= 0;
}

//Sets the pin to HIGH or LOW depending on pinState
digitalWrite(myDataPin, pinState);
//register shifts bits on upstroke of clock pin
digitalWrite(myClockPin, 1);
//zero the data pin after shift to prevent bleed through
digitalWrite(myDataPin, 0);
}

//stop shifting
digitalWrite(myClockPin, 0);
}

clearly you can see i have altered it from the shiftout tutorial on the arduino site and also added what another poster has done which is to shift out so that only 8 leds are on at a time but through POV you see them all on. i then wrote a loop so that what they shifted out goes from 0 to 255 but this is wrong for what i want to do because this actually just shifts out a count, which is not what i want.

i know i need to write some math that shifts out so that all the leds turn on for the full time and then turn on and then off for progressively longer times until they are all off and then do the oppersite for fading them back up.
but the problem is im not sure how to go about writing this.
if anyone could help or point me in the right direction i would be very greatful.

cheers,

sebastian.

There are lots of ways to do this. One way to do it using just integers is Bresenham's line algorithm - Wikipedia Bresenham's line drawing algorithm. How does drawing lines relate to fading? Well, the algorithm is really a generic "rate-relation" that is, the algorithm "moves" a point in 2 dimensions as evenly as possible. For fading, one of your dimensions is time, the other the amount of time that the LED should be on. For example, you want it to light up 20% of the time for 1 second (1,.2), but do so as evenly as possible.

I have written code for the M5451 chip which is a similar serial-shift chipset to the 595 except that is is particularly made for LEDs. I've heard rumors that the bits are even clocked in with the exact same algorithm, but I don't have a 595 to try it. But the M5451 chip is better for this application because it drives constant current outputs instead of logic (so you don't need a resistor on the LEDs, and the colors will be a similar brightness even though they need different voltages, etc).

You might be able to adapt this code, or switch to using the M5451 (I do sell boards, or the chips cost $3.5 from futureelectronics (for one) ). See: http://code.google.com/p/arduino-m5451-current-driver/ for code. The "flickerBrightness" class in particular does the PWMing.

Note that the fastest manual PWM I've gotten out of the Arduino is pretty good. However, at low PWM intensities (on 1/10 of the time or less) you can see some blinking. It depends on the LED, how bright you are driving it, etc. But in my experiments with an RGB LED, if you just don't use the low PWM rates, the rest of the range is plenty to generate a lot of colors.

To do perfect PWMing, you've got to do it off chip. There's a TI SMT part that does it. I forget the name.