Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const int prescaler = 1024; // How many clock cycles it takes before the underlying timer (Timer1) increments
- const int timerHertz = 16000000 / prescaler; // How many times per second the underlying timer (Timer1) increments. 16,000,000 is the Arduino's clock speed
- int maxTasks;
- unsigned long tickIntervalMs;
- int compareMatchRegister;
- struct Task
- {
- void (*action)(void*);
- void* argument;
- unsigned long delayTicks;
- };
- struct Task** tasks;
- void setupTaskScheduler(int _maxTasks, unsigned long _tickIntervalMs)
- {
- if (tasks != NULL)
- {
- for (int i = 0; i < maxTasks; i++)
- {
- Task* task = tasks[i];
- free(task);
- }
- free(tasks);
- }
- tickIntervalMs = _tickIntervalMs;
- double interruptHertz = 1000 / _tickIntervalMs; // interruptHertz = How many times per second the caller is asking to check for and execute due tasks
- maxTasks = _maxTasks;
- tasks = (Task**)calloc(maxTasks, sizeof(Task*));
- compareMatchRegister = timerHertz / interruptHertz; // compareMatchRegister = when the underlying timer (Timer1) hits this value, it interrupts and then resets to zero
- }
- int scheduleTimer1Task(void (*action)(void*), void* argument, unsigned long delayMs)
- {
- for (int i = 0; i < maxTasks; i++)
- {
- if (tasks[i] == NULL)
- {
- Task* ptr = (Task*)malloc(sizeof(struct Task));
- ptr->action = action;
- ptr->argument = argument;
- ptr->delayTicks = delayMs / tickIntervalMs;
- tasks[i] = ptr;
- return true; // Found an empty spot in the task list for this task
- }
- }
- return false; // No spot for this task found, scheduling request rejected
- }
- void startSchedulerTicking()
- {
- noInterrupts();
- TCCR1A = 0;// set entire TCCR1A register to 0
- TCCR1B = 0;// same for TCCR1B
- TCNT1 = 0;//initialize counter value to 0
- // set compare match register for 1hz increments
- OCR1A = compareMatchRegister;// = (16*10^6) / (1*1024) - 1 (must be <65536)
- // turn on CTC mode
- TCCR1B |= (1 << WGM12);
- // Set CS10 and CS12 bits for 1024 prescaler
- TCCR1B |= (1 << CS12) | (1 << CS10);
- // enable timer compare interrupt
- TIMSK1 |= (1 << OCIE1A);
- interrupts();
- }
- // This is the timer interrupt
- ISR( TIMER1_COMPA_vect )
- {
- for (int i = 0; i < maxTasks; i++)
- {
- if (tasks[i] != NULL)
- {
- Task* task = tasks[i];
- unsigned long ticks = task->delayTicks;
- if (ticks == 0)
- {
- void (*action)(void*) = task->action;
- void* argument = task->argument;
- free(task);
- tasks[i] = NULL;
- action(argument);
- }
- else
- {
- task->delayTicks--;
- }
- }
- }
- }
- const unsigned long DelayMs = 30;
- const int AnalogOutMaxForHypnaMode = 30;
- const int MaxFadeMs = 2000;
- const int MinFadeMs = 200;
- const unsigned long RampUpTimeMs = 1800000; // 30 minutes
- const unsigned long RampUpStepIntervalMs = 10000; // 10 seconds
- const unsigned int NumberOfLeds = 2;
- const unsigned int NumberOfColorsPerLed = 3;
- const unsigned long LdModeInitialDelayMs = 1200000; // 60 minutes
- const unsigned long LdModeDelayBetweenPulsesMs = 600000; // 10 minutes
- const unsigned long LdModePulseDurationMs = 10000; // 10 seconds
- const int LedPins[NumberOfLeds][NumberOfColorsPerLed] =
- {
- { 2, 3, 4 },
- { 5, 6, 7 },
- };
- double ledIncrements[NumberOfLeds][NumberOfColorsPerLed] =
- {
- { 0, 0, 0 },
- { 0, 0, 0 },
- };
- double ledTargets[NumberOfLeds][NumberOfColorsPerLed] =
- {
- { 0, 0, 0 },
- { 0, 0, 0 },
- };
- double ledCurrentVoltages[NumberOfLeds][NumberOfColorsPerLed] =
- {
- { 0, 0, 0 },
- { 0, 0, 0 },
- };
- int fadeMs = MaxFadeMs;
- int maxOffTimeMs = fadeMs * 5;
- unsigned long nextLedUpdateTime = 0;
- void setup()
- {
- randomSeed(analogRead(0));
- setupTaskScheduler(NumberOfLeds + NumberOfColorsPerLed + 1, DelayMs);
- startSchedulerTicking();
- scheduleTimer1Task(&rampUp, NULL, RampUpStepIntervalMs);
- for (int led = 0; led < NumberOfLeds; led++)
- {
- for (int color = 0; color < NumberOfColorsPerLed; color++)
- {
- pinMode(LedPins[led][color], OUTPUT);
- }
- scheduleLed(led);
- }
- }
- void loop()
- {
- // 40 Hz
- delay(900000); // Comment this line out unless you want to go into 40 Hz mode
- ldMode40Hz(); // Comment this line out unless you want to go into 40 Hz mode
- unsigned long mill = millis();
- if (mill > LdModeInitialDelayMs)
- {
- ldMode();
- }
- if (mill > nextLedUpdateTime)
- {
- for (int led = 0; led < NumberOfLeds; led++)
- {
- if (ledDo(led))
- {
- scheduleLed(led);
- }
- }
- nextLedUpdateTime = millis() + DelayMs;
- }
- }
- void ldMode()
- {
- for (int led = 0; led < NumberOfLeds; led++)
- {
- for (int color = 0; color < NumberOfColorsPerLed; color++)
- {
- analogWrite(LedPins[led][color], LOW);
- }
- }
- while (true)
- {
- unsigned long startMillis = millis();
- while (millis() < startMillis + LdModePulseDurationMs)
- {
- analogWrite(2, AnalogOutMaxForHypnaMode);
- analogWrite(6, AnalogOutMaxForHypnaMode);
- delay(500);
- analogWrite(2, LOW);
- analogWrite(6, LOW);
- delay(500);
- }
- delay(LdModeDelayBetweenPulsesMs);
- }
- }
- void ldMode40Hz()
- {
- while (1)
- {
- for (int led = 0; led < NumberOfLeds; led++)
- {
- for (int color = 0; color < NumberOfColorsPerLed; color++)
- {
- digitalWrite(LedPins[led][color], HIGH);
- }
- }
- delay(12);
- for (int led = 0; led < NumberOfLeds; led++)
- {
- for (int color = 0; color < NumberOfColorsPerLed; color++)
- {
- digitalWrite(LedPins[led][color], LOW);
- }
- }
- delay(12);
- }
- }
- void rampUp(void*)
- {
- unsigned long mill = millis();
- if (mill > RampUpTimeMs)
- {
- return;
- }
- double multiplier = 1.0 - ((double)mill / (double)RampUpTimeMs);
- fadeMs = (multiplier * (MaxFadeMs - MinFadeMs)) + MinFadeMs;
- maxOffTimeMs = map(fadeMs, MinFadeMs, MaxFadeMs, 1000, maxOffTimeMs);
- scheduleTimer1Task(&rampUp, NULL, RampUpStepIntervalMs);
- }
- // Sets the LED's increments so that it begins moving toward its target
- void updateLed(void* _led)
- {
- int led = *(int*)_led;
- free(_led);
- double numberOfSteps = (double)fadeMs / (double)DelayMs;
- for (int color = 0; color < NumberOfColorsPerLed; color++)
- {
- ledIncrements[led][color] = ledTargets[led][color] / numberOfSteps;
- }
- }
- // Sets the LED's targets and schedules a call to updateLed to start its cycle
- void scheduleLed(int led)
- {
- unsigned long offTimeMs = random(0, maxOffTimeMs);
- for (int color = 0; color < NumberOfColorsPerLed; color++)
- {
- ledTargets[led][color] = random(1, AnalogOutMaxForHypnaMode);
- }
- void* ledVoid = malloc(sizeof(int));
- memcpy(ledVoid, &led, sizeof(int));
- scheduleTimer1Task(&updateLed, ledVoid, offTimeMs);
- }
- // Puts the LED back in its initial off state
- void resetLed(int led)
- {
- for (int color = 0; color < NumberOfColorsPerLed; color++)
- {
- analogWrite(LedPins[led][color], 0);
- ledCurrentVoltages[led][color] = 0;
- ledIncrements[led][color] = 0;
- }
- }
- // Moves the led a step toward its final state
- // Returns true if the led has reached its final state and returned to its initial state (the led has cycled completely from off to on to off again)
- boolean ledDo(int led)
- {
- boolean returnVal = false;
- for (int color = 0; color < NumberOfColorsPerLed; color++)
- {
- double increment = ledIncrements[led][color];
- int pin = LedPins[led][color];
- double output = ledCurrentVoltages[led][color] + increment;
- if (increment == 0)
- {
- continue;
- }
- if (output < 0 || returnVal)
- {
- resetLed(led);
- return true;
- }
- else if (output > ledTargets[led][color])
- {
- ledIncrements[led][color] = -1 * increment;
- }
- else
- {
- analogWrite(pin, output);
- ledCurrentVoltages[led][color] = output;
- }
- }
- return false;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement