I'm currently working on a project with a bunch of 74HC595 shift registers and ULN2003AN darlington arrays. I'm PWMing the light and like many people have been searching for ways to improve the performance of manual bit banging.
Since I've started the project I've learned about SPI, but my current board is using other pins and more importantly, I feel like I'm really starting to understand shift registers (after using them for a few years mostly with blind copy and paste).
The first thing I discovered was writing to PORTB directly instead of using digitalWrite. Wow, that's so much faster it's really quite nice. The deeper I get into microcontrollers the more I appreciate the hard work the arduino folks have put into making this stuff so much easier. That said, there are times to get closer to the metal and I'm there now.
Now, what most of the sample code on the net does is something like this:
- set latch to low (disable the outputs while shifting bits)
- clear data pin
- set clock to low
- loop over the bits in a byte and for each bit
4a. set the clock to low
4b. set the data pin high or low
4c set the clock high (triggers a read from the shift register)
4d. set the data pin low - set the clock to low
- set the latch to high (enable the outputs
What I don't understand is why we would need to do 2, 3 and 4d. If I'm going to set the clock to low at 4a then 3 seems redundant and if I'm setting the value of the data pin at step 4b then step 2 seems redundant.
The only theory I have is that some folks are worried that if there's data on the data bit when I hit step 4a then that will get shifted onto the registers but of course I'm sending 32 bits down the pipe anyway and so that bit will 'fall out the end' of the shift register before I enable the latch.
What am I missing?
Thanks,
-Zeke
Here's my current shiftOut if my pseudocode is too pseudo.
void shiftOut(byte outputData) {
// This shifts 8 bits out MSB first, on the rising edge of the clock, clock idles low
//clear everything out just in case to prepare shift register for bit shifting
bitClear(PORTB, dataPinPortB);
bitClear(PORTB, clockPinPortB);
// loop over the bits in outputData and send them to the shift register
for (int i=7; i>=0; i--)
{
bitClear(PORTB, clockPinPortB);
//Sets the pin to HIGH or LOW depending on pinState
if (bitRead(outputData,i))
{
bitSet(PORTB, dataPinPortB);
}
else
{
bitClear(PORTB, dataPinPortB);
}
//register shifts bits on upstroke of clock pin
bitSet(PORTB, clockPinPortB);
//zero the data pin after shift to prevent bleed through
bitClear(PORTB, dataPinPortB);
}
// the clock pin likes to idle at LOW
bitWrite(PORTB, clockPinPortB, 0);
}