├── .gitattributes ├── .gitignore ├── README.md ├── examples ├── multitask_example │ └── multitask_example.ino ├── on-off_stable │ └── on-off_stable.ino ├── rangeFinder │ └── rangeFinder.ino ├── switch_duration │ └── switch_duration.ino ├── switch_latch │ └── switch_latch.ino ├── switch_previousDuration │ └── switch_previousDuration.ino ├── switch_retrigger │ └── switch_retrigger.ino ├── variable_setOutputRange │ └── variable_setOutputRange.ino ├── variable_stable │ └── variable_stable.ino ├── velocity_MIDI │ └── velocity_MIDI.ino └── velocity_basic │ └── velocity_basic.ino ├── keywords.txt ├── library.properties └── src ├── Flicker.h ├── TouchSwitch.cpp ├── TouchSwitch.h ├── TouchVariable.cpp ├── TouchVariable.h ├── TouchVelocity.cpp └── TouchVelocity.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flicker 2.0.0 2 | ### A library for making capacitive touch easy to use. 3 | ###### by Josh Nishikawa 4 | ###### The "TouchSwitch" class was adapted from the Bounce library by: Thomas O Fredericks, Eric Lowry, Jim Schimpf and Tom Harkaway 5 | Includes all the functions found in the Bounce library, smoothes eratic values to make variable input more useful and includes functions for measuring velocity. 6 | ___ 7 | ### VERSION LOG: 8 | 2.0.0 9 | - Thresholds for TouchSwitch are now set more dynamically and updated when 10 | highest/lowest readings are updated. This better accommodates more setups 11 | regardless of quiescent readings or ranges between highest/lowest readings. 12 | 13 | - setThresholds() MUST be called during setup and requires two arguments: the lowest possible reading that detects your finger and the reading at which a the value should be returned (contact). Use rangeFinder.ino to find these values. 14 | - responsiveRead() is deprecated. Use read() instead. 15 | - Setting outLo and outHi in the constructor is deprecated. Just map the return 16 | value of read() in the sketch. 17 | 18 | 19 | 1.1.4 20 | - Added previousDuration() function that can be used on rising/falling edge to return the length of the input's previous state. 21 | - Added rose() and fell(). risingEdge() and fallingEdge() still work. 22 | - Now using bool data type where appropriate. 23 | 24 | 1.0.4 25 | - created a library.properties file 26 | - made the version number semver compliant (1.0.4 is the first official release) 27 | - moved source files into src/ 28 | 29 | 1.0.3 30 | - Fixed a bug that pushed the quiescent touchRead value above the 31 | offThreshold when using the ADC. 32 | 33 | 1.0.2 34 | - Fine tuned ON and OFF thresholds for TouchSwitch and TouchVariable 35 | 36 | 1.0.0 37 | - Changed "Flicker" to "TouchSwitch" ("Flicker" deprecated but still works) 38 | - Added an option to LATCH the state of a TouchSwitch. 39 | - Added interval() (still useful even if noise reduction isn't time-based) 40 | - Added the TouchVariable class for stable reading of ranges of input. 41 | - Added the TouchVelocity class for detecting velocity of changes in input. 42 | - Started keeping this version log. 43 | ___ 44 | This program is free software; you can redistribute it and/or modify 45 | it under the terms of the GNU General Public License as published by 46 | the Free Software Foundation; either version 2 of the License, or 47 | (at your option) any later version. 48 | 49 | This program is distributed in the hope that it will be useful, 50 | but WITHOUT ANY WARRANTY; without even the implied warranty of 51 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 52 | GNU General Public License for more details. 53 | 54 | You should have received a copy of the GNU General Public License 55 | along with this program; if not, write to the Free Software 56 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 57 | MA 02110-1301, USA. 58 | -------------------------------------------------------------------------------- /examples/multitask_example/multitask_example.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // The input latches ON/OFF if touched more than 1/2 second. 4 | // While it's ON, the LED will toggle ON and OFF. 5 | // Also, a variable reading is taken from the same input, 6 | // mapped to a range of 0~1023 and printed to serial. 7 | 8 | const uint8_t touchPin = 0; // CHOOSE A TOUCH PIN 9 | const uint8_t ledPin = 13; 10 | bool ledState = false; 11 | int preVal = 0; 12 | TouchSwitch mySwitch(touchPin, LATCH); 13 | TouchVariable myVariable(touchPin, 0, 1023); 14 | 15 | void setup(){ 16 | Serial.begin(9600); 17 | pinMode(ledPin,OUTPUT); 18 | 19 | // WARNING! if you setThreshold or setInputRange 20 | // with no arguments, the threshold or input range 21 | // is calculated based on a call to touchRead() 22 | // so DON'T touch the input during setup() 23 | mySwitch.setThreshold(); 24 | mySwitch.interval(500); 25 | myVariable.setInputRange(); 26 | } 27 | 28 | void loop(){ 29 | if (mySwitch.update()){ 30 | bool value = mySwitch.read(); 31 | if (value == HIGH){ 32 | mySwitch.retrigger(500); 33 | ledState = !ledState; 34 | } 35 | else {ledState = LOW; 36 | } 37 | digitalWrite(ledPin, ledState); 38 | } 39 | 40 | int newVal = myVariable.read(); 41 | if (newVal != preVal){ 42 | Serial.println(newVal); 43 | preVal = newVal; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /examples/on-off_stable/on-off_stable.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // If you hold your finger on the input, 4 | // something will happen. 5 | 6 | const uint8_t touchPin = 0; // CHOOSE A TOUCH PIN 7 | const uint8_t ledPin = 13; 8 | TouchSwitch myInput(touchPin); 9 | 10 | void setup() { 11 | Serial.begin(9600); 12 | pinMode(ledPin, OUTPUT); 13 | 14 | // WARNING! if you setThreshold with no argument, 15 | // the threshold is calculated based on a call to 16 | // touchRead() so DON'T touch the input during setup() 17 | myInput.setThreshold(); 18 | 19 | // Use rangeFinder.ino to find a specific threshold 20 | // Then replace '1200' and use the following line instead. 21 | // myInput.setThreshold(1200); 22 | } 23 | 24 | void loop() { 25 | myInput.update(); 26 | 27 | if (myInput.rose()){ 28 | Serial.println("rose"); 29 | } 30 | if (myInput.fell()){ 31 | Serial.println("fell"); 32 | } 33 | 34 | digitalWrite(ledPin, myInput.read()); 35 | } 36 | -------------------------------------------------------------------------------- /examples/rangeFinder/rangeFinder.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This is not an example for how to use this library. 3 | Rather, it's a utility to find a usable range and/or 4 | thresholds for your particular needs. Get the values 5 | printed in the serial monitor to use in other sketches. 6 | */ 7 | 8 | #include "Bounce2.h" 9 | 10 | int touchPin = 0; // Change to the TOUCH pin you want to use. 11 | int resetPin = 19; // you can set a pin to reset hi/lo 12 | Bounce reset = Bounce(resetPin, 50); 13 | int hi; 14 | 15 | void setReset(){ 16 | hi = touchRead(touchPin); 17 | Serial.print("High Touch: "); Serial.println(hi); 18 | } 19 | 20 | void setup(){ 21 | pinMode(resetPin, INPUT_PULLUP); 22 | setReset(); 23 | } 24 | 25 | void loop(){ 26 | reset.update(); 27 | if(reset.rose()){ 28 | setReset(); 29 | } 30 | 31 | int newVal = touchRead(touchPin); 32 | if (newVal > hi){ 33 | hi = newVal; 34 | Serial.print("High Touch: "); Serial.println(hi); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/switch_duration/switch_duration.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // If you hold your finger on the input 4 | // for long enough, something will happen. 5 | 6 | const uint8_t touchPin = 0; // CHOOSE A TOUCH PIN 7 | const uint8_t ledPin = 13; 8 | TouchSwitch myInput(touchPin); 9 | 10 | void setup() { 11 | pinMode(ledPin, OUTPUT); 12 | 13 | // WARNING! if you setThreshold with no argument, 14 | // the threshold is calculated based on a call to 15 | // touchRead() so DON'T touch the input during setup() 16 | myInput.setThreshold(); 17 | 18 | // Use rangeFinder.ino to find a specific threshold 19 | // Then replace '1200' and use the following line instead. 20 | // myInput.setThreshold(1200); 21 | 22 | myInput.interval(300); // How long to hold before response? 23 | } 24 | 25 | void loop() { 26 | myInput.update(); 27 | digitalWrite(ledPin, myInput.read()); 28 | } 29 | -------------------------------------------------------------------------------- /examples/switch_latch/switch_latch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // The input goes on when touched 4 | // and off when touched again. 5 | 6 | byte touchPin = 0; // CHOOSE A TOUCH PIN 7 | byte ledPin = 13; 8 | 9 | // MOMENTARY (the default) or LATCH can be specified 10 | TouchSwitch myInput(touchPin, LATCH); 11 | 12 | void setup() { 13 | pinMode(ledPin, OUTPUT); 14 | 15 | // WARNING! if you setThreshold with no argument, 16 | // the threshold is calculated based on a call to 17 | // touchRead() so DON'T touch the input during setup() 18 | myInput.setThreshold(); 19 | } 20 | 21 | void loop(){ 22 | myInput.update(); 23 | digitalWrite(ledPin, myInput.read()); 24 | } 25 | -------------------------------------------------------------------------------- /examples/switch_previousDuration/switch_previousDuration.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // This will tell you how long the input stayed in its PREVIOUS state. 4 | // It may be useful to call this within rose() or fell(). 5 | 6 | const uint8_t touchPin = 0; // CHOOSE A TOUCH PIN 7 | const uint8_t ledPin = 13; 8 | TouchSwitch myInput(touchPin); 9 | 10 | void setup() { 11 | pinMode(ledPin, OUTPUT); 12 | 13 | // WARNING! if you setThreshold with no argument, 14 | // the threshold is calculated based on a call to 15 | // touchRead() so DON'T touch the input during setup() 16 | myInput.setThreshold(); 17 | } 18 | 19 | void loop() { 20 | myInput.update(); 21 | 22 | if (myInput.fell()){ 23 | // After the input was released, print how long it was held. 24 | Serial.println( myInput.previousDuration() ); 25 | } 26 | 27 | digitalWrite(ledPin, myInput.read()); 28 | } 29 | -------------------------------------------------------------------------------- /examples/switch_retrigger/switch_retrigger.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // As long as the input is held, 4 | // it will be triggered repeatedly. 5 | 6 | const uint8_t touchPin = 0; // CHOOSE A TOUCH PIN 7 | const uint8_t ledPin = 13; 8 | bool ledState = false; 9 | TouchSwitch myInput(touchPin); 10 | 11 | void setup(){ 12 | pinMode(ledPin,OUTPUT); 13 | 14 | // WARNING! if you setThreshold with no argument, 15 | // the threshold is calculated based on a call to 16 | // touchRead() so DON'T touch the input during setup() 17 | myInput.setThreshold(); 18 | } 19 | 20 | void loop(){ 21 | if (myInput.update()){ 22 | if (myInput.read()){ 23 | myInput.retrigger(500); 24 | ledState = !ledState; 25 | } 26 | else {ledState = LOW; 27 | } 28 | digitalWrite(ledPin, ledState); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/variable_setOutputRange/variable_setOutputRange.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Map the variable touuch input to a specific range. 4 | // Examples: 0~1023 to emulate analog; or 0~127 for MIDI. 5 | 6 | byte touchPin = 0; // CHOOSE A TOUCH PIN 7 | int preVal; 8 | TouchVariable myInput(touchPin); 9 | 10 | void setup() { 11 | Serial.begin(9600); 12 | 13 | // WARNING! if you setInputRange with no argument, 14 | // the input range is calculated based on a call to 15 | // touchRead() so DON'T touch the input during setup() 16 | myInput.setInputRange(); 17 | myInput.setOutputRange(0, 1023); // 10-bit analog 18 | } 19 | 20 | void loop(){ 21 | int newVal = myInput.read(); 22 | if (newVal != preVal){ 23 | Serial.print(0); Serial.print(" "); 24 | Serial.print(1023); Serial.print(" "); 25 | Serial.println(newVal); 26 | preVal = newVal; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/variable_stable/variable_stable.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // This reads a touch input and prints a new 4 | // value only when the signal is biased enough. 5 | // The larger the change, the more immediate the response. 6 | 7 | byte touchPin = 0; // CHOOSE A TOUCH PIN 8 | byte ledPin = 13; 9 | int preVal; 10 | TouchVariable myInput(touchPin); 11 | 12 | void setup() { 13 | Serial.begin(9600); 14 | 15 | // WARNING! if you setInputRange with no argument, 16 | // the input range is calculated based on a call to 17 | // touchRead() so DON'T touch the input during setup() 18 | myInput.setInputRange(); 19 | } 20 | 21 | void loop(){ 22 | int newVal = myInput.read(); 23 | if (newVal != preVal){ 24 | Serial.print(myInput.inLo); Serial.print(" "); 25 | Serial.print(myInput.inHi); Serial.print(" "); 26 | Serial.println(newVal); 27 | preVal = newVal; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/velocity_MIDI/velocity_MIDI.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* WARNING! This example is useless if you haven't used the velocity_basic 4 | example to determine the fastest and slowest readings that you want to map 5 | to MIDI velocities. Once you have those numbers, enter them here.*/ 6 | int slowest = 2200; 7 | int fastest = 550; 8 | 9 | byte touchPin = 0; // CHOOSE A TOUCH PIN 10 | int noteNumber = 38; // CHOOSE A NOTE TO PLAY 11 | 12 | TouchVelocity myInput(touchPin); 13 | 14 | void setup() { 15 | // WARNING! You must pass two arguments to setThresholds() 16 | // Use the rangeFinder example to get a reading with your finger 1mm above the 17 | // input and another reading with your finger lightly touching the input. 18 | // You will not likely be able to use these values (900, 1250) as is. 19 | myInput.setThresholds(900, 1250); 20 | } 21 | 22 | void loop(){ 23 | int velocity = myInput.read(); 24 | if (velocity >= 1){ 25 | velocity = map(velocity, slowest, fastest, 1, 127); 26 | velocity = constrain(velocity, 1, 127); 27 | usbMIDI.sendNoteOn(noteNumber, velocity, 0); 28 | } 29 | if (myInput.fell()){ 30 | usbMIDI.sendNoteOff(noteNumber, 0, 0); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/velocity_basic/velocity_basic.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* This determines the interval between the time 4 | your finger is detected hovering over the input 5 | and the time it makes contact with the input. 6 | The LED lights when your finger goes below the 7 | 'hover' threshold to act as a 'ready' light.*/ 8 | 9 | byte touchPin = 0; // CHOOSE A TOUCH PIN 10 | byte LED = 13; 11 | TouchVelocity myInput(touchPin); 12 | 13 | void setup() { 14 | pinMode(LED, OUTPUT); 15 | 16 | // WARNING! You must pass two arguments to setThresholds() 17 | // Use the rangeFinder example to get a reading with your finger 1mm above the 18 | // input and another reading with your finger lightly touching the input. 19 | // You will not likely be able to use these values (900, 1250) as is. 20 | myInput.setThresholds(900, 1250); 21 | 22 | digitalWrite(LED, HIGH); 23 | } 24 | 25 | void loop(){ 26 | int velocity = myInput.read(); 27 | if (myInput.fell()){ 28 | digitalWrite(LED, HIGH); 29 | } 30 | if (myInput.rose()){ 31 | digitalWrite(LED, LOW); 32 | } 33 | if (velocity >= 1){ 34 | Serial.println(velocity); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | Flicker KEYWORD1 2 | //////////////////// 3 | TouchSwitch KEYWORD1 4 | 5 | setThreshold KEYWORD2 6 | update KEYWORD2 7 | read KEYWORD2 8 | risingEdge KEYWORD2 9 | fallingEdge KEYWORD2 10 | duration KEYWORD2 11 | retrigger KEYWORD2 12 | interval KEYWORD2 13 | 14 | LATCH LITERAL1 15 | MOMENTARY LITERAL1 16 | 17 | //////////////////// 18 | TouchVariable KEYWORD1 19 | 20 | setInputRange KEYWORD2 21 | setOutputRange KEYWORD2 22 | setNR KEYWORD2 23 | read KEYWORD2 24 | 25 | //////////////////// 26 | TouchVelocity KEYWORD1 27 | 28 | responsiveRead KEYWORD2 29 | 30 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Flicker 2 | version=2.0.0 3 | author=Josh Nishikawa 4 | maintainer=Josh Nishikawa 5 | sentence=A library for making capacitive touch easy to use. 6 | paragraph=Includes all the functions found in the Bounce library, smoothes eratic values to make variable input more useful and includes a class for measuring velocity. 7 | category=Sensors 8 | url=https://github.com/joshnishikawa/Flicker 9 | architectures=avr 10 | -------------------------------------------------------------------------------- /src/Flicker.h: -------------------------------------------------------------------------------- 1 | #ifndef Flicker_h 2 | #define Flicker_h 3 | 4 | #include "Arduino.h" 5 | #include "TouchSwitch.h" 6 | #include "TouchVariable.h" 7 | #include "TouchVelocity.h" 8 | 9 | // TouchVariable and TouchVelocity are now included in the Flicker libary. 10 | // So, for continuity, the "Flicker" class has been changed to "TouchSwitch". 11 | // "Flicker" continues to be included here for backward compatibility. 12 | class Flicker: public TouchSwitch{ 13 | public: 14 | Flicker() : TouchSwitch(){} 15 | Flicker(byte pin) : TouchSwitch(pin){} 16 | Flicker(byte pin, int threshold) : TouchSwitch(pin, 0, threshold){} 17 | Flicker(byte pin, byte mode, int threshold) : TouchSwitch(pin, mode, threshold){} 18 | }; 19 | 20 | #endif 21 | 22 | -------------------------------------------------------------------------------- /src/TouchSwitch.cpp: -------------------------------------------------------------------------------- 1 | #include "TouchSwitch.h" 2 | 3 | TouchSwitch::TouchSwitch(){}; 4 | 5 | TouchSwitch::TouchSwitch(byte pin){ 6 | this->pin = pin; 7 | latched = false; 8 | setThreshold(); // only works if creating objects during setup 9 | }; 10 | 11 | TouchSwitch::TouchSwitch(byte pin, byte mode){ 12 | this->pin = pin; 13 | this->latched = mode; 14 | setThreshold(); // only works if creating objects during setup 15 | }; 16 | 17 | TouchSwitch::TouchSwitch(byte pin, byte mode, int onT){ 18 | this->pin = pin; 19 | latched = mode; 20 | onThreshold = onT; 21 | setThreshold(onThreshold); // only works if creating objects during setup 22 | }; 23 | 24 | TouchSwitch::~TouchSwitch(){}; 25 | 26 | 27 | void TouchSwitch::setThreshold(){ 28 | analogRead(A0); // The ADC can affect touch values so fire it up first. 29 | inLo = touchRead(pin); 30 | onThreshold = inLo * 1.1; // initial threshold 10% above quiescent 31 | updateThreshold(inLo, onThreshold); // updated on higher reading 32 | } 33 | 34 | 35 | void TouchSwitch::setThreshold(int threshold){ 36 | userSetThreshold = true; 37 | onThreshold = threshold; 38 | analogRead(A0); // The ADC can affect touch values so fire it up first. 39 | inLo = touchRead(pin); 40 | 41 | // breaks if user-set threshold is lower than the quiescent reading 42 | updateThreshold(inLo, onThreshold); 43 | } 44 | 45 | 46 | void TouchSwitch::updateThreshold(int low, int high){ // internal use only 47 | inLo = low; 48 | inHi = high; 49 | int range = inHi - inLo; 50 | 51 | if (!userSetThreshold){ 52 | // Assumes that halfway between lowest & highest readings is a good place 53 | // for a threshold. Still a magic number but at least it's somewhat dynamic. 54 | onThreshold = inLo + range * 0.5; 55 | offThreshold = inLo + range * 0.3; 56 | } 57 | else{ 58 | // The user can forego assumptions and set the threshold themselves. 59 | // We need to know where the threshold is in relation to the range of values 60 | float sens = float(onThreshold - inLo) / float(range); 61 | // Then we set the offThreshold to be 10% below the onThreshold 62 | offThreshold = inLo + range * (sens - 0.1); 63 | } 64 | } 65 | 66 | 67 | int TouchSwitch::update(){ 68 | if (trigger()){ 69 | retrigger(0); 70 | return stateChanged = 1; 71 | } 72 | // We need to retrigger, so simulate a state change 73 | if (retrigger_millis && (millis() - previous_millis >= retrigger_millis)){ 74 | previous_millis = millis(); 75 | retrigger(0); 76 | return stateChanged = 1; 77 | } 78 | return stateChanged = 0; 79 | } 80 | 81 | 82 | int TouchSwitch::read(){ 83 | return (int)state; 84 | } 85 | 86 | 87 | byte TouchSwitch::rose() { return stateChanged && state; } 88 | 89 | byte TouchSwitch::fell() { return stateChanged && !state; } 90 | 91 | 92 | unsigned long TouchSwitch::duration(){ 93 | return millis() - previous_millis; 94 | } 95 | 96 | 97 | void TouchSwitch::retrigger(unsigned long interval){ 98 | retrigger_millis = interval; 99 | } 100 | 101 | 102 | void TouchSwitch::interval(unsigned long interval_millis){ 103 | this->interval_millis = interval_millis; 104 | retrigger_millis = 0; 105 | } 106 | 107 | unsigned long TouchSwitch::previousDuration() 108 | { 109 | return durationOfPreviousState; 110 | } 111 | 112 | // Protected: triggers the pin 113 | int TouchSwitch::trigger(){ 114 | int newValue = touchRead(pin); 115 | int current_millis = millis(); 116 | 117 | if (newValue > inHi){updateThreshold(inLo, newValue);} 118 | else if (newValue < inLo){updateThreshold(newValue, inHi);} 119 | 120 | if(latched){ // LATCH behavior 121 | if (newValue >= onThreshold){ 122 | if (waiting && held_millis >= interval_millis){ 123 | state = !state; 124 | waiting = false; 125 | durationOfPreviousState = current_millis - previous_millis; 126 | previous_millis = current_millis; 127 | return 1; 128 | } 129 | else{return 0;} 130 | } 131 | else if (newValue <= offThreshold){ 132 | waiting = true; 133 | held_millis = 0; 134 | return 0; 135 | } 136 | else{ 137 | held_millis = 0; 138 | return 0; 139 | } 140 | } 141 | else{ // MOMENTARY behavior 142 | if (newValue >= onThreshold){ 143 | if (waiting && held_millis >= interval_millis){ 144 | if (!state){ 145 | state = true; 146 | durationOfPreviousState = current_millis - previous_millis; 147 | previous_millis = current_millis; 148 | return 1; 149 | } 150 | else{ 151 | waiting = false; 152 | return 0; 153 | } 154 | } 155 | else{ 156 | if (!state){ 157 | waiting = true; 158 | return 0; 159 | } 160 | else{return 0;} 161 | } 162 | } 163 | else if (newValue <= offThreshold){ 164 | if(waiting && held_millis >= interval_millis){ 165 | if (state){ 166 | state = false; 167 | durationOfPreviousState = current_millis - previous_millis; 168 | previous_millis = current_millis; 169 | return 1; 170 | } 171 | else{ 172 | waiting = false; 173 | return 0; 174 | } 175 | } 176 | else{ 177 | if (state){ 178 | waiting = true; 179 | return 0; 180 | } 181 | else{return 0;} 182 | } 183 | } 184 | else{ 185 | held_millis = 0; 186 | return 0;} 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/TouchSwitch.h: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | 3 | #ifndef TouchSwitch_h 4 | #define TouchSwitch_h 5 | 6 | #define MOMENTARY 0 7 | #define LATCH 1 8 | 9 | 10 | class TouchSwitch{ 11 | 12 | public: 13 | // Default constructor 14 | TouchSwitch(); 15 | 16 | // Initialize a momentary switch (Also use setThreshold()). 17 | TouchSwitch(byte pin); 18 | 19 | // Initialize a latched switch (Also use setThreshold()). 20 | TouchSwitch(byte pin, byte mode); 21 | 22 | // Initialize a momentary or latched switch with a specific threshold. 23 | TouchSwitch(byte pin, byte mode, int onT); 24 | 25 | // Destructor 26 | ~TouchSwitch(); 27 | 28 | // setThreshold() assumes the input is NOT being touched and automatically 29 | // calculates a threshold. In setup() is a good place to call this function. 30 | void setThreshold(); 31 | 32 | // A specific value can also be given as an argument. 33 | void setThreshold(int threshold); 34 | 35 | // Updates the pin. Returns 1 if state changed ; Returns 0 if not. 36 | int update(); 37 | 38 | // Returns the updated pin state. 39 | int read(); 40 | 41 | // rose() is true for 1 scan after input goes above the threshold. 42 | byte rose(); 43 | byte risingEdge(){return rose();} 44 | 45 | // fell() is true for 1 scan after input goes below the threshold. 46 | byte fell(); 47 | byte fallingEdge(){return fell();} 48 | 49 | // Returns the number of milliseconds the pin has been in the current state. 50 | unsigned long duration(); 51 | 52 | // Forces the pin to signal a change (through update()) in X milliseconds 53 | // even if the state does not actually change. 54 | // Example: press and hold a button and have it repeat every X milliseconds 55 | void retrigger(unsigned long interval); 56 | 57 | // A 'debounce' interval isn't really needed but, if you want one... 58 | void interval(unsigned long interval_millis); 59 | 60 | unsigned long previousDuration(); 61 | 62 | protected: 63 | byte pin = 0; 64 | bool latched = false; 65 | bool waiting = false; 66 | bool stateChanged = false; 67 | int inHi, onThreshold, offThreshold, inLo; 68 | int trigger(); 69 | void updateThreshold(int low, int high); 70 | bool state = false; 71 | bool userSetThreshold = false; 72 | elapsedMillis held_millis = 0; 73 | unsigned long previous_millis = 0; 74 | unsigned long interval_millis = 0; 75 | unsigned long retrigger_millis = 0; 76 | unsigned long durationOfPreviousState; 77 | }; 78 | 79 | #endif -------------------------------------------------------------------------------- /src/TouchVariable.cpp: -------------------------------------------------------------------------------- 1 | #include "TouchVariable.h" 2 | 3 | TouchVariable::TouchVariable(){}; 4 | 5 | TouchVariable::TouchVariable(byte pin){ 6 | this->pin = pin; 7 | setInputRange(); // only works if creating objects during setup 8 | }; 9 | 10 | TouchVariable::TouchVariable(byte pin, int outLo, int outHi){ 11 | this->pin = pin; 12 | this->outLo = outLo; 13 | this->outHi = outHi; 14 | mapped = true; 15 | setInputRange(); // only works if creating objects during setup 16 | }; 17 | 18 | TouchVariable::~TouchVariable(){}; 19 | 20 | 21 | void TouchVariable::setInputRange(){ 22 | adjustInHi = true; // Auto adjust inHi if there is a higher reading. 23 | analogRead(A0); // The ADC can affect touch values so fire it up first. 24 | int qval = touchRead(pin); 25 | inLo = qval * 1.01; // prevent noise on the bottom end 26 | inHi = qval * 1.1; // Higher values are still possible 27 | }; 28 | 29 | void TouchVariable::setInputRange(int inLo, int inHi){ 30 | adjustInHi = false; // Don't increase inHi when getting a higher reading 31 | this->inHi = inHi; // Values can still go higher unless using setOutputRange() 32 | this->inLo = inLo; // Values can still go lower unless using setOutputRange() 33 | }; 34 | 35 | 36 | int TouchVariable::read(){ 37 | int newValue = touchRead(pin); 38 | 39 | // Determine what percent of touchRead() values the threshold should be. 40 | threshold = newValue * (NR/100); 41 | 42 | if (adjustInHi){ 43 | // A conservative inHi of 1.7x is set when setInputRange() is called but, 44 | // the highest reading could be much higher than that. This line adjusts 45 | // inHi if newValue is 1.1x higher. If newValue is higher but less than 46 | // 1.1* higher, inHi is left alone allowing you to 'max out' the input. 47 | // Use setInputRange(int inLo, int inHi) to prevent this auto-adjustment. 48 | inHi = newValue > inHi * 1.1 ? newValue : inHi; 49 | } 50 | if (mapped){ 51 | newValue = map(newValue, inLo, inHi, outLo, outHi); 52 | newValue = constrain(newValue, outLo, outHi); 53 | } 54 | int difference = newValue - balancedValue; 55 | buffer = newValue == balancedValue ? buffer/2 : buffer + difference; 56 | if (buffer*buffer > threshold*threshold){ // "abs(buffer) > NR" doesn't work 57 | balancedValue = newValue; 58 | 59 | buffer = 0; 60 | } 61 | return balancedValue; 62 | }; 63 | 64 | 65 | void TouchVariable::setOutputRange(int outLo, int outHi){ 66 | this->outLo = outLo; 67 | this->outHi = outHi; 68 | mapped = true; 69 | }; 70 | 71 | void TouchVariable::setNR(int amount){ 72 | this->NR = float(amount); 73 | }; 74 | -------------------------------------------------------------------------------- /src/TouchVariable.h: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | 3 | #ifndef TouchVariable_h 4 | #define TouchVariable_h 5 | 6 | class TouchVariable{ 7 | 8 | public: 9 | // Default constructor 10 | TouchVariable(); 11 | 12 | // Initialize a variable touch input. 13 | TouchVariable(byte pin); 14 | 15 | // Initialize a variable touch input with a predetermined output range. 16 | // WARNING! Also call setInputRange() for this to work properly. 17 | TouchVariable(byte pin, int outLo, int outHi); 18 | 19 | // Destructor 20 | ~TouchVariable(); 21 | 22 | // setInputRange() assumes the input is NOT being touched and automatically 23 | // calculates a usable range. In setup() is a good place to call this Fn. 24 | void setInputRange(); 25 | 26 | // Specific values can also be given as arguments. 27 | void setInputRange(int inLo, int inHi); 28 | 29 | // Maps the inLo and inHi to a predetermined output range. 30 | void setOutputRange(int outLo, int outHi); 31 | 32 | // Returns the value of touchRead() with some noise reduction. 33 | int read(); 34 | 35 | // Sets the level of noise reduction. 0 for none, 36 | void setNR(int amount); // 0 = raw touchRead() values. 100 = maximum NR. 37 | 38 | int inLo = 0; 39 | int inHi = 0; 40 | int outLo = 0; 41 | int outHi = 0; 42 | 43 | protected: 44 | byte pin = 0; 45 | bool mapped = false; // true maps input to a predetermined output range 46 | bool adjustInHi = true;//false if using setInputRange(int inLo, int inHi) 47 | 48 | int buffer = 0; /* Think of this variable as a container like a capacitor 49 | acting as a low-pass filter. */ 50 | 51 | int threshold = 0;// This would be the variable capacity of the capacitor. 52 | 53 | float NR = 100.0; /* This is the percent of the touchRead() value that will 54 | be used as the threshold. A percent of the touchRead() 55 | value is used because higher touchRead() values have 56 | greater variance, thus requiring more noise reduction.*/ 57 | 58 | int balancedValue = 0; // The "noise-reduced" output of touchRead() 59 | 60 | }; 61 | 62 | #endif -------------------------------------------------------------------------------- /src/TouchVelocity.cpp: -------------------------------------------------------------------------------- 1 | #include "TouchVelocity.h" 2 | 3 | TouchVelocity::TouchVelocity(){}; 4 | 5 | TouchVelocity::TouchVelocity(byte pin){ 6 | this->pin = pin; 7 | }; 8 | 9 | TouchVelocity::~TouchVelocity(){}; 10 | 11 | 12 | void TouchVelocity::setThresholds(int hoverThreshold, int touchThreshold){ 13 | hoverOnThreshold = hoverThreshold; 14 | touchOnThreshold = touchThreshold; 15 | touchOffThreshold = touchOnThreshold * 0.9; 16 | hoverOffThreshold = hoverOnThreshold * 0.99; 17 | } 18 | 19 | 20 | int TouchVelocity::read(){ 21 | int newValue = touchRead(pin); 22 | 23 | if (state == 0){ // idle 24 | stateChanged = false; 25 | timer = 0; 26 | if (newValue >= hoverOnThreshold){ 27 | state = 1; 28 | } 29 | return 0; 30 | } 31 | else if (state == 1){ 32 | if (newValue >= touchOnThreshold){ // return velocity 33 | stateChanged = true; 34 | state = 2; // wait for release 35 | return timer; 36 | } 37 | else if (newValue <= hoverOffThreshold){ // return to idle 38 | state = 0; 39 | return 0; 40 | } 41 | else{ // keep waiting for touch 42 | return 0; 43 | } 44 | } 45 | else if (state == 2){ // waiting for release 46 | stateChanged = false; 47 | if (newValue <= hoverOffThreshold){ 48 | stateChanged = true; 49 | state = 0; // idle 50 | } 51 | else{stateChanged = false;} 52 | return 0; 53 | } 54 | else return 0; 55 | }; 56 | 57 | 58 | byte TouchVelocity::rose(){ 59 | return stateChanged && state == 2; 60 | }; 61 | 62 | byte TouchVelocity::fell(){ 63 | return stateChanged && state == 0; 64 | }; 65 | -------------------------------------------------------------------------------- /src/TouchVelocity.h: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | 3 | #ifndef TouchVelocity_h 4 | #define TouchVelocity_h 5 | 6 | class TouchVelocity{ 7 | 8 | public: 9 | // Default constructor 10 | TouchVelocity(); 11 | 12 | // Initialize a velocity touch input. 13 | TouchVelocity(byte pin); 14 | 15 | // Destructor 16 | ~TouchVelocity(); 17 | 18 | // Use this any time for specific thresholds (touchRead() is not called) 19 | void setThresholds(int hoverThreshold, int touchThreshold); 20 | 21 | // On rising edge, this returns the amount of time (in micros) between 22 | // breaking the hoverOnThreshold and breaking the touchOnThreshold. 23 | // Returns 0 if not rising edge. 24 | int read(); 25 | 26 | // rose() is true for 1 scan after input goes above touchOnThreshold 27 | byte rose(); 28 | byte risingEdge(){ return rose(); } 29 | 30 | // fell() is true for 1 scan after input goes 31 | // below hoverOffThreshold when read() is used OR 32 | // below touchOffThreshold when responsiveRead() is used 33 | byte fell(); 34 | byte fallingEdge(){ return fell(); } 35 | 36 | 37 | protected: 38 | byte pin; 39 | int state, 40 | touchOnThreshold, touchOffThreshold, 41 | hoverOnThreshold, hoverOffThreshold; 42 | bool stateChanged; 43 | elapsedMicros timer; 44 | }; 45 | 46 | #endif 47 | --------------------------------------------------------------------------------