diff --git a/.github/workflows/LibraryBuild.yml b/.github/workflows/LibraryBuild.yml index 26d61f9..7ebb81b 100644 --- a/.github/workflows/LibraryBuild.yml +++ b/.github/workflows/LibraryBuild.yml @@ -38,17 +38,17 @@ jobs: - arduino:avr:uno - arduino:avr:leonardo - arduino:avr:mega - - digistump:avr:digispark-tiny1 + - digistump:avr:digispark-tiny:clock=clock1 - digistump:avr:digispark-pro - ATTinyCore:avr:attinyx5:chip=85,clock=1internal # Choose the right platform for the boards we want to test. (maybe in the future Arduino will automatically do this for you) - # With examples-exclude you may exclude specific examples for a board. Use a comma separated list. + # With sketches-exclude you may exclude specific examples for a board. Use a comma separated list. ############################################################################################################# include: - - arduino-boards-fqbn: digistump:avr:digispark-tiny1 # ATtiny85 board @1 MHz + - arduino-boards-fqbn: digistump:avr:digispark-tiny:clock=clock1 # ATtiny85 board @1 MHz platform-url: https://raw.githubusercontent.com/ArminJo/DigistumpArduino/master/package_digistump_index.json - examples-build-properties: + build-properties: EasyButtonExample: -DTX_PIN=PB0 @@ -57,7 +57,7 @@ jobs: - arduino-boards-fqbn: ATTinyCore:avr:attinyx5:chip=85,clock=1internal platform-url: http://drazzy.com/package_drazzy.com_index.json - examples-build-properties: + build-properties: EasyButtonExample: -DTX_PIN=PB0 @@ -73,5 +73,5 @@ jobs: with: arduino-board-fqbn: ${{ matrix.arduino-boards-fqbn }} platform-url: ${{ matrix.platform-url }} - examples-exclude: ${{ matrix.examples-exclude }} - examples-build-properties: ${{ toJson(matrix.examples-build-properties) }} + sketches-exclude: ${{ matrix.sketches-exclude }} + build-properties: ${{ toJson(matrix.build-properties) }} diff --git a/README.md b/README.md index 805bacf..f886a61 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # [EasyButton](https://github.com/ArminJo/EasyButtonAtInt01) Available as Arduino library "EasyButtonAtInt01" -### [Version 3.1.0](https://github.com/ArminJo/EasyButtonAtInt01/releases) +### [Version 3.2.0](https://github.com/ArminJo/EasyButtonAtInt01/releases) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Installation instructions](https://www.ardu-badge.com/badge/EasyButtonAtInt01.svg?)](https://www.ardu-badge.com/EasyButtonAtInt01) @@ -11,10 +11,10 @@ Available as Arduino library "EasyButtonAtInt01" Lightweight Arduino library for handling push buttons just connected between ground and INT0 and / or INT1 pin.
- No external pullup, **no polling needed**. -- The library is totally **based on interrupt** and **debouncing is implemented in a not blocking way**. +- The library is totally **based on interrupt** and **debouncing is implemented in a not blocking way**. Debouncing is merely done by ignoring a button change within the debouncing time (default 50 ms). So **button state is instantly available** without debouncing delay! -- Each button press toggles a state variable, so **no external logic for implementing a toggle button is needed**. +- Implements **toggle button** functionality. - Support for **double press detection** is included. See [EasyButtonExample](examples/EasyButtonExample/EasyButtonExample.ino#L112) and [Callback example](examples/Callback/Callback.ino#L78). - Support for **long press detection**, is included. See [Callback example](examples/Callback/Callback.ino#L98). - Support for **active high buttons**. @@ -24,12 +24,12 @@ So **button state is instantly available** without debouncing delay! ## Table of available pins for the 2 buttons | CPU | Button 0 | Button 1 using INT1 | Button 1 using PCINT, if INT1_PIN is defined !=3 | |-|-|-|-| -| ATmega328* | D2 | D3 | Pin 0 to 2, 4 to 7 | +| ATmega328* | D2 | D3 | Pin 0 to 2, 4 to 13, A0 to A5 | | ATtiny5x | PB2 | | PB0 - PB5 | | ATtiny167 | PB6 | PA3 | PA0 to PA2, PA4 to PA7 | To use the PCINT buttons instead of the default one, just define INT1_PIN **before** including *EasyButtonAtInt01.cpp.h*.
-E.g. `#define INT1_PIN 7`. See [EasyButtonExample.cpp](examples/EasyButtonExample/EasyButtonExample.ino#L46). +E.g. `#define INT1_PIN 7`. See [EasyButtonExample.cpp](examples/EasyButtonExample/EasyButtonExample.ino#L52). ## Usage To use a single button, it needs only: @@ -70,7 +70,7 @@ void loop() { The button press callback function is is called on every button press with ButtonToggleState as parameter.
**The value at the first call (after first press) is true**.
The button release callback function is called on every button release with the additional parameter ButtonPressDurationMillis.
-Both callback functions run in an interrupt service context, which means they should be as short as possible. +Both callback functions run in an interrupt service context, which means they should be as short as possible. But before a callback function is called, interrupts are enabled. This allows the timer interrupt for millis() to work and therfore **delay() and millis() can be used in a callback function**. @@ -136,11 +136,11 @@ void loop() {} ## Handling the `multiple definition` error If you get the error `multiple definition of __vector_1` (or `__vector_2`) because another library uses the attachInterrupt() function, -then comment out the line `#define USE_ATTACH_INTERRUPT` in *EasyButtonAtInt01.h* or +then activate the line `#define USE_ATTACH_INTERRUPT` in *EasyButtonAtInt01.h* or define global symbol with `-DUSE_ATTACH_INTERRUPT` which is not yet possible in Arduino IDE:-(.
-## Consider to use [Sloeber](http://eclipse.baeyens.it/stable.php?OS=Windows) as IDE
-If you are using Sloeber as your IDE, you can easily define global symbols at *Properties/Arduino/CompileOptions*.
+## Consider using [Sloeber](http://eclipse.baeyens.it/stable.php?OS=Windows) as IDE
+If you are using Sloeber as your IDE, you can easily define global symbols at *Properties > Arduino > CompileOptions*.
## Class methods ``` @@ -165,6 +165,9 @@ bool checkForForButtonNotPressedTime(uint16_t aTimeoutMillis); ``` # Revision History +### Version 3.2.0 +- Allow button1 on pin 8 to 13 and A0 to A5 for ATmega328. + ### Version 3.1.0 - 2 sets of constructors, one for only one button used and one for the second button if two buttons used. - Map pin numbers for Digispark pro boards, for use with with digispark library. @@ -196,7 +199,7 @@ The library examples are tested with GitHub Actions for the following boards: - arduino:avr:uno - arduino:avr:leonardo -- arduino:avr:mega +- arduino:avr:mega - digistump:avr:digispark-tiny1 - digistump:avr:digispark-pro - ATTinyCore:avr:attinyx5:chip=85,clock=1internal diff --git a/examples/Callback/Callback.ino b/examples/Callback/Callback.ino index 91698ce..3bf14fa 100644 --- a/examples/Callback/Callback.ino +++ b/examples/Callback/Callback.ino @@ -49,9 +49,8 @@ void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(115200); -#if defined(__AVR_ATmega32U4__) - while (!Serial) - ; //delay for Leonardo +#if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) + delay(2000); // To be able to connect Serial monitor after reset and before first printout #endif // Just to know which program is running on my Arduino Serial.println(F("START " __FILE__ "\r\nUsing library version " VERSION_EASY_BUTTON " from " __DATE__)); @@ -61,8 +60,8 @@ void loop() { delay(10); } -void blinkLEDBlocking(uint8_t aLedPin, uint16_t aDelay, uint8_t aRepetitions) { - for (uint8_t i = 0; i < aRepetitions; ++i) { +void blinkLEDBlocking(uint8_t aLedPin, uint8_t aBlinkCount, uint16_t aDelay) { + for (int i = 0; i < aBlinkCount; ++i) { digitalWrite(aLedPin, HIGH); delay(aDelay); digitalWrite(aLedPin, LOW); @@ -84,7 +83,7 @@ void handleButtonPress(bool aButtonToggleState) { Serial.println(F(" ms detected")); // let the led blink twice short - blinkLEDBlocking(LED_BUILTIN, BLINK_SHORT_MILLIS, 2); + blinkLEDBlocking(2, LED_BUILTIN, BLINK_SHORT_MILLIS); Button0AtPin2.ButtonToggleState = false; } Serial.println(F("Button pressed")); @@ -104,7 +103,7 @@ void handleButtonRelease(bool aButtonToggleState, uint16_t aButtonPressDurationM Serial.println(F(" ms detected")); // let the led blink long - blinkLEDBlocking(LED_BUILTIN, BLINK_LONG_MILLIS, 2); + blinkLEDBlocking(2, LED_BUILTIN, BLINK_LONG_MILLIS); Button0AtPin2.ButtonToggleState = false; } } diff --git a/examples/DebounceTest/DebounceTest.ino b/examples/DebounceTest/DebounceTest.ino index 5c10fbf..0c4e872 100644 --- a/examples/DebounceTest/DebounceTest.ino +++ b/examples/DebounceTest/DebounceTest.ino @@ -53,9 +53,8 @@ void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(115200); -#if defined(__AVR_ATmega32U4__) - while (!Serial) - ; //delay for Leonardo +#if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) + delay(2000); // To be able to connect Serial monitor after reset and before first printout #endif // Just to know which program is running on my Arduino Serial.println(F("START " __FILE__ "\r\nUsing library version " VERSION_EASY_BUTTON " from " __DATE__)); diff --git a/examples/EasyButtonExample/ATtinySerialOut.cpp b/examples/EasyButtonExample/ATtinySerialOut.cpp index dd04690..d4e1090 100644 --- a/examples/EasyButtonExample/ATtinySerialOut.cpp +++ b/examples/EasyButtonExample/ATtinySerialOut.cpp @@ -32,10 +32,11 @@ * */ -#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) -#include +#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) \ + || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) \ + || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) #include "ATtinySerialOut.h" -#include // for eeprom_read_byte() +#include // for eeprom_read_byte() in writeString_E() #ifndef _NOP #define _NOP() __asm__ volatile ("nop") @@ -45,10 +46,49 @@ #define PORTB (*(volatile uint8_t *)((0x18) + 0x20)) #endif +#if defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) +# ifndef TX_PORT +#define TX_PORT PORTA +#define TX_PORT_ADDR 0x02 // PORTA +#define TX_DDR DDRA + +//#define TX_PORT PORTB +//#define TX_PORT_ADDR 0x05 +//#define TX_DDR DDRB +# endif + +#else +// ATtinyX5 here +#define TX_PORT PORTB +#define TX_PORT_ADDR 0x18 // PORTB +#define TX_DDR DDRB +#endif // defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) + +void write1Start8Data1StopNoParity(uint8_t aValue); + +bool sUseCliSeiForWrite = true; + +void initTXPin() { + // TX_PIN is active LOW, so set it to HIGH initially + TX_PORT |= (1 << TX_PIN); + // set pin direction to output + TX_DDR |= (1 << TX_PIN); +} + +void write1Start8Data1StopNoParityWithCliSei(uint8_t aValue) { + uint8_t oldSREG = SREG; + cli(); + write1Start8Data1StopNoParity(aValue); + SREG = oldSREG; +} + +void writeValue(uint8_t aValue) { + write1Start8Data1StopNoParity(aValue); +} + /* * Used for writeString() and therefore all write() and print */ -bool sUseCliSeiForWrite = true; void useCliSeiForStrings(bool aUseCliSeiForWrite) { sUseCliSeiForWrite = aUseCliSeiForWrite; } @@ -56,14 +96,14 @@ void useCliSeiForStrings(bool aUseCliSeiForWrite) { /* * Write String residing in RAM */ -void writeString(const char * aStringPtr) { -#ifndef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT +void writeString(const char *aStringPtr) { +#ifndef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT if (sUseCliSeiForWrite) { #endif while (*aStringPtr != 0) { write1Start8Data1StopNoParityWithCliSei(*aStringPtr++); } -#ifndef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT +#ifndef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT } else { while (*aStringPtr != 0) { write1Start8Data1StopNoParity(*aStringPtr++); @@ -75,11 +115,11 @@ void writeString(const char * aStringPtr) { /* * Write string residing in program space (FLASH) */ -void writeString_P(const char * aStringPtr) { +void writeString_P(const char *aStringPtr) { uint8_t tChar = pgm_read_byte((const uint8_t * ) aStringPtr); // Comparing with 0xFF is safety net for wrong string pointer while (tChar != 0 && tChar != 0xFF) { -#ifdef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT +#ifdef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT write1Start8Data1StopNoParityWithCliSei(tChar); #else if (sUseCliSeiForWrite) { @@ -95,12 +135,12 @@ void writeString_P(const char * aStringPtr) { /* * Write string residing in program space (FLASH) */ -void writeString(const __FlashStringHelper * aStringPtr) { +void writeString(const __FlashStringHelper *aStringPtr) { PGM_P tPGMStringPtr = reinterpret_cast(aStringPtr); uint8_t tChar = pgm_read_byte((const uint8_t * ) aStringPtr); // Comparing with 0xFF is safety net for wrong string pointer while (tChar != 0 && tChar != 0xFF) { -#ifdef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT +#ifdef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT write1Start8Data1StopNoParityWithCliSei(tChar); #else if (sUseCliSeiForWrite) { @@ -116,11 +156,11 @@ void writeString(const __FlashStringHelper * aStringPtr) { /* * Write string residing in EEPROM space */ -void writeString_E(const char * aStringPtr) { +void writeString_E(const char *aStringPtr) { uint8_t tChar = eeprom_read_byte((const uint8_t *) aStringPtr); // Comparing with 0xFF is safety net for wrong string pointer while (tChar != 0 && tChar != 0xFF) { -#ifdef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT +#ifdef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT write1Start8Data1StopNoParityWithCliSei(tChar); #else if (sUseCliSeiForWrite) { @@ -133,30 +173,30 @@ void writeString_E(const char * aStringPtr) { } } -void writeStringWithoutCliSei(const char * aStringPtr) { +void writeStringWithoutCliSei(const char *aStringPtr) { while (*aStringPtr != 0) { write1Start8Data1StopNoParity(*aStringPtr++); } } -void writeStringWithCliSei(const char * aStringPtr) { +void writeStringWithCliSei(const char *aStringPtr) { while (*aStringPtr != 0) { write1Start8Data1StopNoParityWithCliSei(*aStringPtr++); } } -void writeStringSkipLeadingSpaces(const char * aStringPtr) { +void writeStringSkipLeadingSpaces(const char *aStringPtr) { // skip leading spaces while (*aStringPtr == ' ' && *aStringPtr != 0) { aStringPtr++; } -#ifndef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT +#ifndef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT if (sUseCliSeiForWrite) { #endif while (*aStringPtr != 0) { write1Start8Data1StopNoParityWithCliSei(*aStringPtr++); } -#ifndef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT +#ifndef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT } else { while (*aStringPtr != 0) { write1Start8Data1StopNoParity(*aStringPtr++); @@ -166,7 +206,7 @@ void writeStringSkipLeadingSpaces(const char * aStringPtr) { } void writeBinary(uint8_t aByte) { -#ifdef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT +#ifdef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT write1Start8Data1StopNoParityWithCliSei(aByte); #else if (sUseCliSeiForWrite) { @@ -192,23 +232,6 @@ void writeUnsignedByte(uint8_t aByte) { writeStringSkipLeadingSpaces(tStringBuffer); } -/* - * 2 Byte Hex output with 2 Byte prefix "0x" - */ -void writeUnsignedByteHexWithPrefix(uint8_t aByte) { - writeBinary('0'); - writeBinary('x'); - writeUnsignedByteHex(aByte); -} - -char nibbleToHex(uint8_t aByte) { - aByte = aByte & 0x0F; - if (aByte < 10) { - return aByte + '0'; - } - return aByte + 'A' - 10; -} - /* * 2 Byte Hex output */ @@ -227,6 +250,23 @@ void writeUnsignedByteHex(uint8_t aByte) { writeString(tStringBuffer); } +/* + * 2 Byte Hex output with 2 Byte prefix "0x" + */ +void writeUnsignedByteHexWithPrefix(uint8_t aByte) { + writeBinary('0'); + writeBinary('x'); + writeUnsignedByteHex(aByte); +} + +char nibbleToHex(uint8_t aByte) { + aByte = aByte & 0x0F; + if (aByte < 10) { + return aByte + '0'; + } + return aByte + 'A' - 10; +} + void writeByte(int8_t aByte) { char tStringBuffer[5]; itoa(aByte, tStringBuffer, 10); @@ -269,31 +309,16 @@ void writeFloat(double aFloat, uint8_t aDigits) { writeStringSkipLeadingSpaces(tStringBuffer); } -/* - * The Serial Instance!!! - */ - -// #if ... to be compatible with ATTinyCores and AttinyDigisparkCores -#if ((!defined(UBRRH) && !defined(UBRR0H)) || (defined(USE_SOFTWARE_SERIAL) && (USE_SOFTWARE_SERIAL != 0))) || defined(TINY_DEBUG_SERIAL_SUPPORTED) || ((defined(UBRRH) || defined(UBRR0H) || defined(LINBRRH)) && (defined(USE_SOFTWARE_SERIAL) && (USE_SOFTWARE_SERIAL == 0))) -// Switch to SerialOut since Serial is already defined or comment out -// at line 54 in TinySoftwareSerial.h included in in ATTinyCores/src/tiny/Arduino.h at line 228 for ATTinyCores -// or line 71 in HardwareSerial.h included in ATTinyCores/src/tiny/Arduino.h at line 227 for ATTinyCores -// or line 627ff TinyDebugSerial.h included in AttinyDigisparkCores/src/tiny/WProgram.h at line 18 for AttinyDigisparkCores -TinySerialOut SerialOut; -#else -TinySerialOut Serial; -#endif - -/* - * Member functions for TinySerialOut - */ - +/****************************************************** + * The TinySerialOut class fuctions which implements + * the Serial + printHex() and printlnHex() functions + ******************************************************/ /* * An alternative way to call the init function :-) */ void TinySerialOut::begin(long aBaudrate) { initTXPin(); -#if defined(USE_115200BAUD) //else smaller code, but only 38400 baud at 1 MHz +#if defined(USE_115200BAUD) // else smaller code, but only 38400 baud at 1 MHz if (aBaudrate != 115200) { println(F("Only 115200 supported!")); } @@ -346,11 +371,11 @@ size_t TinySerialOut::write(uint8_t aByte) { return 1; } -void TinySerialOut::print(const char* aStringPtr) { +void TinySerialOut::print(const char *aStringPtr) { writeString(aStringPtr); } -void TinySerialOut::print(const __FlashStringHelper * aStringPtr) { +void TinySerialOut::print(const __FlashStringHelper *aStringPtr) { writeString(aStringPtr); } @@ -406,12 +431,12 @@ void TinySerialOut::println(char aChar) { println(); } -void TinySerialOut::println(const char* aStringPtr) { +void TinySerialOut::println(const char *aStringPtr) { print(aStringPtr); println(); } -void TinySerialOut::println(const __FlashStringHelper * aStringPtr) { +void TinySerialOut::println(const __FlashStringHelper *aStringPtr) { print(aStringPtr); println(); } @@ -451,6 +476,20 @@ void TinySerialOut::println() { print('\n'); } +/* + * The Serial Instance!!! + */ +// #if ... to be compatible with ATTinyCores and AttinyDigisparkCores +#if (!defined(UBRRH) && !defined(UBRR0H)) /*AttinyDigisparkCore and AttinyDigisparkCore condition*/ \ + || USE_SOFTWARE_SERIAL /*AttinyDigisparkCore condition*/\ + || ((defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(LINBRRH)) && !USE_SOFTWARE_SERIAL)/*AttinyDigisparkCore condition for HardwareSerial*/ +// Switch to SerialOut since Serial is already defined +// or activate line 745 in TinyDebugSerial.h included in AttinyDigisparkCores/src/tiny/WProgram.h at line 24 for AttinyDigisparkCores +TinySerialOut SerialOut; +#else +TinySerialOut Serial; +#endif + /******************************** * Basic serial output function *******************************/ @@ -813,4 +852,3 @@ void write1Start8Data1StopNoParity_C_Version(uint8_t aValue) { delay4CyclesInlineExact(4); // gives minimum 25 cycles for stop bit :-) } #endif // defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) - diff --git a/examples/EasyButtonExample/ATtinySerialOut.h b/examples/EasyButtonExample/ATtinySerialOut.h index 17ee3e0..4260c43 100644 --- a/examples/EasyButtonExample/ATtinySerialOut.h +++ b/examples/EasyButtonExample/ATtinySerialOut.h @@ -52,98 +52,65 @@ #ifndef ATTINY_SERIAL_OUT_H_ #define ATTINY_SERIAL_OUT_H_ -#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) +#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) \ + || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) \ + || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) #include -#define VERSION_ATTINY_SERIAL_OUT "1.1.0" +#define VERSION_ATTINY_SERIAL_OUT "1.2.1" #define VERSION_ATTINY_SERIAL_OUT_MAJOR 1 -#define VERSION_ATTINY_SERIAL_OUT_MINOR 1 +#define VERSION_ATTINY_SERIAL_OUT_MINOR 2 #if (F_CPU != 1000000) && (F_CPU != 8000000) && (F_CPU != 16000000) -#error "F_CPU value must be 1000000, 8000000 or 16000000." +#error F_CPU value must be 1000000, 8000000 or 16000000. #endif -/* - * Change this, if you need another pin as serial output - * or set it as Symbol like "-DTX_PIN PB1" - * or when switching port (e.g. for ATiny167), then we need more Symbols like "-DTX_PIN PB1 -DTX_PORT PORTB -DTX_PORT_ADDR 0x05 -TX_DDR DDRB" - */ #if defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) -#ifndef TX_PIN +# ifndef TX_PIN #define TX_PIN PA1 // (package pin 2 / TXD on Tiny167) - can use one of PA0 to PA7 here -#endif -#ifndef TX_PORT -#define TX_PORT PORTA -#define TX_PORT_ADDR 0x02 // PORTA -#define TX_DDR DDRA - -//#define TX_PORT PORTB -//#define TX_PORT_ADDR 0x05 -//#define TX_DDR DDRB -#endif - +# endif #else // defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) -#ifndef TX_PIN +# ifndef TX_PIN #define TX_PIN PB2 // (package pin 7 on Tiny85) - can use one of PB0 to PB4 (+PB5) here +# endif #endif -#define TX_PORT PORTB -#define TX_PORT_ADDR 0x18 // PORTB -#define TX_DDR DDRB -#endif // defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) + +/* + * Activate this, if you want to save 10 bytes code size and if you can live + * with 87 micro seconds intervals of disabled interrupts for each sent byte @115200 baud. + */ +//#define USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT + /* * @1 MHz use bigger (+120 bytes for unrolled loop) but faster code. Otherwise only 38400 baud is possible. * @8/16 MHz use 115200 baud instead of 230400 baud. */ +//#define TINY_SERIAL_DO_NOT_USE_115200BAUD #ifndef TINY_SERIAL_DO_NOT_USE_115200BAUD // define this to force using other baud rates #define USE_115200BAUD #endif -/* - * Define or comment this out, if you want to save code size and if you can live with 87 micro seconds intervals of disabled interrupts for each sent byte. - */ -//#define USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT -extern bool sUseCliSeiForWrite; // default is true -void useCliSeiForStrings(bool aUseCliSeiForWrite); // might be useful to set to false if output is done from ISR, to avoid to call unwanted sei(). - -inline void initTXPin() { - // TX_PIN is active LOW, so set it to HIGH initially - TX_PORT |= (1 << TX_PIN); - // set pin direction to output - TX_DDR |= (1 << TX_PIN); -} - -void write1Start8Data1StopNoParity(uint8_t aValue); -inline void write1Start8Data1StopNoParityWithCliSei(uint8_t aValue) { - uint8_t oldSREG = SREG; - cli(); - write1Start8Data1StopNoParity(aValue); - SREG = oldSREG; -} - -inline void writeValue(uint8_t aValue) { - write1Start8Data1StopNoParity(aValue); -} - // The same class definition as for plain arduino -#if defined(ARDUINO_AVR_DIGISPARK) -// The digispark library defines (2/2019) F but not __FlashStringHelper -//# define F(string_literal) ((fstr_t*)PSTR(string_literal)) -# if ! defined(__FlashStringHelper) -#define __FlashStringHelper fstr_t -# endif -#endif #if not defined(F) class __FlashStringHelper; #define F(string_literal) (reinterpret_cast(PSTR(string_literal))) #endif -void writeString(const char * aStringPtr); -void writeString(const __FlashStringHelper * aStringPtr); -void writeString_P(const char * aStringPtr); -void writeString_E(const char * aStringPtr); -void writeStringWithCliSei(const char * aStringPtr); -void writeStringWithoutCliSei(const char * aStringPtr); -void writeStringSkipLeadingSpaces(const char * aStringPtr); +extern bool sUseCliSeiForWrite; // default is true +void useCliSeiForStrings(bool aUseCliSeiForWrite); // might be useful to set to false if output is done from ISR, to avoid to call unwanted sei(). + +void initTXPin(); +void write1Start8Data1StopNoParity(uint8_t aValue); +void write1Start8Data1StopNoParityWithCliSei(uint8_t aValue); +void writeValue(uint8_t aValue); + +void writeString(const char *aStringPtr); +void writeString(const __FlashStringHelper *aStringPtr); +void writeString_P(const char *aStringPtr); +void writeString_E(const char *aStringPtr); +void writeStringWithCliSei(const char *aStringPtr); +void writeStringWithoutCliSei(const char *aStringPtr); +void writeStringSkipLeadingSpaces(const char *aStringPtr); void writeBinary(uint8_t aByte); // write direct without decoding void writeChar(uint8_t aChar); // Synonym for writeBinary @@ -176,10 +143,10 @@ class TinySerialOut // virtual functions of Print class size_t write(uint8_t aByte); - operator bool() { return true; } // To support "while (!Serial); // wait for serial port to connect. Needed for Leonardo only + operator bool(); // To support "while (!Serial); // wait for serial port to connect. Required for Leonardo only - void print(const __FlashStringHelper * aStringPtr); - void print(const char* aStringPtr); + void print(const __FlashStringHelper *aStringPtr); + void print(const char *aStringPtr); void print(char aChar); void print(uint8_t aByte, uint8_t aBase = 10); void print(int16_t aInteger, uint8_t aBase = 10); @@ -188,8 +155,8 @@ class TinySerialOut void print(uint32_t aLong, uint8_t aBase = 10); void print(double aFloat, uint8_t aDigits = 2); - void println(const char* aStringPtr); - void println(const __FlashStringHelper * aStringPtr); + void println(const char *aStringPtr); + void println(const __FlashStringHelper *aStringPtr); void println(char aChar); void println(uint8_t aByte, uint8_t aBase = 10); void println(int16_t aInteger, uint8_t aBase = 10); @@ -203,14 +170,17 @@ class TinySerialOut }; // #if ... to be compatible with ATTinyCores and AttinyDigisparkCores -#if ((!defined(UBRRH) && !defined(UBRR0H)) || (defined(USE_SOFTWARE_SERIAL) && (USE_SOFTWARE_SERIAL != 0))) || defined(TINY_DEBUG_SERIAL_SUPPORTED) || ((defined(UBRRH) || defined(UBRR0H) || defined(LINBRRH)) && (defined(USE_SOFTWARE_SERIAL) && (USE_SOFTWARE_SERIAL == 0))) -// Switch to SerialOut since Serial is already defined or comment out -// at line 54 in TinySoftwareSerial.h included in in ATTinyCores/src/tiny/Arduino.h at line 228 for ATTinyCores -// or line 71 in HardwareSerial.h included in ATTinyCores/src/tiny/Arduino.h at line 227 for ATTinyCores -// or line 627ff TinyDebugSerial.h included in AttinyDigisparkCores/src/tiny/WProgram.h at line 18 for AttinyDigisparkCores +#if (!defined(UBRRH) && !defined(UBRR0H)) /*AttinyDigisparkCore and AttinyDigisparkCore condition*/ \ + || USE_SOFTWARE_SERIAL /*AttinyDigisparkCore condition*/\ + || ((defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(LINBRRH)) && !USE_SOFTWARE_SERIAL)/*AttinyDigisparkCore condition for HardwareSerial*/ +// Switch to SerialOut since Serial is already defined +// or activate line 745 in TinyDebugSerial.h included in AttinyDigisparkCores/src/tiny/WProgram.h at line 24 for AttinyDigisparkCores extern TinySerialOut SerialOut; #define Serial SerialOut #else +# if defined(Serial) +#undef Serial +# endif extern TinySerialOut Serial; #endif #define Print TinySerialOut diff --git a/examples/EasyButtonExample/EasyButtonExample.ino b/examples/EasyButtonExample/EasyButtonExample.ino index 02c65e1..836eb26 100644 --- a/examples/EasyButtonExample/EasyButtonExample.ino +++ b/examples/EasyButtonExample/EasyButtonExample.ino @@ -38,7 +38,7 @@ #include "ATtinySerialOut.h" # if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) && TX_PIN == PB2 -#error "Please change TX_PIN in ATtinySerialOut.h from PB2 to e.g. PB0 for use with this example" +#error Please change TX_PIN in ATtinySerialOut.h from PB2 to e.g. PB0 for use with this example # endif # if defined(ARDUINO_AVR_DIGISPARK) @@ -72,9 +72,8 @@ void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(115200); -#if defined(__AVR_ATmega32U4__) - while (!Serial) - ; //delay for Leonardo +#if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) + delay(2000); // To be able to connect Serial monitor after reset and before first printout #endif // Just to know which program is running on my Arduino Serial.println(F("START " __FILE__ "\r\nUsing library version " VERSION_EASY_BUTTON " from " __DATE__)); diff --git a/examples/OneButton/OneButton.ino b/examples/OneButton/OneButton.ino index 73413af..1bff8fc 100644 --- a/examples/OneButton/OneButton.ino +++ b/examples/OneButton/OneButton.ino @@ -46,9 +46,8 @@ void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(115200); -#if defined(__AVR_ATmega32U4__) - while (!Serial) - ; //delay for Leonardo +#if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) + delay(2000); // To be able to connect Serial monitor after reset and before first printout #endif // Just to know which program is running on my Arduino Serial.println(F("START " __FILE__ "\r\nUsing library version " VERSION_EASY_BUTTON " from " __DATE__)); diff --git a/library.json b/library.json index 6cbb003..36738b8 100644 --- a/library.json +++ b/library.json @@ -1,12 +1,12 @@ { - "name": "ServoEasing", - "keywords": "Servo", - "description": "Arduino library to enable smooth servo movement.", + "name": "EasyButtonAtInt01", + "keywords": "Button, debounce, interrupt", + "description": "Small and easy to use Arduino library for using push buttons at any PinChangeInterrupt pin. Automatic debouncing, no delay required.", "repository": { "type": "git", - "url": "https://github.com/ArminJo/ServoEasing" + "url": "https://github.com/ArminJo/EasyButtonAtInt01" }, - "version": "2.0.0", + "version": "3.2.0", "exclude": "pictures", "authors": { "name": "Armin Joachimsmeyer", @@ -15,11 +15,6 @@ "license": "GPL-3.0-or-later", "frameworks": "arduino", "platforms": [ - "atmelavr", - "atmelmegaavr", - "atmelsam", - "espressif8266", - "espressif32", - "ststm32" + "atmelavr" ] } \ No newline at end of file diff --git a/library.properties b/library.properties index b9b3606..a7cc386 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=EasyButtonAtInt01 -version=3.1.0 +version=3.2.0 author=Armin Joachimsmeyer -maintainer=Armin Joachimsmeyer -sentence=Small and easy to use Arduino library for using push buttons at INT0/pin2 and / or INT1/pin3 using interrupts.
Functions for long and double press detection are included.

Just connect buttons between ground and pin 2 or 3 of your Arduino - that's it

No call of begin() or polling function like update() required. No blocking debouncing delay.
-paragraph=
Define an EasyButtonIn in you main program and use ButtonStateIsActive or ButtonToggleState to determine your action.
Or use a callback function which will be called once on every button press or release.

Usage:
#define USE_BUTTON_0
#include "EasyButtonAtInt01.cpp.h"
EasyButton Button0AtPin2;

void setup() {}
void loop() {
...
digitalWrite(LED_BUILTIN, Button0AtPin2.ButtonToggleState);
...
}


New: 2 sets of constructors.
+maintainer=Armin Joachimsmeyer +sentence=Small and easy to use Arduino library for using push buttons at INT0/pin2 and / or any PinChangeInterrupt pin.
Functions for long and double press detection are included.

Just connect buttons between ground and any pin of your Arduino - that's it

No call of begin() or polling function like update() required. No blocking debouncing delay.
+paragraph=
Define an EasyButtonIn in you main program and use ButtonStateIsActive or ButtonToggleState to determine your action.
Or use a callback function which will be called once on every button press or release.

Usage:
#define USE_BUTTON_0
#include "EasyButtonAtInt01.cpp.h"
EasyButton Button0AtPin2;

void setup() {}
void loop() {
...
digitalWrite(LED_BUILTIN, Button0AtPin2.ButtonToggleState);
...
}


New: Second button now possible on each ATmega328 pin.
category=Signal Input/Output url=https://github.com/ArminJo/EasyButtonAtInt01 architectures=avr diff --git a/src/EasyButtonAtInt01.cpp.h b/src/EasyButtonAtInt01.cpp.h index 9c9ecf9..c6b4619 100644 --- a/src/EasyButtonAtInt01.cpp.h +++ b/src/EasyButtonAtInt01.cpp.h @@ -34,6 +34,7 @@ * along with this program. If not, see . */ +#if defined(__AVR__) #include #include "EasyButtonAtInt01.h" @@ -52,17 +53,19 @@ // For external measurement of code timing //#define MEASURE_EASY_BUTTON_INTERRUPT_TIMING -#if defined(MEASURE_EASY_BUTTON_INTERRUPT_TIMING) || defined (LED_FEEDBACK_TEST) +#if defined(MEASURE_EASY_BUTTON_INTERRUPT_TIMING) || defined(LED_FEEDBACK_TEST) #include "digitalWriteFast.h" #endif #if defined(USE_BUTTON_0) -EasyButton * EasyButton::sPointerToButton0ForISR; +EasyButton *EasyButton::sPointerToButton0ForISR; #endif #if defined(USE_BUTTON_1) -EasyButton * EasyButton::sPointerToButton1ForISR; +EasyButton *EasyButton::sPointerToButton1ForISR; #endif +// @formatter:off // the eclipse formatter has problems with // comments in undefined code blocks + /* * These constructors are deterministic if only one button is enabled * If two buttons are enabled they can be taken for the 1. button at INT0 @@ -267,19 +270,25 @@ void EasyButton::init(bool aIsButtonAtINT0) { GIMSK |= 1 << PCIE; // PCINT enable, we have only one PCMSK = digitalPinToBitMask(INT1_PIN); # endif -# elif (INT1_PIN != 3) - /* - * ATmega328 (Uno, Nano ) etc. Enable pin change interrupt for port PD0 to PD7 (Arduino pin 0 to 7) - */ - PCICR |= 1 << PCIE2; - PCMSK2 = digitalPinToBitMask(INT1_PIN); +# elif INT1_PIN == 4 || INT1_PIN == 5 || INT1_PIN == 6 || INT1_PIN == 7 + //ATmega328 (Uno, Nano ) etc. Enable pin change interrupt for port PD0 to PD7 (Arduino pin 0 to 7) + PCICR |= 1 << PCIE2; + PCMSK2 = digitalPinToBitMask(INT1_PIN); +# elif INT1_PIN == 8 || INT1_PIN == 9 || INT1_PIN == 10 || INT1_PIN == 11 || INT1_PIN == 12 || INT1_PIN == 13 + //ATmega328 (Uno, Nano ) etc. Enable pin change interrupt 0 to 5 for port PB0 to PB5 (Arduino pin 8 to 13) + PCICR |= _BV(PCIE0); + PCMSK0 = digitalPinToBitMask(INT1_PIN); +# elif INT1_PIN == A0 || INT1_PIN == A1 || INT1_PIN == A2 || INT1_PIN == A3 || INT1_PIN == A4 || INT1_PIN == A5 + //ATmega328 (Uno, Nano ) etc. Enable pin change interrupt 8 to 13 for port PC0 to PC5 (Arduino pin A0 to A5) + PCICR |= _BV(PCIE1); + PCMSK1 = digitalPinToBitMask(INT1_PIN); # else # if defined(USE_ATTACH_INTERRUPT) - attachInterrupt(digitalPinToInterrupt(INT1_PIN), &handleINT1Interrupt, CHANGE); + attachInterrupt(digitalPinToInterrupt(INT1_PIN), &handleINT1Interrupt, CHANGE); # else - EICRA |= (1 << ISC10); // interrupt on any logical change - EIFR |= 1 << INTF1; // clear interrupt bit - EIMSK |= 1 << INT1; // enable interrupt on next change + EICRA |= (1 << ISC10); // interrupt on any logical change + EIFR |= 1 << INTF1; // clear interrupt bit + EIMSK |= 1 << INT1; // enable interrupt on next change # endif //USE_ATTACH_INTERRUPT # endif // ! defined(ISC10) } @@ -294,35 +303,37 @@ void EasyButton::init(bool aIsButtonAtINT0) { bool EasyButton::readButtonState() { #if defined(USE_BUTTON_0) && not defined(USE_BUTTON_1) # if defined(BUTTON_IS_ACTIVE_HIGH) - return (INT0_IN_PORT & _BV(INT0_BIT)); // = digitalReadFast(2); + return (INT0_IN_PORT & _BV(INT0_BIT)); // = digitalReadFast(2); # else - return !(INT0_IN_PORT & _BV(INT0_BIT)); // = digitalReadFast(2); + return !(INT0_IN_PORT & _BV(INT0_BIT)); // = digitalReadFast(2); # endif #elif defined(USE_BUTTON_1) && not defined(USE_BUTTON_0) # if defined(BUTTON_IS_ACTIVE_HIGH) - return (INT1_IN_PORT & _BV(INT1_BIT)); // = digitalReadFast(3); + return (INT1_IN_PORT & _BV(INT1_BIT)); // = digitalReadFast(3); # else - return !(INT1_IN_PORT & _BV(INT1_BIT)); // = digitalReadFast(3); + return !(INT1_IN_PORT & _BV(INT1_BIT)); // = digitalReadFast(3); # endif #elif defined(USE_BUTTON_0) && defined(USE_BUTTON_1) # if defined(BUTTON_IS_ACTIVE_HIGH) - if (isButtonAtINT0) { - return (INT0_IN_PORT & _BV(INT0_BIT)); // = digitalReadFast(2); - } else { - return (INT1_IN_PORT & _BV(INT1_BIT)); // = digitalReadFast(3); - } + if (isButtonAtINT0) { + return (INT0_IN_PORT & _BV(INT0_BIT)); // = digitalReadFast(2); + } else { + return (INT1_IN_PORT & _BV(INT1_BIT)); // = digitalReadFast(3); + } # else - if (isButtonAtINT0) { - return !(INT0_IN_PORT & _BV(INT0_BIT)); // = digitalReadFast(2); - } else { - return !(INT1_IN_PORT & _BV(INT1_BIT)); // = digitalReadFast(3); - } + if (isButtonAtINT0) { + return !(INT0_IN_PORT & _BV(INT0_BIT)); // = digitalReadFast(2); + } else { + return !(INT1_IN_PORT & _BV(INT1_BIT)); // = digitalReadFast(3); + } # endif #endif } +// @formatter:on // the eclipse formatter has problems with // comments in undefined code blocks + /* * Returns stored state if in debouncing period otherwise current state of button */ @@ -654,9 +665,15 @@ ISR(INT0_vect) { # if (! defined(ISC10)) || ((defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)) && INT1_PIN != 3) // on ATtinyX5 we do not have a INT1_vect but we can use the PCINT0_vect ISR(PCINT0_vect) -# elif (INT1_PIN != 3) +# elif INT1_PIN == 4 || INT1_PIN == 5 || INT1_PIN == 6 || INT1_PIN == 7 // PCINT for ATmega328 Arduino pins 0 to 7 ISR(PCINT2_vect) +# elif INT1_PIN == 8 || INT1_PIN == 9 || INT1_PIN == 10 || INT1_PIN == 11 || INT1_PIN == 12 || INT1_PIN == 13 +// PCINT for ATmega328 Arduino pins 8 (PB0) to 13 (PB5) - (PCINT 0 to 5) +ISR(PCINT0_vect) +# elif INT1_PIN == A0 || INT1_PIN == A1 || INT1_PIN == A2 || INT1_PIN == A3 || INT1_PIN == A4 || INT1_PIN == A5 +// PCINT for ATmega328 Arduino pins A1 (PC0) to A5 (PC5) - (PCINT 8 to 13) +ISR(PCINT1_vect) # else ISR(INT1_vect) # endif @@ -671,3 +688,5 @@ ISR(INT1_vect) } # endif #endif // not defined(USE_ATTACH_INTERRUPT) + +#endif // defined(__AVR__) diff --git a/src/EasyButtonAtInt01.h b/src/EasyButtonAtInt01.h index cef0c8d..4ce6041 100644 --- a/src/EasyButtonAtInt01.h +++ b/src/EasyButtonAtInt01.h @@ -34,33 +34,12 @@ #ifndef EASY_BUTTON_AT_INT01_H_ #define EASY_BUTTON_AT_INT01_H_ -#define VERSION_EASY_BUTTON "3.1.0" +#define VERSION_EASY_BUTTON "3.2.0" #define VERSION_EASY_BUTTON_MAJOR 3 -#define VERSION_EASY_BUTTON_MINOR 1 - -/* - * Version 3.1.0 - 6/2020 - * - 2 sets of constructors, one for only one button used and one for the second button if two buttons used. - * - Map pin numbers for Digispark pro boards, for use with with digispark library. - * - * Version 3.0.0 - 5/2020 - * - Added button release handler and adapted examples. - * - Revoke change for "only one true result per press for checkForLongPressBlocking()". It is superseded by button release handler. - * - Support buttons which are active high by defining BUTTON_IS_ACTIVE_HIGH. - * - Improved detection of maximum bouncing period used in DebounceTest. - * - * Version 2.1.0 - 5/2020 - * - Avoid 1 ms delay for checkForLongPressBlocking() if button is not pressed. - * - Only one true result per press for checkForLongPressBlocking(). - * - * Version 2.0.0 - 1/2020 - * - Ported to ATtinyX5 and ATiny167. - * - Support also PinChangeInterrupt for button 1 on Pin PA0 to PA7 for ATtiniy87/167. - * - Long press detection support. - * - Double press detection support. - * - Renamed to EasyButtonAtInt01.cpp.h - */ +#define VERSION_EASY_BUTTON_MINOR 2 +// The change log is at the bottom of the file +#if defined(__AVR__) #include /* @@ -82,7 +61,7 @@ //#define BUTTON_IS_ACTIVE_HIGH /* * Define USE_ATTACH_INTERRUPT to force use of the arduino function attachInterrupt(). - * Needed if you get the error " multiple definition of `__vector_1'" (or `__vector_2'), because another library uses the attachInterrupt() function. + * Required if you get the error " multiple definition of `__vector_1'" (or `__vector_2'), because another library uses the attachInterrupt() function. * For one button it needs additional 160 bytes FLASH, for 2 buttons it needs additional 88 bytes. */ //#define USE_ATTACH_INTERRUPT @@ -105,7 +84,7 @@ #endif /* - * Comment this out to save 2 bytes RAM and 64 bytes FLASH + * Activate this to save 2 bytes RAM and 64 bytes FLASH */ //#define NO_BUTTON_RELEASE_CALLBACK // @@ -123,9 +102,9 @@ * Activate LED_BUILTIN as long as button is pressed */ //#define LED_FEEDBACK_TEST -#if defined (LED_FEEDBACK_TEST) +#if defined(LED_FEEDBACK_TEST) # if ! defined(BUTTON_TEST_FEEDBACK_LED_PIN) -# if defined (LED_BUILTIN) +# if defined(LED_BUILTIN) # define BUTTON_TEST_FEEDBACK_LED_PIN LED_BUILTIN // if not specified, use built in led - pin 13 on Uno board # else # error "LED_FEEDBACK_TEST defined but no BUTTON_TEST_FEEDBACK_LED_PIN or LED_BUILTIN defined" @@ -145,7 +124,7 @@ //#define TRACE #ifdef TRACE -#warning "If using TRACE, the timing of the interrupt service routine changes, e.g. you will see more spikes, than expected!" +#warning If using TRACE, the timing of the interrupt service routine changes, e.g. you will see more spikes, than expected! #endif /* @@ -170,7 +149,7 @@ # if ! defined(INT1_PIN) #define INT1_PIN 3 # elif (INT1_PIN != 2) && (INT1_PIN > 5) -#error "INT1_PIN (for PCINT0 interrupt) can only be 0,1,3,4,5" +#error INT1_PIN (for PCINT0 interrupt) can only be 0,1,3,4,5 # endif #define INT1_DDR_PORT (DDRB) #define INT1_IN_PORT (PINB) @@ -217,11 +196,11 @@ #undef INT1_PIN #define INT1_PIN 6 // PA6 # else -#error "INT1_PIN (for PCINT0 interrupt) can only be 5 to 12" +#error INT1_PIN (for PCINT0 interrupt) can only be 5 to 12 # endif # else // defined(ARDUINO_AVR_DIGISPARKPRO) # if (INT1_PIN > 7) -#error "INT1_PIN (for PCINT0 interrupt) can only be 0 to 7" +#error INT1_PIN (for PCINT0 interrupt) can only be 0 to 7 # endif # endif // defined(ARDUINO_AVR_DIGISPARKPRO) #define INT1_DDR_PORT (DDRA) @@ -240,7 +219,7 @@ # if ! defined(INT1_PIN) #define INT1_PIN 3 # elif (INT1_PIN > 7) -#error "INT1_PIN (for PCINT2 interrupt) can only be Arduino pins 0 to 7 (PD0 to PD7)" +#error INT1_PIN (for PCINT2 interrupt) can only be Arduino pins 0 to 7 (PD0 to PD7) # endif #define INT1_DDR_PORT (DDRD) #define INT1_IN_PORT (PIND) @@ -254,7 +233,7 @@ #if defined(USE_BUTTON_1) && ((! defined(ISC10)) || ((defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)) && INT1_PIN != 3)) \ && ! defined(INTENTIONALLY_USE_PCI0_FOR_BUTTON1) && !(defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)) -#warning "Using PCINT0 interrupt for button 1" +#warning Using PCINT0 interrupt for button 1 #endif #if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) @@ -356,10 +335,10 @@ class EasyButton { #endif #if defined(USE_BUTTON_0) - static EasyButton * sPointerToButton0ForISR; + static EasyButton *sPointerToButton0ForISR; #endif #if defined(USE_BUTTON_1) - static EasyButton * sPointerToButton1ForISR; + static EasyButton *sPointerToButton1ForISR; #endif }; // end of class definition @@ -378,6 +357,31 @@ void __attribute__ ((weak)) handleINT0Interrupt(); void __attribute__ ((weak)) handleINT1Interrupt(); #endif +#endif // defined(__AVR__) + +/* + * Version 3.1.0 - 6/2020 + * - 2 sets of constructors, one for only one button used and one for the second button if two buttons used. + * - Map pin numbers for Digispark pro boards, for use with with digispark library. + * + * Version 3.0.0 - 5/2020 + * - Added button release handler and adapted examples. + * - Revoke change for "only one true result per press for checkForLongPressBlocking()". It is superseded by button release handler. + * - Support buttons which are active high by defining BUTTON_IS_ACTIVE_HIGH. + * - Improved detection of maximum bouncing period used in DebounceTest. + * + * Version 2.1.0 - 5/2020 + * - Avoid 1 ms delay for checkForLongPressBlocking() if button is not pressed. + * - Only one true result per press for checkForLongPressBlocking(). + * + * Version 2.0.0 - 1/2020 + * - Ported to ATtinyX5 and ATiny167. + * - Support also PinChangeInterrupt for button 1 on Pin PA0 to PA7 for ATtiniy87/167. + * - Long press detection support. + * - Double press detection support. + * - Renamed to EasyButtonAtInt01.cpp.h + */ + #endif /* EASY_BUTTON_AT_INT01_H_ */ #pragma once diff --git a/src/digitalWriteFast.h b/src/digitalWriteFast.h index 8e83af1..3bbfc97 100644 --- a/src/digitalWriteFast.h +++ b/src/digitalWriteFast.h @@ -39,7 +39,7 @@ #endif // workarounds for ARM microcontrollers -#if (!defined(__AVR__) || \ +#if (!defined(__AVR__) && !defined(ESP8266) || \ defined(ARDUINO_ARCH_SAM) || \ defined(ARDUINO_ARCH_SAMD)) @@ -209,9 +209,22 @@ (((P) == 3 || (P) == 4) ? 5 : 7))))))))))))))) -// --- Arduino 644 --- -#elif (defined(__AVR_ATmega644__) || \ - defined(__AVR_ATmega644P__)) +// --- Arduino MightyCore standard pinout --- +#elif defined(__AVR_ATmega1284P__) || \ + defined(__AVR_ATmega1284P__) || \ + defined(__AVR_ATmega644P__) || \ + defined(__AVR_ATmega644__) || \ + defined(__AVR_ATmega324PB__) || \ + defined(__AVR_ATmega324PA__) || \ + defined(__AVR_ATmega324P__) || \ + defined(__AVR_ATmega324A__) || \ + defined(__AVR_ATmega164P__) || \ + defined(__AVR_ATmega164A__) || \ + defined(__AVR_ATmega32__) || \ + defined(__AVR_ATmega16__) || \ + defined(__AVR_ATmega8535__) && \ + !defined(BOBUINO_PINOUT) && \ + !defined(SANGUINO_PINOUT) #define UART_RX_PIN (8) //PD0 #define UART_TX_PIN (9) //PD1 @@ -224,6 +237,16 @@ #define SPI_HW_MISO_PIN (6) //PB6 #define SPI_HW_SCK_PIN (7) //PB7 +#if defined(__AVR_ATmega324PB__) +#define __digitalPinToPortReg(P) \ +(((P) >= 0 && (P) <= 7) ? &PORTB : (((P) >= 8 && (P) <= 15) ? &PORTD : (((P) >= 16 && (P) <= 23) ? &PORTC : (((P) >= 24 && (P) <= 31) ? &PORTA : &PORTE)))) +#define __digitalPinToDDRReg(P) \ +(((P) >= 0 && (P) <= 7) ? &DDRB : (((P) >= 8 && (P) <= 15) ? &DDRD : (((P) >= 8 && (P) <= 15) ? &DDRC : (((P) >= 24 && (P) <= 31) ? &DDRA : &DDRE)))) +#define __digitalPinToPINReg(P) \ +(((P) >= 0 && (P) <= 7) ? &PINB : (((P) >= 8 && (P) <= 15) ? &PIND : (((P) >= 8 && (P) <= 15) ? &PINC : (((P) >= 24 && (P) <= 31) ? &PINA : &PINE)))) +#define __digitalPinToBit(P) \ +(((P) >= 0 && (P) <= 7) ? (P) : (((P) >= 8 && (P) <= 15) ? (P) - 8 : (((P) >= 16 && (P) <= 23) ? (P) - 16 : (((P) >= 16 && (P) <= 23) ? (P) - 24 : (P) - 32)))) +#else #define __digitalPinToPortReg(P) \ (((P) >= 0 && (P) <= 7) ? &PORTB : (((P) >= 8 && (P) <= 15) ? &PORTD : (((P) >= 16 && (P) <= 23) ? &PORTC : &PORTA))) #define __digitalPinToDDRReg(P) \ @@ -232,7 +255,7 @@ (((P) >= 0 && (P) <= 7) ? &PINB : (((P) >= 8 && (P) <= 15) ? &PIND : (((P) >= 8 && (P) <= 15) ? &PINC : &PINA))) #define __digitalPinToBit(P) \ (((P) >= 0 && (P) <= 7) ? (P) : (((P) >= 8 && (P) <= 15) ? (P) - 8 : (((P) >= 16 && (P) <= 23) ? (P) - 16 : (P) - 24))) - +#endif // --- Arduino Leonardo and ATmega16U4/32U4 based boards --- #elif (defined(ARDUINO_AVR_LEONARDO) || \ @@ -263,9 +286,15 @@ // --- Arduino Uno and ATmega168/328 based boards --- #elif (defined(ARDUINO_AVR_UNO) || \ defined(ARDUINO_AVR_DUEMILANOVE) || \ + defined(__AVR_ATmega8__) || \ + defined(__AVR_ATmega48__) || \ + defined(__AVR_ATmega48P__) || \ + defined(__AVR_ATmega48PB__) || \ + defined(__AVR_ATmega88P__) || \ + defined(__AVR_ATmega88PB__) || \ defined(__AVR_ATmega168__) || \ - defined(__AVR_ATmega168A__) || \ defined(__AVR_ATmega168PA__) || \ + defined(__AVR_ATmega168PB__) || \ defined(__AVR_ATmega328__) || \ defined(__AVR_ATmega328P__) || \ defined(__AVR_ATmega328PB__)) @@ -281,7 +310,7 @@ #define SPI_HW_MISO_PIN (12) //PB3 #define SPI_HW_SCK_PIN (13) //PB1 -#if defined(__AVR_ATmega328PB__) +#if defined(__AVR_ATmega48PB__) || defined(__AVR_ATmega88PB__) || defined(__AVR_ATmega168PB__) || defined(__AVR_ATmega328PB__) #define __digitalPinToPortReg(P) \ (((P) >= 0 && (P) <= 7) ? &PORTD : (((P) >= 8 && (P) <= 13) ? &PORTB : (((P) >= 14 && (P) <= 19) ? &PORTC : &PORTE))) #define __digitalPinToDDRReg(P) \ @@ -301,14 +330,52 @@ (((P) >= 0 && (P) <= 7) ? (P) : (((P) >= 8 && (P) <= 13) ? (P) - 8 : (P) - 14)) #endif +#elif defined(__AVR_ATmega4809__) // Uno WiFi Rev 2, Nano Every + +#define UART_RX_PIN (0) //PB0 +#define UART_TX_PIN (1) //PB1 + +#define I2C_SDA_PIN (22) //PA2 +#define I2C_SCL_PIN (23) //PA3 + +#define SPI_HW_SS_PIN (8) //PE3 +#define SPI_HW_MOSI_PIN (11) //PE0 +#define SPI_HW_MISO_PIN (12) //PE1 +#define SPI_HW_SCK_PIN (13) //PE2 + +#define __digitalPinToPortReg(P) \ +(((P) == 2 || (P) == 7 ) ? &VPORTA.OUT : ((P) == 5 || (P) == 9 || (P) == 10) ? &VPORTB.OUT : ((P) == 4) ? &VPORTC.OUT : (((P) >= 14 && (P) <= 17) || (P) == 20 || (P) == 21) ? &VPORTD.OUT : ((P) == 8 || (P) == 11 || (P) == 12 || (P) == 13) ? &VPORTE.OUT : &VPORTF.OUT) +#define __digitalPinToDDRReg(P) \ +(((P) == 2 || (P) == 7 ) ? &VPORTA.DIR : ((P) == 5 || (P) == 9 || (P) == 10) ? &VPORTB.DIR : ((P) == 4) ? &VPORTC.DIR : (((P) >= 14 && (P) <= 17) || (P) == 20 || (P) == 21) ? &VPORTD.DIR : ((P) == 8 || (P) == 11 || (P) == 12 || (P) == 13) ? &VPORTE.DIR : &VPORTF.DIR) +#define __digitalPinToPINReg(P) \ +(((P) == 2 || (P) == 7 ) ? &VPORTA.IN : ((P) == 5 || (P) == 9 || (P) == 10) ? &VPORTB.IN : ((P) == 4) ? &VPORTC.IN : (((P) >= 14 && (P) <= 17) || (P) == 20 || (P) == 21) ? &VPORTD.IN : ((P) == 8 || (P) == 11 || (P) == 12 || (P) == 13) ? &VPORTE.IN : &VPORTF.IN) +#define __digitalPinToBit(P) \ +(((P) == 2 || (P) == 9 || (P) == 11 || (P) == 17) ? 0 : ((P) == 7 || (P) == 10 || (P) == 12 || (P) == 16) ? 1 : ((P) == 5 || (P) == 13 || (P) == 15 || (P) == 18) ? 2 : ((P) == 9 || (P) == 14 || (P) == 19) ? 3 : ((P) == 6 || (P) == 20) ? 4 : ((P) == 3 || (P) == 21) ? 5 : 6 ) + + // --- ATtinyX5 --- #elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) // we have only PORTB #define __digitalPinToPortReg(P) (&PORTB) #define __digitalPinToDDRReg(P) (&DDRB) #define __digitalPinToPINReg(P) (&PINB) -#define __digitalPinToBit(P) \ -(((P) >= 0 && (P) <= 7) ? (P) : (((P) >= 8 && (P) <= 13) ? (P) - 8 : (P) - 14)) +#define __digitalPinToBit(P) (( (P) <= 7) ? (P) : (((P) >= 8 && (P) <= 13) ? (P) - 8 : (P) - 14)) + + +// --- ATtiny88 --- +#elif defined(__AVR_ATtiny88__) +# if defined(ARDUINO_AVR_DIGISPARKPRO) +#define __digitalPinToPortReg(P) ((P) <= 7 ? &PORTD : ((P) <= 14 ? &PORTB : ((P) <= 18 ? &PORTA : &PORTC))) +#define __digitalPinToDDRReg(P) ((P) <= 7 ? &DDRD : ((P) <= 14 ? &DDRB : ((P) <= 18 ? &DDRA : &DDRC))) +#define __digitalPinToPINReg(P) ((P) <= 7 ? &PIND : ((P) <= 14 ? &PINB : ((P) <= 18 ? &PINA : &PINC))) +#define __digitalPinToBit(P) ( (P) <= 7 ? (P) : ((P) <= 13 ? ((P) - 8) : ((P) == 14 ? 7 : ((P) <= 16 ? ((P) - 14) : ((P) <= 18 ? ((P) - 17) : ((P) == 25 ? 7 : ((P) - 19)))))) ) +# else +#define __digitalPinToPortReg(P) ((P) <= 7 ? &PORTD : ((P) <= 15 ? &PORTB : ((P) <= 22 ? &PORTC : ((P) <= 26 ? &PORTA : &PORTC)))) +#define __digitalPinToDDRReg(P) ((P) <= 7 ? &DDRD : ((P) <= 15 ? &DDRB : ((P) <= 22 ? &DDRC : ((P) <= 26 ? &DDRA : &DDRC)))) +#define __digitalPinToPINReg(P) ((P) <= 7 ? &PIND : ((P) <= 15 ? &PINB : ((P) <= 22 ? &PINC : ((P) <= 26 ? &PINA : &PINC)))) +#define __digitalPinToBit(P) ((P) <= 15 ? ((P) & 0x7) : ((P) == 16 ? (7) : ((P) <= 22 ? ((P) - 17) : ((P) == 27 ? (6) : ((P) - 23))))) +# endif + // --- ATtinyX4 + ATtinyX7 --- #elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) @@ -328,6 +395,7 @@ #define __digitalPinToBit(P) (((P) <= 7) ? (P) : (P) - 8 ) # endif + // --- Other --- #else @@ -346,7 +414,7 @@ #ifndef digitalWriteFast #if (defined(__AVR__) || defined(ARDUINO_ARCH_AVR)) #define digitalWriteFast(P, V) \ -if (__builtin_constant_p(P) && __builtin_constant_p(V)) { \ +if (__builtin_constant_p(P)) { \ BIT_WRITE(*__digitalPinToPortReg(P), __digitalPinToBit(P), (V)); \ } else { \ digitalWrite((P), (V)); \ @@ -361,8 +429,8 @@ if (__builtin_constant_p(P) && __builtin_constant_p(V)) { \ #define pinModeFast(P, V) \ if (__builtin_constant_p(P) && __builtin_constant_p(V)) { \ if (V == INPUT_PULLUP) {\ - BIT_WRITE(*__digitalPinToDDRReg(P), __digitalPinToBit(P), (INPUT)); \ - BIT_WRITE(*__digitalPinToPortReg(P), __digitalPinToBit(P), (HIGH)); \ + BIT_CLEAR(*__digitalPinToDDRReg(P), __digitalPinToBit(P)); \ + BIT_SET(*__digitalPinToPortReg(P), __digitalPinToBit(P)); \ } else { \ BIT_WRITE(*__digitalPinToDDRReg(P), __digitalPinToBit(P), (V)); \ } \ @@ -378,8 +446,8 @@ if (__builtin_constant_p(P) && __builtin_constant_p(V)) { \ #if (defined(__AVR__) || defined(ARDUINO_ARCH_AVR)) #define digitalReadFast(P) ( (int) __digitalReadFast((P)) ) #define __digitalReadFast(P ) \ - (__builtin_constant_p(P) ) ? ( \ - ( BIT_READ(*__digitalPinToPINReg(P), __digitalPinToBit(P))) ? HIGH:LOW ) : \ + (__builtin_constant_p(P) ) ? \ + (( BIT_READ(*__digitalPinToPINReg(P), __digitalPinToBit(P))) ? HIGH:LOW ) : \ digitalRead((P)) #else #define digitalReadFast digitalRead @@ -388,7 +456,14 @@ if (__builtin_constant_p(P) && __builtin_constant_p(V)) { \ #ifndef digitalToggleFast #if (defined(__AVR__) || defined(ARDUINO_ARCH_AVR)) -#define digitalToggleFast(P) BIT_SET(*__digitalPinToPINReg(P), __digitalPinToBit(P)) +#define digitalToggleFast(P) \ +if (__builtin_constant_p(P)) { \ + BIT_SET(*__digitalPinToPINReg(P), __digitalPinToBit(P)); \ +} else { \ + digitalWrite(P, ! digitalRead(P)); \ +} +#else +#define digitalToggleFast(P) digitalWrite(P, ! digitalRead(P)) #endif #endif