So I started playing around with a 74hc595 because there was a chapter in my Sainsmart Starter Kit on it and when I researched
on the forum it looked like there was quite a lot to be said about using it. I started on this page here:
http://arduino.cc/en/Reference/shiftOut#.UwKUGPldV8E
and clicked on a link there and wound up here :
Started breadboarding the circuits and running examples and then when I ran the first example I saw this statement:
shiftOut(dataPin, clockPin, MSBFIRST, numberToDisplay);
The ShiftOut function was obviously built into the Arduino IDE which seemed convenient but when I looked at this
example:
I noticed that it had a shiftOut funtion defined:
// 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);
}
and this function had 3 arguments whereas the builtin one had 4.
All the code seemed to originate from the same authors but I couldn’t find any explanation for why:
- they needed to write the second function.
- how the IDE knows which function it’s running if they are spelled the same (does the second one supercede the first ?)
- Why the first one takes a format argument (MSBfirst/LSBfirst) whereas the second one omits that argument ?
- Is there a reason why you would still want to use the second function even if you didn’t care about the MSB/LSB order ?
After playing around with (using) the second function a little I discovered that it was really easy to use
and I was able to create a Knight Rider type display (attached) using an array and the second function . Researching online
I found an example program on the Nudatech website that does the same display using the first function. (attached)
When I researched on the forum I found this thread about arrays:
where the OP posted this:
i.e. This fails;
Code:
byte dataArrayRED[10]; //global
int dataArrayRED = {0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0xE0}; //local
whereas this works, with the array being loaded with values below;
Code:
byte dataArrayRED[10];//global
dataArrayRED[0] = 0xFF;
dataArrayRED[1] = 0xFE;
dataArrayRED[2] = 0xFC;
dataArrayRED[3] = 0xF8;
dataArrayRED[4] = 0xF0;
dataArrayRED[5] = 0xE0;
dataArrayRED[6] = 0xC0;
dataArrayRED[7] = 0x80;
dataArrayRED[8] = 0x00;
dataArrayRED[9] = 0xE0; //local
and then later happily posted this , saying “nevermind , I got it”:
byte ArrayRED[] = {0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0xE0};
for (int i =0;i<=sizeof(ArrayRED);i++)
{
dataArrayRED[i]=ArrayRED[i];
}
to which someone replied this:
So, you successfully re-invented the memcpy() function. Except without any bounds checking.
to which the OP replied this:
I take it memcpy() eliminates the need for bounds checking?
to which the other person replied this:
I take it memcpy() eliminates the need for bounds checking?
No. You can use memcpy() to copy a large array “into” a small array, and it will happily crap all over the place.
All this because the OP did want to do this :
whereas this works, with the array being loaded with values below;
Code:
byte dataArrayRED[10];//global
dataArrayRED[0] = 0xFF;
dataArrayRED[1] = 0xFE;
dataArrayRED[2] = 0xFC;
dataArrayRED[3] = 0xF8;
dataArrayRED[4] = 0xF0;
dataArrayRED[5] = 0xE0;
dataArrayRED[6] = 0xC0;
dataArrayRED[7] = 0x80;
dataArrayRED[8] = 0x00;
dataArrayRED[9] = 0xE0; //local
because it is not as “elegant”
All of this is about the proper way to declare and call arrays and two dimensional arrays , which seems to be quite
relevant to how I should write programs for the 74c595, which while great for led displays, also has a more useful
function of adding I/O to an arduino with little overhead and a $5 chip. (or less), which I definitely need to know
how to do. So my 5th and final question is,
5. Is the way I did it in my program that used the second function (the one not built into the IDE, that only has 3 args)
the correct way to do it ?
byte mydata[15] ={ 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
Is it functionally the same as this : ?
whereas this works, with the array being loaded with values below;
Code:
byte dataArrayRED[10];//global
dataArrayRED[0] = 0xFF;
dataArrayRED[1] = 0xFE;
dataArrayRED[2] = 0xFC;
dataArrayRED[3] = 0xF8;
dataArrayRED[4] = 0xF0;
dataArrayRED[5] = 0xE0;
dataArrayRED[6] = 0xC0;
dataArrayRED[7] = 0x80;
dataArrayRED[8] = 0x00;
dataArrayRED[9] = 0xE0; //local
Which method is most useful for General Purpose I/O (Panel Indicator Leds, Relays, turning on/off motors (fans) and other
GPIO you would expect to find on a piece of industrial equipment ?
(unlike most posters, this is not about solving a problem, but about learning how to do things correctly so I won’t have
any , (problems).
PaulS ,
If you’re out there I know you have the answers.
My_Shift_Register_ARRAY_Knight_Rider.ino (4.69 KB)