Skip to content

Instantly share code, notes, and snippets.

@kbob
Last active January 9, 2024 07:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kbob/bc09de95dbbbe4fe27fd840bec63fa80 to your computer and use it in GitHub Desktop.
Save kbob/bc09de95dbbbe4fe27fd840bec63fa80 to your computer and use it in GitHub Desktop.
LED rotor Arduino sketch
// 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