Hi folks,
I'm working on an Infinity Cube and I am having trouble with my menu system.
As it is now, the menu has a list of 10 animations, a timed playlist of all animations and a lamp that I can scroll through with a rotary encoder and click the button to activate selection.
This works as it should but I would like to have a brightness control that is selected with a double click, then just up and down changes the brightness as it happens, then after 3 seconds or so with no movement it returns to the list screen.
My code does detect the double click in serial monitor but I can not get it to display the brightness screen.
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Fonts/FreeSans9pt7b.h>
#include <Arduino.h>
#include <RotaryEncoder.h>
#include <OneButton.h>
#include <FastLED.h>
#define NUM_LEDS 336
#define LED_PIN 27
#define BRIGHTNESS 70
#define BRIGHTNESS2 50 // brightness level
#define BRIGHTNESS3 20 // brightness level for lamp
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
int encoderValue = 0;
int brightnessValue = map(encoderValue, 0, 1023, 0, 255);
uint8_t hue = 0;
uint8_t colorIndex[144];
CRGB leds[NUM_LEDS]; // color data for each led - sets up an array that we can manipulate to set/clear led data.
CRGB leds_buffor[168]; // half of the total number of pixels
CRGB leds_in_segments[14];
/// Encoder used is KY-040 / HW-040
#define PIN_IN1 2 // CLK pin
#define PIN_IN2 5 // DT pin
#define PIN_INPUT 32 // SW / button pin
#define ROTARYSTEPS 1 // encoder step
#define ROTARYMIN 1 // encoder min
#define ROTARYMAX 12 // encoder max
#define ROTARYMAX2 25 // encoder max
int lastPos = -1;
int newPos = 1;
int newPos2 = 1;
int newPos3 = 1;
#define OLED_ADDR 0x3C
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//---------------
volatile int interrupts;
int totalInterrupts;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTime() {
portENTER_CRITICAL_ISR(&timerMux);
interrupts++;
portEXIT_CRITICAL_ISR(&timerMux);
}
// A pointer to the dynamic created rotary encoder instance.
// This will be done in setup()
RotaryEncoder *encoder = nullptr;
// @brief The interrupt service routine will be called on any change of one of the input signals.
IRAM_ATTR void checkPosition()
{
encoder->tick(); // just call tick() to check the state.
}
OneButton button(PIN_INPUT, true,true);
//unsigned long pressStartTime;
ICACHE_RAM_ATTR void checkTicks() {
// include all buttons here to be checked
button.tick(); // just call tick() to check the state.
}
// this function will be called when the button was pressed 1 time only.
void singleClick() {
Serial.println("singleClick() detected.");
newPos2 = newPos;
} // singleClick
// this function will be called when the button was pressed 2 times in a short timeframe.
void doubleClick() {
Serial.println("doubleClick() detected.");
newPos3 = newPos;
} // doubleClick
// this function will be called when the button was held down for 1 second or more.
DEFINE_GRADIENT_PALETTE( matrix_gp ) { //gradient for pattern usage
0, 173,229, 51,
73, 139,199, 45,
140, 46,176, 37,
204, 7, 88, 5,
255, 0, 24, 0};
CRGBPalette16 greenblue2 = matrix_gp;
DEFINE_GRADIENT_PALETTE( spellbound_gp ) { //gradient2 for pattern usage
0, 232,235, 40,
12, 157,248, 46,
25, 100,246, 51,
45, 53,250, 33,
63, 18,237, 53,
81, 11,211,162,
94, 18,147,214,
101, 43,124,237,
112, 49, 75,247,
127, 49, 75,247,
140, 92,107,247,
150, 120,127,250,
163, 130,138,252,
173, 144,131,252,
186, 148,112,252,
196, 144, 37,176,
211, 113, 18, 87,
221, 163, 33, 53,
234, 255,101, 78,
247, 229,235, 46,
255, 229,235, 46};
CRGBPalette16 greenblue = spellbound_gp;
void setup() {
//--------------------------------
// Configure Prescaler to 80, as our timer runs @ 80Mhz
// Giving an output of 80,000,000 / 80 = 1,000,000 ticks / second
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTime, true);
// Fire Interrupt every 1m ticks, so 1s
timerAlarmWrite(timer, 5000000, true);
timerAlarmEnable(timer);
//--------------------------------
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS); // setup leds
FastLED.setBrightness(brightnessValue);
Serial.begin(9600);
while (!Serial)
;
// setup the rotary encoder functionality
encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);
// register interrupt routine
attachInterrupt(digitalPinToInterrupt(PIN_IN1), checkPosition, CHANGE);
attachInterrupt(digitalPinToInterrupt(PIN_IN2), checkPosition, CHANGE);
encoder->setPosition(1 / ROTARYSTEPS); // start with the value of 10.
// setup interrupt routine
attachInterrupt(digitalPinToInterrupt(PIN_INPUT), checkTicks, CHANGE);
button.attachClick(singleClick);
button.attachDoubleClick(doubleClick);
button.setPressMs(1000); // that is the time when LongPressStart is called - not in use
display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
display.display();
display.clearDisplay(); // Clear the buffer
for (int i = 0; i < 168; i++) {
colorIndex[i] = random8();
}
} // setup() close
typedef void (*SimplePatternList[])();
SimplePatternList gPatterns = {rainbow, matrix, spellPattern, dots, colourSnake, confetti, randomStar, colourful, beat, snake};
int secondsPerPattern[] = {20, 5, 5, 20, 20, 20, 20,20,20,20};
uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
uint8_t gHue = 0; // rotating "base color"
void screen() { //funtion for screen operation
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(28, 0);
display.println("LIGHTING MODES");
display.drawLine(4, 12, 128, 12, WHITE);
switch (newPos) {
case 0:
break;
case 1:
highlight();
display.setCursor(6, 32);
display.println(" Rainbow ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Matrix ");
break;
case 2:
display.setCursor(6, 20);
display.println(" Rainbow ");
highlight();
display.setCursor(6, 32);
display.println(" Matrix ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Spell Pattern ");
break;
case 3:
display.setCursor(6, 20);
display.println(" Matrix ");
highlight();
display.setCursor(6, 32);
display.println(" Spell Pattern ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Move Dots ");
break;
case 4:
display.setCursor(6, 20);
display.println(" Spell Pattern ");
highlight();
display.setCursor(6, 32);
display.println(" Move Dots ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Colour Snake ");
break;
case 5:
display.setCursor(6, 20);
display.println(" Move Dots ");
highlight();
display.setCursor(6, 32);
display.println(" Colour Snake ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Confetti ");
break;
case 6:
display.setCursor(6, 20);
display.println(" Colour Snake ");
highlight();
display.setCursor(6, 32);
display.println(" Confetti ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Random Star");
break;
case 7:
display.setCursor(6, 20);
display.println(" Confetti ");
highlight();
display.setCursor(6, 32);
display.println(" Random Star ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Colorful ");
break;
case 8:
display.setCursor(6, 20);
display.println(" Random Star ");
highlight();
display.setCursor(6, 32);
display.println(" Colorful ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Beat ");
break;
case 9:
display.setCursor(6, 20);
display.println(" Colorful ");
highlight();
display.setCursor(6, 32);
display.println(" Beat ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Snake ");
break;
case 10:
display.setCursor(6, 20);
display.println(" Beat ");
highlight();
display.setCursor(6, 32);
display.println(" Snake ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Playlist ");
break;
case 11:
display.setCursor(6, 20);
display.println(" Snake ");
highlight();
display.setCursor(6, 32);
display.println(" Playlist ");
display.setTextColor(WHITE);
display.setCursor(6, 44);
display.println(" Lamp ");
break;
case 12:
display.setCursor(6, 20);
display.println(" Playlist ");
highlight();
display.setCursor(6, 32);
display.println(" Lamp ");
display.setTextColor(WHITE);
break;
}
display.display();
delay(100);
display.clearDisplay();
}
void screen2() {
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(32, 0);
display.println("BRIGHTNESS");
display.drawLine(27, 12, 95, 12, WHITE);
switch (newPos) {
case 0:
break;
case 1:
highlight();
display.setTextSize(2);
display.setCursor(6, 28);
display.println(" UP + ");
display.setTextColor(WHITE);
display.setCursor(6, 48);
display.println(" DOWN - ");
break;
case 2:
display.setCursor(6, 28);
display.println(" UP + ");
highlight();
display.setCursor(6, 32);
display.println(" DOWN - ");
display.setTextColor(WHITE);
break;
}
display.display();
delay(100);
display.clearDisplay();
}
void highlight() {
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
}
void rainbow() {
FastLED.setBrightness(BRIGHTNESS); // set brightness level
for (uint8_t j = 0; j < 168; j++) {
leds_buffor[j]= CHSV(hue+(j*10), 255, 255);
}
mirror();
FastLED.show();
EVERY_N_MILLISECONDS(10){
hue++;
}
}
void matrix() {
FastLED.setBrightness(BRIGHTNESS3); // set brightness level
for (int i = 0; i < 168; i++) {
leds_buffor[i] = ColorFromPalette(greenblue2, colorIndex[i]);
}
EVERY_N_MILLISECONDS(5){
for (int i = 0; i < 168; i++) {
colorIndex[i]++;
}
}
mirror();
FastLED.show();
}
void dots() {
FastLED.setBrightness(BRIGHTNESS); // set brightness level
uint16_t posBeat = beatsin16(30, 0, 14, 0, 0);
uint16_t posBeat2 = beatsin16(60, 0, 14, 0, 0);
uint16_t posBeat3 = beatsin16(30, 0, 14, 0, 32767);
uint16_t posBeat4 = beatsin16(60, 0, 14, 0, 32767);
// Wave for LED color
uint8_t colBeat = beatsin8(45, 0, 255, 0, 0);
leds_in_segments[(posBeat + posBeat2) / 2] = CHSV(colBeat, 255, 255);
//leds_segments[(posBeat3 + posBeat4) / 2] = CHSV(colBeat, 255, 255);
fadeToBlackBy(leds_in_segments, 14, 15);
segments();
FastLED.show();
}
void colourful() {
FastLED.setBrightness(BRIGHTNESS); // set brightness level
static uint16_t sPseudotime = 0;
static uint16_t sLastMillis = 0;
static uint16_t sHue16 = 0;
uint8_t sat8 = beatsin88( 87, 220, 250);
uint8_t brightdepth = beatsin88( 341, 96, 224);
uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256));
uint8_t msmultiplier = beatsin88(147, 23, 60);
uint16_t hue16 = sHue16;//gHue * 256;
uint16_t hueinc16 = beatsin88(113, 1, 3000);
uint16_t ms = millis();
uint16_t deltams = ms - sLastMillis ;
sLastMillis = ms;
sPseudotime += deltams * msmultiplier;
sHue16 += deltams * beatsin88( 400, 5,9);
uint16_t brightnesstheta16 = sPseudotime;
for( uint16_t i = 0 ; i < 168; i++) {
hue16 += hueinc16;
uint8_t hue8 = hue16 / 256;
brightnesstheta16 += brightnessthetainc16;
uint16_t b16 = sin16( brightnesstheta16 ) + 32768;
uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
bri8 += (255 - brightdepth);
CRGB newcolor = CHSV( hue8, sat8, bri8);
uint16_t pixelnumber = i;
pixelnumber = (167) - pixelnumber;
nblend( leds_buffor[pixelnumber], newcolor, 64);
}
mirror();
FastLED.show();
}
void snake() {
FastLED.setBrightness(BRIGHTNESS); // set brightness level
fadeToBlackBy( leds_in_segments, 14, 20);
int pos = beatsin16( 30, 0, 13 );
leds_in_segments[pos] += CHSV( hue, 255, 192);
segments();
FastLED.show();
EVERY_N_MILLISECONDS(100){
hue++;
}
}
void spellPattern() {
FastLED.setBrightness(BRIGHTNESS3); // set brightness level
for (int i = 0; i < 168; i++) {
leds_buffor[i] = ColorFromPalette(greenblue, colorIndex[i]);
}
EVERY_N_MILLISECONDS(5){
for (int i = 0; i < 168; i++) {
colorIndex[i]++;
}
}
mirror();
FastLED.show();
}
void beat() {
FastLED.setBrightness(BRIGHTNESS); // set brightness level
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
uint8_t BeatsPerMinute = 30;
CRGBPalette16 palette = PartyColors_p;
uint8_t beat = beatsin8( BeatsPerMinute, 64, 255);
for( int i = 0; i < 14; i++) { //9948
leds_in_segments[i] = ColorFromPalette(palette, hue+(i*2), beat-hue+(i*10));
}
segments();
FastLED.show();
EVERY_N_MILLISECONDS(20){
hue++;
}
}
void confetti() {
FastLED.setBrightness(BRIGHTNESS); // set brightness level
// random colored speckles that blink in and fade smoothly
fadeToBlackBy( leds_buffor, 168, 10);
int pos = random16(168);
leds_buffor[pos] += CHSV( hue + random8(64), 200, 255);
mirror();
FastLED.show();
EVERY_N_MILLISECONDS(20){
hue++;
}
}
void colourSnake() {
FastLED.setBrightness(BRIGHTNESS); // set brightness level
// eight colored dots, weaving in and out of sync with each other
fadeToBlackBy( leds_buffor, 168, 30);
uint8_t dothue = 0;
for( int i = 0; i < 8; i++) {
leds_buffor[beatsin16( i+1, 0, 168 )] |= CHSV(dothue, 200, 255); // i+1 change to i+7 fot faster effect
dothue += 32;
}
mirror();
FastLED.show();
EVERY_N_MILLISECONDS(20){
hue++;
}
}
void randomStar() {
FastLED.setBrightness(BRIGHTNESS); // set brightness level
EVERY_N_MILLISECONDS(100) {
leds_buffor[random16(0, 168)] = CHSV((random16(130, 160)), (random16(0, 255)), 255);
}
fadeToBlackBy(leds_buffor, 168, 5);
mirror();
FastLED.show();
}
void lamp() {
FastLED.setBrightness(BRIGHTNESS2); // set brightness level
fill_solid(leds, NUM_LEDS, CRGB::White);
FastLED.show();
}
void playlist() {
gPatterns[gCurrentPatternNumber]();
FastLED.show();
EVERY_N_MILLISECONDS( 20 ) {
gHue++; // slowly cycle base color through rainbow
}
//EVERY_N_SECONDS(secondsPerPattern[gCurrentPatternNumber]) {
static long lastChangeMs = 0;
if(millis() - lastChangeMs >= secondsPerPattern[gCurrentPatternNumber]*1000L){
lastChangeMs = millis();
// add one to the current pattern number, and wrap around at the end
gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns);
}
}
//--------------------------------------------------end patterns---------
// this function puts the seperate sections in to pairs
void mirror() {
for (uint8_t i = 0; i < 14; i++) {
leds[i] = leds_buffor[i]; // section 1
leds[335-i]=leds[i]; // section 24
leds[14+i] = leds_buffor[14+i]; // section 2
leds[293-i]=leds[14+i]; // section 21
leds[28+i] = leds_buffor[28+i]; // section 3
leds[83-i]=leds[28+i]; // section 6
leds[42+i] = leds_buffor[42+i]; // section 4
leds[69-i]=leds[42+i]; // section 5
leds[84+i] = leds_buffor[56+i]; // section 7
leds[279-i]=leds[84+i]; // section 20
leds[98+i] = leds_buffor[70+i]; // section 8
leds[153-i]=leds[98+i]; // section 11
leds[125-i] = leds_buffor[84+i]; // section 9
leds[139-i]=leds[112+i]; // section 10
leds[154+i] = leds_buffor[98+i]; // section 12
leds[265-i]=leds[154+i]; // section 19
leds[168+i] = leds_buffor[112+i]; // section 13
leds[251-i]=leds[168+i]; // section 18
leds[182+i]=leds_buffor[126+i]; // section 14
leds[209-i]=leds[182+i]; // section 15
leds[210+i] = leds_buffor[140+i]; // section 16
leds[237-i]=leds[210+i]; // section 17
leds[307-i] = leds_buffor[154+i]; // section 22
leds[308+i]=leds[307-i]; // section 23
}
}
// this function puts the strip in to 24 equal sections of 14 pixels
void segments() {
for (uint8_t i = 0; i < 14; i++) {
leds[i] = leds_in_segments[i]; // section
leds[252+i]=leds_in_segments[i]; // section
leds[27-i] = leds_in_segments[i]; // section
leds[168+i]=leds_in_segments[i]; // section
leds[28+i] = leds_in_segments[i]; // section
leds[112+i]=leds_in_segments[i]; // section
leds[55-i] = leds_in_segments[i]; // section
leds[56+i]=leds_in_segments[i]; // section
leds[83-i] = leds_in_segments[i]; // section
leds[279-i]=leds_in_segments[i]; // section
leds[84+i] = leds_in_segments[i]; // section
leds[307-i]=leds_in_segments[i]; // section
leds[111-i] = leds_in_segments[i]; // section
leds[139-i]=leds_in_segments[i]; // section
leds[140+i] = leds_in_segments[i]; // section
leds[280+i]=leds_in_segments[i]; // section
leds[167-i] = leds_in_segments[i]; // section
leds[195-i]=leds_in_segments[i]; // section
leds[196+i] = leds_in_segments[i]; // section
leds[308+i]=leds_in_segments[i]; // section
leds[224+i] = leds_in_segments[i]; // section
leds[251-i]=leds_in_segments[i]; // section
leds[223-i] = leds_in_segments[i]; // section
leds[335-i] = leds_in_segments[i]; // section
}
}
//------------------------Main loop--------------
void loop() {
static int pos = 0;
button.tick();
encoder->tick(); // just call tick() to check the state.
newPos = encoder->getPosition() * ROTARYSTEPS;
if (newPos < ROTARYMIN) {
encoder->setPosition(ROTARYMIN / ROTARYSTEPS);
newPos = ROTARYMIN;
}
else if (newPos > ROTARYMAX) {
encoder->setPosition(ROTARYMAX / ROTARYSTEPS);
newPos = ROTARYMAX;
}
else if (newPos > ROTARYMAX2) {
encoder->setPosition(ROTARYMAX2 / ROTARYSTEPS);
newPos = ROTARYMAX2;
}
if (lastPos != newPos) {
Serial.print(newPos);
lastPos = newPos;
screen();
}
else if(lastPos != newPos2) {
Serial.print(newPos);
lastPos = newPos;
screen2();
}
switch (newPos2) {
// play order of animations
case 0: // Serial.print(newPos);
break;
case 1: rainbow(); break;
case 2: matrix(); break;
case 3: SpellPattern(); break;
case 4: dots(); break;
case 5: ColourSnake(); break;
case 6: confetti(); break;
case 7: RandomStar(); break;
case 8: colourful(); break;
case 9: beat(); break;
case 10: snake(); break;
case 11: playlist(); break;
case 12: lamp(); break;
}
switch (newPos3) {
case 0:
break;
case 1: FastLED.setBrightness(brightnessValue); break;
case 2: FastLED.setBrightness(brightnessValue); break;
}
//--------
if (interrupts > 0) {
portENTER_CRITICAL(&timerMux);
interrupts--;
portEXIT_CRITICAL(&timerMux);
totalInterrupts++;
Serial.print("totalInterrupts");
Serial.println(totalInterrupts);
}
}
This is my first project with a screen and rotary encoder. I think everything is there, just maybe not written correct or in the wrong place.
Could anyone point me in the right direction with this please, my last hurdle in this project.
Thanks