├── README.md ├── examples ├── AVRRotaryEncoderAdvancedInterruptsLCD │ └── AVRRotaryEncoderAdvancedInterruptsLCD.ino ├── AVRRotaryEncoderAdvancedMultiValuesLCD │ └── AVRRotaryEncoderAdvancedMultiValuesLCD.ino ├── AVRRotaryEncoderInterruptsLCD │ └── AVRRotaryEncoderInterruptsLCD.ino ├── AVRRotaryEncoderInterruptsSerial │ └── AVRRotaryEncoderInterruptsSerial.ino ├── AVRRotaryEncoderTimer1InterruptsLCD │ └── AVRRotaryEncoderTimer1InterruptsLCD.ino ├── ESP8266RotaryEncoderAdvancedInterruptsLCD │ └── ESP8266RotaryEncoderAdvancedInterruptsLCD.ino ├── ESP8266RotaryEncoderInterruptsLCD │ └── ESP8266RotaryEncoderInterruptsLCD.ino ├── ESP8266RotaryEncoderInterruptsSerial │ └── ESP8266RotaryEncoderInterruptsSerial.ino ├── ESP8266RotaryEncoderTickerSerial │ └── ESP8266RotaryEncoderTickerSerial.ino ├── STM32RotaryEncoderAdvancedInterruptsLCD │ └── STM32RotaryEncoderAdvancedInterruptsLCD.ino ├── STM32RotaryEncoderInterruptsLCD │ └── STM32RotaryEncoderInterruptsLCD.ino ├── STM32RotaryEncoderInterruptsSerial │ └── STM32RotaryEncoderInterruptsSerial.ino └── STM32RotaryEncoderInterruptsSerialDirection │ └── STM32RotaryEncoderInterruptsSerialDirection.ino ├── images └── rotary_encoder_shematic.png ├── keywords.txt ├── library.json ├── library.properties └── src ├── RotaryEncoder.cpp ├── RotaryEncoder.h ├── RotaryEncoderAdvanced.h └── RotaryEncoderAdvanced.tpp /README.md: -------------------------------------------------------------------------------- 1 | [![license-badge][]][license] ![version] [![stars][]][stargazers] ![hit-count] [![github-issues][]][issues] 2 | 3 | # RotaryEncoder 4 | This is small and fast Arduino library for Rotary Encoder with interrupts. **Debounce capacitors to ground required!!! Otherwise, skipped steps and unstable performance may occur.** 5 | 6 | Supports: 7 | - Arduino AVR 8 | - Arduino ESP8266 9 | - Arduino ESP32 10 | - Arduino STM32 11 | 12 | ![alt text][rotary_encoder_shematic_image] 13 | 14 | [license-badge]: https://img.shields.io/badge/License-GPLv3-blue.svg 15 | [license]: https://choosealicense.com/licenses/gpl-3.0/ 16 | [version]: https://img.shields.io/badge/Version-1.4.2-green.svg 17 | [stars]: https://img.shields.io/github/stars/enjoyneering/RotaryEncoder.svg 18 | [stargazers]: https://github.com/enjoyneering/RotaryEncoder/stargazers 19 | [hit-count]: https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fenjoyneering%2FRotaryEncoder&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false 20 | [github-issues]: https://img.shields.io/github/issues/enjoyneering/RotaryEncoder.svg 21 | [issues]: https://github.com/enjoyneering/RotaryEncoder/issues/ 22 | 23 | [rotary_encoder_shematic_image]: https://github.com/enjoyneering/RotaryEncoder/blob/master/images/rotary_encoder_shematic.png 24 | -------------------------------------------------------------------------------- /examples/AVRRotaryEncoderAdvancedInterruptsLCD/AVRRotaryEncoderAdvancedInterruptsLCD.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering 6 | sourse code: https://github.com/enjoyneering/RotaryEncoder 7 | 8 | This library uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximum 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | Frameworks & Libraries: 21 | AVR Core - https://github.com/arduino/ArduinoCore-avr 22 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 23 | ESP32 Core - https://github.com/espressif/arduino-esp32 24 | ESP8266 Core - https://github.com/esp8266/Arduino 25 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 26 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 27 | 28 | GNU GPL license, all text above must be included in any redistribution, 29 | see link for details - https://www.gnu.org/licenses/licenses.html 30 | */ 31 | /***************************************************************************************************/ 32 | #pragma GCC optimize ("Os") //code optimization controls, "O2" or "O3" code performance & "Os" code size 33 | 34 | #include 35 | #include //https://github.com/enjoyneering/LiquidCrystal_I2C 36 | #include 37 | 38 | 39 | #define LCD_ROWS 4 //quantity of lcd rows 40 | #define LCD_COLUMNS 20 //quantity of lcd columns 41 | 42 | #define LCD_SPACE_SYMBOL 0x20 //space symbol from lcd ROM, see p.9 of GDM2004D datasheet 43 | 44 | #define PIN_A 2 //ky-040 clk pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 45 | #define PIN_B 4 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 46 | #define BUTTON 3 //ky-040 sw pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 47 | 48 | uint16_t buttonCounter = 0; 49 | 50 | RotaryEncoderAdvanced encoder(PIN_A, PIN_B, BUTTON, 0.1, 0.0, 3.3); //0.1 step per click, minimum value 0.0, maximum value 3.3 51 | LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); 52 | 53 | 54 | /**************************************************************************/ 55 | /* 56 | encoderISR() 57 | 58 | Encoder A & B pin interrupt service routine 59 | 60 | NOTE: 61 | - use interrupt pin for A pin!!! 62 | - add 100nF/0.1uF capacitors between A pin & ground!!! 63 | - add 100nF/0.1uF capacitors between B pin & ground!!! 64 | */ 65 | /**************************************************************************/ 66 | void encoderISR() 67 | { 68 | encoder.readAB(); 69 | } 70 | 71 | /**************************************************************************/ 72 | /* 73 | encoderButtonISR() 74 | 75 | Encoder button interrupt service routine 76 | 77 | NOTE: 78 | - use interrupt pin!!! 79 | - add 100nF/0.1uF capacitors between pin & ground!!! 80 | */ 81 | /**************************************************************************/ 82 | void encoderButtonISR() 83 | { 84 | encoder.readPushButton(); 85 | } 86 | 87 | /**************************************************************************/ 88 | /* 89 | setup() 90 | 91 | Main setup 92 | */ 93 | /**************************************************************************/ 94 | void setup() 95 | { 96 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 97 | 98 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 99 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high to low changes 100 | 101 | /* LCD connection check */ 102 | while (lcd.begin(LCD_COLUMNS, LCD_ROWS) != true) //20x4 display 103 | { 104 | for (uint8_t i = 0; i < 5; i++) //5 blinks if PCF8574/LCD is not connected or wrong pins declaration 105 | { 106 | digitalWrite(LED_BUILTIN, HIGH); 107 | delay(500); 108 | digitalWrite(LED_BUILTIN, LOW); 109 | delay(500); 110 | } 111 | } 112 | 113 | lcd.print(F("PCF8574 is OK")); //(F()) saves string to flash & keeps dynamic memory free 114 | delay(1500); 115 | 116 | lcd.clear(); 117 | 118 | /* prints static text */ 119 | lcd.print(F("VALUE :")); 120 | lcd.setCursor(0, 1); //set 1-st column, 2-nd row 121 | lcd.print(F("BUTTON:")); 122 | lcd.setCursor(8, 1); 123 | lcd.print(buttonCounter); 124 | lcd.setCursor(0, 2); 125 | lcd.print(F("UPTIME:")); 126 | } 127 | 128 | /**************************************************************************/ 129 | /* 130 | loop() 131 | 132 | Main loop 133 | */ 134 | /**************************************************************************/ 135 | void loop() 136 | { 137 | lcd.setCursor(8, 0); 138 | lcd.print(encoder.getValue()); 139 | lcd.write(LCD_SPACE_SYMBOL); 140 | 141 | if (encoder.getPushButton() == true) 142 | { 143 | lcd.setCursor(8, 1); 144 | lcd.print(buttonCounter++); 145 | 146 | if (buttonCounter % 4 == 0) lcd.noBacklight(); //every 4-th button click backlight is off 147 | else lcd.backlight(); 148 | } 149 | 150 | lcd.setCursor(8, 2); 151 | lcd.print((millis() / 1000)); 152 | } 153 | -------------------------------------------------------------------------------- /examples/AVRRotaryEncoderAdvancedMultiValuesLCD/AVRRotaryEncoderAdvancedMultiValuesLCD.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering 6 | sourse code: https://github.com/enjoyneering/RotaryEncoder 7 | 8 | This library uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximum 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | Frameworks & Libraries: 21 | AVR Core - https://github.com/arduino/ArduinoCore-avr 22 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 23 | ESP32 Core - https://github.com/espressif/arduino-esp32 24 | ESP8266 Core - https://github.com/esp8266/Arduino 25 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 26 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 27 | 28 | GNU GPL license, all text above must be included in any redistribution, 29 | see link for details - https://www.gnu.org/licenses/licenses.html 30 | */ 31 | /***************************************************************************************************/ 32 | #pragma GCC optimize ("Os") //code optimization controls, "O2" or "O3" code performance & "Os" code size 33 | 34 | #include 35 | #include //https://github.com/enjoyneering/LiquidCrystal_I2C 36 | #include 37 | 38 | 39 | #define LCD_ROWS 4 //quantity of lcd rows 40 | #define LCD_COLUMNS 20 //quantity of lcd columns 41 | 42 | #define LCD_SPACE_SYMBOL 0x20 //space symbol from lcd ROM, see p.9 of GDM2004D datasheet 43 | 44 | #define PIN_A 2 //ky-040 clk pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 45 | #define PIN_B 4 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 46 | #define BUTTON 3 //ky-040 sw pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 47 | 48 | #define V_STEPS_PER_CLICK 0.01 //0.01v per click 49 | #define V_MIN_VALUE 0 //minimum value 0.00v 50 | #define V_MAX_VALUE 15 //maximum value 15.00v 51 | 52 | #define A_STEPS_PER_CLICK 0.1 //0.1A per click 53 | #define A_MIN_VALUE 0 //minimum value 0.0A 54 | #define A_MAX_VALUE 3 //maximum value 3.0A 55 | 56 | uint8_t buttonCounter = 0; 57 | float backupVoltageValue = 0; 58 | float backupCurrentValue = 0; 59 | 60 | 61 | RotaryEncoderAdvanced encoder(PIN_A, PIN_B, BUTTON, V_STEPS_PER_CLICK, V_MIN_VALUE, V_MAX_VALUE); 62 | LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); 63 | 64 | 65 | /**************************************************************************/ 66 | /* 67 | setup() 68 | 69 | Main setup 70 | */ 71 | /**************************************************************************/ 72 | void setup() 73 | { 74 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 75 | 76 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 77 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high to low changes 78 | 79 | /* LCD connection check */ 80 | while (lcd.begin(LCD_COLUMNS, LCD_ROWS) != true) //20x4 display 81 | { 82 | for (uint8_t i = 0; i < 5; i++) //5 blinks if PCF8574/LCD is not connected or wrong pins declaration 83 | { 84 | digitalWrite(LED_BUILTIN, HIGH); 85 | delay(500); 86 | digitalWrite(LED_BUILTIN, LOW); 87 | delay(500); 88 | } 89 | } 90 | 91 | lcd.print(F("PCF8574 is OK")); //(F()) saves string to flash & keeps dynamic memory free 92 | delay(1500); 93 | 94 | lcd.clear(); 95 | 96 | /* prints static text */ 97 | lcd.print(F("VOLTAGE:")); 98 | 99 | lcd.setCursor(0, 1); //set 1-st column, 2-nd row 100 | lcd.print(F("CURRENT:")); 101 | } 102 | 103 | /**************************************************************************/ 104 | /* 105 | loop() 106 | 107 | Main loop 108 | */ 109 | /**************************************************************************/ 110 | void loop() 111 | { 112 | pushButtonHandler(); 113 | } 114 | 115 | /**************************************************************************/ 116 | /* 117 | encoderISR() 118 | 119 | Encoder A & B pin interrupt service routine 120 | 121 | NOTE: 122 | - use interrupt pin for A pin!!! 123 | - add 100nF/0.1uF capacitors between A pin & ground!!! 124 | - add 100nF/0.1uF capacitors between B pin & ground!!! 125 | */ 126 | /**************************************************************************/ 127 | void encoderISR() 128 | { 129 | encoder.readAB(); 130 | } 131 | 132 | /**************************************************************************/ 133 | /* 134 | encoderButtonISR() 135 | 136 | Encoder button interrupt service routine 137 | 138 | NOTE: 139 | - use interrupt pin!!! 140 | - add 100nF/0.1uF capacitors between pin & ground!!! 141 | */ 142 | /**************************************************************************/ 143 | void encoderButtonISR() 144 | { 145 | encoder.readPushButton(); 146 | } 147 | 148 | /**************************************************************************/ 149 | /* 150 | pushButtonHandler() 151 | 152 | Push button handler 153 | 154 | NOTE: 155 | - press 1 time to change VOLTAGE 156 | - press 2 times to change CURRENT 157 | - press 3 times to exit 158 | */ 159 | /**************************************************************************/ 160 | void pushButtonHandler() 161 | { 162 | if (encoder.getPushButton() == true) buttonCounter++; 163 | 164 | switch (buttonCounter) 165 | { 166 | case 1: 167 | setPrintVoltage(); 168 | break; 169 | 170 | case 2: 171 | setPrintCurrent(); 172 | break; 173 | 174 | default: 175 | buttonCounter = 0; 176 | break; 177 | } 178 | } 179 | 180 | /**************************************************************************/ 181 | /* 182 | setPrintVoltage() 183 | 184 | Set & print VOLTAGE value 185 | */ 186 | /**************************************************************************/ 187 | void setPrintVoltage() 188 | { 189 | encoder.setValues(backupVoltageValue, V_STEPS_PER_CLICK, V_MIN_VALUE, V_MAX_VALUE); //load "VOLTAGE" values to encoder 190 | 191 | while (encoder.getPushButton() != true) 192 | { 193 | lcd.setCursor(8, 0); //set 9-th column, 1-st row 194 | 195 | lcd.print(encoder.getValue()); 196 | lcd.write(LCD_SPACE_SYMBOL); 197 | 198 | lcd.printHorizontalGraph('V', 2, encoder.getValue(), V_MAX_VALUE); //name of the bar, 3-rd row, value, maximun value 199 | } 200 | 201 | backupVoltageValue = encoder.getValue(); //backup "VOLTAGE" value 202 | 203 | buttonCounter++; //jump to next menu 204 | } 205 | 206 | /**************************************************************************/ 207 | /* 208 | setPrintCurrent() 209 | 210 | Set & print CURRENT value 211 | */ 212 | /**************************************************************************/ 213 | void setPrintCurrent() 214 | { 215 | encoder.setValues(backupCurrentValue, A_STEPS_PER_CLICK, A_MIN_VALUE, A_MAX_VALUE); //load "CURRENT" values to encoder 216 | 217 | while (encoder.getPushButton() != true) 218 | { 219 | lcd.setCursor(8, 1); //set 9-th column, 2-nd row 220 | 221 | lcd.print(encoder.getValue()); 222 | lcd.write(LCD_SPACE_SYMBOL); 223 | 224 | lcd.printHorizontalGraph('A', 3, encoder.getValue(), A_MAX_VALUE); //name of the bar, 4-th row, value, maximun value 225 | } 226 | 227 | backupCurrentValue = encoder.getValue(); //backup "CURRENT" value 228 | 229 | buttonCounter++; //jump to next menu 230 | } 231 | -------------------------------------------------------------------------------- /examples/AVRRotaryEncoderInterruptsLCD/AVRRotaryEncoderInterruptsLCD.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/ 7 | 8 | This sketch uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximun 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | PCF8574 chip uses I2C bus to communicate, specials pins are required to interface 21 | Board: SDA SCL Level 22 | Uno, Mini, Pro, ATmega168, ATmega328..... A4 A5 5v 23 | Mega2560................................. 20 21 5v 24 | Due, SAM3X8E............................. 20 21 3.3v 25 | Leonardo, Micro, ATmega32U4.............. 2 3 5v 26 | Digistump, Trinket, ATtiny85............. 0/physical pin no.5 2/physical pin no.7 5v 27 | Blue Pill, STM32F103xxxx boards.......... PB7 PB6 3.3v/5v 28 | ESP8266 ESP-01........................... GPIO0/D5 GPIO2/D3 3.3v/5v 29 | NodeMCU 1.0, WeMos D1 Mini............... GPIO4/D2 GPIO5/D1 3.3v/5v 30 | ESP32.................................... GPIO21/D21 GPIO22/D22 3.3v 31 | 32 | NOTE: 33 | - LOW interrupt trigges whenever the pin is low 34 | - HIGH interrupt triggers whenever the pin is high (Arduino Due, Zero, MKR1000 only) 35 | - CHANGE interrupt triggers whenever the pin changes value 36 | - RISING interrupt triggers when the pin goes from low to high 37 | - FALLING interrupt triggers when the pin goes from high to low 38 | 39 | Frameworks & Libraries: 40 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 41 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 42 | ESP32 Core - https://github.com/espressif/arduino-esp32 43 | ESP8266 Core - https://github.com/esp8266/Arduino 44 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 45 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 46 | 47 | GNU GPL license, all text above must be included in any redistribution, 48 | see link for details - https://www.gnu.org/licenses/licenses.html 49 | */ 50 | /***************************************************************************************************/ 51 | #pragma GCC optimize ("Os") //code optimization controls, "O2" or "O3" code performance & "Os" code size 52 | 53 | #include 54 | #include //https://github.com/enjoyneering/LiquidCrystal_I2C 55 | #include 56 | 57 | #define LCD_ROWS 4 //quantity of lcd rows 58 | #define LCD_COLUMNS 20 //quantity of lcd columns 59 | 60 | #define LCD_SPACE_SYMBOL 0x20 //space symbol from lcd ROM, see p.9 of GDM2004D datasheet 61 | 62 | #define PIN_A 2 //ky-040 clk pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 63 | #define PIN_B 4 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 64 | #define BUTTON 3 //ky-040 sw pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 65 | 66 | uint16_t buttonCounter = 0; 67 | 68 | RotaryEncoder encoder(PIN_A, PIN_B, BUTTON); 69 | LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); 70 | 71 | 72 | /**************************************************************************/ 73 | /* 74 | encoderISR() 75 | 76 | Encoder A & B pin interrupt service routine 77 | 78 | NOTE: 79 | - use interrupt pin for A pin!!! 80 | - add 100nF/0.1uF capacitors between A pin & ground!!! 81 | - add 100nF/0.1uF capacitors between B pin & ground!!! 82 | */ 83 | /**************************************************************************/ 84 | void encoderISR() 85 | { 86 | encoder.readAB(); 87 | } 88 | 89 | /**************************************************************************/ 90 | /* 91 | encoderButtonISR() 92 | 93 | Encoder button interrupt service routine 94 | 95 | NOTE: 96 | - use interrupt pin!!! 97 | - add 100nF/0.1uF capacitors between pin & ground!!! 98 | */ 99 | /**************************************************************************/ 100 | void encoderButtonISR() 101 | { 102 | encoder.readPushButton(); 103 | } 104 | 105 | /**************************************************************************/ 106 | /* 107 | setup() 108 | 109 | Main setup 110 | */ 111 | /**************************************************************************/ 112 | void setup() 113 | { 114 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 115 | 116 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 117 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high to low changes 118 | 119 | /* LCD connection check */ 120 | while (lcd.begin(LCD_COLUMNS, LCD_ROWS) != true) //20x4 display 121 | { 122 | for (uint8_t i = 0; i < 5; i++) //5 blinks if PCF8574/LCD is not connected or wrong pins declaration 123 | { 124 | digitalWrite(LED_BUILTIN, HIGH); 125 | delay(500); 126 | digitalWrite(LED_BUILTIN, LOW); 127 | delay(500); 128 | } 129 | } 130 | 131 | lcd.print(F("PCF8574 is OK")); //(F()) saves string to flash & keeps dynamic memory free 132 | delay(1500); 133 | 134 | Wire.setClock(400000); //experimental! AVR i2c bus speed: 31kHz..400kHz/31000UL..400000UL, default 100000UL 135 | 136 | lcd.clear(); 137 | 138 | /* prints static text */ 139 | lcd.print(F("POSITION:")); 140 | lcd.setCursor(0, 1); //set 1-st column, 2-nd row 141 | lcd.print(F("BUTTON :")); 142 | lcd.setCursor(10, 1); 143 | lcd.print(buttonCounter); 144 | lcd.setCursor(0, 2); 145 | lcd.print(F("UPTIME :")); 146 | } 147 | 148 | /**************************************************************************/ 149 | /* 150 | loop() 151 | 152 | Main loop 153 | */ 154 | /**************************************************************************/ 155 | void loop() 156 | { 157 | lcd.setCursor(10, 0); 158 | lcd.print(encoder.getPosition()); 159 | lcd.write(LCD_SPACE_SYMBOL); 160 | 161 | if (encoder.getPushButton() == true) 162 | { 163 | lcd.setCursor(10, 1); 164 | lcd.print(buttonCounter++); 165 | 166 | if (buttonCounter % 4 == 0) lcd.noBacklight(); //every 4-th button click the backlight is off 167 | else lcd.backlight(); 168 | } 169 | 170 | lcd.setCursor(10, 2); 171 | lcd.print((millis() / 1000)); 172 | } 173 | -------------------------------------------------------------------------------- /examples/AVRRotaryEncoderInterruptsSerial/AVRRotaryEncoderInterruptsSerial.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/ 7 | 8 | This sketch uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximun 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | NOTE: 21 | - LOW interrupt trigges whenever the pin is low 22 | - HIGH interrupt triggers whenever the pin is high (Arduino Due, Zero, MKR1000 only) 23 | - CHANGE interrupt triggers whenever the pin changes value 24 | - RISING interrupt triggers when the pin goes from low to high 25 | - FALLING interrupt triggers when the pin goes from high to low 26 | 27 | Frameworks & Libraries: 28 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 29 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 30 | ESP32 Core - https://github.com/espressif/arduino-esp32 31 | ESP8266 Core - https://github.com/esp8266/Arduino 32 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 33 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 34 | 35 | GNU GPL license, all text above must be included in any redistribution, 36 | see link for details - https://www.gnu.org/licenses/licenses.html 37 | */ 38 | /***************************************************************************************************/ 39 | #pragma GCC optimize ("Os") //code optimization controls, "O2" or "O3" code performance & "Os" code size 40 | 41 | #include 42 | 43 | #define PIN_A 2 //ky-040 clk pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 44 | #define PIN_B 4 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 45 | #define BUTTON 3 //ky-040 sw pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 46 | 47 | int16_t position = 0; 48 | 49 | RotaryEncoder encoder(PIN_A, PIN_B, BUTTON); 50 | 51 | 52 | /**************************************************************************/ 53 | /* 54 | encoderISR() 55 | 56 | Encoder A & B pin interrupt service routine 57 | 58 | NOTE: 59 | - use interrupt pin for A pin!!! 60 | - add 100nF/0.1uF capacitors between A pin & ground!!! 61 | - add 100nF/0.1uF capacitors between B pin & ground!!! 62 | */ 63 | /**************************************************************************/ 64 | void encoderISR() 65 | { 66 | encoder.readAB(); 67 | } 68 | 69 | /**************************************************************************/ 70 | /* 71 | encoderButtonISR() 72 | 73 | Encoder button interrupt service routine 74 | 75 | NOTE: 76 | - use interrupt pin!!! 77 | - add 100nF/0.1uF capacitors between pin & ground!!! 78 | */ 79 | /**************************************************************************/ 80 | void encoderButtonISR() 81 | { 82 | encoder.readPushButton(); 83 | } 84 | 85 | /**************************************************************************/ 86 | /* 87 | setup() 88 | 89 | Main setup 90 | */ 91 | /**************************************************************************/ 92 | void setup() 93 | { 94 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 95 | 96 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 97 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call encoderButtonISR() every high to low changes 98 | 99 | Serial.begin(115200); 100 | } 101 | 102 | /**************************************************************************/ 103 | /* 104 | loop() 105 | 106 | Main loop 107 | */ 108 | /**************************************************************************/ 109 | void loop() 110 | { 111 | if (position != encoder.getPosition()) 112 | { 113 | position = encoder.getPosition(); 114 | Serial.println(position); 115 | } 116 | 117 | if (encoder.getPushButton() == true) Serial.println(F("PRESSED")); //(F()) saves string to flash & keeps dynamic memory free 118 | } 119 | -------------------------------------------------------------------------------- /examples/AVRRotaryEncoderTimer1InterruptsLCD/AVRRotaryEncoderTimer1InterruptsLCD.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/ 7 | 8 | This sketch uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximun 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | PCF8574 chip uses I2C bus to communicate, specials pins are required to interface 21 | Board: SDA SCL Level 22 | Uno, Mini, Pro, ATmega168, ATmega328..... A4 A5 5v 23 | Mega2560................................. 20 21 5v 24 | Due, SAM3X8E............................. 20 21 3.3v 25 | Leonardo, Micro, ATmega32U4.............. 2 3 5v 26 | Digistump, Trinket, ATtiny85............. 0/physical pin no.5 2/physical pin no.7 5v 27 | Blue Pill, STM32F103xxxx boards.......... PB7 PB6 3.3v/5v 28 | ESP8266 ESP-01........................... GPIO0/D5 GPIO2/D3 3.3v/5v 29 | NodeMCU 1.0, WeMos D1 Mini............... GPIO4/D2 GPIO5/D1 3.3v/5v 30 | ESP32.................................... GPIO21/D21 GPIO22/D22 3.3v 31 | 32 | NOTE: 33 | - LOW interrupt trigges whenever the pin is low 34 | - HIGH interrupt triggers whenever the pin is high (Arduino Due, Zero, MKR1000 only) 35 | - CHANGE interrupt triggers whenever the pin changes value 36 | - RISING interrupt triggers when the pin goes from low to high 37 | - FALLING interrupt triggers when the pin goes from high to low 38 | 39 | Frameworks & Libraries: 40 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 41 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 42 | ESP32 Core - https://github.com/espressif/arduino-esp32 43 | ESP8266 Core - https://github.com/esp8266/Arduino 44 | STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32 45 | 46 | GNU GPL license, all text above must be included in any redistribution, 47 | see link for details - https://www.gnu.org/licenses/licenses.html 48 | */ 49 | /***************************************************************************************************/ 50 | #pragma GCC optimize ("Os") //code optimization controls, "O2" or "O3" code performance & "Os" code size 51 | 52 | #include 53 | #include //https://github.com/PaulStoffregen/TimerOne 54 | #include //https://github.com/enjoyneering/LiquidCrystal_I2C 55 | #include 56 | 57 | #define LCD_ROWS 4 //quantity of lcd rows 58 | #define LCD_COLUMNS 20 //quantity of lcd columns 59 | 60 | #define LCD_SPACE_SYMBOL 0x20 //space symbol from lcd ROM, see p.9 of GDM2004D datasheet 61 | 62 | #define PIN_A 5 //ky-040 clk pin, add 100nF/0.1uF capacitors between pin & ground!!! 63 | #define PIN_B 4 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 64 | #define BUTTON 3 //ky-040 sw pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 65 | 66 | uint16_t buttonCounter = 0; 67 | 68 | RotaryEncoder encoder(PIN_A, PIN_B, BUTTON); 69 | LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); 70 | 71 | 72 | void encoderISR() 73 | { 74 | encoder.readAB(); 75 | } 76 | 77 | void encoderButtonISR() 78 | { 79 | encoder.readPushButton(); 80 | } 81 | 82 | void setup() 83 | { 84 | Timer1.initialize(); //optionally timer's period can be set here in usec, default 1 sec. this breaks analogWrite() for pins 9 & 10 85 | 86 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 87 | 88 | Timer1.attachInterrupt(encoderISR, 10000); //call encoderISR() every 10000 microseconds/0.01 seconds 89 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high to low changes 90 | 91 | /* LCD connection check */ 92 | while (lcd.begin(LCD_COLUMNS, LCD_ROWS) != true) //20x4 display 93 | { 94 | for (uint8_t i = 0; i < 5; i++) //5 blinks if PCF8574/LCD is not connected or wrong pins declaration 95 | { 96 | digitalWrite(LED_BUILTIN, HIGH); 97 | delay(500); 98 | digitalWrite(LED_BUILTIN, LOW); 99 | delay(500); 100 | } 101 | } 102 | 103 | lcd.print(F("PCF8574 is OK")); //(F()) saves string to flash & keeps dynamic memory free 104 | delay(1500); 105 | 106 | lcd.clear(); 107 | 108 | /* prints static text */ 109 | lcd.print(F("POSITION:")); 110 | lcd.setCursor(0, 1); //set 1-st column, 2-nd row 111 | lcd.print(F("BUTTON :")); 112 | lcd.setCursor(10, 1); 113 | lcd.print(buttonCounter); 114 | lcd.setCursor(0, 2); 115 | lcd.print(F("UPTIME :")); 116 | } 117 | 118 | void loop() 119 | { 120 | lcd.setCursor(10, 0); 121 | lcd.print(encoder.getPosition()); 122 | lcd.write(LCD_SPACE_SYMBOL); 123 | 124 | if (encoder.getPushButton() == true) 125 | { 126 | lcd.setCursor(10, 1); 127 | lcd.print(buttonCounter++); 128 | 129 | if (buttonCounter % 4 == 0) lcd.noBacklight(); //every 4-th button click the backlight is off 130 | else lcd.backlight(); 131 | } 132 | 133 | lcd.setCursor(10, 2); 134 | lcd.print((millis() / 1000)); 135 | } 136 | -------------------------------------------------------------------------------- /examples/ESP8266RotaryEncoderAdvancedInterruptsLCD/ESP8266RotaryEncoderAdvancedInterruptsLCD.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering 6 | sourse code: https://github.com/enjoyneering/RotaryEncoder 7 | 8 | This library uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximum 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | Frameworks & Libraries: 21 | AVR Core - https://github.com/arduino/ArduinoCore-avr 22 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 23 | ESP32 Core - https://github.com/espressif/arduino-esp32 24 | ESP8266 Core - https://github.com/esp8266/Arduino 25 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 26 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 27 | 28 | GNU GPL license, all text above must be included in any redistribution, 29 | see link for details - https://www.gnu.org/licenses/licenses.html 30 | */ 31 | /***************************************************************************************************/ 32 | #pragma GCC optimize ("Os") //code optimization controls, "O2" or "O3" code performance & "Os" code size 33 | 34 | #include //use bug free i2c driver https://github.com/enjoyneering/ESP8266-I2C-Driver 35 | #include 36 | #include //https://github.com/enjoyneering/LiquidCrystal_I2C 37 | #include 38 | 39 | 40 | #define LCD_ROWS 4 //quantity of lcd rows 41 | #define LCD_COLUMNS 20 //quantity of lcd columns 42 | 43 | #define LCD_SPACE_SYMBOL 0x20 //space symbol from lcd ROM, see p.9 of GDM2004D datasheet 44 | 45 | #define PIN_A D5 //ky-040 clk pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 46 | #define PIN_B D6 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 47 | #define BUTTON D7 //ky-040 sw pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 48 | 49 | uint16_t buttonCounter = 0; 50 | 51 | RotaryEncoderAdvanced encoder(PIN_A, PIN_B, BUTTON, 0.1, 0.0, 3.3); //0.1 step per click, minimum value 0, maximum value 3.3 52 | LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); 53 | 54 | 55 | void ICACHE_RAM_ATTR encoderISR() //interrupt service routines need to be in ram 56 | { 57 | encoder.readAB(); 58 | } 59 | 60 | void ICACHE_RAM_ATTR encoderButtonISR() 61 | { 62 | encoder.readPushButton(); 63 | } 64 | 65 | void setup() 66 | { 67 | WiFi.persistent(false); //disable saving wifi config into SDK flash area 68 | WiFi.forceSleepBegin(); //disable AP & station by calling "WiFi.mode(WIFI_OFF)" & put modem to sleep 69 | 70 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 71 | 72 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 73 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high->low changes 74 | 75 | Serial.begin(115200); 76 | 77 | /* LCD connection check */ 78 | while (lcd.begin(LCD_COLUMNS, LCD_ROWS, LCD_5x8DOTS, D2, D1) != true) //colums - 20, rows - 4, pixels - LCD_5x8DOTS, SDA - D2, SCL - D1 79 | { 80 | Serial.println(F("PCF8574 is not connected or lcd pins declaration is wrong. Only pins numbers: 4,5,6,16,11,12,13,14 are legal.")); 81 | delay(5000); 82 | } 83 | 84 | lcd.print(F("PCF8574 is OK")); //(F()) saves string to flash & keeps dynamic memory free 85 | delay(1500); 86 | 87 | lcd.clear(); 88 | 89 | /* prints static text */ 90 | lcd.print(F("VALUE :")); 91 | lcd.setCursor(0, 1); //set 1-st column, 2-nd row 92 | lcd.print(F("BUTTON:")); 93 | lcd.setCursor(8, 1); 94 | lcd.print(buttonCounter); 95 | lcd.setCursor(0, 2); 96 | lcd.print(F("UPTIME:")); 97 | } 98 | 99 | void loop() 100 | { 101 | lcd.setCursor(8, 0); 102 | lcd.print(encoder.getValue(), 1); 103 | lcd.write(LCD_SPACE_SYMBOL); 104 | 105 | if (encoder.getPushButton() == true) 106 | { 107 | lcd.setCursor(8, 1); 108 | lcd.print(buttonCounter++); 109 | 110 | if (buttonCounter % 4 == 0) lcd.noBacklight(); //every 4-th button click backlight is off 111 | else lcd.backlight(); 112 | } 113 | 114 | lcd.setCursor(8, 2); 115 | lcd.print((millis() / 1000)); 116 | } 117 | -------------------------------------------------------------------------------- /examples/ESP8266RotaryEncoderInterruptsLCD/ESP8266RotaryEncoderInterruptsLCD.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/ 7 | 8 | This sketch uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximun 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | PCF8574 chip uses I2C bus to communicate, specials pins are required to interface 21 | Board: SDA SCL Level 22 | Uno, Mini, Pro, ATmega168, ATmega328..... A4 A5 5v 23 | Mega2560................................. 20 21 5v 24 | Due, SAM3X8E............................. 20 21 3.3v 25 | Leonardo, Micro, ATmega32U4.............. 2 3 5v 26 | Digistump, Trinket, ATtiny85............. 0/physical pin no.5 2/physical pin no.7 5v 27 | Blue Pill, STM32F103xxxx boards.......... PB7 PB6 3.3v/5v 28 | ESP8266 ESP-01........................... GPIO0/D5 GPIO2/D3 3.3v/5v 29 | NodeMCU 1.0, WeMos D1 Mini............... GPIO4/D2 GPIO5/D1 3.3v/5v 30 | ESP32.................................... GPIO21/D21 GPIO22/D22 3.3v 31 | 32 | NOTE: 33 | - LOW interrupt trigges whenever the pin is low 34 | - HIGH interrupt triggers whenever the pin is high (Arduino Due, Zero, MKR1000 only) 35 | - CHANGE interrupt triggers whenever the pin changes value 36 | - RISING interrupt triggers when the pin goes from low to high 37 | - FALLING interrupt triggers when the pin goes from high to low 38 | 39 | Frameworks & Libraries: 40 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 41 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 42 | ESP32 Core - https://github.com/espressif/arduino-esp32 43 | ESP8266 Core - https://github.com/esp8266/Arduino 44 | STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32 45 | 46 | GNU GPL license, all text above must be included in any redistribution, 47 | see link for details - https://www.gnu.org/licenses/licenses.html 48 | */ 49 | /***************************************************************************************************/ 50 | #include //use bug free i2c driver https://github.com/enjoyneering/ESP8266-I2C-Driver 51 | #include //https://github.com/enjoyneering/LiquidCrystal_I2C 52 | #include 53 | #include 54 | 55 | #define LCD_ROWS 4 //quantity of lcd rows 56 | #define LCD_COLUMNS 20 //quantity of lcd columns 57 | 58 | #define LCD_SPACE_SYMBOL 0x20 //space symbol from lcd ROM, see p.9 of GDM2004D datasheet 59 | 60 | #define PIN_A D5 //ky-040 clk pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 61 | #define PIN_B D6 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 62 | #define BUTTON D7 //ky-040 sw pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 63 | 64 | uint16_t buttonCounter = 0; 65 | 66 | RotaryEncoder encoder(PIN_A, PIN_B, BUTTON); 67 | LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); 68 | 69 | 70 | void ICACHE_RAM_ATTR encoderISR() //interrupt service routines need to be in ram 71 | { 72 | encoder.readAB(); 73 | } 74 | 75 | void ICACHE_RAM_ATTR encoderButtonISR() 76 | { 77 | encoder.readPushButton(); 78 | } 79 | 80 | void setup() 81 | { 82 | WiFi.persistent(false); //disable saving wifi config into SDK flash area 83 | WiFi.forceSleepBegin(); //disable AP & station by calling "WiFi.mode(WIFI_OFF)" & put modem to sleep 84 | 85 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 86 | 87 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 88 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high->low changes 89 | 90 | Serial.begin(115200); 91 | 92 | /* LCD connection check */ 93 | while (lcd.begin(LCD_COLUMNS, LCD_ROWS, LCD_5x8DOTS, D2, D1) != true) //colums - 20, rows - 4, pixels - LCD_5x8DOTS, SDA - D2, SCL - D1 94 | { 95 | Serial.println(F("PCF8574 is not connected or lcd pins declaration is wrong. Only pins numbers: 4,5,6,16,11,12,13,14 are legal.")); 96 | delay(5000); 97 | } 98 | 99 | lcd.print(F("PCF8574 is OK")); //(F()) saves string to flash & keeps dynamic memory free 100 | delay(1500); 101 | 102 | lcd.clear(); 103 | 104 | /* prints static text */ 105 | lcd.print(F("POSITION:")); 106 | lcd.setCursor(0, 1); //set 1-st column, 2-nd row 107 | lcd.print(F("BUTTON :")); 108 | lcd.setCursor(10, 1); 109 | lcd.print(buttonCounter); 110 | lcd.setCursor(0, 2); 111 | lcd.print(F("UPTIME :")); 112 | } 113 | 114 | void loop() 115 | { 116 | lcd.setCursor(10, 0); 117 | lcd.print(encoder.getPosition()); 118 | lcd.write(LCD_SPACE_SYMBOL); 119 | 120 | if (encoder.getPushButton() == true) 121 | { 122 | lcd.setCursor(10, 1); 123 | lcd.print(buttonCounter++); 124 | 125 | if (buttonCounter % 4 == 0) lcd.noBacklight(); //every 4-th button click backlight is off 126 | else lcd.backlight(); 127 | } 128 | 129 | lcd.setCursor(10, 2); 130 | lcd.print((millis() / 1000)); 131 | } 132 | -------------------------------------------------------------------------------- /examples/ESP8266RotaryEncoderInterruptsSerial/ESP8266RotaryEncoderInterruptsSerial.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/ 7 | 8 | This sketch uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximun 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | NOTE: 21 | - LOW interrupt trigges whenever the pin is low 22 | - HIGH interrupt triggers whenever the pin is high (Arduino Due, Zero, MKR1000 only) 23 | - CHANGE interrupt triggers whenever the pin changes value 24 | - RISING interrupt triggers when the pin goes from low to high 25 | - FALLING interrupt triggers when the pin goes from high to low 26 | 27 | Frameworks & Libraries: 28 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 29 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 30 | ESP32 Core - https://github.com/espressif/arduino-esp32 31 | ESP8266 Core - https://github.com/esp8266/Arduino 32 | STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32 33 | 34 | GNU GPL license, all text above must be included in any redistribution, 35 | see link for details - https://www.gnu.org/licenses/licenses.html 36 | */ 37 | /***************************************************************************************************/ 38 | #include 39 | #include 40 | 41 | #define PIN_A D5 //ky-040 clk pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 42 | #define PIN_B D6 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 43 | #define BUTTON D7 //ky-040 sw pin, interrupt & add 100nF/0.1uF capacitors between pin & ground!!! 44 | 45 | int16_t position = 0; 46 | 47 | RotaryEncoder encoder(PIN_A, PIN_B, BUTTON); 48 | 49 | 50 | void ICACHE_RAM_ATTR encoderISR() //interrupt service routines need to be in ram 51 | { 52 | encoder.readAB(); 53 | } 54 | 55 | void ICACHE_RAM_ATTR encoderButtonISR() 56 | { 57 | encoder.readPushButton(); 58 | } 59 | 60 | void setup() 61 | { 62 | WiFi.persistent(false); //disable saving wifi config into SDK flash area 63 | WiFi.forceSleepBegin(); //disable AP & station by calling "WiFi.mode(WIFI_OFF)" & put modem to sleep 64 | 65 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 66 | 67 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 68 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call encoderButtonISR() every high->low changes 69 | 70 | Serial.begin(115200); 71 | } 72 | 73 | void loop() 74 | { 75 | if (position != encoder.getPosition()) 76 | { 77 | position = encoder.getPosition(); 78 | Serial.println(position); 79 | } 80 | 81 | if (encoder.getPushButton() == true) Serial.println(F("PRESSED")); //(F()) saves string to flash & keeps dynamic memory free 82 | } 83 | -------------------------------------------------------------------------------- /examples/ESP8266RotaryEncoderTickerSerial/ESP8266RotaryEncoderTickerSerial.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using build-in Arduino ESP8266 Ticker 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/ 7 | 8 | Frameworks & Libraries: 9 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 10 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 11 | ESP32 Core - https://github.com/espressif/arduino-esp32 12 | ESP8266 Core - https://github.com/esp8266/Arduino 13 | STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32 14 | 15 | GNU GPL license, all text above must be included in any redistribution, 16 | see link for details - https://www.gnu.org/licenses/licenses.html 17 | */ 18 | /***************************************************************************************************/ 19 | #include 20 | #include 21 | #include 22 | 23 | #define PIN_A D5 //ky-040 clk pin, add 100nF/0.1uF capacitors between pin & ground!!! 24 | #define PIN_B D6 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 25 | #define BUTTON D7 //ky-040 sw pin, add 100nF/0.1uF capacitors between pin & ground!!! 26 | 27 | int16_t position = 0; 28 | 29 | RotaryEncoder encoder(PIN_A, PIN_B, BUTTON); 30 | 31 | Ticker encoderRotary; 32 | Ticker encoderButton; 33 | 34 | 35 | void encoderISR() 36 | { 37 | encoder.readAB(); 38 | } 39 | 40 | void encoderButtonISR() 41 | { 42 | encoder.readPushButton(); 43 | } 44 | 45 | void setup() 46 | { 47 | WiFi.persistent(false); //disable saving wifi config into SDK flash area 48 | WiFi.forceSleepBegin(); //disable AP & station by calling "WiFi.mode(WIFI_OFF)" & put modem to sleep 49 | 50 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 51 | 52 | encoderRotary.attach_ms(10, encoderISR); //call encoderISR() every 10 milliseconds/0.010 seconds 53 | encoderButton.attach_ms(15, encoderButtonISR); //call encoderButtonISR() every 15 milliseconds/0.015 seconds 54 | 55 | Serial.begin(115200); 56 | } 57 | 58 | void loop() 59 | { 60 | if (position != encoder.getPosition()) 61 | { 62 | position = encoder.getPosition(); 63 | Serial.println(position); 64 | } 65 | 66 | if (encoder.getPushButton() == true) Serial.println(F("PRESSED")); //(F()) save string to flash & keep dynamic memory free 67 | } 68 | -------------------------------------------------------------------------------- /examples/STM32RotaryEncoderAdvancedInterruptsLCD/STM32RotaryEncoderAdvancedInterruptsLCD.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering 6 | sourse code: https://github.com/enjoyneering/RotaryEncoder 7 | 8 | This library uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximum 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | NOTE: 21 | - LOW interrupt trigges whenever the pin is low 22 | - HIGH interrupt triggers whenever the pin is high (Arduino Due, Zero, MKR1000 only) 23 | - CHANGE interrupt triggers whenever the pin changes value 24 | - RISING interrupt triggers when the pin goes from low to high 25 | - FALLING interrupt triggers when the pin goes from high to low 26 | 27 | Frameworks & Libraries: 28 | AVR Core - https://github.com/arduino/ArduinoCore-avr 29 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 30 | ESP32 Core - https://github.com/espressif/arduino-esp32 31 | ESP8266 Core - https://github.com/esp8266/Arduino 32 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 33 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 34 | 35 | GNU GPL license, all text above must be included in any redistribution, 36 | see link for details - https://www.gnu.org/licenses/licenses.html 37 | */ 38 | /***************************************************************************************************/ 39 | #include 40 | #include //https://github.com/enjoyneering/LiquidCrystal_I2C 41 | #include 42 | 43 | 44 | #define LCD_ROWS 4 //quantity of lcd rows 45 | #define LCD_COLUMNS 20 //quantity of lcd columns 46 | 47 | #define LCD_SPACE_SYMBOL 0x20 //space symbol from lcd ROM, see p.9 of GDM2004D datasheet 48 | 49 | /* if use SWD pins PA13 & PA14 disconnect ST-LINK right after upload */ 50 | #define PIN_A PB12 //ky-040 clk pin, add 100nF/0.1uF capacitors between pin & ground!!! 51 | #define PIN_B PB15 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 52 | #define BUTTON PB8 //ky-040 sw pin, add 100nF/0.1uF capacitors between pin & ground!!! 53 | 54 | uint16_t buttonCounter = 0; 55 | 56 | RotaryEncoderAdvanced encoder(PIN_A, PIN_B, BUTTON, 0.1, 0.0, 3.3); //0.1 step per click, minimum value 0, maximum value 3.3 57 | LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); 58 | 59 | 60 | void encoderISR() 61 | { 62 | encoder.readAB(); 63 | } 64 | 65 | void encoderButtonISR() 66 | { 67 | encoder.readPushButton(); 68 | } 69 | 70 | void setup() 71 | { 72 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 73 | 74 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 75 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high->low changes 76 | 77 | Serial.begin(115200); 78 | 79 | /* LCD connection check */ 80 | while (lcd.begin(LCD_COLUMNS, LCD_ROWS, LCD_5x8DOTS) != true) //colums - 20, rows - 4, pixels - LCD_5x8DOTS 81 | { 82 | Serial.println(F("PCF8574 is not connected or lcd pins declaration is wrong. Only pins numbers: 4,5,6,16,11,12,13,14 are legal.")); 83 | delay(5000); 84 | } 85 | 86 | lcd.print(F("PCF8574 is OK")); //(F()) saves string to flash & keeps dynamic memory free 87 | delay(1500); 88 | 89 | lcd.clear(); 90 | 91 | /* prints static text */ 92 | lcd.print(F("VALUE :")); 93 | lcd.setCursor(0, 1); //set 1-st column, 2-nd row 94 | lcd.print(F("BUTTON:")); 95 | lcd.setCursor(8, 1); 96 | lcd.print(buttonCounter); 97 | lcd.setCursor(0, 2); 98 | lcd.print(F("UPTIME:")); 99 | } 100 | 101 | void loop() 102 | { 103 | lcd.setCursor(8, 0); 104 | lcd.print(encoder.getValue(), 1); 105 | lcd.write(LCD_SPACE_SYMBOL); 106 | 107 | if (encoder.getPushButton() == true) 108 | { 109 | lcd.setCursor(8, 1); 110 | lcd.print(buttonCounter++); 111 | 112 | if (buttonCounter % 4 == 0) lcd.noBacklight(); //every 4-th button click backlight is off 113 | else lcd.backlight(); 114 | } 115 | 116 | lcd.setCursor(8, 2); 117 | lcd.print((millis() / 1000)); 118 | } 119 | -------------------------------------------------------------------------------- /examples/STM32RotaryEncoderInterruptsLCD/STM32RotaryEncoderInterruptsLCD.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/ 7 | 8 | This sketch uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximun 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | NOTE: 21 | - LOW interrupt trigges whenever the pin is low 22 | - HIGH interrupt triggers whenever the pin is high (Arduino Due, Zero, MKR1000 only) 23 | - CHANGE interrupt triggers whenever the pin changes value 24 | - RISING interrupt triggers when the pin goes from low to high 25 | - FALLING interrupt triggers when the pin goes from high to low 26 | 27 | Frameworks & Libraries: 28 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 29 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 30 | ESP32 Core - https://github.com/espressif/arduino-esp32 31 | ESP8266 Core - https://github.com/esp8266/Arduino 32 | STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32 33 | 34 | GNU GPL license, all text above must be included in any redistribution, 35 | see link for details - https://www.gnu.org/licenses/licenses.html 36 | */ 37 | /***************************************************************************************************/ 38 | #include 39 | #include //https://github.com/enjoyneering/LiquidCrystal_I2C 40 | #include 41 | 42 | #define LCD_ROWS 4 //quantity of lcd rows 43 | #define LCD_COLUMNS 20 //quantity of lcd columns 44 | 45 | #define LCD_SPACE_SYMBOL 0x20 //space symbol from lcd ROM, see p.9 of GDM2004D datasheet 46 | 47 | #define PIN_A PB13 //ky-040 clk pin, add 100nF/0.1uF capacitors between pin & ground!!! 48 | #define PIN_B PB14 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 49 | #define BUTTON PB15 //ky-040 sw pin, add 100nF/0.1uF capacitors between pin & ground!!! 50 | 51 | uint16_t buttonCounter = 0; 52 | 53 | RotaryEncoder encoder(PIN_A, PIN_B, BUTTON); 54 | LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); 55 | 56 | 57 | void encoderISR() 58 | { 59 | encoder.readAB(); 60 | } 61 | 62 | void encoderButtonISR() 63 | { 64 | encoder.readPushButton(); 65 | } 66 | 67 | void setup() 68 | { 69 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 70 | 71 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 72 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high->low changes 73 | 74 | Serial.begin(115200); 75 | 76 | /* LCD connection check */ 77 | while (lcd.begin(LCD_COLUMNS, LCD_ROWS, LCD_5x8DOTS) != true) //colums - 20, rows - 4, pixels - LCD_5x8DOTS 78 | { 79 | Serial.println(F("PCF8574 is not connected or lcd pins declaration is wrong. Only pins numbers: 4,5,6,16,11,12,13,14 are legal.")); 80 | delay(5000); 81 | } 82 | 83 | lcd.print(F("PCF8574 is OK")); //(F()) saves string to flash & keeps dynamic memory free 84 | delay(1500); 85 | 86 | lcd.clear(); 87 | 88 | /* prints static text */ 89 | lcd.print(F("POSITION:")); 90 | lcd.setCursor(0, 1); //set 1-st column, 2-nd row 91 | lcd.print(F("BUTTON :")); 92 | lcd.setCursor(10, 1); 93 | lcd.print(buttonCounter); 94 | lcd.setCursor(0, 2); 95 | lcd.print(F("UPTIME :")); 96 | } 97 | 98 | void loop() 99 | { 100 | lcd.setCursor(10, 0); 101 | lcd.print(encoder.getPosition()); 102 | lcd.write(LCD_SPACE_SYMBOL); 103 | 104 | if (encoder.getPushButton() == true) 105 | { 106 | lcd.setCursor(10, 1); 107 | lcd.print(buttonCounter++); 108 | 109 | if (buttonCounter % 4 == 0) lcd.noBacklight(); //every 4-th button click the backlight is off 110 | else lcd.backlight(); 111 | } 112 | 113 | lcd.setCursor(10, 2); 114 | lcd.print((millis() / 1000)); 115 | } 116 | -------------------------------------------------------------------------------- /examples/STM32RotaryEncoderInterruptsSerial/STM32RotaryEncoderInterruptsSerial.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/ 7 | 8 | This sketch uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximun 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | NOTE: 21 | - LOW interrupt trigges whenever the pin is low 22 | - HIGH interrupt triggers whenever the pin is high (Arduino Due, Zero, MKR1000 only) 23 | - CHANGE interrupt triggers whenever the pin changes value 24 | - RISING interrupt triggers when the pin goes from low to high 25 | - FALLING interrupt triggers when the pin goes from high to low 26 | 27 | Frameworks & Libraries: 28 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 29 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 30 | ESP32 Core - https://github.com/espressif/arduino-esp32 31 | ESP8266 Core - https://github.com/esp8266/Arduino 32 | STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32 33 | 34 | GNU GPL license, all text above must be included in any redistribution, 35 | see link for details - https://www.gnu.org/licenses/licenses.html 36 | */ 37 | /***************************************************************************************************/ 38 | #include 39 | 40 | #define PIN_A PB13 //ky-040 clk pin, add 100nF/0.1uF capacitors between pin & ground!!! 41 | #define PIN_B PB14 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 42 | #define BUTTON PB15 //ky-040 sw pin, add 100nF/0.1uF capacitors between pin & ground!!! 43 | 44 | int16_t position = 0; 45 | 46 | RotaryEncoder encoder(PIN_A, PIN_B, BUTTON); 47 | 48 | 49 | void encoderISR() 50 | { 51 | encoder.readAB(); 52 | } 53 | 54 | void encoderButtonISR() 55 | { 56 | encoder.readPushButton(); 57 | } 58 | 59 | void setup() 60 | { 61 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 62 | 63 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 64 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high->low changes 65 | 66 | Serial.begin(115200); 67 | } 68 | 69 | void loop() 70 | { 71 | if (position != encoder.getPosition()) 72 | { 73 | position = encoder.getPosition(); 74 | Serial.println(position); 75 | } 76 | 77 | if (encoder.getPushButton() == true) Serial.println(F("PRESSED")); //(F()) saves string to flash & keeps dynamic memory free 78 | } 79 | -------------------------------------------------------------------------------- /examples/STM32RotaryEncoderInterruptsSerialDirection/STM32RotaryEncoderInterruptsSerialDirection.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino sketch for RotaryEncoder library using interrupts 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/ 7 | 8 | This sketch uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximun 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | NOTE: 21 | - LOW interrupt trigges whenever the pin is low 22 | - HIGH interrupt triggers whenever the pin is high (Arduino Due, Zero, MKR1000 only) 23 | - CHANGE interrupt triggers whenever the pin changes value 24 | - RISING interrupt triggers when the pin goes from low to high 25 | - FALLING interrupt triggers when the pin goes from high to low 26 | 27 | Frameworks & Libraries: 28 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 29 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 30 | ESP32 Core - https://github.com/espressif/arduino-esp32 31 | ESP8266 Core - https://github.com/esp8266/Arduino 32 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 33 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 34 | 35 | GNU GPL license, all text above must be included in any redistribution, 36 | see link for details - https://www.gnu.org/licenses/licenses.html 37 | */ 38 | /***************************************************************************************************/ 39 | #include 40 | 41 | #define PIN_A PB13 //ky-040 clk pin, add 100nF/0.1uF capacitors between pin & ground!!! 42 | #define PIN_B PB14 //ky-040 dt pin, add 100nF/0.1uF capacitors between pin & ground!!! 43 | #define BUTTON PB15 //ky-040 sw pin, add 100nF/0.1uF capacitors between pin & ground!!! 44 | 45 | int8_t cw_ccw_idle = 0; //1=CW, 0=idle, -1=CCW, 46 | int16_t encoderPosition = 0; //encoder click counter, limit -32768..32767 47 | 48 | RotaryEncoder encoder(PIN_A, PIN_B, BUTTON); 49 | 50 | 51 | /**************************************************************************/ 52 | /* 53 | encoderISR() 54 | 55 | Encoder A & B pin interrupt service routine 56 | 57 | NOTE: 58 | - use interrupt pin for A pin!!! 59 | - add 100nF/0.1uF capacitors between A pin & ground!!! 60 | - add 100nF/0.1uF capacitors between B pin & ground!!! 61 | */ 62 | /**************************************************************************/ 63 | void encoderISR() 64 | { 65 | encoder.readAB(); 66 | } 67 | 68 | 69 | /**************************************************************************/ 70 | /* 71 | encoderButtonISR() 72 | 73 | Encoder button interrupt service routine 74 | 75 | NOTE: 76 | - use interrupt pin!!! 77 | - add 100nF/0.1uF capacitors between pin & ground!!! 78 | */ 79 | /**************************************************************************/ 80 | void encoderButtonISR() 81 | { 82 | encoder.readPushButton(); 83 | } 84 | 85 | 86 | /**************************************************************************/ 87 | /* 88 | setup() 89 | 90 | Main setup 91 | */ 92 | /**************************************************************************/ 93 | void setup() 94 | { 95 | encoder.begin(); //set encoders pins as input & enable built-in pullup resistors 96 | 97 | attachInterrupt(digitalPinToInterrupt(PIN_A), encoderISR, CHANGE); //call encoderISR() every high->low or low->high changes 98 | attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high->low changes 99 | 100 | Serial.begin(115200); 101 | 102 | Serial.println(); //start new line 103 | } 104 | 105 | 106 | /**************************************************************************/ 107 | /* 108 | loop() 109 | 110 | Main loop 111 | */ 112 | /**************************************************************************/ 113 | void loop() 114 | { 115 | if (encoderPosition != encoder.getPosition()) 116 | { 117 | encoderPosition = encoder.getPosition(); 118 | 119 | if (encoderPosition == 32767 || encoderPosition == -32767) 120 | { 121 | encoder.setPosition(0); 122 | 123 | encoderPosition = 0; 124 | } 125 | 126 | Serial.print(encoderPosition); 127 | } 128 | 129 | if (encoder.getPosition() > encoderPosition) 130 | { 131 | cw_ccw_idle = 1; //encoder rotating CW 132 | } 133 | else if (encoder.getPosition() < encoderPosition) 134 | { 135 | cw_ccw_idle = -1; //encoder rotating CCW 136 | } 137 | else 138 | { 139 | cw_ccw_idle = 0; //encoder idle 140 | } 141 | 142 | switch (cw_ccw_idle) 143 | { 144 | case 1: 145 | Serial.println(F(", CW")); //(F()) saves string to flash & keeps dynamic memory free 146 | break; 147 | 148 | case -1: 149 | Serial.println(F(", CCW")); 150 | break; 151 | } 152 | 153 | if (encoder.getPushButton() == true) Serial.println(F("PRESSED")); 154 | } 155 | -------------------------------------------------------------------------------- /images/rotary_encoder_shematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoyneering/RotaryEncoder/84bc2d99ef6f7b437386dd792c8b4cd03b81dec9/images/rotary_encoder_shematic.png -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map RotaryEncoder 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | ####################################### 10 | # Methods and Functions (KEYWORD2) 11 | ####################################### 12 | 13 | begin KEYWORD2 14 | readAB KEYWORD2 15 | readPushButton KEYWORD2 16 | 17 | getPosition KEYWORD2 18 | getPushButton KEYWORD2 19 | setPosition KEYWORD2 20 | setPushButton KEYWORD2 21 | 22 | getValue KEYWORD2 23 | setValue KEYWORD2 24 | 25 | getStepsPerClick KEYWORD2 26 | setStepsPerClick KEYWORD2 27 | 28 | getMinValue KEYWORD2 29 | setMinValue KEYWORD2 30 | 31 | getMaxValue KEYWORD2 32 | setMaxValue KEYWORD2 33 | 34 | setValues KEYWORD2 35 | 36 | ####################################### 37 | # Instances (KEYWORD2) 38 | ####################################### 39 | 40 | RotaryEncoder KEYWORD2 41 | RotaryEncoderAdvanced KEYWORD2 42 | 43 | ####################################### 44 | # Constants (LITERAL1) 45 | ####################################### 46 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RotaryEncoder", 3 | "keywords": "rotary, encoder, quadrature, ky-040, TimerOne, interrupt, sensor", 4 | "description": "Rotary Encoder with interrupts", 5 | "authors": 6 | { 7 | "name": "ejoyneering", 8 | "email": "enjoyneering@protonmail.com" 9 | }, 10 | "repository": 11 | { 12 | "type": "git", 13 | "url": "https://github.com/enjoyneering/RotaryEncoder.git" 14 | }, 15 | "version": "1.4.2", 16 | "frameworks": "arduino", 17 | "platforms": "*" 18 | } 19 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name = RotaryEncoder 2 | version = 1.4.2 3 | author = Enjoyneering 4 | maintainer = Enjoyneering 5 | sentence = Rotary Encoder with interrupts 6 | paragraph = Rotary Encoder with interrupts 7 | category = Device Control 8 | url = https://github.com/enjoyneering/RotaryEncoder 9 | architectures = * 10 | -------------------------------------------------------------------------------- /src/RotaryEncoder.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino library for Quadrature Rotary Encoder 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/RotaryEncoder 7 | 8 | This library uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximum 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | NOTE: 21 | - Quadrature encoder makes two waveforms that are 90° out of phase: 22 | _______ _______ __ 23 | PinA ___| |_______| |_______| PinA 24 | CCW <-- _______ _______ 25 | PinB _______| |_______| |______ PinB 26 | 27 | _______ _______ 28 | PinA _______| |_______| |______ PinA 29 | CW --> _______ _______ __ 30 | PinB ___| |_______| |_______| PinB 31 | 32 | 33 | The half of the pulses from top to bottom create full state array: 34 | 35 | prev.A+B cur.A+B (prev.AB+cur.AB) Array Encoder State 36 | ------- --------- -------------- ----- ------------- 37 | 00 00 0000 0 stop/idle 38 | 00 01 0001 1 CW, 0x01 39 | 00 10 0010 -1 CCW, 0x02 40 | 00 11 0011 0 invalid state 41 | 01 00 0100 -1 CCW, 0x04 42 | 01 01 0101 0 stop/idle 43 | 01 10 0110 0 invalid state 44 | 01 11 0111 1 CW, 0x07 45 | 10 00 1000 1 CW, 0x08 46 | 10 01 1001 0 invalid state 47 | 10 10 1010 0 stop/idle 48 | 10 11 1011 -1 CCW, 0x0B 49 | 11 00 1100 0 invalid state 50 | 11 01 1101 -1 CCW, 0x0D 51 | 11 10 1110 1 CW, 0x0E 52 | 11 11 1111 0 stop/idle 53 | 54 | - CW states 0b0001, 0b0111, 0b1000, 0b1110 55 | - CCW states 0b0010, 0b0100, 0b1011, 0b1101 56 | 57 | Frameworks & Libraries: 58 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 59 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 60 | ESP32 Core - https://github.com/espressif/arduino-esp32 61 | ESP8266 Core - https://github.com/esp8266/Arduino 62 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 63 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 64 | 65 | GNU GPL license, all text above must be included in any redistribution, 66 | see link for details - https://www.gnu.org/licenses/licenses.html 67 | */ 68 | /***************************************************************************************************/ 69 | 70 | #include "RotaryEncoder.h" 71 | 72 | 73 | /**************************************************************************/ 74 | /* 75 | Constructor 76 | */ 77 | /**************************************************************************/ 78 | RotaryEncoder::RotaryEncoder(uint8_t encoderA, uint8_t encoderB, uint8_t encoderButton) 79 | { 80 | _encoderA = encoderA; 81 | _encoderB = encoderB; 82 | _encoderButton = encoderButton; 83 | } 84 | 85 | /**************************************************************************/ 86 | /* 87 | begin 88 | 89 | Sets encoders pins as input & enables built-in pullup resistors 90 | 91 | NOTE: 92 | - high value of pull-up resistor limits the speed 93 | - typical value of external pull-up resistor is 10kOhm, acceptable 94 | range 5kOhm..100kOhm 95 | - for ESP8266 value of internal pull-up resistors is 30kOhm..100kOhm 96 | - for AVR value of internal pull-up resistors is 30kOhm..60kOhm 97 | */ 98 | /**************************************************************************/ 99 | void RotaryEncoder::begin() 100 | { 101 | pinMode(_encoderA, INPUT_PULLUP); //enable internal pull-up resistors 102 | pinMode(_encoderB, INPUT_PULLUP); 103 | pinMode(_encoderButton, INPUT_PULLUP); 104 | } 105 | 106 | /**************************************************************************/ 107 | /* 108 | readAB() 109 | 110 | Reads "A" & "B" pins value 111 | 112 | NOTE: 113 | - always call this function before getPosition() 114 | - 100nF/0.1μF capacitors between A & B channel pin & ground is a must!!! 115 | - for fast MCU like Cortex use Interrupt Service Routine with "CHANGE" 116 | parameter, ISR called when pin "A" changes from "1" to "0" 117 | or from "0" to "1" 118 | - for slow MCU like 8-bit AVR use Timer1 interrupt & TimerOne library 119 | - the ISR function must take no parameters & return nothing 120 | - delay() doesn't work during ISR & millis() doesn't increment 121 | - declare all global variables inside ISR as "volatile", it prevent 122 | compiler to make any optimization & unnecessary changes in the code 123 | with the variable 124 | */ 125 | /**************************************************************************/ 126 | void RotaryEncoder::readAB() 127 | { 128 | noInterrupts(); //disable interrupts 129 | 130 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) //slow MCU 131 | _currValueAB = (uint8_t)_digitalReadFast(_encoderA) << 1; 132 | _currValueAB |= (uint8_t)_digitalReadFast(_encoderB); 133 | #else //fast MCU 134 | _currValueAB = digitalRead(_encoderA) << 1; 135 | _currValueAB |= digitalRead(_encoderB); 136 | #endif 137 | 138 | switch ((_prevValueAB | _currValueAB)) 139 | { 140 | #if defined(__AVR__) //slow MCU 141 | case 0b1110: //CW states, 1 count per click 142 | //case 0b0001: case 0b1110: //CW states, 2 counts per click 143 | #else //fast MCU 144 | case 0b0001: case 0b1110: //CW states, 1 count per click 145 | //case 0b0001: case 0b1110: case 0b1000: case 0b0111: //CW states, 2 counts per click 146 | #endif 147 | _counter++; 148 | break; 149 | 150 | #if defined(__AVR__) //slow MCU 151 | case 0b0100: //CCW states, 1 count per click 152 | //case 0b0100: case 0b1011: //CCW states, 2 count per click 153 | #else //fast MCU 154 | case 0b0100: case 0b1011: //CCW states, 1 count per click 155 | //case 0b0100: case 0b1011: case 0b0010: case 0b1101: //CCW states, 2 counts per click 156 | #endif 157 | _counter--; 158 | break; 159 | } 160 | 161 | _prevValueAB = _currValueAB << 2; //update previouse state 162 | 163 | interrupts(); //enable interrupts 164 | } 165 | 166 | /**************************************************************************/ 167 | /* 168 | readPushButton() 169 | 170 | Reads push button value 171 | 172 | NOTE: 173 | - always call this function before getPushButton() 174 | - add 100nF/0.1μF capacitors between button pin & ground to 175 | reduce bounce!!! 176 | - designed to use with Interrupt Service Routine with "FALLING" 177 | parameter, ISR called when push button pin changes from "1" to "0" 178 | - the ISR function must take no parameters & return nothing 179 | - delay() doesn't work during ISR & millis() doesn't increment 180 | - declare all global variables inside ISR as "volatile", it prevent 181 | compiler to make any optimization & unnecessary changes in the code 182 | with the variable 183 | */ 184 | /**************************************************************************/ 185 | void RotaryEncoder::readPushButton() 186 | { 187 | noInterrupts(); //disable interrupts 188 | 189 | _buttonState = digitalRead(_encoderButton); //HIGH not pressed & LOW pressed, because internal pull-up resistor is enabled 190 | 191 | interrupts(); //enable interrupts 192 | } 193 | 194 | /**************************************************************************/ 195 | /* 196 | getPosition() 197 | 198 | Return encoder position 199 | */ 200 | /**************************************************************************/ 201 | int16_t RotaryEncoder::getPosition() 202 | { 203 | return _counter; 204 | } 205 | 206 | /**************************************************************************/ 207 | /* 208 | getPushButton() 209 | 210 | Return encoder button state 211 | 212 | NOTE: 213 | - convert "HIGH" to "false" when button is not presses 214 | - convert "LOW" to "true" when button is pressed 215 | */ 216 | /**************************************************************************/ 217 | bool RotaryEncoder::getPushButton() 218 | { 219 | if (_buttonState == true) return false; //button is not pressed 220 | 221 | _buttonState = true; //else button is pressed, flip variable to idle value 222 | 223 | return _buttonState; 224 | } 225 | 226 | /**************************************************************************/ 227 | /* 228 | setPosition() 229 | 230 | Manualy sets encoder position 231 | */ 232 | /**************************************************************************/ 233 | void RotaryEncoder::setPosition(int16_t position) 234 | { 235 | _counter = position; 236 | } 237 | 238 | /**************************************************************************/ 239 | /* 240 | setPushButton() 241 | 242 | Manualy sets encoder push button state 243 | 244 | NOTE: 245 | - "true" button is pressed 246 | - "false" button is not pressed 247 | */ 248 | /**************************************************************************/ 249 | void RotaryEncoder::setPushButton(bool state) 250 | { 251 | _buttonState = !state; 252 | } 253 | 254 | 255 | /**************************************************************************/ 256 | /* 257 | _fastDigitalRead() 258 | 259 | Replacemet for Arduino AVR "digitalRead()" function 260 | 261 | NOTE: 262 | - make shure you call "pinMode(pin, OUTPUT)" before using this 263 | function 264 | - Arduino AVR "digitalRead()" is so slow that MCU can't read both 265 | "A" & "B" pins fast enough during ISR to determine position of encoder 266 | - about 2.86 times faster than "digitalRead()" 267 | - ATmega8, ATmega168 & ATmega328P have 3 ports for pins: 268 | - port B, digital pins 8..13 (do not use B6 & B7, mapped to crystal) 269 | - port C, analog input pins 0..5 270 | - port D, digital pins 0..7 (do not use PD0 & PD1, mapped to serial) 271 | - each port is controlled by 3 registers & each bit of these registers 272 | corresponds to a single pin: 273 | - DDRx, port x Data Direction Register & determines whether the pin 274 | is an INPUT or OUTPUT (where x can be B, C or D) 275 | - PORTx, port x Data Register & controls whether the pin is HIGH or 276 | LOW 277 | - PINx, port x Input Pins Register & reads the state of INPUT pins 278 | */ 279 | /**************************************************************************/ 280 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) 281 | bool RotaryEncoder::_digitalReadFast(uint8_t pin) 282 | { 283 | switch (pin) //write spaces around " ... ", otherwise it may be parsed wrong 284 | { 285 | case 2: 286 | case 3: 287 | case 4: 288 | case 5: 289 | case 6: 290 | case 7: 291 | return (PIND) & (1 << (pin % 8)); //pin 2 (PIND) & 0x04; or (PIND) & (1 << PD2); 292 | 293 | case 9: 294 | case 10: 295 | case 11: 296 | case 12: 297 | case 13: 298 | return (PINB) & (1 << (pin % 8)); //pin 3 (PIND) & 0x08; or (PIND) & (1 << PD3); 299 | } 300 | 301 | return false; 302 | } 303 | #endif 304 | -------------------------------------------------------------------------------- /src/RotaryEncoder.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino library for Quadrature Rotary Encoder 4 | 5 | written by : enjoyneering79 6 | sourse code: https://github.com/enjoyneering/RotaryEncoder 7 | 8 | This library uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximum 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | NOTE: 21 | - Quadrature encoder makes two waveforms that are 90° out of phase: 22 | _______ _______ __ 23 | PinA ___| |_______| |_______| PinA 24 | CCW <-- _______ _______ 25 | PinB _______| |_______| |______ PinB 26 | 27 | _______ _______ 28 | PinA _______| |_______| |______ PinA 29 | CW --> _______ _______ __ 30 | PinB ___| |_______| |_______| PinB 31 | 32 | 33 | The half of the pulses from top to bottom create full state array: 34 | 35 | prev.A+B cur.A+B (prev.AB+cur.AB) Array Encoder State 36 | ------- --------- -------------- ----- ------------- 37 | 00 00 0000 0 stop/idle 38 | 00 01 0001 1 CW, 0x01 39 | 00 10 0010 -1 CCW, 0x02 40 | 00 11 0011 0 invalid state 41 | 01 00 0100 -1 CCW, 0x04 42 | 01 01 0101 0 stop/idle 43 | 01 10 0110 0 invalid state 44 | 01 11 0111 1 CW, 0x07 45 | 10 00 1000 1 CW, 0x08 46 | 10 01 1001 0 invalid state 47 | 10 10 1010 0 stop/idle 48 | 10 11 1011 -1 CCW, 0x0B 49 | 11 00 1100 0 invalid state 50 | 11 01 1101 -1 CCW, 0x0D 51 | 11 10 1110 1 CW, 0x0E 52 | 11 11 1111 0 stop/idle 53 | 54 | - CW states 0b0001, 0b0111, 0b1000, 0b1110 55 | - CCW states 0b0010, 0b0100, 0b1011, 0b1101 56 | 57 | Frameworks & Libraries: 58 | TimerOne AVR - https://github.com/PaulStoffregen/TimerOne 59 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 60 | ESP32 Core - https://github.com/espressif/arduino-esp32 61 | ESP8266 Core - https://github.com/esp8266/Arduino 62 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 63 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 64 | 65 | GNU GPL license, all text above must be included in any redistribution, 66 | see link for details - https://www.gnu.org/licenses/licenses.html 67 | */ 68 | /***************************************************************************************************/ 69 | #ifndef RotaryEncoder_h 70 | #define RotaryEncoder_h 71 | 72 | #if defined(ARDUINO) && ((ARDUINO) >= 100) //Arduino core v1.0 or later 73 | #include 74 | #else 75 | #include 76 | #endif 77 | 78 | #if defined(__AVR__) 79 | #include //PROGMEM support Arduino AVR 80 | #elif defined(ESP8266) 81 | #include //PROGMEM support Arduino ESP8266 82 | #elif defined(_VARIANT_ARDUINO_STM32_) 83 | #include //PROGMEM support Arduino STM32 84 | #endif 85 | 86 | 87 | class RotaryEncoder 88 | { 89 | public: 90 | RotaryEncoder(uint8_t encoderA, uint8_t encoderB, uint8_t encoderButton); 91 | 92 | void begin(); 93 | void readAB(); 94 | void readPushButton(); 95 | 96 | int16_t getPosition(); 97 | bool getPushButton(); 98 | 99 | void setPosition(int16_t position); 100 | void setPushButton(bool state); 101 | 102 | protected: 103 | volatile int16_t _counter = 0; //encoder click counter, limit -32768..32767 104 | 105 | private: 106 | volatile bool _buttonState = true; //encoder button status, idle value is "true" because internal pull-up resistor is enabled 107 | volatile uint8_t _prevValueAB = 0; //previouse state of "A"+"B" 108 | volatile uint8_t _currValueAB = 0; //current state of "A"+"B" 109 | 110 | uint8_t _encoderA; //pin "A" 111 | uint8_t _encoderB; //pin "B" 112 | uint8_t _encoderButton; //pin "button" 113 | 114 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) 115 | bool _digitalReadFast(uint8_t pin); 116 | #endif 117 | }; 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /src/RotaryEncoderAdvanced.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino library for Quadrature Rotary Encoder 4 | 5 | written by : enjoyneering 6 | sourse code: https://github.com/enjoyneering/RotaryEncoder 7 | 8 | This library uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximum 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | NOTE: 21 | - Quadrature encoder makes two waveforms that are 90 degree out of phase: 22 | _______ _______ __ 23 | PinA ___| |_______| |_______| PinA 24 | CCW <-- _______ _______ 25 | PinB _______| |_______| |______ PinB 26 | 27 | _______ _______ 28 | PinA _______| |_______| |______ PinA 29 | CW --> _______ _______ __ 30 | PinB ___| |_______| |_______| PinB 31 | 32 | 33 | The half of the pulses from top to bottom create full state array: 34 | 35 | prev.A+B cur.A+B (prev.AB+cur.AB) Array Encoder State 36 | ------- --------- -------------- ----- ------------- 37 | 00 00 0000 0 stop/idle 38 | 00 01 0001 1 CW, 0x01 39 | 00 10 0010 -1 CCW, 0x02 40 | 00 11 0011 0 invalid state 41 | 01 00 0100 -1 CCW, 0x04 42 | 01 01 0101 0 stop/idle 43 | 01 10 0110 0 invalid state 44 | 01 11 0111 1 CW, 0x07 45 | 10 00 1000 1 CW, 0x08 46 | 10 01 1001 0 invalid state 47 | 10 10 1010 0 stop/idle 48 | 10 11 1011 -1 CCW, 0x0B 49 | 11 00 1100 0 invalid state 50 | 11 01 1101 -1 CCW, 0x0D 51 | 11 10 1110 1 CW, 0x0E 52 | 11 11 1111 0 stop/idle 53 | 54 | - CW states 0b0001, 0b0111, 0b1000, 0b1110 55 | - CCW states 0b0010, 0b0100, 0b1011, 0b1101 56 | 57 | Frameworks & Libraries: 58 | AVR Core - https://github.com/arduino/ArduinoCore-avr 59 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 60 | ESP32 Core - https://github.com/espressif/arduino-esp32 61 | ESP8266 Core - https://github.com/esp8266/Arduino 62 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 63 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 64 | 65 | GNU GPL license, all text above must be included in any redistribution, 66 | see link for details - https://www.gnu.org/licenses/licenses.html 67 | */ 68 | /***************************************************************************************************/ 69 | #ifndef RotaryEncoderAdvanced_h 70 | #define RotaryEncoderAdvanced_h 71 | 72 | #include "RotaryEncoder.h" 73 | 74 | 75 | template class RotaryEncoderAdvanced : public RotaryEncoder 76 | { 77 | public: 78 | RotaryEncoderAdvanced(uint8_t encoderA, uint8_t encoderB, uint8_t encoderButton, T stepsPerClick, T minValue, T maxValue); 79 | 80 | T getValue(); 81 | void setValue(T value); 82 | 83 | T getStepsPerClick(); 84 | void setStepsPerClick(T value); 85 | 86 | T getMinValue(); 87 | void setMinValue(T value); 88 | 89 | T getMaxValue(); 90 | void setMaxValue(T value); 91 | 92 | void setValues(T currValue, T stepsPerClick, T minValue, T maxValue); 93 | 94 | private: 95 | T _stepsPerClick; //steps per click 96 | T _minValue; //min returned value 97 | T _maxValue; //max returned value 98 | }; 99 | 100 | #include "RotaryEncoderAdvanced.tpp" //linker can't find the *.cpp, see https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /src/RotaryEncoderAdvanced.tpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************************************/ 2 | /* 3 | This is an Arduino library for Quadrature Rotary Encoder 4 | 5 | written by : enjoyneering 6 | sourse code: https://github.com/enjoyneering/RotaryEncoder 7 | 8 | This library uses interrupts, specials pins are required to interface 9 | Board: int.0 int.1 int.2 int.3 int.4 int.5 Level 10 | Uno, Mini, Pro, ATmega168, ATmega328..... 2 3 x x x x 5v 11 | Mega2560................................. 2 3 21 20 19 18 5v 12 | Leonardo, Micro, ATmega32U4.............. 3 2 0 1 7 x 5v 13 | Digistump, Trinket, ATtiny85............. 2/physical pin 7 5v 14 | Due, SAM3X8E............................. all digital pins 3v 15 | Zero, ATSAMD21G18........................ all digital pins, except pin 4 3v 16 | Blue Pill, STM32F103xxxx boards.......... all digital pins, maximum 16 pins at the same time 3v 17 | ESP8266.................................. all digital pins, except gpio6 - gpio11 & gpio16 3v/5v 18 | ESP32.................................... all digital pins 3v 19 | 20 | NOTE: 21 | - Quadrature encoder makes two waveforms that are 90 degree out of phase: 22 | _______ _______ __ 23 | PinA ___| |_______| |_______| PinA 24 | CCW <-- _______ _______ 25 | PinB _______| |_______| |______ PinB 26 | 27 | _______ _______ 28 | PinA _______| |_______| |______ PinA 29 | CW --> _______ _______ __ 30 | PinB ___| |_______| |_______| PinB 31 | 32 | 33 | The half of the pulses from top to bottom create full state array: 34 | 35 | prev.A+B cur.A+B (prev.AB+cur.AB) Array Encoder State 36 | ------- --------- -------------- ----- ------------- 37 | 00 00 0000 0 stop/idle 38 | 00 01 0001 1 CW, 0x01 39 | 00 10 0010 -1 CCW, 0x02 40 | 00 11 0011 0 invalid state 41 | 01 00 0100 -1 CCW, 0x04 42 | 01 01 0101 0 stop/idle 43 | 01 10 0110 0 invalid state 44 | 01 11 0111 1 CW, 0x07 45 | 10 00 1000 1 CW, 0x08 46 | 10 01 1001 0 invalid state 47 | 10 10 1010 0 stop/idle 48 | 10 11 1011 -1 CCW, 0x0B 49 | 11 00 1100 0 invalid state 50 | 11 01 1101 -1 CCW, 0x0D 51 | 11 10 1110 1 CW, 0x0E 52 | 11 11 1111 0 stop/idle 53 | 54 | - CW states 0b0001, 0b0111, 0b1000, 0b1110 55 | - CCW states 0b0010, 0b0100, 0b1011, 0b1101 56 | 57 | Frameworks & Libraries: 58 | AVR Core - https://github.com/arduino/ArduinoCore-avr 59 | ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 60 | ESP32 Core - https://github.com/espressif/arduino-esp32 61 | ESP8266 Core - https://github.com/esp8266/Arduino 62 | STM32 Core - https://github.com/stm32duino/Arduino_Core_STM32 63 | - https://github.com/rogerclarkmelbourne/Arduino_STM32 64 | 65 | GNU GPL license, all text above must be included in any redistribution, 66 | see link for details - https://www.gnu.org/licenses/licenses.html 67 | */ 68 | /***************************************************************************************************/ 69 | 70 | #include "RotaryEncoderAdvanced.h" 71 | 72 | 73 | 74 | /**************************************************************************/ 75 | /* 76 | Constructor 77 | */ 78 | /**************************************************************************/ 79 | template RotaryEncoderAdvanced::RotaryEncoderAdvanced(uint8_t encoderA, uint8_t encoderB, uint8_t encoderButton, T stepsPerClick, T minValue, T maxValue) : RotaryEncoder(encoderA, encoderB, encoderButton) 80 | { 81 | setStepsPerClick(stepsPerClick); 82 | setMinValue(minValue); 83 | setMaxValue(maxValue); 84 | } 85 | 86 | /**************************************************************************/ 87 | /* 88 | getValue() 89 | 90 | Return encoder value 91 | */ 92 | /**************************************************************************/ 93 | template T RotaryEncoderAdvanced::getValue() 94 | { 95 | T value = (T)_counter * _stepsPerClick; 96 | 97 | /* make shure value never gets higher or lower thresholds */ 98 | if (value > _maxValue) 99 | { 100 | value = _maxValue; 101 | setValue(value); 102 | } 103 | else if (value < _minValue) 104 | { 105 | value = _minValue; 106 | setValue(value); 107 | } 108 | 109 | return value; 110 | } 111 | 112 | /**************************************************************************/ 113 | /* 114 | setValue() 115 | 116 | Manualy sets encoder value 117 | */ 118 | /**************************************************************************/ 119 | template void RotaryEncoderAdvanced::setValue(T value) 120 | { 121 | _counter = value / _stepsPerClick; 122 | } 123 | 124 | /**************************************************************************/ 125 | /* 126 | getStepsPerClick() 127 | 128 | Return steps per click value 129 | */ 130 | /**************************************************************************/ 131 | template T RotaryEncoderAdvanced::getStepsPerClick() 132 | { 133 | return _stepsPerClick; 134 | } 135 | 136 | /**************************************************************************/ 137 | /* 138 | setStepsPerClick() 139 | 140 | Set steps per click value 141 | */ 142 | /**************************************************************************/ 143 | template void RotaryEncoderAdvanced::setStepsPerClick(T value) 144 | { 145 | if (value == 0) return; //division by zero is prohibited 146 | 147 | _stepsPerClick = value; 148 | } 149 | 150 | /**************************************************************************/ 151 | /* 152 | getMinValue() 153 | 154 | Return minimum value 155 | */ 156 | /**************************************************************************/ 157 | template T RotaryEncoderAdvanced::getMinValue() 158 | { 159 | return _minValue; 160 | } 161 | 162 | /**************************************************************************/ 163 | /* 164 | setMinValue() 165 | 166 | Set minimum value 167 | */ 168 | /**************************************************************************/ 169 | template void RotaryEncoderAdvanced::setMinValue(T value) 170 | { 171 | _minValue = value; 172 | } 173 | 174 | /**************************************************************************/ 175 | /* 176 | getMaxValue() 177 | 178 | Return maximun value 179 | */ 180 | /**************************************************************************/ 181 | template T RotaryEncoderAdvanced::getMaxValue() 182 | { 183 | return _maxValue; 184 | } 185 | 186 | /**************************************************************************/ 187 | /* 188 | setMaxValue() 189 | 190 | Set maximun value 191 | */ 192 | /**************************************************************************/ 193 | template void RotaryEncoderAdvanced::setMaxValue(T value) 194 | { 195 | _maxValue = value; 196 | } 197 | 198 | /**************************************************************************/ 199 | /* 200 | setValues() 201 | 202 | Set current value, steps per click, minimum & maximun values 203 | */ 204 | /**************************************************************************/ 205 | template void RotaryEncoderAdvanced::setValues(T currValue, T stepsPerClick, T minValue, T maxValue) 206 | { 207 | noInterrupts(); //disable interrupts 208 | 209 | setStepsPerClick(stepsPerClick); 210 | setMinValue(minValue); 211 | setMaxValue(maxValue); 212 | setValue(currValue); 213 | 214 | interrupts(); //enable interrupts 215 | } 216 | --------------------------------------------------------------------------------