0miker0:
Hey KirAsh4,
Could you post the working code that you are happy with? I'm having the same problem with my project.
Here's a break down of what I ended up doing, which works great for what my daughter wants since this is going on a Lilypad, sewn onto a jacket. What started small quickly grew once she saw what the possibilities were. You will have to adjust to your liking of course.
Project goals:
- have a predefined number of LEDs repeat a specific blink pattern (with a random pause between each cycle)
- have several patterns available, selectable through a single push button which cycles through patterns
- have a pattern indicator (the LED display is out of line of sight, so the user needs an indicator near the button)
- Ability to add more patterns later
First I was only using digital pins but then she asked to add more LEDs so I decided to use the analog pins as well - anything after this and I would have to use a shift register (I think).
So, using all available pins, I created an array of alternating pins, using the Lilypad's + and - pins as the divider:int myPins[] = {5, 4, 6, 3, 7, 2, 8, A5, 9, A4, 10, A3, 11, A2, A0, A1};
If you look at a Lilypad layout (LilyPad Arduino 328 Main Board - DEV-13342 - SparkFun Electronics), imagine a dividing line that runs between pins 4 and 5 through to pins A0 and A1. So the first half, from left to right, would be pins 5, 6, 7, 8, 9, 10, 11, and A0, while the other half are pins 4, 3, 2, A5, A4, A3, A2, and A1.
Pins 12 and 13 are used for the pattern indicator and button respectively. I specifically wanted the button on pin 13 because I used that as the button indicator itself (the on board LED would light up when you depress the button.)
When I wired this up on my Uno, I put all green LEDs on one half, and all red LEDs on the other half so I can get a good visual of what's happening. I refer to these as the left and right sides.
The bare minimum for code became:
int blinker = 12; // Phase indicator
int inPin = 13; // Button (and builtin LED)
// The sequence of pins is for the Lilypad, splitting in in half at the battery poles
// Bottom half are pins 5, 6, 7, 8, 9, 10, 11, A0
// Upper half are pins 4, 3, 2, A5, A4, A3, A2, A1
int myPins[] = {5, 4, 6, 3, 7, 2, 8, A5, 9, A4, 10, A3, 11, A2, A0, A1};
int previous = HIGH;
int reading;
int stage = 0;
int pause;
int p;
int resetDone = 0;
int blinkerPause = 300;
int counter = 0;
long time = 0;
long debounce = 200; // debounce time
long prevMillis = millis();
long currentMillis = 0;
long blinkerMillis = 0;
void setup() {
// Set button pin to INPUT
pinMode(inPin, INPUT);
// Set blinker LED
pinMode(blinker, OUTPUT);
// Set all LED pins to OUTPUT
for (p = 0; p < 16; p++) {
pinMode(myPins[p], OUTPUT);
}
}
void resetAll() {
pause = 0;
for (p = 0; p < 16; p++) {
digitalWrite(myPins[p], LOW);
}
}
void blinkLed(int stage) {
if (stage != 0) {
if ((millis() - blinkerMillis > blinkerPause) && (digitalRead(blinker) == LOW)) {
digitalWrite(blinker, HIGH);
blinkerMillis = millis();
}
if ((millis() - blinkerMillis > 1) && (digitalRead(blinker) == HIGH)) {
digitalWrite(blinker, LOW);
blinkerMillis = millis();
counter++;
if (counter >= stage) {
blinkerPause = 1000;
counter = 0;
} else {
blinkerPause = 300;
}
}
}
if (millis() - prevMillis > pause) {
switch(stage) {
case 1:
// Phase one
break;
case 2:
// Phase two
break;
case n-th:
// Phase n-th
break;
default:
// Turn everything off
pause = 0;
resetAll();
digitalWrite(blinker, LOW);
break;
}
prevMillis = millis();
}
}
void loop() {
currentMillis = millis();
reading = digitalRead(inPin);
if (reading == HIGH && previous == LOW && millis() - time > debounce) {
time = millis();
stage++;
switch(stage) {
case 1:
// Set variables pertaining to Phase one
counter = 0;
break;
case 2:
// Set variables pertaining to Phase two
counter = 0;
break;
case n-th:
// Set variables pertaining to Phase n-th
counter = 0;
break;
default:
// Turn everything off
stage = 0;
break;
}
}
blinkLed(stage);
previous = reading;
}
What that does is this:
a) sets array pins and blinker pin to OUTPUT, and pin 13 as INPUT for the button
b) sets the blinker rate outside of the switch/case routines so that it continues to blink at a set interval, regardless of the pause on the loop itself (more on this later)
c) allows me to set variables outside of the main switch/case inside of the loop() function
d) allows me to reset the full array and add global variables
So what happens is this, Lilypad (or Uno) comes on and does nothing. Depress the button once and you will get a visual indicator by form of the on board LED lighting up when you depress the button, and the blinker starts to blink once per second (set from stage) indicating it's in Phase one, or pattern one. What that pattern is gets defined in the blinkLed() switch/case. I'll list an example later.
Depress the button again and you increment the stage counter. This sets the stage for the switch/case which also determines how many times the blinker goes off and the blinkLed() function now only triggers whatever is in the 2nd switch/case, etc., etc.
I had to move some of the variables outside of the resetAll() function and into the main loop() function because otherwise the switch/case inside of blinkLed() would get confused when I call the resetAll() function multiple times within the same loop.
So now an example of what would go inside of the blinkLed() function, let's say case 1:
// Ascending chase, both sides
if (resetDone != 1) {
resetAll();
resetDone = 1;
}
if (millis() - startMillis > longPause) {
pause = 50;
if (n < 16) {
digitalWrite(myPins[n], HIGH);
}
if (n > 2) {
digitalWrite(myPins[n - 3], LOW);
}
n++;
if (n == 19) {
n = 0;
startMillis = millis();
longPause = random(shortPauseInt, longPauseInt);
}
}
This does a 3 LED chase from one end to the other end of the array. It starts off resetting the whole array in case the button was depressed while it was finishing a previous pattern. Then it does a time check against 'longPause'. That 'longPause' is set at the end of a chase and is a random number between whatever you want it set to. In my case, I choose 10 to 30 seconds so I have the following defined:
int shortPauseInt = 10000;
int longPauseInt = 30000;
It also gets reset to 0 whenever the stage changes, so the next stage doesn't sit there and wait for 'longPause' to timeout.
Then the routine just runs through the array to turn on or off the LEDs, taking into account that I'm leaving up to 3 of them on at any given time, except for the first and last 2 cycles where there are only one and two LED lit up (reversed at the end), so I had to check for what the value of 'n' is so that I don't try to set a non-existing pin HIGH or LOW.
Now, copy and paste that same piece of code inside of the case 2 loop and you get the same thing, except your blinker now blinks twice then pauses for a second. What you put in each switch/case is up to you. I have different patterns defined:
phase 1: ascending three led chase (both sides)
phase 2: descending three led chase (both sides)
phase 3: ascending followed by descending chase (both sides)
phase 4: sequentially turn all LEDs on then off again (go up then down, both sides)
phase 5: random blinking (both sides)
phase 6: chase going up one side and down the other
phase 7: opposite of phase 6
default: everything off
Depressing the button will simply cycle through those patterns, so you can set it to one of them and leave it there till you either change it, or the Arduino loses power and/or gets reset.
Now, with phase 5, I realized I had to pull some variables out of the resetAll() function and into a separate switch/case in the main loop(). Reason being I was blinking for a specific amount of blinks (50 blinks) and when it reaches that number, it resets the whole array back to off and goes into its longPause. If I left the counter inside of the resetAll() function, it will cause problems when resetAll() is called in the middle of the blinker doing its thing - remember, it's doing it regardless of what the pattern loop is doing. Adding additional patterns means extending the switch/case in both the main loop() and the blinkLed() function.
I'm sure there are plenty of folks on here that will find short comings with my code. Nothing helps me better than receiving input from others, especially if it makes it better. As long as people can remember, this works for us and does what we want. Sorry hobbified, this throws your Change #4 right out the window. 
0miker0, I hope this helps you out.