/*
Solution For:
Topics: Combine multiple millis() to control relais and neopixel simultanious
Category: Programming Questions
Link: https://forum.arduino.cc/t/combine-multiple-millis-to-control-relais-and-neopixel-simultanious/1099091
Sketch: AuCP_RandomPipes.ino (https://wokwi.com/projects/358817800677315585)
Created: 11-Mar-2023 (GMT+7)
MicroBeaut (μB)
10-Mar-2023: changed for changes 10-Mar-2023?!
https://wokwi.com/projects/358876197860297729
By: @alto777
12-Mar-2023: Changed,
- Modified TimerOn by adding getTimeDelay() function and renaming "done" to "isDone"
- Defined Pipe color status
- Added RandomCollector() subroutine for pipes
- Added Dropping() subroutine
https://wokwi.com/projects/359013222335749121
By: @MicroBeaut
*/
# include <Adafruit_NeoPixel.h>
# define PIN 8 // Neopixel pin with PWM
# define PIPESTS_PIN 9 // NeoPixel Pipe Status pin
# define NUMPIXELS 12 // number of LEDs on strip
Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); // Declare our NeoPixel strip object
Adafruit_NeoPixel pipeStatus(NUMPIXELS, PIPESTS_PIN, NEO_GRB + NEO_KHZ800); // Declare our NeoPixel strip object
# define PIPE_GREEN pipeStatus.Color(0, 255, 0) // Pipe Available
# define PIPE_RED pipeStatus.Color(255, 0, 0) // Pipe Dropping
# define PIPE_BLACK pipeStatus.Color(0, 0, 0) // Pipe Droped
/*
===========================================================================
Class: TimerOn
The rising edge of input "input" starts a timer of duration "timeDelay".
When the elapsed time is greater than or equal to "timeDelay",
the timer stops and output changes from FALSE to TRUE.
The next falling edge of input "input" initializes the timer
===========================================================================
*/
class TimerOn {
private:
bool prevInput;
bool output;
unsigned long startTime;
unsigned long timeDelay;
public:
TimerOn() {
prevInput = false;
output = false;
// timeDelay = 500000UL; 500 microseconds
}
// Convert milliseconds to microseconds
void setTimeDelay(long msTimeDelay) {
timeDelay = msTimeDelay * 1000UL;
}
// Timer ON Condition
bool timerOn(bool input = true) {
if (input) {
if (!prevInput) {
startTime = micros();
} else if (!output) {
unsigned long elapsedTime = micros() - startTime;
if (elapsedTime >= timeDelay) {
// elapsedTime = timeDelay;
output = true;
}
}
} else {
output = false;
}
prevInput = input;
return output;
}
uint16_t getTimeDelay() {
return timeDelay / 1000UL;
}
bool isDone() {
return output;
}
};
#define RANDOM_MIN 1000L // Random Min x milliseconds
#define RANDOM_MAX 7000L // Random Max y milliseconds
#define BLINK_DELAY 500 // 500 microseconds
const uint8_t numberOfPipes = 12; // Number of Pipes
// TimerOn pipeTimerOns[numberOfPipes]; // Timer On objects
TimerOn pipeTON; // Pipe Drop Timer On
uint8_t pipeCollector[numberOfPipes]; // Pipe Index Collector
uint8_t pipeIndex; // Pipe Index
TimerOn blinkTON; // Blinking Timer On
bool toggleState;
//TimerOn myTO;
void RunGame();
void rainbow();
uint32_t Wheel(byte WheelPos);
void RandomCollector();
void Dropping();
void PrintPipeInfo();
void setup() {
Serial.begin(115200);
Serial.println(" timer focus \n");
randomSeed(analogRead(0));
strip.begin();
pipeStatus.begin();
// strip check - are we talking or what?
if (1) {
strip.setPixelColor(7, 0xffffff);
strip.show();
delay(777);
}
for (uint8_t index = 0; index < numberOfPipes; index++) {
// long newDelay = random(RANDOM_MIN, RANDOM_MAX); // Initial Random Time n milliseconds
// pipeTimerOns[index].setTimeDelay(newDelay); // Set delay time to object
pipeCollector[index] = index;
}
uint16_t newDelay = random(RANDOM_MIN, RANDOM_MAX); // Initial Random Time n milliseconds
blinkTON.setTimeDelay(BLINK_DELAY); // Set Blink Time Delay
pipeTON.setTimeDelay (newDelay); // Initial time delay for first pipe
RandomCollector(); // Randomize Pipe
pipeIndex = 0; // Initil Pipe Index
PrintPipeInfo(); // Print dropping info. for first pipe
toggleState = true;
}
unsigned long now;
void loop() {
now = millis();
Dropping();
RunGame();
rainbow();
}
void RunGame() {
if (pipeTON.timerOn(true)) {
pipeTON.timerOn(false); // Reset timer
uint16_t newDelay = random(RANDOM_MIN, RANDOM_MAX); // New Random Time n milliseconds
pipeTON.setTimeDelay(newDelay); // Set new Delay Time
pipeStatus.setPixelColor(pipeCollector[pipeIndex], PIPE_BLACK); // Pipe dropped
pipeIndex = (pipeIndex + 1) % numberOfPipes; // Increase Pipe Index modular with numberOfPipes
if (pipeIndex == 0) RandomCollector(); // Random for new game
pipeStatus.setPixelColor(pipeCollector[pipeIndex], PIPE_RED); // Set status for pipe
pipeStatus.show(); // Update NeoPixel
// for (uint8_t index = 0; index < numberOfPipes; index++) {
// pipeTimerOns[index].timerOn(true); // True = Enable or Start, False = Disable or Stop or Reset
// if (pipeTimerOns[index].isDone()) { // Timer On Done?
// pipeTimerOns[index].timerOn(false); // Reset Timer On
// randomSeed(analogRead(0)); // Use an unconnected pin for randomSeed()
// long newDelay = random(RANDOM_MIN, RANDOM_MAX); // New Random Time n milliseconds
// pipeTimerOns[index].setTimeDelay(newDelay); // Set delay time to object
PrintPipeInfo(); // Print dropping info.
// }
}
}
// modified from Adafruit example to make it a output machine
void rainbow()
{
static uint16_t j = 0;
static unsigned long lastUpdate;
if (now - lastUpdate < 40)
return;
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i + j) & 255));
}
strip.show();
j++;
if (j >= 256) j = 0;
lastUpdate = now; // time for next change to the display
}
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if (WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
void Dropping() {
if (blinkTON.timerOn(true)) {
blinkTON.timerOn(false);
toggleState = !toggleState;
if (toggleState) {
pipeStatus.setPixelColor(pipeCollector[pipeIndex], PIPE_RED);
} else {
pipeStatus.setPixelColor(pipeCollector[pipeIndex], PIPE_GREEN);
}
pipeStatus.show();
}
}
// Random Collector for pipes
void RandomCollector() {
for (uint8_t index = 0; index < numberOfPipes; index++) {
uint8_t randomNumber = random(index, numberOfPipes);
uint8_t temp = pipeCollector[index];
pipeCollector[index] = pipeCollector[randomNumber];
pipeCollector[randomNumber] = temp;
pipeStatus.setPixelColor(index, PIPE_GREEN);
}
pipeStatus.show();
}
void PrintPipeInfo() {
if (pipeIndex == 0) {
Serial.println("\nNew Game...");
}
Serial.print(millis()); Serial.print(" dropping ");
Serial.print(pipeCollector[pipeIndex]); Serial.print(" delay ");
Serial.print(pipeTON.getTimeDelay()); Serial.print(" mS to next");
Serial.println("");
}