// DIO sequencer version 4 - using PROGMEM
// - char arrays are flat (one long string, no comma separators)
// - edit array elements using (star) "*" for "ON" and (dot) "." for "OFF"
// - each row in an array must be the same length
// https://forum.arduino.cc/t/uno-nano-dio-sequencer/1364441
#include <avr/pgmspace.h> // to offload arrays from RAM to PROGMEM
byte ledPin[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; // DIO pins for LEDs. ** Leave pin 2 and 3 for hardware interrupts
int ledCount = sizeof(ledPin) / sizeof(ledPin[0]); // number of LEDs
int loops; // for repeating a sequence
bool firstTime = 1; // flag for printing Loop Time
// Multiply "spacing" times "columns" for total time to complete one loop
unsigned long columnSpacing = 50; // milliseconds per element - speed control
const char sequence[] PROGMEM = { // single-dimension array of sequenced elements
//12345...1.........2.........3.........4.........5.........6.........7.........8.........9.........1 // elements or columns
"...******...........*.......*..........*...*...*.........*..*.......*...*...*...............*..........******...........*.......*..........*...*...*.........*..*.......*...*...*...............*......." // LED[0]... sequence[0][0..n]
"...*********.......*.........*.........*...*...*........*....*.....*....*.....*..........*.....*.......*********.......*.........*.........*...*...*........*....*.....*....*.....*..........*.....*...." // LED[1]... sequence[1][0..n]
"...************...*...........*........*...*...*.......*......*...*.....*.......*.....*...........*....************...*...........*........*...*...*.......*......*...*.....*.......*.....*...........*." // LED[2]... sequence[2][0..n]
"...******...........*.......*..........*...*...*.........*..*.......*...*...*...............*..........******...........*.......*..........*...*...*.........*..*.......*...*...*...............*......." // LED[3]... sequence[3][0..n]
"...*********.......*.........*.........*...*...*........*....*.....*....*.....*..........*.....*.......*********.......*.........*.........*...*...*........*....*.....*....*.....*..........*.....*...." // LED[4]... sequence[4][0..n]
"...************...*...........*........*...*...*.......*......*...*.....*.......*.....*...........*....************...*...........*........*...*...*.......*......*...*.....*.......*.....*...........*." // LED[5]... sequence[5][0..n]
"...************...*...........*........*...*...*.......*......*...*.....*.......*...........*..........************...*...........*........*...*...*.......*......*...*.....*.......*...........*......." // LED[6]... sequence[6][0..n]
"...******...........*.......*..........*...*...*.........*..*.......*...*...*............*.....*.......******...........*.......*..........*...*...*.........*..*.......*...*...*............*.....*...." // LED[7]... sequence[7][0..n]
"...*********.......*.........*.........*...*...*........*....*.....*....*.....*.......*...........*....*********.......*.........*.........*...*...*........*....*.....*....*.....*.......*...........*." // LED[8]... sequence[8][0..n]
"...************...*...........*........*...*...*.......*......*...*.....*.......*.....*...........*....************...*...........*........*...*...*.......*......*...*.....*.......*.....*...........*." // LED[9]... sequence[9][0..n]
};
const char scan[] PROGMEM = {
//2345....1.........2
"*................."
".*...............*"
"..*.............*."
"...*...........*.."
"....*.........*..."
".....*.......*...."
"......*.....*....."
".......*...*......"
"........*.*......."
".........*........"
};
const char wigwag[] PROGMEM = {
//2345....1.........2
".....*......"
".....*......"
".....*......"
".....*......"
".....*......"
"...........*"
"...........*"
"...........*"
"...........*"
"...........*"
};
const char zigzag[] PROGMEM = {
//2345....1.........2
"...........*"
".....*......"
"...........*"
".....*......"
"...........*"
".....*......"
"...........*"
".....*......"
"...........*"
".....*......"
};
const char wowow[] PROGMEM = {
//2345....1.........2.........3
"*........*........*........*"
".*......*.*......*.*......*."
"..*....*...*....*...*....*.."
"...*..*.....*..*.....*..*..."
"....**.......**.......**...."
"....**.......**.......**...."
"...*..*.....*..*.....*..*..."
"..*....*...*....*...*....*.."
".*......*.*......*.*......*."
"*........*........*........*"
};
const char clear[] PROGMEM = {
"."
"."
"."
"."
"."
"."
"."
"."
"."
"."
};
void setup() {
randomSeed(analogRead(A0)); // increase pseudo-randomness
Serial.begin(115200); // start serial communications
for (int i = 0; i < ledCount; i++) // count through LED pins
pinMode(ledPin[i], OUTPUT); // configure pins for OUTPUT
}
void loop() {
delay(random(1000, 3000)); // random delay before sequence
columnSpacing = random(50, 100); // random spacing inside this sequence
loops = random (1, 5); // random sequence number of loops
switch (random (5)) { // call a random sequence
case 0: {
sequencer(sequence, sizeof(sequence) / ledCount, loops);
break;
}
case 1: {
sequencer(scan, sizeof(scan) / ledCount, loops);
break;
}
case 2: {
sequencer(wigwag, sizeof(wigwag) / ledCount, loops);
break;
}
case 3: {
sequencer(wowow, sizeof(wowow) / ledCount, loops);
break;
}
default: break;
}
sequencer(clear, sizeof(clear) / ledCount, 1); // clear LEDs
}
void sequencer(char list[], int columns, int loops) {
for (int lop = 0; lop < loops; lop++) { // count through loops
loopTime(columnSpacing, columns, loops); // display Loop Time
for (int col = 0; col < columns; col++) { // count through row length
for (int row = 0; row < ledCount; row++) { // count through number of LEDs
switch (pgm_read_byte(&list[row * columns + col])) { // locate element row and column location
case '*': digitalWrite(ledPin[row], HIGH); break; // turn LED ON
case '.': digitalWrite(ledPin[row], LOW); break; // turn LED OFF
default: break;
}
}
delay(columnSpacing); // regulate the speed of the sequence
}
}
firstTime = 1; // set first time flag for LoopTime display
}
void loopTime(unsigned long spacing, unsigned long columns, unsigned long loops) { // display Loop Time on Serial Monitor
if (firstTime) { // only if "firstTime" flag is set...
Serial.print("Loop Time (");
Serial.print(loops * spacing * columns); // multiply all the values
Serial.print("ms)");
Serial.print(" = loops (");
Serial.print(loops);
Serial.print(") * spacing (");
Serial.print(spacing);
Serial.print("ms) * columns (");
Serial.print(columns);
Serial.println(" elements)");
firstTime = 0; // clear "firstTime" flag
}
}