button menu-interface
This commit is contained in:
parent
63a2b7f23d
commit
1d8cb0d2f0
38
src/button.cpp
Normal file
38
src/button.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "button.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "countdown.h"
|
||||||
|
|
||||||
|
bool buttonLastState = false;
|
||||||
|
|
||||||
|
bool buttonLongPressed = false;
|
||||||
|
|
||||||
|
unsigned long buttonLastMillis = 0;
|
||||||
|
|
||||||
|
void buttonSetup() {
|
||||||
|
pinMode(25, INPUT_PULLUP);
|
||||||
|
buttonLastState = digitalRead(25) == LOW;
|
||||||
|
buttonLastMillis = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
void buttonLoop() {
|
||||||
|
const auto currentMillis = millis();
|
||||||
|
const auto durationMillis = currentMillis - buttonLastMillis;
|
||||||
|
if (durationMillis >= 100) {
|
||||||
|
const auto currentState = digitalRead(25) == LOW;
|
||||||
|
if (buttonLastState != currentState) {
|
||||||
|
buttonLastState = currentState;
|
||||||
|
buttonLastMillis = currentMillis;
|
||||||
|
buttonLongPressed = false;
|
||||||
|
if (!buttonLastState) {
|
||||||
|
if (durationMillis < 1000) {
|
||||||
|
countdownShortPress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buttonLastState && currentMillis - buttonLastMillis >= 1000 && !buttonLongPressed) {
|
||||||
|
buttonLongPressed = true;
|
||||||
|
countdownLongPress();
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/button.h
Normal file
8
src/button.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef WS2812B_BUTTON_H
|
||||||
|
#define WS2812B_BUTTON_H
|
||||||
|
|
||||||
|
void buttonSetup();
|
||||||
|
|
||||||
|
void buttonLoop();
|
||||||
|
|
||||||
|
#endif
|
||||||
173
src/countdown.cpp
Normal file
173
src/countdown.cpp
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#include "countdown.h"
|
||||||
|
|
||||||
|
#include "display.h"
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
CONFIG, READY, RUNNING, PAUSED, END
|
||||||
|
};
|
||||||
|
|
||||||
|
State state = CONFIG;
|
||||||
|
|
||||||
|
long configMillis = 6 * 60 * 1000;
|
||||||
|
|
||||||
|
long rest = configMillis;
|
||||||
|
|
||||||
|
unsigned long last = 0;
|
||||||
|
|
||||||
|
void updateTime() {
|
||||||
|
if (state != RUNNING) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto now = max(1UL, millis());
|
||||||
|
if (last != 0) {
|
||||||
|
const auto diff = now - last;
|
||||||
|
rest -= (long) diff;
|
||||||
|
if (rest < 0) {
|
||||||
|
rest = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawDashes() {
|
||||||
|
displayClear();
|
||||||
|
drawChar(0, '-', true, RED);
|
||||||
|
drawChar(1, '-', true, RED);
|
||||||
|
drawChar(2, '-', true, RED);
|
||||||
|
drawChar(3, '-', true, RED);
|
||||||
|
displayShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawWhite() {
|
||||||
|
displayClear();
|
||||||
|
drawChar(0, '8', true, WHITE);
|
||||||
|
drawChar(1, '8', true, WHITE);
|
||||||
|
drawDots(WHITE, WHITE, WHITE, WHITE);
|
||||||
|
drawChar(2, '8', true, WHITE);
|
||||||
|
drawChar(3, '8', true, WHITE);
|
||||||
|
displayShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawBlack() {
|
||||||
|
displayClear();
|
||||||
|
displayShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawSequence() {
|
||||||
|
for (int x = 0; x < 3; ++x) {
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
drawWhite();
|
||||||
|
delay(100);
|
||||||
|
drawBlack();
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
drawDashes();
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setState(State newState) {
|
||||||
|
if (state == newState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = newState;
|
||||||
|
const char *name;
|
||||||
|
switch (state) {
|
||||||
|
case CONFIG:
|
||||||
|
rest = configMillis;
|
||||||
|
name = "CONFIG";
|
||||||
|
break;
|
||||||
|
case READY:
|
||||||
|
rest = configMillis;
|
||||||
|
name = "READY";
|
||||||
|
break;
|
||||||
|
case RUNNING:
|
||||||
|
last = millis();
|
||||||
|
name = "RUNNING";
|
||||||
|
break;
|
||||||
|
case PAUSED:
|
||||||
|
name = "PAUSED";
|
||||||
|
break;
|
||||||
|
case END:
|
||||||
|
name = "END";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
name = "[???]";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.printf("Mode: %s\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void countdownUpdate() {
|
||||||
|
switch (state) {
|
||||||
|
case CONFIG:
|
||||||
|
drawMillis(rest, MAGENTA);
|
||||||
|
break;
|
||||||
|
case READY:
|
||||||
|
drawMillis(rest, GREEN);
|
||||||
|
break;
|
||||||
|
case RUNNING: {
|
||||||
|
if (rest > 0) {
|
||||||
|
const auto color = rest >= 60000 ? WHITE : (rest >= 10000 ? YELLOW : RED);
|
||||||
|
drawMillis(rest, color);
|
||||||
|
} else {
|
||||||
|
drawSequence();
|
||||||
|
setState(END);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PAUSED:
|
||||||
|
drawMillis(rest, BLUE);
|
||||||
|
break;
|
||||||
|
case END:
|
||||||
|
drawDashes();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void countdownSetup() {
|
||||||
|
setState(READY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void countdownLoop() {
|
||||||
|
updateTime();
|
||||||
|
countdownUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void countdownLongPress() {
|
||||||
|
switch (state) {
|
||||||
|
case CONFIG:
|
||||||
|
setState(READY);
|
||||||
|
break;
|
||||||
|
case READY:
|
||||||
|
case END:
|
||||||
|
setState(CONFIG);
|
||||||
|
break;
|
||||||
|
case RUNNING:
|
||||||
|
case PAUSED:
|
||||||
|
setState(READY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void countdownShortPress() {
|
||||||
|
switch (state) {
|
||||||
|
case CONFIG: {
|
||||||
|
auto seconds = (configMillis / 30000) * 30 % (15 * 60) + 30;
|
||||||
|
configMillis = seconds * 1000;
|
||||||
|
rest = configMillis;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RUNNING:
|
||||||
|
setState(PAUSED);
|
||||||
|
break;
|
||||||
|
case READY:
|
||||||
|
case PAUSED:
|
||||||
|
setState(RUNNING);
|
||||||
|
break;
|
||||||
|
case END:
|
||||||
|
setState(READY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/countdown.h
Normal file
12
src/countdown.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef WS2812B_COUNTDOWN_H
|
||||||
|
#define WS2812B_COUNTDOWN_H
|
||||||
|
|
||||||
|
void countdownSetup();
|
||||||
|
|
||||||
|
void countdownLoop();
|
||||||
|
|
||||||
|
void countdownLongPress();
|
||||||
|
|
||||||
|
void countdownShortPress();
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,11 +1,18 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
|
#define DIGIT_COUNT 4
|
||||||
#define SEGMENTS_PER_DIGIT 7
|
#define SEGMENTS_PER_DIGIT 7
|
||||||
#define LEDS_PER_SEGMENT 6
|
#define LEDS_PER_SEGMENT 6
|
||||||
#define LEDS_PER_DOT 2
|
#define LEDS_PER_DOT 2
|
||||||
#define DOT_COUNT 4
|
#define DOT_COUNT 4
|
||||||
#define DOTS_AFTER_DIGIT 1
|
#define DOTS_AFTER_DIGIT 1
|
||||||
|
|
||||||
|
#define GPIO 26
|
||||||
|
#define PIXELS (DIGIT_COUNT * SEGMENTS_PER_DIGIT * LEDS_PER_SEGMENT + DOT_COUNT * LEDS_PER_DOT)
|
||||||
|
#define BRIGHTNESS 32
|
||||||
|
|
||||||
|
Adafruit_NeoPixel pixels(PIXELS, GPIO, NEO_GRB + NEO_KHZ800);
|
||||||
|
|
||||||
uint8_t CHARS[] = {
|
uint8_t CHARS[] = {
|
||||||
0b11111100, // 0
|
0b11111100, // 0
|
||||||
0b00110000, // 1
|
0b00110000, // 1
|
||||||
@ -50,11 +57,26 @@ uint8_t mapChar(char c) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawChar(Adafruit_NeoPixel& pixels, int digit, char c, const Color& color) {
|
void displaySetup() {
|
||||||
drawChar(pixels, digit, c, true, color);
|
pixels.begin();
|
||||||
|
pixels.setBrightness(BRIGHTNESS);
|
||||||
|
pixels.clear();
|
||||||
|
pixels.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawChar(Adafruit_NeoPixel& pixels, int digit, char c, bool showIfZero, const Color& color) {
|
void displayClear() {
|
||||||
|
pixels.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayShow() {
|
||||||
|
pixels.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawChar(int digit, char c, const Color& color) {
|
||||||
|
drawChar(digit, c, true, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawChar(int digit, char c, bool showIfZero, const Color& color) {
|
||||||
if (c == '0' && !showIfZero) {
|
if (c == '0' && !showIfZero) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -75,55 +97,57 @@ void drawChar(Adafruit_NeoPixel& pixels, int digit, char c, bool showIfZero, con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawNumber(Adafruit_NeoPixel& pixels, int digit, int number, bool zero, const Color& color) {
|
void drawNumber(int digit, int number, bool zero, const Color& color) {
|
||||||
const char ten = '0' + (number / 10 % 10);
|
const char ten = '0' + (number / 10 % 10);
|
||||||
const char one = '0' + (number % 10);
|
const char one = '0' + (number % 10);
|
||||||
drawChar(pixels, digit + 0, ten, zero, color);
|
drawChar(digit + 0, ten, zero, color);
|
||||||
drawChar(pixels, digit + 1, one, true, color);
|
drawChar(digit + 1, one, true, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawDot(Adafruit_NeoPixel& pixels, int dot, const Color& c) {
|
void drawDot(int dot, const Color& c) {
|
||||||
int index = 2 * SEGMENTS_PER_DIGIT * LEDS_PER_SEGMENT + dot * LEDS_PER_DOT;
|
int index = 2 * SEGMENTS_PER_DIGIT * LEDS_PER_SEGMENT + dot * LEDS_PER_DOT;
|
||||||
pixels.setPixelColor(index + 0, c.r, c.g, c.b);
|
pixels.setPixelColor(index + 0, c.r, c.g, c.b);
|
||||||
pixels.setPixelColor(index + 1, c.r, c.g, c.b);
|
pixels.setPixelColor(index + 1, c.r, c.g, c.b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawDots(Adafruit_NeoPixel& pixels, const Color& bottom, const Color& middleBottom, const Color& middleTop, const Color& top) {
|
void drawDots(const Color& bottom, const Color& middleBottom, const Color& middleTop, const Color& top) {
|
||||||
drawDot(pixels, 0, bottom);
|
drawDot(0, bottom);
|
||||||
drawDot(pixels, 1, middleBottom);
|
drawDot(1, middleBottom);
|
||||||
drawDot(pixels, 2, middleTop);
|
drawDot(2, middleTop);
|
||||||
drawDot(pixels, 3, top);
|
drawDot(3, top);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawMillis(Adafruit_NeoPixel& pixels, const unsigned long millisTotal, const Color& color) {
|
void drawMillisDeci(unsigned long millisTotal, const Color& color) {
|
||||||
const auto secondsTotal = millisTotal / 1000;
|
const auto secondsTotal = millisTotal / 1000;
|
||||||
const auto minutes = (int) secondsTotal / 60;
|
const auto minutes = (int) secondsTotal / 60;
|
||||||
const auto seconds = (int) secondsTotal % 60;
|
const auto seconds = (int) secondsTotal % 60;
|
||||||
|
|
||||||
if (minutes > 0) {
|
|
||||||
static auto lastSeconds = -1;
|
|
||||||
if (lastSeconds == seconds) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastSeconds = seconds;
|
|
||||||
|
|
||||||
Serial.printf("%2d:%02d\n", minutes, seconds);
|
|
||||||
|
|
||||||
pixels.clear();
|
|
||||||
drawNumber(pixels, 0, minutes, false, color);
|
|
||||||
drawDots(pixels, BLACK, color, color, BLACK);
|
|
||||||
drawNumber(pixels, 2, seconds, true, color);
|
|
||||||
pixels.show();
|
|
||||||
} else {
|
|
||||||
const auto deci = (int) millisTotal / 100 % 10;
|
const auto deci = (int) millisTotal / 100 % 10;
|
||||||
Serial.printf("%2d.%02d\n", seconds, deci);
|
|
||||||
|
|
||||||
pixels.clear();
|
pixels.clear();
|
||||||
|
if (minutes > 0) {
|
||||||
|
drawNumber(0, minutes, false, color);
|
||||||
|
drawDots(BLACK, color, color, BLACK);
|
||||||
|
drawNumber(2, seconds, true, color);
|
||||||
|
} else {
|
||||||
if (seconds > 0) {
|
if (seconds > 0) {
|
||||||
drawNumber(pixels, 0, seconds, false, color);
|
drawNumber(0, seconds, false, color);
|
||||||
drawDots(pixels, color, BLACK, BLACK, BLACK);
|
drawDots(color, BLACK, BLACK, BLACK);
|
||||||
|
}
|
||||||
|
drawChar(2, '0' + deci, true, color);
|
||||||
}
|
}
|
||||||
drawChar(pixels, 2, '0' + deci, true, color);
|
|
||||||
pixels.show();
|
pixels.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drawMillis(unsigned long millisTotal, const Color& color) {
|
||||||
|
const auto secondsTotal = (unsigned long) ceil(millisTotal / 1000.0);
|
||||||
|
const auto minutes = (int) secondsTotal / 60;
|
||||||
|
const auto seconds = (int) secondsTotal % 60;
|
||||||
|
|
||||||
|
pixels.clear();
|
||||||
|
if (minutes > 0) {
|
||||||
|
drawNumber(0, minutes, false, color);
|
||||||
|
drawDots(BLACK, color, color, BLACK);
|
||||||
|
}
|
||||||
|
drawNumber(2, seconds, minutes > 0, color);
|
||||||
|
pixels.show();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,14 +5,22 @@
|
|||||||
|
|
||||||
#include "Color.h"
|
#include "Color.h"
|
||||||
|
|
||||||
void drawChar(Adafruit_NeoPixel& pixels, int digit, char c, const Color& color);
|
void displaySetup();
|
||||||
|
|
||||||
void drawChar(Adafruit_NeoPixel& pixels, int digit, char c, bool showIfZero, const Color& color);
|
void displayClear();
|
||||||
|
|
||||||
void drawNumber(Adafruit_NeoPixel& pixels, int digit, int number, bool zero, const Color& color);
|
void displayShow();
|
||||||
|
|
||||||
void drawDots(Adafruit_NeoPixel& pixels, const Color& bottom, const Color& middleBottom, const Color& middleTop, const Color& top);
|
void drawChar(int digit, char c, const Color& color);
|
||||||
|
|
||||||
void drawMillis(Adafruit_NeoPixel& pixels, unsigned long millisTotal, const Color& color);
|
void drawChar(int digit, char c, bool showIfZero, const Color& color);
|
||||||
|
|
||||||
|
void drawNumber(int digit, int number, bool zero, const Color& color);
|
||||||
|
|
||||||
|
void drawDots(const Color& bottom, const Color& middleBottom, const Color& middleTop, const Color& top);
|
||||||
|
|
||||||
|
void drawMillisDeci(unsigned long millisTotal, const Color& color);
|
||||||
|
|
||||||
|
void drawMillis(unsigned long millisTotal, const Color& color);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
90
src/main.cpp
90
src/main.cpp
@ -1,93 +1,17 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include "button.h"
|
||||||
#define GPIO 26
|
#include "countdown.h"
|
||||||
#define PIXELS (4 * 7 * 6 + 4 * 4)
|
|
||||||
#define BRIGHTNESS 32
|
|
||||||
|
|
||||||
Adafruit_NeoPixel pixels(PIXELS, GPIO, NEO_GRB + NEO_KHZ800);
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
delay(500);
|
delay(500);
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
Serial.println("\n\n\nstartup");
|
Serial.println("\n\n\nstartup");
|
||||||
pixels.begin();
|
buttonSetup();
|
||||||
pixels.setBrightness(BRIGHTNESS);
|
displaySetup();
|
||||||
pixels.clear();
|
countdownSetup();
|
||||||
pixels.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
long configCountdownMillis = 6 * 60 * 1000;
|
|
||||||
|
|
||||||
long rest = configCountdownMillis;
|
|
||||||
|
|
||||||
unsigned long last = 0;
|
|
||||||
|
|
||||||
void updateTime() {
|
|
||||||
const auto now = max(1UL, millis());
|
|
||||||
if (last != 0) {
|
|
||||||
const auto diff = now - last;
|
|
||||||
rest -= (long) diff;
|
|
||||||
if (rest < 0) {
|
|
||||||
rest = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool running = true;
|
|
||||||
|
|
||||||
void dashes() {
|
|
||||||
pixels.clear();
|
|
||||||
drawChar(pixels, 0, '-', true, RED);
|
|
||||||
drawChar(pixels, 1, '-', true, RED);
|
|
||||||
drawChar(pixels, 2, '-', true, RED);
|
|
||||||
drawChar(pixels, 3, '-', true, RED);
|
|
||||||
pixels.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void white() {
|
|
||||||
pixels.clear();
|
|
||||||
drawChar(pixels, 0, '8', true, WHITE);
|
|
||||||
drawChar(pixels, 1, '8', true, WHITE);
|
|
||||||
drawDots(pixels, WHITE, WHITE, WHITE, WHITE);
|
|
||||||
drawChar(pixels, 2, '8', true, WHITE);
|
|
||||||
drawChar(pixels, 3, '8', true, WHITE);
|
|
||||||
pixels.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void black() {
|
|
||||||
pixels.clear();
|
|
||||||
pixels.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void endSequence() {
|
|
||||||
for (int x = 0; x < 3; ++x) {
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
|
||||||
white();
|
|
||||||
delay(100);
|
|
||||||
black();
|
|
||||||
delay(100);
|
|
||||||
}
|
|
||||||
dashes();
|
|
||||||
delay(500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void showTime() {
|
|
||||||
if (!running) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rest > 0) {
|
|
||||||
const auto color = rest >= 60000 ? WHITE : (rest >= 10000 ? YELLOW : RED);
|
|
||||||
drawMillis(pixels, rest, color);
|
|
||||||
} else {
|
|
||||||
running = false;
|
|
||||||
Serial.println("END");
|
|
||||||
endSequence();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
updateTime();
|
buttonLoop();
|
||||||
showTime();
|
countdownLoop();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user