Decided to test the 74HC595 shift register in the circuit instead of testing the analog ports.. I'll get to that later, maybe.
The 74HC595 is an 8-bit serial to parallel shift register. What that means is you send it 8-bits in a row, one at a time on its input pin, flip a switch and it throws all 8 bits to 8 output pins at the same time, in parallel. This shift out example was very helpful in explaining how the 74HC595 works and how to wire it up to the duino.
This is overkill for my test, but useful. It basically allows you to turn 3 ports into 8 ports - you use 3 ports from the duino to control the shift register: 1 to send the data, 1 to tell the 74HC595 to "shift in" the bit you are sending it, and 1 to flip the "latch" when you're done to send out the data to the parallel pins.
I used the shift out example's hello world example, modified it slightly for my test (i used different duino ports and only 4 LEDs) and felt pretty confident about using this little guy in my circuits.
So I had all these grand ideas of how I could use classes and dynamic arrays to build bytes to send to the shift register and turn my BlinkPlus sketch into an awesomely elegant piece of code. This is where I learned some lessons about the limitations of programming a microcontroller like the duino and how the code is built and compiled. So much for dynamic array type definitions, linked lists, and so on and so forth.
Eventually, I updated BlinkPlus to use the shift register. Right now I only implemented one of the patterns, but it should be pretty quick and painless to convert the rest. Here's how it works...
First I set up the 3 digital ports that the duino will use to control the 595:
//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 3;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 2;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 7;
// control variables
int delayCount = 500;
int repeatCount = 4;
byte pos = 1;
byte neg = 0;
byte pattern = 0;
// the setup routine runs once when you press reset:
void setup() {
//set pins to output so you can control the shift register
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
The main loop iterates through each of the 4 LEDs and blinks them on and off a set number of times:
// the loop routine runs over and over again forever:
void loop() {
reset();
delay(delayCount*2);
for (int i=0; i < 4; i++)
{
for (int j=0; j < repeatCount; j++)
{
blinkoUno(i);
}
}
// toggle negative
setPos(neg);
}
blinkoUno was rewritten to modify the bits of the global byte variable named "pattern" instead of sending HIGHs and LOWs directly to the LEDs.
// blink the given bit on then off
void blinkoUno(int ledNum) {
bitWrite(pattern, ledNum, pos);
displayPattern();
delay(delayCount);
bitWrite(pattern, ledNum, neg);
displayPattern();
delay(delayCount);
}
It calls the displayPattern function which jumps through all the necessary hoops to send the byte to the 595 serially (one bit at a time) and then flip the latch switch to send all 8 bits to the 595's 8 output pins:
// sends the given byte to the shift register
void displayPattern() {
// take the latchPin low so
// the LEDs don't change while you're sending in bits:
digitalWrite(latchPin, LOW);
// shift out the bits:
shiftOut(dataPin, clockPin, MSBFIRST, pattern);
//take the latch pin high so the LEDs will light up:
digitalWrite(latchPin, HIGH);
}
Just in case... a byte consists of 8 bits. A bit is a value that can either be 1 or 0, bits are like switches, they are on (1) or off (0). Each bit corresponds to one of the shift register's ouput pins... the first bit in the byte controls the first ouput pin, the second bit controls the 2nd ouput pin, etc. So if I want to turn on both the first and third LEDs, i would send the byte 00000101 (assuming the first LED is wired to the first output pin, and so on).
One thing that can be confusing is that most people look at a row of LEDs and think the leftmost LED is the first LED. In the byte, the rightmost bit is the first bit: 00000001.
I used the bitWrite command to turn the bits on and off. To turn on bits 1 and 3 in the byte variable "pattern", you would do this;
bitWrite(pattern, 1, 1); // set bit 1 of the byte "pattern" to 1 (on)
bitWrite(pattern, 3, 1); // set bit 3 of the byte "pattern" to 1 (on)
Another way to do this would be using the bitSet command:
bitSet(pattern, 1); // set bit 1 of the byte "pattern" to 1 (on)
bitSet(pattern, 3); // set bit 3 of the byte "pattern" to 1 (on)
To turn bits off, you can either use the bitWrite or bitClear commands:
bitWrite(pattern, 2, 0); // set bitv2 of the byte "pattern" to 0 (off)
bitWrite(pattern, 4, 0); // set bit 4 of the byte "pattern" to 0 (off)
bitClear(pattern, 2); // set bit 2 of the byte "pattern" to 0 (off)
bitClear(pattern, 4); // set bit 4 of the byte "pattern" to 0 (off)
Anyway... a couple more procedures from the code that I haven't mentioned yet are reset and setPos.
SetPos lets you switch the values of the pos and neg variable to on or off to easily display the patterns as negative images.
void setPos(byte posVal)
{
pos = posVal;
neg = !pos;
}
This is why I used the bitWrite command instead of bitSet and bitClear. I just send bitWrite either "pos" or "neg" to generally define the pattern and calling setPos defines whether pos is on and neg is off, or the other way around.
Reset switches all bits off:
// sets all bits to off
void reset() {
if (pos == 1)
{
pattern = 0;
}
else
{
pattern = ~0;
}
displayPattern();
}
If pos is set to display positive images, then I set the byte to 0 (which is really 00000000). If it is set to display negative images, then I set it to ~0, which uses the bitwise NOT operator - which flips every bit in the byte to the opposite setting. So if 0 = 00000000, then ~0 = 11111111. I could have also just set it to 255, which is the decimal equivalent of 11111111, but I wanted to have an example of ~ in my toolbox.
So the complete code is all checked into git, and what it does is:
- reset, turn all 4 LEDs off
- blink the first LED on and off 4 times
- blink the second LED on and off 4 times
- blink the third LED on and off 4 times
- blink the fourth LED on and off 4 times
- set pos to 0 (OFF, or negative mode)
- reset, turn all 4 LEDs ON
- blink the first LED off and on 4 times
- blink the second LED off and on 4 times
- blink the third LED off and on 4 times
- blink the fourth LED off and on 4 times
- repeat until you unplug it or something breaks
I'm going to update it to display more patterns and do the whole random thingy stuff.
No comments:
Post a Comment