In working to get 16 levels of PWM brightness levels via a normal shift register (74HC595), I quickly hit limits on the number of shiftOut calls in a timer process before the loop fails due to timer interrupt activity.
I created a faster version that writes directly to the PORTD bit and that allowed MANY more shiftOut calls in the interrupt .. which basically means it is much faster. There may be faster ways .. but this one proves to work better than the built in one. So if anyone is having speed issues with the shiftOut .. this may help.
Why I do this. I want to run whatever in the loop and not have my loop attempting to have perfect timing for PWMing. Putting a long loop in a timer process .. not advised .. hence needing a faster shiftOut. I do each of the 16 steps in it's own loop and then start over .. not looping the entire thing inside the timer process .. so a very fast process is needed for a tight loop.
This example shows the simples use of a shift register in action and where it hit limits. Notice the shiftOut can run 6 shift registers
/***************************************************************
Name : shiftOutFast
By : Joseph Francis
Shows the difference between shiftOut and shiftOutFast
Date : 02 Oct, 2009
Version : 1.0
Notes : Code for using a 74HC595 Shift Register
: to count from 0 to 255 Really Fast
****************************************************************/
#include <TimerOne.h>
int tempCounter = 0;
//--- Using standard shiftOut:
// at 1 Shift Register - 225 works
// at 2 Shift Registers - 225 fails, 275 works ..
// at 3 Shift Registers - 275 fails, 325 fails, 375 works ..
// at 4 Shift Registers - 375 fails, 425 fails, 475 fails, 525 works ..
// at 5 Shift Registers - 525 fails, 625 works ..
// at 6 Shift Registers - 625 fails, 725 works ..
// --- Rough Pattern Developing Here ...
//--- Using shiftOutFast:
// at 1 Shift Register - 25 fails, 50 works
// at 2 Shift Register - 50 fails, 75 works
// at 3 Shift Register - 75 fails, 100 works
//...
// at 6 Shift Registers - 200 fails, 225 works ..
// --- Rough Pattern Developing Here ...
int timerDelay = 225;
//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;
//--- Important: All Pins must be 8 or higher (in PORTB range)
int latchPinPORTB = latchPin - 8;
int clockPinPORTB = clockPin - 8;
int dataPinPORTB = dataPin - 8;
void setup() {
randomSeed(analogRead(0));
Serial.begin(9600);
//set pins to output because they are addressed in the main loop
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
Timer1.initialize(timerDelay); // Timer for updating pwm pins
Timer1.attachInterrupt(iProcess);
}
void iProcess(){
byte data1 = B11111111;
byte data2 = B11111110;
byte data3 = B11111110;
byte data4 = B11111111;
byte data5 = B11111111;
byte data6 = B11111111;
byte data7 = B11111111;
byte data8 = B11111111;
// This took a timer of 725 to work
/*
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, data6);
shiftOut(dataPin, clockPin, MSBFIRST, data5);
shiftOut(dataPin, clockPin, MSBFIRST, data4);
shiftOut(dataPin, clockPin, MSBFIRST, data3);
shiftOut(dataPin, clockPin, MSBFIRST, data2);
shiftOut(dataPin, clockPin, MSBFIRST, data1);
digitalWrite(latchPin, HIGH);
*/
//--- This code can run using a 200 timer delay
latchOff();
/*
*/
shiftOutFast(dataPin, clockPin, data6);
shiftOutFast(dataPin, clockPin, data5);
shiftOutFast(dataPin, clockPin, data4);
shiftOutFast(dataPin, clockPin, data3);
shiftOutFast(dataPin, clockPin, data2);
shiftOutFast(dataPin, clockPin, data1);
latchOn();
}
void loop() {
tempCounter++;
if( tempCounter > 100)
tempCounter = 0;
Serial.print("Hi am here ");
Serial.println(tempCounter, DEC);
delay(500);
}
//--- shiftOutFast - Shiftout method done in a faster way .. needed for tighter timer process
void shiftOutFast(int myDataPin, int myClockPin, byte myDataOut) {
//=== This function shifts 8 bits out MSB first much faster than the normal shiftOut function by writing directly to the memory address for port
//--- clear data pin
dataOff();
//Send each bit of the myDataOut byte MSBFIRST
for (int i=7; i>=0; i--) {
clockOff();
//--- Turn data on or off based on value of bit
if ( bitRead(myDataOut,i) == 1) {
dataOn();
}
else {
dataOff();
}
//register shifts bits on upstroke of clock pin
clockOn();
//zero the data pin after shift to prevent bleed through
dataOff();
}
//stop shifting
digitalWrite(myClockPin, 0);
}
void dataOff(){
bitClear(PORTB,dataPinPORTB);
}
void clockOff(){
bitClear(PORTB,clockPinPORTB);
}
void clockOn(){
bitSet(PORTB,clockPinPORTB);
}
void dataOn(){
bitSet(PORTB,dataPinPORTB);
}
void latchOn(){
bitSet(PORTB,latchPinPORTB);
}
void latchOff(){
bitClear(PORTB,latchPinPORTB);
}