/* --------------------------------------------------------- * | Arduino Experimentation Kit Example Code | * | CIRC-05 .: 8 More LEDs :. (74HC595 Shift Register) | * --------------------------------------------------------- * * We have already controlled 8 LEDs however this does it in a slightly * different manner. Rather than using 8 pins we will use just three * and an additional chip. * * */ //Pin Definitions //The 74HC595 uses a serial communication //link which has three pins int data = 2; int clock = 3; int latch = 4; //An array to recieve a binary 4-bit number for the scanWidth input (4DIP or 4bit rotary encoder) //The Fritzing layout uses a 4-position DIP switch because there isn't a 4bit rotary encoder //in the core parts bin. int dipPins[] = {10,11,12,13}; //Which analog pin to use for the timing input (wiper of a pot) int analogPin = 0; //Used for single LED manipulation int ledState = 1; const int ON = HIGH; const int OFF = LOW; /* * setup() - this function runs once when you turn your Arduino on * We set the three control pins to outputs */ void setup() { pinMode(data, OUTPUT); pinMode(clock, OUTPUT); pinMode(latch, OUTPUT); updateLEDs(1); //Start everything how the pattern will end at then end of void loop() //Set each pin connected to the rotary DIP switch as an input //Use sizeof() to dynamically get the size of the array. sizeof returns the number of bytes, so need //devide by size of the datatype (in this case int). for(int i = 0; i < (sizeof(dipPins)/sizeof(int)); i++){ //Initialized as INPUT_PULLUP to reduce the part count of the board by 4 resistors. pinMode(dipPins[i], INPUT_PULLUP); } } /* * loop() - this function will start after setup finishes and then repeat * we set which LEDs we want on then call a routine which sends the states to the 74HC595 */ void loop() // run over and over again { scanUp(); scanDown(); } /* * scanUp() - starting with the first LED on, scan up to the last LED, leaving * scanWidth number of LEDs on. End with only the last LED on. */ void scanUp(){ for(int i = 1; i <= 7 + scanWidth(); i++){ delay(delayTime()); //Turn on the next LED as long as it's a valid LED number if(i <= 7){ changeLED(i, HIGH); } //Turn off the previous LED on the other side of scanWidth as long as it's a valid LED number int offLED = i - scanWidth(); if(offLED >= 0 && offLED < 7){ //leave the last LED on. changeLED(offLED, LOW); } } } /* * scanDown() - starting with the last LED on, scan down to the first LED, leaving * scanWidth number of LEDs on. End with only the first LED on. */ void scanDown(){ for(int i = 6; i >= 0 - scanWidth(); i--){ delay(delayTime()); //Turn on the next LED as long as it's a valid LED number if(i >= 0){ changeLED(i, HIGH); } //Turn off the previous LED on the other side of scanWidth as long as it's a valid LED number int offLED = i + scanWidth(); if(offLED <= 7 && offLED > 0){ //leave the first LED on. changeLED(offLED, LOW); } } } //These are used in the bitwise math that we use to change individual LEDs //For more details http://en.wikipedia.org/wiki/Bitwise_operation int bits[] = {B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000}; int masks[] = {B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111}; /* * changeLED(int led, int state) - changes an individual LED * LEDs are 0 to 7 and state is either 0 - OFF or 1 - ON */ void changeLED(int led, int state){ ledState = ledState & masks[led]; //clears ledState of the bit we are addressing if(state == ON){ledState = ledState | bits[led];} //if the bit is on we will add it to ledState updateLEDs(ledState); //send the new LED state to the shift register } /* * updateLEDs() - sends the LED states set in ledStates to the 74HC595 * sequence */ void updateLEDs(int value){ digitalWrite(latch, LOW); //Pulls the chips latch low shiftOut(data, clock, LSBFIRST, value); //Shifts out the 8 bits to the shift register digitalWrite(latch, HIGH); //Pulls the latch high displaying the data } /* * delayTime() - Calculate the delay time in milliseconds based on the value of an analog input. * For example, a potentiometer. Scaled to a range of 5 to 150. */ int delayTime(){ int ret = analogRead(analogPin); ret = map(ret, 0, 1023, 5, 150); return ret; } /* * scanWidth() - converts a binary value on multiple digital inputs to an integer. Use this * integer for the number of LEDs wide we want the scan pattern. */ int scanWidth(){ int ret = 0; int bitValue[] = {1,2,4,8,16,32,64,128}; for(int i = 0; i < (sizeof(dipPins)/sizeof(int)); i++){ //Because the pins are using the internal pull-ups, we want to treat them as low-active. //Therefore, if the switch or rotary encoder position is open (off) on a pin, the pin will read high. if(digitalRead(dipPins[i]) == LOW){ ret = ret + bitValue[i]; } } return ret; }