{"id":16218909,"url":"https://github.com/arminjo/easybuttonatint01","last_synced_at":"2025-03-19T10:31:14.659Z","repository":{"id":93079008,"uuid":"175797025","full_name":"ArminJo/EasyButtonAtInt01","owner":"ArminJo","description":"Arduino library for push buttons at INT0 and / or INT1 pin (pin 2 / 3). Provides debouncing and toggle button functionality.","archived":false,"fork":false,"pushed_at":"2024-10-08T09:24:27.000Z","size":154,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-17T06:35:21.977Z","etag":null,"topics":["arduino-library","button-control","debounce-button","doubleclick","interrupts","long-press","toggle-button"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ArminJo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-15T10:14:13.000Z","updated_at":"2025-03-01T00:18:20.000Z","dependencies_parsed_at":"2023-10-16T13:29:03.170Z","dependency_job_id":"40f9f902-3040-4b2f-897e-56593fd92361","html_url":"https://github.com/ArminJo/EasyButtonAtInt01","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArminJo%2FEasyButtonAtInt01","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArminJo%2FEasyButtonAtInt01/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArminJo%2FEasyButtonAtInt01/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArminJo%2FEasyButtonAtInt01/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ArminJo","download_url":"https://codeload.github.com/ArminJo/EasyButtonAtInt01/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244407836,"owners_count":20447854,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino-library","button-control","debounce-button","doubleclick","interrupts","long-press","toggle-button"],"created_at":"2024-10-10T11:51:23.750Z","updated_at":"2025-03-19T10:31:14.414Z","avatar_url":"https://github.com/ArminJo.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align = center\u003e\n\n# [EasyButton](https://github.com/ArminJo/EasyButtonAtInt01)\nLightweight Arduino library for handling push buttons just connected between ground and INT0 and / or INT1 or any other PCINT pin.\n\n[![Badge License: GPLv3](https://img.shields.io/badge/License-GPLv3-brightgreen.svg)](https://www.gnu.org/licenses/gpl-3.0)\n \u0026nbsp; \u0026nbsp; \n[![Badge Version](https://img.shields.io/github/v/release/ArminJo/EasyButtonAtInt01?include_prereleases\u0026color=yellow\u0026logo=DocuSign\u0026logoColor=white)](https://github.com/ArminJo/EasyButtonAtInt01/releases/latest)\n \u0026nbsp; \u0026nbsp; \n[![Badge Commits since latest](https://img.shields.io/github/commits-since/ArminJo/EasyButtonAtInt01/latest?color=yellow)](https://github.com/ArminJo/EasyButtonAtInt01/commits/master)\n \u0026nbsp; \u0026nbsp; \n[![Badge Build Status](https://github.com/ArminJo/EasyButtonAtInt01/workflows/LibraryBuild/badge.svg)](https://github.com/ArminJo/EasyButtonAtInt01/actions)\n \u0026nbsp; \u0026nbsp; \n![Badge Hit Counter](https://visitor-badge.laobi.icu/badge?page_id=ArminJo_EasyButtonAtInt01)\n\u003cbr/\u003e\n\u003cbr/\u003e\n[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua)\n\nAvailable as [Arduino library \"EasyButtonAtInt01\"](https://www.arduinolibraries.info/libraries/easy-button-at-int01).\n\n[![Button Install](https://img.shields.io/badge/Install-brightgreen?logoColor=white\u0026logo=GitBook)](https://www.ardu-badge.com/EasyButtonAtInt01)\n \u0026nbsp; \u0026nbsp; \n[![Button Changelog](https://img.shields.io/badge/Changelog-blue?logoColor=white\u0026logo=AzureArtifacts)](https://github.com/ArminJo/EasyButtonAtInt01?tab=readme-ov-file#revision-history)\n\n\u003c/div\u003e\n\n#### If you find this library useful, please give it a star.\n\n\u0026#x1F30E; [Google Translate](https://translate.google.com/translate?sl=en\u0026u=https://github.com/ArminJo/EasyButtonAtInt01)\n\n\u003cbr/\u003e\n\n# Features\n- No external pullup, **no polling needed**.\n- The library is totally **based on interrupt** and **debouncing is implemented in a not blocking way**.\nDebouncing is merely done by ignoring a button change within the debouncing time (default 50 ms).\nSo **button state is instantly available** without debouncing delay!\n- Implements **toggle button** functionality.\n- Support for **double press detection** is included. See [TwoButtons](examples/TwoButtons/TwoButtons.ino#L111) and [Callback example](examples/Callback/Callback.ino#L77).\n- Support for **long press detection**, is included. See [Callback example](examples/Callback/Callback.ino#L97).\n- Support for **active high buttons**.\n- Small memory footprint.\n- Support to **measure maximum bouncing period of a button**. See [DebounceTest example](examples/DebounceTest/DebounceTest.ino#L62).\n- Button 1 can used at any pin supporting pin change interrupt.\n- The exact pin numbers of the buttons are available by the macros INT0_PIN and INT1_PIN, which are set after the include.\n\n## Table of available pins for the 2 buttons\n| CPU | Button 0 | Button 1 using INT1 | Button 1 using PCINT, if INT1_PIN is defined != 3 |\n|-|-|-|-|\n| ATmega328* | D2 | D3 | Pin 0 to 2, 4 to 13, A0 to A5 |\n| ATtiny5x | PB2 | | PB0 - PB5 |\n| ATtiny167 | PB6 | PA3 | PA0 to PA2, PA4 to PA7 |\n\nTo use the PCINT buttons instead of the default one, just define INT1_PIN **before** including *EasyButtonAtInt01.hpp*.\u003cbr/\u003e\nE.g. `#define INT1_PIN 7`. See [TwoButtons.cpp](examples/TwoButtons/TwoButtons.ino#L52).\n\n## Usage\nTo use a single button, it needs only:\n\n```c++\n#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)\n#include \"EasyButtonAtInt01.hpp\"\nEasyButton Button0AtPin2;\n\nvoid setup() {}\nvoid loop() {\n...\n    digitalWrite(LED_BUILTIN, Button0AtPin2.ButtonToggleState); // The value at the first call after first press is true\n...\n}\n```\nTo use 2 buttons, it needs only:\n\n```c++\n#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)\n#define USE_BUTTON_1 // Enable code for button at INT1 (pin3) or PCINT[0:7]\n#include \"EasyButtonAtInt01.hpp\"\nEasyButton Button0AtPin2();  // no parameter -\u003e Button is connected to INT0 (pin2)\nEasyButton Button1AtPin3(BUTTON_AT_INT1_OR_PCINT); // Button is connected to INT1 (pin3)\n\nvoid setup() {\n    Serial.print(F(\"Button0 pin=\"));\n    Serial.print(INT0_PIN);\n    Serial.print(F(\" Button1 pin=\"));\n    Serial.println(INT1_PIN);\n}\nvoid loop() {\n...\n    digitalWrite(LED_BUILTIN, Button0AtPin2.ButtonToggleState);\n    delay(100);\n    digitalWrite(LED_BUILTIN, Button1AtPin3.ButtonToggleState);\n    delay(200);\n...\n}\n```\n\n## Usage of callback functions\nThe button press callback function is is called on every button press with ButtonToggleState as parameter.\u003cbr/\u003e\n**The value at the first call (after first press) is true**.\u003cbr/\u003e\nThe button release callback function is called on every button release with the additional parameter `ButtonPressDurationMillis`.\u003cbr/\u003e\nBoth callback functions run in an interrupt service context, which means they should be as short/fast as possible.\nIn this library, interrupts are enabled before the callback function is called. This allows the timer interrupt for millis() to work and therefore **delay() and millis() can be used in a callback function**.\n\n```c++\n#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)\n#include \"EasyButtonAtInt01.hpp\"\n\n// Initial value is false, so first call is with true\nvoid handleButtonPress(bool aButtonToggleState) {\n    digitalWrite(LED_BUILTIN, aButtonToggleState);\n}\nEasyButton Button0AtPin2(\u0026handleButtonPress); // Button is connected to INT0 (pin2)\n\nvoid setup() {}\nvoid loop() {}\n```\n\n## Long press detection\nThe easiest way is to use the button release handler. Keep in mind, that you will get a press callback at the start of the long press.\n\n```c++\n#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)\n#include \"EasyButtonAtInt01.hpp\"\n\nvoid handleButtonRelease(bool aButtonToggleState, uint16_t aButtonPressDurationMillis);\nEasyButton Button0AtPin2(NULL, \u0026handleButtonRelease); // Button is connected to INT0 (pin2)\n\nhandleButtonRelease(bool aButtonToggleState, uint16_t aButtonPressDurationMillis) {\n    if (aButtonPressDurationMillis \u003e= EASY_BUTTON_LONG_PRESS_DEFAULT_MILLIS) { // 400 ms\n        Serial.print(F(\"Long press \"));\n        Serial.print(aButtonPressDurationMillis);\n        Serial.println(F(\" ms detected\"));\n    }\n}\n\nvoid setup() {}\nvoid loop() {}\n```\n\nOr check in loop, this enables to react with feedback as soon as long press duration is reached.\n\n```c++\n#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)\n#include \"EasyButtonAtInt01.hpp\"\n\nbool sLongPressMessageSent = false;\nvoid handleButtonPress(bool aButtonToggleState, uint16_t aButtonPressDurationMillis) {sLongPressMessageSent = false};\nEasyButton Button0AtPin2(\u0026handleButtonPress); // Button is connected to INT0 (pin2)\n\nvoid setup() {}\nvoid loop() {\nif (!sLongPressMessageSent \u0026\u0026 Button0AtPin2.checkForLongPress(1000) == EASY_BUTTON_LONG_PRESS_DETECTED) {\n        Serial.println(F(\"Long press of 1000 ms just detected\"));\n        sLongPressMessageSent = true; // Print message only once per long press\n}\n\n```\n\n\n    if (sLCDDisplayPage == POWER_METER_PAGE_INFO \u0026\u0026 PageButtonAtPin3.checkForLongPress(1000) == EASY_BUTTON_LONG_PRESS_DETECTED) {\n\n\n## Double press detection\n**Call checkForDoublePress() only from button press callback function**. It will not work as expected, if called outside this callback function.\n\n```c++\n#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)\n#include \"EasyButtonAtInt01.hpp\"\n\nvoid handleButtonPress(bool aButtonToggleState);\nEasyButton Button0AtPin2(\u0026printButtonToggleState);\n\n// Initial value is false, so first call is with true\nvoid handleButtonPress(bool aButtonToggleState) {\n     // This function works reliable only if called early in callback function\n    if (Button0AtPin2.checkForDoublePress()) {\n        Serial.println(F(\"Button 0 double press (\u003c 400 ms) detected\"));\n    }\n    digitalWrite(LED_BUILTIN, aButtonToggleState);\n}\n\nvoid setup() {}\nvoid loop() {}\n```\n\n\u003cbr/\u003e\n\n# Handling the `multiple definition` error\nIf you get the error `multiple definition of __vector_1` (or `__vector_2`) because another library uses the attachInterrupt() function,\nthen insert the line `#define USE_ATTACH_INTERRUPT` in your program **before** the line `#include \"EasyButtonAtInt01.hpp\"`.\n\n\u003cbr/\u003e\n\n\n# Compile options / macros for this library\nTo customize the library to different requirements, there are some compile options / macros available.\u003cbr/\u003e\nThese macros must be defined in your program **before** the line `#include \"EasyButtonAtInt01.hpp\"` to take effect.\u003cbr/\u003e\nModify them by enabling / disabling them, or change the values if applicable.\n\n| Name | Default value | Description |\n|-|-:|-|\n| `USE_BUTTON_0` | disabled | Enables code for button at INT0 (pin2 on 328P, PB6 on ATtiny167, PB2 on ATtinyX5). The macro INT0_PIN is set after the include. |\n| `USE_BUTTON_1` | disabled | Enables code for button at INT1 (pin3 on 328P, PA3 on ATtiny167, PCINT0 / PCx for ATtinyX5). The macro INT1_PIN is set after the include. |\n| `INT1_PIN` | % | It overrides the usage of pin at the processors INT1 pin. Thus, it is the pin number of the pin for button 1 to use with Pin Change Interrupts. |\n| `NO_INITIALIZE_IN_CONSTRUCTOR` | disabled | Disables the auto initializing in all constructors without the \"aIsButtonAtINT0\" parameter. Must be used if buttons must be initialized manually (e.g. later in setup). |\n| `BUTTON_IS_ACTIVE_HIGH` | disabled | Enable this if your buttons are active high. |\n| `USE_ATTACH_INTERRUPT` | disabled | This forces use of the arduino function attachInterrupt(). It is required if you get the error \"multiple definition of \\`__vector_1'\" (or \\`__vector_2'), because another library uses the attachInterrupt() function. |\n| `NO_BUTTON_RELEASE_CALLBACK` | disabled | Disables the code for release callback. This saves 2 bytes RAM and 64 bytes program memory. |\n| `BUTTON_DEBOUNCING_MILLIS` | 50 | With this you can adapt to the characteristic of your button. |\n| `ANALYZE_MAX_BOUNCING_PERIOD` | disabled | Analyze the buttons actual debounce value. |\n| `BUTTON_LED_FEEDBACK` | disabled | This activates LED_BUILTIN as long as button is pressed. |\n| `BUTTON_LED_FEEDBACK_PIN` | disabled | The pin to use for button LED feedback. |\n| `INTENTIONALLY_USE_PCI0_FOR_BUTTON1` | disabled | Activate it to suppress the warning: \"Using PCINT0 interrupt for button 1\". |\n| `USE_INT2_FOR_BUTTON_0` | disabled | Hack, especially for ATmega644 etc, where INT0 and INT1 are occupied by 2. USART. |\n\nThe exact pin numbers of the buttons used internally are available by the macros INT0_PIN and INT1_PIN, which are set after the include.\n\n## Class methods\n```c++\nEasyButton(); // Constructor for button at INT0\nEasyButton(void (*aButtonPressCallback)(bool aButtonToggleState)); // Constructor for button at INT0\n\nEasyButton(bool aIsButtonAtINT0); // Constructor\nEasyButton(bool aIsButtonAtINT0, void (*aButtonPressCallback)(bool aButtonToggleState));\nEasyButton(bool aIsButtonAtINT0, void (*aButtonPressCallback)(bool aButtonToggleState), void (*aButtonReleaseCallback)(bool aButtonToggleState, uint16_t aButtonPressDurationMillis));\nvoid init(); // used by constructors\n\n#define EASY_BUTTON_LONG_PRESS_DEFAULT_MILLIS 400\n#define EASY_BUTTON_DOUBLE_PRESS_DEFAULT_MILLIS 400\n\nbool readButtonState();\nbool readDebouncedButtonState();\nbool updateButtonState();\nuint16_t updateButtonPressDuration();\nuint8_t checkForLongPress(uint16_t aLongPressThresholdMillis = EASY_BUTTON_LONG_PRESS_DEFAULT_MILLIS);\nbool checkForLongPressBlocking(uint16_t aLongPressThresholdMillis = EASY_BUTTON_LONG_PRESS_DEFAULT_MILLIS);\nbool checkForDoublePress(uint16_t aDoublePressDelayMillis = EASY_BUTTON_DOUBLE_PRESS_DEFAULT_MILLIS);\nbool checkForForButtonNotPressedTime(uint16_t aTimeoutMillis);\n```\n\n# Revision History\n###  Version 3.4.1 - work in progress\n- Avoid wrong double press detection if calling checkForDoublePress() after release of button.\n- Hack for ATmega 644.\n\n###  Version 3.4.0\n- Added `NO_INITIALIZE_IN_CONSTRUCTOR` macro to enable late initializing.\n- `ButtonStateIsActive` is now private, since it is not reliable after bouncing. Use `readButtonState()` or `readDebouncedButtonState()` instead.\n\n###  Version 3.3.1\n- Avoid mistakenly double press detection after boot.\n\n###  Version 3.3.0\n- Renamed EasyButtonAtInt01.cpp.h to EasyButtonAtInt01.hpp.\n\n###  Version 3.2.0\n- Allow button1 on pin 8 to 13 and A0 to A5 for ATmega328.\n\n###  Version 3.1.0\n- 2 sets of constructors, one for only one button used and one for the second button if two buttons used.\n- Map pin numbers for Digispark pro boards, for use with with digispark library.\n\n###  Version 3.0.0\n- Added button release handler and adapted examples.\n- Revoke change for \"only one true result per press for checkForLongPressBlocking()\". It is superseded by button release handler.\n- Support buttons which are active high by defining `BUTTON_IS_ACTIVE_HIGH`.\n- Improved detection of maximum bouncing period used in DebounceTest.\n\n###  Version 2.1.0\n- Avoid 1 ms delay for `checkForLongPressBlocking()` if button is not pressed.\n- Only one true result per press for `checkForLongPressBlocking()`.\n\n### Version 2.0.0\n- Ported to ATtinyX5 and ATiny167.\n- Support also PinChangeInterrupt for button 1 on Pin PA0 to PA7 for ATtiny87/167.\n- Long button press detection support.\n- Analyzes maximum debouncing period.\n- Double button press detection support.\n- Very short button press handling.\n- Renamed to EasyButtonAtInt01.hpp\n\n### Version 1.0.0\n- initial version for ATmega328.\n\n# CI\nThe library examples are tested with GitHub Actions for the following boards:\n\n- arduino:avr:uno\n- arduino:avr:leonardo\n- arduino:avr:mega\n- digistump:avr:digispark-tiny1\n- digistump:avr:digispark-pro\n- ATTinyCore:avr:attinyx5:chip=85,clock=1internal\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farminjo%2Feasybuttonatint01","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farminjo%2Feasybuttonatint01","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farminjo%2Feasybuttonatint01/lists"}