// EncoderRing https://wokwi.com/projects/417712838205345793
// Control the a FastLED strip's NUM_LEDS, Hue, Saturation, and Value
// Based on
// https://wokwi.com/projects/304919215794553409 -- Wokwi Encoder Volume
// https://wokwi.com/projects/417720757017823233 -- Wokwi Encoder 6 variables
//
// https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#Basicframework
//
// See also https://forum.arduino.cc/t/wokwi-simulations-for-arduino-built-in-examples/1304754/9
#include "FastLED.h" // https://github.com/FastLED/FastLED
#include <Encoder.h> // https://github.com/PaulStoffregen/Encoder
#define NUM_LEDS 60
CRGB leds[NUM_LEDS];
#define PIN 6
const byte EncClockPin = 2;
const byte EncDataPin = 5;
const byte EncSwPin = 7;
Encoder enc(EncClockPin, EncDataPin);
uint8_t hue = 0;
uint8_t sat = 255;
uint8_t val = 255;
uint8_t num = NUM_LEDS - 5 ; // leave an initial gap
bool lastSwitchPressed;
uint32_t lastChangeMs = 0;
uint32_t lastChangedMs;
bool dirty = false;
typedef enum {
SET_NUM,
SET_HUE,
SET_SAT,
SET_VALUE,
} EncoderMode;
EncoderMode encoderMode = SET_NUM;
void report() {
char* names[] = {"Num", "Hue", "Sat", "Val"};
Serial.print("EncoderMode:");
Serial.print(encoderMode);
Serial.print(",");
Serial.print(names[encoderMode]);
Serial.print(" num:");
Serial.print(num);
Serial.print(" H:");
Serial.print(hue);
Serial.print(" S:");
Serial.print(sat);
Serial.print(" V:");
Serial.print(val);
Serial.println();
}
void refreshStrip() { // refresh if dirty
const uint32_t interval = 100;
static uint32_t lastUpdate = -interval;
// if (millis() - lastUpdate >= interval) {
if (dirty) {
lastUpdate = millis();
for (int ii = 0; ii < NUM_LEDS; ++ii) {
if (ii < num ) {
leds[ii].setHSV( hue, sat, val);
} else {
leds[ii].setRGB( 0, 0, 0);
}
}
showStrip();
}
}
// Encoder State machine handling
void nextMode() { // advance through button-pressing
switch (encoderMode) {
case SET_NUM:
encoderMode = SET_HUE;
break;
case SET_HUE:
encoderMode = SET_SAT;
break;
case SET_SAT:
encoderMode = SET_VALUE;
break;
case SET_VALUE:
encoderMode = SET_NUM;
break;
}
}
void updateValue(int delta) { // tweak variables based on encoderMode
switch (encoderMode) {
case SET_NUM:
num = constrain(num + delta, 0, NUM_LEDS);
break;
case SET_HUE:
hue = (hue + delta) &0xFF; // loop around
break;
case SET_SAT:
sat = constrain(sat + delta, 0, 255);
break;
case SET_VALUE:
val = constrain(val + delta, 0, 255);
break;
}
}
// neopixel/fastled Generalizing bits
void showStrip() {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.show();
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
FastLED.show();
#endif
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.setPixelColor(Pixel, strip.Color(red, green, blue));
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
#endif
}
void setAll(byte red, byte green, byte blue) {
for (int i = 0; i < NUM_LEDS; i++ ) {
setPixel(i, red, green, blue);
}
showStrip();
}
// Arduino main()-called functions:
void setup()
{
FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
Serial.begin(115200);
pinMode(EncSwPin, INPUT_PULLUP);
lastSwitchPressed = digitalRead(EncSwPin) == LOW;
dirty = true;
}
void loop() {
static long lastEncVal = 0;
long encVal = enc.read() >> 2;
bool switchPressed = digitalRead(EncSwPin) == LOW;
if (switchPressed != lastSwitchPressed && millis() - lastChangedMs > 300 ) {
lastChangedMs = millis();
nextMode();
//Serial.print(encoderMode);
dirty = true; // mark for refresh
}
if (encVal != lastEncVal) {
int delta = encVal - lastEncVal > 0 ? -1 : 1;
lastEncVal = encVal;
updateValue(delta);
dirty = true; // mark for refresh
}
if (dirty) {
refreshStrip();
report();
dirty = false;
}
}