Last active
January 9, 2024 07:21
-
-
Save kbob/bc09de95dbbbe4fe27fd840bec63fa80 to your computer and use it in GitHub Desktop.
LED rotor Arduino sketch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example Arduino sketch shows how to make a "rotor" of LEDs that light up, | |
// then fade away as the rotor passes them by. | |
// See https://mstdn.social/@alpenglow/111722310220283286 | |
#define ROTOR_LED_COUNT 10 | |
#define ROTOR_UPDATE_MSEC 1 | |
#define ROTOR_ADVANCE_MSEC 100 | |
#define ROTOR_MAX_BRIGHTNESS 255 | |
#define ROTOR_MIN_BRIGHTNESS 0 | |
// N.B. | |
// Each rotor LED has an attack phase, then a decay phase. | |
// Rotor attack is in steps/msec. It takes at most 256 msec to go to full brightness. | |
// Rotor decay is in msec/step. It takes at least 256 msec to go dark. | |
#define ROTOR_ATTACK_STEPS 4 | |
#define ROTOR_DECAY_MSEC 3 | |
const int rotor_pwm_pins[ROTOR_LED_COUNT] = {3, 4, 5, 6, 9, 10, 20, 21, 22, 23}; | |
// true when an LED is in its attack phase | |
bool rotor_is_attacking[ROTOR_LED_COUNT]; | |
// current brightness of each LED | |
int rotor_brightness[ROTOR_LED_COUNT]; | |
// count updates until it's time to decay the LED brightness | |
int rotor_decay_counter[ROTOR_LED_COUNT]; | |
// Which LED attacks next? | |
int rotor_position; | |
// These are times comparable to the time returned by millis(). | |
unsigned long rotor_update_time; | |
unsigned long rotor_advance_time; | |
// Cheap approximation to exponential brightness. | |
long brightness_to_pwm(int brightness) { | |
// 0 <= brightness < 256 | |
return brightness * (brightness + 1); | |
} | |
void setup() { | |
//Teensy supports 16 bit PWM. | |
analogWriteResolution(16); | |
// Set all rotor pins to output mode. | |
for (int i = 0; i < ROTOR_LED_COUNT; i++) { | |
pinMode(rotor_pwm_pins[i], OUTPUT); | |
rotor_is_attacking[i] = false; | |
} | |
rotor_update_time = millis() + ROTOR_UPDATE_MSEC; | |
rotor_advance_time = rotor_update_time; | |
} | |
void update_rotor() { | |
if (rotor_advance_time <= rotor_update_time) { | |
// advance the rotor | |
rotor_is_attacking[rotor_position] = true; | |
rotor_position = (rotor_position + 1) % ROTOR_LED_COUNT; | |
rotor_advance_time += ROTOR_ADVANCE_MSEC; | |
} | |
for (int i = 0; i < ROTOR_LED_COUNT; i++) { | |
int pin = rotor_pwm_pins[i]; | |
int bright = rotor_brightness[i]; | |
if (rotor_is_attacking[i]) { | |
// Attack phase. Increase brightness. | |
// When we reach max, enter decay phase. | |
bright += ROTOR_ATTACK_STEPS; | |
if (bright > ROTOR_MAX_BRIGHTNESS) { | |
bright = ROTOR_MAX_BRIGHTNESS; | |
rotor_is_attacking[i] = false; // begin decay phase | |
rotor_decay_counter[i] = 0; | |
} | |
analogWrite(pin, brightness_to_pwm(bright)); | |
} else { | |
// Decay phase. Increment counter; decrease brightness | |
// when it overflows. When we reach MIN, stay there. | |
rotor_decay_counter[i]++; | |
if (rotor_decay_counter[i] >= ROTOR_DECAY_MSEC) { | |
rotor_decay_counter[i] = 0; | |
bright--; | |
if (bright < ROTOR_MIN_BRIGHTNESS) { | |
bright = ROTOR_MIN_BRIGHTNESS; | |
} | |
analogWrite(pin, brightness_to_pwm(bright)); | |
} | |
} | |
// save the updated brightness | |
rotor_brightness[i] = bright; | |
} | |
} | |
void loop() { | |
unsigned long now = millis(); | |
if (now >= rotor_update_time) { | |
update_rotor(); | |
rotor_update_time += ROTOR_UPDATE_MSEC; | |
} | |
// update other subsystems here... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment