// Code from https://github.com/j-bellavance/Tutorials/blob/master/State%20machines%20Tutorial/CommentedSketches/Part%201/LightShow/LightShow.ino
// modified to add reporting
// for https://forum.arduino.cc/t/how-to-organize-code-for-a-count-down-time-based-sequence-to-multiple-outputs-nasa-style/1138372/11?u=davex
// https://wokwi.com/projects/367706483993231361
/*
LightShow.ino
Author: Jacques Bellavance
Released: October 13, 2017
under GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 b
This code is to demonstrate the use of state machines in an Arduino sketch.
It is fully explained in the tutorial: State machine with Arduino (Part 1)
Changes from the previous sketch are shown with <<<<<
*/
#include <FastLED.h>
#define LED_PIN 13
#define NUM_LEDS 16
#define PATTERN_LEN 4
#define BRIGHTNESS 255
#define LED_TYPE WS2812B
#define COLOR_ORDER RGB
CRGB leds[NUM_LEDS];
CRGB pattern[PATTERN_LEN] = { CRGB::Blue, CRGB(244, 7, 7), CRGB(1, 255, 34), CRGB::White };
long time = -100 ; // NASA countdown time state variable;
long lastTime = -101; // track for one-shots.
unsigned long currentTime = 0;
//We use tables for the attributes of each LED
enum LedStates {ON, OFF}; //The two possible states for an LED
LedStates ledState[8] = {ON, ON, ON, ON, ON, ON, ON, ON}; //<<<<<All LEDs start states are ON
byte ledPin[8] = {2, 3, 4, 5, 6, 7, 8, 9}; //<<<<<The pins for the LEDs (Don't forget resistors for all LEDs)
int delayOff[8] = {5240, 2560, 1280, 640, 320, 160, 80, 40}; //<<<<<The time in milliseconds that each LED will stay off
int delayOn[8] = {2560, 1280, 640, 320, 160, 80, 40, 20}; //<<<<<The time in milliseconds that each LED will stay on
unsigned long chrono[8];
void blinkMachine(byte i) { //<<<<<We added a parameter: the index for the LED [0..7]
switch (ledState[i]) { //<<<<<Use ledState of LED i
case OFF: { //state is OFF
if (currentTime - chrono[i] >= delayOff[i]) { //<<<<<Use chrono and delayOff of LED i
chrono[i] = currentTime; //<<<<<Reset chrono of LED i
digitalWrite(ledPin[i], HIGH); //<<<<<Write HIGH to LED i
ledState[i] = ON; //<<<<<State of LED i is now ON
}
break; //Get out of switch
}
case ON: { //state is ON
if (currentTime - chrono[i] >= delayOn[i]) { //<<<<<Use chrono and delayOff of LED i
chrono[i] = currentTime; //<<<<<Reset chrono of LED i
digitalWrite(ledPin[i], LOW); //<<<<<Write LOW to LED i
ledState[i] = OFF; //<<<<<State of LED i is now OFF
}
break; //Get out of switch
}
}
}
void setup() {
for (byte i = 0 ; i < 8 ; i++) { //<<<<<For all leads [0..7]
pinMode(ledPin[i], OUTPUT); //<<<<<The pin mode of LED i is OUTPUT
digitalWrite(ledPin[i], HIGH);
} //<<<<<Bring the pin of LED i HIGH (We said that Start state of all LEDs is ON on line 17)
Serial.begin(500000);
pinMode(LED_PIN, OUTPUT);
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness( BRIGHTNESS );
}
void loop() {
currentTime = millis();
for (int i = 0 ; i < 8 ; i++) //<<<<<For all leads [0..7]
blinkMachine(i); //<<<<<Run the machine with LED i
NasaTimer();
if (time != lastTime) { // do once-per-second one-shots
switch (time) {
case -99: {
Serial.println("99 bottles of beer on the wall");
} break;
case -60: {
Serial.println("one minute to go");
} break;
case 0: {
Serial.println("Blast off");
} break;
case 60: {
Serial.println("one minute past launch");
} break;
case 10000: {
Serial.println("reached orbit");
} break;
default:
break;
}
}
reportTiming();
//reportStates();
reportADC();
reportDig();
neoUpdate();
neoUpdateRoll();
lastTime = time; // update for oneshots
}
void reportTiming() {
static uint32_t count = 0;
static uint32_t last = 0;
++count;
if (currentTime - last < 1000) return;
last += 1000;
Serial.print(" iterations:");
Serial.print(count);
Serial.print(" msPerIteration:");
Serial.print(1000.0 / count, 3);
Serial.println();
count = 0;
}
void reportStates() {
const int interval = 10;
static uint32_t last = 0;
if (currentTime - last < interval) return;
//last += interval; // sychronized
last = currentTime; // slipping
for (auto &i : ledState) {
Serial.print(i == ON ? '@' : '.');
}
Serial.println("|");
}
void reportADC() {
const int interval = 100;
static uint32_t last = 0;
if (currentTime - last < interval) return;
//last += interval; // sychronized
last = currentTime; // slipping
const byte adcpins[] = {A0, A1, A2, A3, A4, A5};
Serial.print(" ");
for (auto &i : adcpins) {
Serial.print(analogRead(i) / 103);
}
Serial.println("|");
}
void reportDig() {
const int interval = 10;
static uint32_t last = 0;
if (currentTime - last < interval) return;
//last += interval; // sychronized
last = currentTime; // slipping
Serial.print("");
for (auto &i : ledPin) {
Serial.print(digitalRead(i) == LOW ? '.' : '@');
}
Serial.println("|");
}
void neoUpdate(void) {
// Start at the first LED
static uint8_t startIndex = 0;
const int interval = 100;
static uint32_t last = -interval;
static int lastADC = -1;
if (currentTime - last < interval) return;
//last += interval; // sychronized
last = currentTime; // slipping
int adcState = analogRead(A0), analogRead(A0);
if (adcState == lastADC) return;
int i = adcState / (1024 / NUM_LEDS);
int j = adcState % PATTERN_LEN;
if (1) {
Serial.print(" ADC:");
Serial.print(adcState);
Serial.print(" i:");
Serial.print(i);
Serial.print(" j:");
Serial.print(j);
Serial.println();
}
leds[i] = pattern[j];
lastADC = adcState;
FastLED.show();
}
void neoUpdateRoll(void) {
const int interval = 100;
static uint32_t last = -interval;
static int lastADC = -1;
if (currentTime - last < interval) return;
//last += interval; // sychronized
last = currentTime; // slipping
CRGB save = leds[0];
for (int i = 1; i < NUM_LEDS; ++i) {
leds[i - 1] = leds[i];
}
leds[NUM_LEDS - 1] = save;
FastLED.show();
}
void NasaTimer() {
const int interval = 1000;
static uint32_t last = -interval;
if (currentTime - last < interval) return;
last += interval; // sychronized
++time; // increment the variable
//last = currentTime; // slipping
Serial.print("######## T:");
Serial.print(time);
Serial.print(" ######## at:");
Serial.print(currentTime / 1000);
Serial.print('.');
Serial.println(currentTime % 1000);
}