int dataPin = 0; // physical pin 5 int clockPin = 1; // physical pin 6 int registerPin = 2; // physical pin 7 int buttonPin = 4; // physical pin 3 int debouncer = 0; // timer for debouncing boolean buttonState = LOW; // debounced button state boolean oldButtonState = LOW; // this helps to determine if the buttons was just recently pressed, or held down unsigned long buttonHeld = 0; // microseconds button was held for, for randomization purposes unsigned long timer = 0; // this counts milliseconds to go with sequenceDelay below float sequenceDelayMultiplier = 1; // change this to adjust relative speed of all animations; lower values are higher speed int sequenceDelay = 300; // milliseconds between display changes; updated per sequence in findAndWriteStep() int sequenceNumber = 0; // which pattern is currently playing int sequenceProgress = 0; // which step of the pattern we're on int sequenceTotal = 6; // total number of patterns; change to 7 to enable a randomized pattern int sequenceLengths[7] = {1, 2, 14, 28, 16, 14, 1}; // number of steps in each pattern and below are the sequence arrays themselves unsigned int sequenceZero[1] = {(B11111111 + (B11111111 << 8))}; // bytes that have been shifted left("<< 8") will be shifted out first, to the register whose serial input isn't directly connected to the microcontroller unsigned int sequenceOne[2] = {0, (B11111111 + (B11111111 << 8))}; unsigned int sequenceTwo[14] = {(B00010000 << 8), (B00001000 << 8), (B00000100 << 8), (B00000010 << 8), (B10000000), (B01000000), (B00100000), (B00010000), (B00001000), (B00000100), (B00000010), (B10000000 << 8), (B01000000 << 8), (B00100000 << 8)}; unsigned int sequenceThree[28] = {B00010000, B00011000, B00011100, B00011110, (B00011110 + (B10000000 << 8)), (B00011110 + (B11000000 << 8)), (B00011110 + (B11100000 << 8)), (B00011110 + (B11110000 << 8)), (B00011110 + (B11111000 << 8)), (B00011110 + (B11111100 << 8)), (B00011110 + (B11111110 << 8)), (B10011110 + (B11111110 << 8)), (B11011110 + (B11111110 << 8)), (B11111110 + (B11111110 << 8)), (B11101110 + (B11111110 << 8)), (B11100110 + (B11111110 << 8)), (B11100010 + (B11111110 << 8)), (B11100000 + (B11111110 << 8)), (B11100000 + (B01111110 << 8)), (B11100000 + (B00111110 << 8)), (B11100000 + (B00011110 << 8)), (B11100000 + (B00001110 << 8)), (B11100000 + (B00000110 << 8)), (B11100000 + (B00000010 << 8)), B11100000, B01100000, B00100000, 0}; unsigned int sequenceFour[16] = {(B11111110 + (B11111110 << 8)), (B11101110 + (B11111110 << 8)), (B11010110 + (B11111110 << 8)), (B10111010 + (B11111110 << 8)), (B01111100 + (B11111110 << 8)), (B11111110 + (B01111100 << 8)), (B11111110 + (B10111010 << 8)), (B11111110 + (B11010110 << 8)), (B11111110 + (B11101110 << 8)), (B11111110 + (B11010110 << 8)), (B11111110 + (B10111010 << 8)), (B11111110 + (B01111100 << 8)), (B01111100 + (B11111110 << 8)), (B10111010 + (B11111110 << 8)), (B11010110 + (B11111110 << 8)), (B11101110 + (B11111110 << 8))}; unsigned int sequenceFive[14] = {(B00010000 << 8), (B00110000 << 8), (B00111000 << 8), (B01111000 << 8), (B01111100 << 8), (B11111100 << 8), (B11111110 << 8), (B00010000 + (B11111110 << 8)), (B10010000 + (B11111110 << 8)), (B10010010 + (B11111110 << 8)), (B10110010 + (B11111110 << 8)), (B10111010 + (B11111110 << 8)), (B11111010 + (B11111110 << 8)), (B11111110 + (B11111110 << 8))}; // sequenceSix does not exist, as a call to findAndWriteStep(6, x) simply generates a random frame; a place for it in sequenceTotal and sequenceLengths keeps the code manageable void writeStep(int toBeShifted) // does the actual display changes { digitalWrite(registerPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, (toBeShifted >> 8)); shiftOut(dataPin, clockPin, MSBFIRST, (toBeShifted)); digitalWrite(registerPin, HIGH); } void findAndWriteStep(int sequence, int progression) // converts pattern number to a named array; a multidimensional array may have been better here, but meh { int passData = 65535; switch(sequence) { case 0: sequenceDelay = 1000; // this value doesn't matter, as the first sequence has only one step; I use a high value so the shift registers aren't "updated" as frequently passData = sequenceZero[progression]; break; case 1: sequenceDelay = 300; passData = sequenceOne[progression]; break; case 2: sequenceDelay = 300; passData = sequenceTwo[progression]; break; case 3: sequenceDelay = 150; // it's a long sequence, so let's run it double speed passData = sequenceThree[progression]; break; case 4: sequenceDelay = 300; passData = sequenceFour[progression]; break; case 5: sequenceDelay = 250; passData = sequenceFive[progression]; break; case 6: // here is our random pattern; I've disabled it by default, but change sequenceTotal to 7 if you want to enable it sequenceDelay = 50; // random blinking looks ugly if it isn't really fast, in my opinion passData = random(65535); break; } writeStep(passData); } void setup() { pinMode(dataPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(registerPin, OUTPUT); pinMode(buttonPin, INPUT); digitalWrite(registerPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, 0); // clear high byte shiftOut(dataPin, clockPin, MSBFIRST, 0); // clear low byte digitalWrite(registerPin, HIGH); timer = millis(); // initialize timer } void loop() { if(digitalRead(buttonPin) == HIGH) { debouncer = 0; buttonState = LOW; buttonHeld = micros() - buttonHeld; // store difference in microseconds between button pushed and released randomSeed(buttonHeld); // regenerate random numbers only when they'll change } else { if(debouncer < 10) { debouncer += 1; } } if(debouncer >= 10) { oldButtonState = buttonState; buttonState = HIGH; } if(oldButtonState == LOW && buttonState == HIGH) // if button barely changed state; prevents repeated switching from holding the button down { // code here for button press digitalWrite(3, HIGH); delay(100); digitalWrite(3, LOW); sequenceNumber += 1; // increment sequence number, reset to zero if too high if(sequenceNumber >= sequenceTotal) { sequenceNumber = 0; } sequenceProgress = 0; // when button pressed, reset counter buttonHeld = micros(); // store current time in microseconds } if(millis() - (sequenceDelay * sequenceDelayMultiplier) >= timer) // if enough time has passed since last update { findAndWriteStep(sequenceNumber, sequenceProgress); sequenceProgress += 1; // increment sequence step, reset to zero if too high timer = millis(); } if(sequenceProgress >= sequenceLengths[sequenceNumber]) { sequenceProgress = 0; } }