/* reserved for two-in-one version
const byte ledPins[numLeds] = {2, 3, 4, 5};
const byte buttonPins[numLeds] = {7, 8, 9, 10};
*/
// forum.arduino.cc/t/dart-board-scoreboard-project-led-control/1437125
// https://wokwi.com/projects/459567665471256577
const byte numLeds = 4;
# define K16 16
const byte ledPins[numLeds] = {2, 3, 4, 5};
const byte buttonPins[numLeds] = {7, 8, 9, 10};
const unsigned long slowBlinkPeriod = 888;
const unsigned long fastBlinkPeriod = 444;
unsigned long lastSlowBlink;
unsigned long lastFastBlink;
bool slowBlinkPhase;
bool fastBlinkPhase;
unsigned long now;
enum LedState {
LED_OFF = 0,
LED_SLOW_BLINK,
LED_FAST_BLINK,
LED_ON
};
LedState ledStates[K16];
bool buttonState[K16];
void setup() {
setupButtonsLEDs();
setupMuxNeopixel();
}
void setupButtonsLEDs() {
for (byte i = 0; i < numLeds; i++) {
pinMode(ledPins[i], OUTPUT);
pinMode(buttonPins[i], INPUT_PULLUP);
}
}
void loop() {
now = millis();
blinker(); // maintains both slow and fast phase flags
// buttons and LEDs:
buttonsLEDsLoop();
// i/o expander and neopixels:
muxNeopixelLoop();
}
void blinker()
{
if (now - lastSlowBlink >= slowBlinkPeriod) {
for (byte i = 0; i < numLeds; ++i) {
if (ledStates[i] == LED_SLOW_BLINK) {
digitalWrite(ledPins[i], slowBlinkPhase ? LOW : HIGH);
}
}
slowBlinkPhase = !slowBlinkPhase;
lastSlowBlink = now;
}
if (now - lastFastBlink >= fastBlinkPeriod) {
for (byte i = 0; i < numLeds; ++i) {
if (ledStates[i] == LED_FAST_BLINK)
digitalWrite(ledPins[i], fastBlinkPhase ? LOW : HIGH);
}
fastBlinkPhase = !fastBlinkPhase;
lastFastBlink = now;
}
}
void buttonsLEDsLoop() {
// now = millis(); // yes it does
for (int i = 0; i < numLeds; ++i) {
bool pressed = false;
bool buttonReading = digitalRead(buttonPins[i]) == LOW; // true is closed, pressed, down whatever
if (buttonReading != buttonState[i]) { // is it different to previous value?
if (buttonReading) pressed = true; // then it just went down
buttonState[i] = buttonReading;
}
if (pressed)
switch (ledStates[i]) {
case LED_OFF:
ledStates[i] = LED_SLOW_BLINK;
break;
case LED_SLOW_BLINK:
ledStates[i] = LED_FAST_BLINK;
break;
case LED_FAST_BLINK:
ledStates[i] = LED_ON;
digitalWrite(ledPins[i], HIGH);
break;
case LED_ON:
ledStates[i] = LED_OFF;
digitalWrite(ledPins[i], LOW); //... seems like an idea
break;
default:
break;
}
}
for (int i = 0; i < numLeds; ++i) {
if (ledStates[i] == LED_SLOW_BLINK) digitalWrite(ledPins[i], slowBlinkPhase ? LOW : HIGH);
if (ledStates[i] == LED_FAST_BLINK) digitalWrite(ledPins[i], fastBlinkPhase ? LOW : HIGH);
}
delay(20); // cheerful poor man's debounce
}
// this is all mux/neopixel stuff
# include <Adafruit_NeoPixel.h>
# define PIN 6 // the pin
# define NPIXELS 16 // number of LEDs on strip
Adafruit_NeoPixel stab(NPIXELS, PIN, NEO_GRB + NEO_KHZ800);
const unsigned long offColor = 0x202020;
const unsigned long slowColor = 0xff0000;
const unsigned long fastColor = 0xffff00;
const unsigned long onColor = 0x00ff00;
const byte muxOutput = 12; // *input* for COM CD4067 output
# define NT 16 // up to... 16
# define RATE 177
void setupMuxNeopixel() {
Serial.begin(115200);
Serial.println("hi Mom!");
stab.begin();
stab.setPixelColor(0, 0xff0000);
stab.setPixelColor(1, 0x00ff00);
stab.setPixelColor(NPIXELS - 1, 0x0000ff);
stab.show();
delay(777);
DDRC |= 0xf; // A0 .. A3 outputs
pinMode(muxOutput, INPUT_PULLUP); // probably use a real resistor
}
bool lampState[16];
void muxNeopixelLoop() {
// now = millis(); // yes it does
// INPUT
static unsigned int lastButtons;
unsigned int buttons = inReader();
unsigned int acts = buttons & ~lastButtons;
lastButtons = buttons;
// PROCESS
for (byte ii = 0; ii < K16; ++ii) {
if (acts & 1)
switch (ledStates[ii]) {
case LED_OFF :
ledStates[ii] = LED_SLOW_BLINK;
break;
case LED_SLOW_BLINK :
ledStates[ii] = LED_FAST_BLINK;
break;
case LED_FAST_BLINK :
ledStates[ii] = LED_ON;
break;
case LED_ON :
ledStates[ii] = LED_OFF;
break;
}
acts >>= 1;
}
// OUTPUT
for (byte ii = 0; ii < K16; ii++)
switch (ledStates[ii]) {
case LED_OFF :
stab.setPixelColor(ii, offColor);
break;
case LED_SLOW_BLINK :
stab.setPixelColor(ii, slowBlinkPhase ? offColor : slowColor);
break;
case LED_FAST_BLINK :
stab.setPixelColor(ii, fastBlinkPhase ? offColor : fastColor);
break;
case LED_ON :
stab.setPixelColor(ii, onColor);
break;
}
stab.show();
}
// read 16 bits from the mux
// debounced here by not reading again too soon
unsigned int inReader()
{
static unsigned long lastTime;
static unsigned int lastReport;
unsigned int result = 0;
if (now - lastTime < 20) return lastReport;
lastTime = now;
for (byte ii = 0; ii < NT; ii++) {
PORTC &= 0xf0;
PORTC |= ii;
result >>= 1;
if (digitalRead(muxOutput) == LOW) result |= 0x8000; // pressed is LOW
}
lastReport = result;
return result;
}
/*
// poor man's logic probe
// setup
pinMode(13, OUTPUT);
pinMode(A5, INPUT_PULLUP);
// and loop
digitalWrite(13, digitalRead(A5));
// INPUT
unsigned int buttons = inReader();
static unsigned int lastButtons;
unsigned int acts = buttons & ~lastButtons;
lastButtons = buttons;
if (0) { // test mux, buttons and strip
unsigned int myActs = acts;
for (int ii = 0; ii < 16; ii++) {
if (myActs & 1) lampState[ii] = !lampState[ii];
stab.setPixelColor(ii, lampState[ii] ? 0xff0000 : 0x404040);
myActs >>= 1;
}
stab.show();
return;
}
*/