diff --git a/Debounce.cpp b/Debounce.cpp new file mode 100644 index 0000000..789afcf --- /dev/null +++ b/Debounce.cpp @@ -0,0 +1,63 @@ +/* + Debounce - v1.1 - November 19, 2014. + Arduino library for button debouncing. + Clearly based on the debounce example from the site: + http://arduino.cc/en/Tutorial/Debounce + Created by William Koch. + Released into the public domain. +*/ + +#include "Debounce.h" + +// Debounces an input pin. +// 50ms as default debounce delay. +Debounce::Debounce(byte button, boolean invert, boolean pullup) { + pinMode(button, pullup ? INPUT_PULLUP : INPUT); + _button = button; + _delay = 50; // default delay. + _state = _lastState = _reading = (invert ^ digitalRead(_button)); + _last = millis(); + _count = 0; + _invert = invert; +} + +// Debounces an input pin. +// Adjustable debounce delay. +Debounce::Debounce(byte button, unsigned long delay, boolean invert, boolean pullup) { + pinMode(button, pullup ? INPUT_PULLUP : INPUT); + _button = button; + _delay = delay; // user defined delay. + _state = _lastState = _reading = (invert ^ digitalRead(_button)); + _last = millis(); + _count = 0; + _invert = invert; +} + +byte Debounce::read() { + _reading = _invert ^ digitalRead(_button); // get current button state. + if (_reading != _lastState) { // detect edge: current vs last state: + _last = millis(); // store millis if change was detected. + _wait = true; // Just to avoid calling millis() unnecessarily. + } + + if (_wait && (millis() - _last) > _delay) { // after the delay has passed: + if (_reading != _state) { // if the change wasn't stored yet: + _count++; // Stores each change. + _state = _reading; // store the button state change. + _wait = false; + } + } + _lastState = _reading; + return _state; +} + +// Returns the number of times the button was pressed. +unsigned int Debounce::count() { + Debounce::read(); + return _count / 2; // Counts only a full press + release. +} + +void Debounce::resetCount() { + _count = 0; + return; +} \ No newline at end of file diff --git a/Debounce.h b/Debounce.h new file mode 100644 index 0000000..4701744 --- /dev/null +++ b/Debounce.h @@ -0,0 +1,37 @@ +/* + Debounce - v1.1 - November 19, 2014. + Arduino library for button debouncing. + Clearly based on the debounce example from the site: + http://arduino.cc/en/Tutorial/Debounce + Created by William Koch. + Released into the public domain. +*/ + +#ifndef Debounce_h +#define Debounce_h + +#include "Arduino.h" + +class Debounce +{ +public: + // Debounces an input pin. + // 50ms as default debounce delay. + Debounce(byte button, boolean invert = false, boolean pullup = false); + + // Debounces an input pin. + // Adjustable debounce delay. + Debounce(byte button, unsigned long delay, boolean invert = false, boolean pullup = false); + + byte read(); // returns the debounced button state: LOW or HIGH. + unsigned int count(); // Returns the number of times the button was pressed. + void resetCount(); // Resets the button count number. +private: + byte _button, _state, _lastState, _reading; + unsigned int _count; + unsigned long _delay, _last; + boolean _wait; + boolean _invert; +}; + +#endif \ No newline at end of file diff --git a/bounce2.cpp b/bounce2.cpp deleted file mode 100644 index d175805..0000000 --- a/bounce2.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// Please read Bounce2.h for information about the liscence and authors - - -#include "bounce2.h" - - - - -Bounce::Bounce() - : previous_millis(0) - , interval_millis(10) - , state(0) - , pin(0) -{} - -void Bounce::attach(int pin) { - this->pin = pin; - state = 0; - if (readCurrentState()) { - setStateFlag(DEBOUNCED_STATE | UNSTABLE_STATE); - } -#ifdef BOUNCE_LOCK_OUT - previous_millis = 0; -#else - previous_millis = millis(); -#endif -} - -void Bounce::attach(int pin, int mode){ - setPinMode(pin, mode); - this->attach(pin); -} - -void Bounce::interval(uint16_t interval_millis) -{ - this->interval_millis = interval_millis; -} - -bool Bounce::update() -{ - - unsetStateFlag(CHANGED_STATE); -#ifdef BOUNCE_LOCK_OUT - - // Ignore everything if we are locked out - if (millis() - previous_millis >= interval_millis) { - bool currentState = readCurrentState(); - if ( currentState != getStateFlag(DEBOUNCED_STATE) ) { - previous_millis = millis(); - changeState(); - } - } - - -#elif defined BOUNCE_WITH_PROMPT_DETECTION - // Read the state of the switch port into a temporary variable. - bool readState = readCurrentState(); - - - if ( readState != getStateFlag(DEBOUNCED_STATE) ) { - // We have seen a change from the current button state. - - if ( millis() - previous_millis >= interval_millis ) { - // We have passed the time threshold, so a new change of state is allowed. - // set the STATE_CHANGED flag and the new DEBOUNCED_STATE. - // This will be prompt as long as there has been greater than interval_misllis ms since last change of input. - // Otherwise debounced state will not change again until bouncing is stable for the timeout period. - changeState(); - } - } - - // If the readState is different from previous readState, reset the debounce timer - as input is still unstable - // and we want to prevent new button state changes until the previous one has remained stable for the timeout. - if ( readState != getStateFlag(UNSTABLE_STATE) ) { - // Update Unstable Bit to macth readState - toggleStateFlag(UNSTABLE_STATE); - previous_millis = millis(); - } - - -#else - // Read the state of the switch in a temporary variable. - bool currentState = readCurrentState(); - - - // If the reading is different from last reading, reset the debounce counter - if ( currentState != getStateFlag(UNSTABLE_STATE) ) { - previous_millis = millis(); - toggleStateFlag(UNSTABLE_STATE); - } else - if ( millis() - previous_millis >= interval_millis ) { - // We have passed the threshold time, so the input is now stable - // If it is different from last state, set the STATE_CHANGED flag - if (currentState != getStateFlag(DEBOUNCED_STATE) ) { - previous_millis = millis(); - - - changeState(); - } - } - - -#endif - - return changed(); - -} - -// WIP HELD -unsigned long Bounce::previousDuration() { - return durationOfPreviousState; -} - -unsigned long Bounce::duration() { - return (millis() - stateChangeLastTime); -} - -inline void Bounce::changeState() { - toggleStateFlag(DEBOUNCED_STATE); - setStateFlag(CHANGED_STATE) ; - durationOfPreviousState = millis() - stateChangeLastTime; - stateChangeLastTime = millis(); -} - -bool Bounce::read() -{ - return getStateFlag(DEBOUNCED_STATE); -} - -bool Bounce::rose() -{ - return getStateFlag(DEBOUNCED_STATE) && getStateFlag(CHANGED_STATE); -} - -bool Bounce::fell() -{ - return !getStateFlag(DEBOUNCED_STATE) && getStateFlag(CHANGED_STATE); -} diff --git a/bounce2.h b/bounce2.h deleted file mode 100644 index 14d4c66..0000000 --- a/bounce2.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - The MIT License (MIT) - - Copyright (c) 2013 thomasfredericks - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * - Main code by Thomas O Fredericks (tof@t-o-f.info) - Previous contributions by Eric Lowry, Jim Schimpf and Tom Harkaway - * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/** - * @todo Make Bounce2 more abstract. Split it from the hardware layer. - * @body Remove deboucing code from Bounce2 and make a new Debounce class from that code. - * Bounce2 should extend Debounce. - */ - - -#ifndef Bounce2_h -#define Bounce2_h - -#if defined(ARDUINO) && ARDUINO >= 100 -#include "Arduino.h" -#else -#include "WProgram.h" -#endif - -// Uncomment the following line for "LOCK-OUT" debounce method -//#define BOUNCE_LOCK_OUT - -// Uncomment the following line for "BOUNCE_WITH_PROMPT_DETECTION" debounce method -//#define BOUNCE_WITH_PROMPT_DETECTION - -#include - -/** - @example bounce.ino - Simple example of the Bounce library that switches the debug LED when a button is pressed. -*/ - -/** - @example change.ino - This example toggles the debug LED (pin 13) on or off when a button on pin 2 is pressed. -*/ - -/** - @example bounce_multiple.ino - Detect the falling edge of multiple buttons. Eight buttons with internal pullups. Toggles a - LED when any button is pressed. Buttons on pins 2,3,4,5,6,7,8,9 -*/ - -/** - @example bounce2buttons.ino - Example of two instances of the Bounce class that switches the debug LED when either one of - the two buttons is pressed. - */ - -static const uint8_t DEBOUNCED_STATE = 0b00000001; -static const uint8_t UNSTABLE_STATE = 0b00000010; -static const uint8_t CHANGED_STATE = 0b00000100; - -/** - The Bounce class. - */ -class Bounce -{ - public: - -/*! - @brief Create an instance of the Bounce class. - - @code - - // Create an instance of the Bounce class. - Bounce() button; - - @endcode -*/ - Bounce(); - - -/*! - @brief Attach to a pin and sets that pin's mode (INPUT, INPUT_PULLUP or OUTPUT). - - @param pin - The pin that is to be debounced. - @param mode - A valid Arduino pin mode (INPUT, INPUT_PULLUP or OUTPUT). -*/ - void attach(int pin, int mode); - - /** - Attach to a pin for advanced users. Only attach the pin this way once you have previously - set it up. Otherwise use attach(int pin, int mode). - */ - void attach(int pin); - - - /** - @brief Sets the debounce interval in milliseconds. - - @param interval_millis - The interval time in milliseconds. - - */ - void interval(uint16_t interval_millis); - - -/*! - @brief Updates the pin's state. - - Because Bounce does not use interrupts, you have to "update" the object before reading its - value and it has to be done as often as possible (that means to include it in your loop()). - Only call update() once per loop(). - - @return True if the pin changed state. -*/ - - bool update(); - - /** - @brief Returns the pin's state (HIGH or LOW). - - @return HIGH or LOW. - */ - bool read(); - - /** - @brief Returns true if pin signal transitions from high to low. - */ - bool fell(); - - /** - @brief Returns true if pin signal transitions from low to high. - */ - bool rose(); - - - /** - @brief Deprecated (i.e. do not use). Included for partial compatibility for programs written - with Bounce version 1 - */ - bool risingEdge() { return rose(); } - /** - @brief Deprecated (i.e. do not use). Included for partial compatibility for programs written - with Bounce version 1 - */ - bool fallingEdge() { return fell(); } - /** - @brief Deprecated (i.e. do not use). Included for partial compatibility for programs written - with Bounce version 1 - */ - Bounce(uint8_t pin, unsigned long interval_millis ) : Bounce() { - attach(pin); - interval(interval_millis); - } - - /** - @brief Returns the duration in milliseconds of the current state. - - Is reset to 0 once the pin rises ( rose() ) or falls ( fell() ). - - @return The duration in milliseconds (unsigned long) of the current state. - */ - - unsigned long duration(); - - /** - @brief Returns the duration in milliseconds of the previous state. - - Takes the values of duration() once the pin changes state. - - @return The duration in milliseconds (unsigned long) of the previous state. - */ - unsigned long previousDuration(); - - protected: - unsigned long previous_millis; - uint16_t interval_millis; - uint8_t state; - uint8_t pin; - unsigned long stateChangeLastTime; - unsigned long durationOfPreviousState; - virtual bool readCurrentState() { return digitalRead(pin); } - virtual void setPinMode(int pin, int mode) { -#if defined(ARDUINO_ARCH_STM32F1) - pinMode(pin, (WiringPinMode)mode); -#else - pinMode(pin, mode); -#endif - } - - private: - inline void changeState(); - inline void setStateFlag(const uint8_t flag) {state |= flag;} - inline void unsetStateFlag(const uint8_t flag) {state &= ~flag;} - inline void toggleStateFlag(const uint8_t flag) {state ^= flag;} - inline bool getStateFlag(const uint8_t flag) {return((state & flag) != 0);} - - public: - bool changed( ) { return getStateFlag(CHANGED_STATE); } - -}; - -#endif diff --git a/holiday-lights.ino b/holiday-lights.ino index 74ecd9c..9c7862a 100644 --- a/holiday-lights.ino +++ b/holiday-lights.ino @@ -3,7 +3,7 @@ #endif #include -#include "bounce2.h" +#include "Debounce.h" #include "durations.h" #include "morse.h" #include "pulse.h" @@ -74,34 +74,32 @@ const char *message = ( ); -// These colors mirror pretty closely some cheapo LED lights we have -const uint32_t colors[] = { - 0xdd4400, // Yellow - 0xff0000, // Red - 0xdd2200, // Amber - 0x004400, // Green - - 0xdd4400, // Yellow - 0xff0000, // Red - 0xdd2200, // Amber - 0x880044, // Purple - - 0xdd4400, // Yellow - 0xff0000, // Red - 0xdd2200, // Amber - 0x000088, // Blue -}; -const int ncolors = sizeof(colors) / sizeof(*colors); - CRGB leds[NUM_LEDS]; -Bounce button; +Debounce button(BUTTON_PIN, false, true); void setup() { FastLED.addLeds(leds, NUM_LEDS); - button.attach(BUTTON_PIN, INPUT_PULLUP); + FastLED.setBrightness(52); pinMode(LED_BUILTIN, OUTPUT); } +uint8_t RandomHue() { + switch (random(12)) { + case 0 ... 2: + return 52; // reddish yellow + case 3 ... 5: + return HUE_RED; + case 6 ... 8: + return 28; // reddish orange + case 9: + return HUE_BLUE; + case 10: + return HUE_GREEN; + case 11: + return 204; // reddish purple + } +} + Pulse mainPulse = Pulse(DELAY_MS); bool strandUpdate(bool white) { @@ -112,18 +110,19 @@ bool strandUpdate(bool white) { for (int group = 0; group < NUM_GROUPS; ++group) { int pos = (group * LEDS_PER_GROUP) + random(LEDS_PER_GROUP); if (random(100) < GROUP_UPDATE_PROBABILITY) { + uint8_t hue = 0; + uint8_t saturation = 255; + uint8_t value = 255; if (random(100) < ACTIVITY) { - uint32_t color; - if (white) { - color = WHITE; + saturation = 0; } else { - color = colors[random(ncolors)]; + hue = RandomHue(); } - leds[pos] = color; } else { - leds[pos] = 0; + value = 0; } + leds[pos] = CHSV(hue, saturation, value); group = (group + 1) % NUM_GROUPS; } } @@ -144,15 +143,17 @@ bool black() { bool morseUpdate() { static MorseEncoder enc; static Pulse pulse = Pulse(DIT_DURATION_MS); + bool ret = false; - leds[MORSE_PIXEL] = enc.Transmitting ? MORSE_COLOR : CRGB::Black; if (pulse.Ticked()) { if (!enc.Tick()) { enc.SetText(message); } - return true; + ret = true; } - return false; + leds[MORSE_PIXEL] = enc.Transmitting ? MORSE_COLOR : CRGB::Black; + + return ret; } bool millisUpdate() { @@ -164,13 +165,11 @@ bool millisUpdate() { } void loop() { - static bool white = false; + bool white = false; bool update = false; - button.update(); - if (button.fell()) { - white = !white; - } + button.read(); + white = (button.count() % 2 == 1); if (FOREVER || white || (millis() % SNOSSLOSS_DAY < ON_FOR)) { update |= strandUpdate(white);