├── .github └── FUNDING.yml ├── pb_config.h ├── LICENSE.TXT ├── pb.h ├── README.md └── pb.c /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | 4 | github: [nimaltd] 5 | patreon: # Replace with a single Patreon username 6 | open_collective: # Replace with a single Open Collective username 7 | ko_fi: nimaltd 8 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 9 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 10 | otechie: # Replace with a single Otechie username 11 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 12 | -------------------------------------------------------------------------------- /pb_config.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * @file pb_config.h 4 | * @brief Push-Button driver 5 | * @author Nima Askari 6 | * @version 1.0.0 7 | * @license See the LICENSE file in the root folder. 8 | * 9 | * @note All my libraries are dual-licensed. 10 | * Please review the licensing terms before using them. 11 | * For any inquiries, feel free to contact me. 12 | * 13 | * @github https://www.github.com/nimaltd 14 | * @linkedin https://www.linkedin.com/in/nimaltd 15 | * @youtube https://www.youtube.com/@nimaltd 16 | * @instagram https://instagram.com/github.nimaltd 17 | * 18 | * Copyright (C) 2025 Nima Askari - NimaLTD. All rights reserved. 19 | */ 20 | 21 | #ifndef _PB_CONFIG_H_ 22 | #define _PB_CONFIG_H_ 23 | 24 | /*************************************************************************************************/ 25 | /** Includes **/ 26 | /*************************************************************************************************/ 27 | 28 | /* USER CODE BEGIN PB_INCLUDES */ 29 | 30 | /* USER CODE END PB_INCLUDES */ 31 | 32 | /*************************************************************************************************/ 33 | /** Configurations **/ 34 | /*************************************************************************************************/ 35 | 36 | /* USER CODE BEGIN PB_CONFIGURATION */ 37 | 38 | /* Timer used for periodic button scanning */ 39 | #define PB_TIM htim3 40 | 41 | /* Timer interval in milliseconds (scan period) */ 42 | #define PB_INTERVAL_MS 10 43 | 44 | /* Beep on duration (ms) */ 45 | #define PB_BEEP_TIME_MS 50 46 | 47 | /* Minimum press duration (ms) to register a short press */ 48 | #define PB_SHORT_TIME_MS 50 49 | 50 | /* Minimum press duration (ms) to register a long press */ 51 | #define PB_LONG_TIME_MS 1000 52 | 53 | /* Size of the event queue (number of events that can be stored) */ 54 | #define PB_EVN_QUEUE_SIZE 4 55 | 56 | /* Set idle state */ 57 | #define PB_IDLE_IS_HIGH 1 58 | 59 | /* Number of buttons configured */ 60 | #define PB_CONFIG_COUNT 3 61 | 62 | /* Pin definitions */ 63 | #define PB_CONFIG {.gpio = KEY_DOWN_GPIO_Port, .pin = KEY_DOWN_Pin}, \ 64 | {.gpio = KEY_UP_GPIO_Port, .pin = KEY_UP_Pin}, \ 65 | {.gpio = KEY_ENTER_GPIO_Port, .pin = KEY_ENTER_Pin} 66 | 67 | /* USER CODE END PB_CONFIGURATION */ 68 | 69 | /*************************************************************************************************/ 70 | /** End of File **/ 71 | /*************************************************************************************************/ 72 | 73 | #endif /* _PB_CONFIG_H_ */ 74 | -------------------------------------------------------------------------------- /LICENSE.TXT: -------------------------------------------------------------------------------- 1 | # Software License Terms 2 | 3 | This software is dual-licensed under the **GNU General Public License v2 (GPLv2)** and a **Commercial License**. 4 | 5 | --- 6 | 7 | ## 1. GNU General Public License v2 (GPLv2) 8 | This software is licensed under the GNU General Public License version 2 (GPLv2) **only**, as published by the Free Software Foundation. 9 | 10 | - You may redistribute and/or modify this software under the terms of GPLv2. 11 | - This license is provided **without any warranty**, including but not limited to implied warranties of **MERCHANTABILITY** or **FITNESS FOR A PARTICULAR PURPOSE**. 12 | - See for details. 13 | 14 | --- 15 | 16 | ## 2. Commercial License 17 | 18 | A commercial license is available for entities who wish to use this software **without the restrictions of GPLv2** (e.g., in closed-source or proprietary products). 19 | 20 | ### 2.1 Grant of License 21 | - A valid commercial license removes GPLv2 restrictions and grants the right to use, modify, and distribute the software in proprietary or closed-source products. 22 | - Commercial use of this software **requires obtaining a valid license agreement** from the copyright holder. 23 | 24 | ### 2.2 License Models 25 | - **Single-Product License** – Permits usage in **one specific product**. 26 | - **Company-Wide License** – Permits usage across **all products of the company**. 27 | 28 | ### 2.3 Maintenance & Updates 29 | - The licensor *may*, at its sole discretion, provide updates, bug fixes, or new releases. 30 | - The licensor has **no obligation** to release updates or support on a specific schedule. 31 | 32 | --- 33 | 34 | ## 3. Disclaimer of Warranty 35 | 36 | THIS SOFTWARE IS PROVIDED **"AS IS"** AND WITHOUT ANY WARRANTIES OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY. 37 | THIS INCLUDES, BUT IS NOT LIMITED TO, THE IMPLIED WARRANTIES OF **MERCHANTABILITY**, **FITNESS FOR A PARTICULAR PURPOSE**, AND **NON-INFRINGEMENT**. 38 | 39 | --- 40 | 41 | ## 4. Limitation of Liability 42 | 43 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. 44 | THIS INCLUDES, BUT IS NOT LIMITED TO, DAMAGES FOR LOSS OF PROFITS, LOSS OF DATA, BUSINESS INTERRUPTION, OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING OUT OF OR RELATED TO THE USE OF THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 45 | 46 | --- 47 | 48 | ## 5. Reservation of Rights 49 | 50 | All rights not expressly granted under this license are **reserved by the copyright holder**. 51 | 52 | --- 53 | 54 | 📌 For commercial licensing inquiries, please contact: 55 | **Nima Askari** 56 | ✉️ Email: **nima.askari@gmail.com** 57 | 58 | --- 59 | 60 | © 2025 Nima Askari. All rights reserved. 61 | -------------------------------------------------------------------------------- /pb.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * @file pb.h 4 | * @brief Push-Button driver 5 | * @author Nima Askari 6 | * @version 1.0.0 7 | * @license See the LICENSE file in the root folder. 8 | * 9 | * @note All my libraries are dual-licensed. 10 | * Please review the licensing terms before using them. 11 | * For any inquiries, feel free to contact me. 12 | * 13 | * @github https://www.github.com/nimaltd 14 | * @linkedin https://www.linkedin.com/in/nimaltd 15 | * @youtube https://www.youtube.com/@nimaltd 16 | * @instagram https://instagram.com/github.nimaltd 17 | * 18 | * Copyright (C) 2025 Nima Askari - NimaLTD. All rights reserved. 19 | */ 20 | 21 | #ifndef _PB_H_ 22 | #define _PB_H_ 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /*************************************************************************************************/ 29 | /** Includes **/ 30 | /*************************************************************************************************/ 31 | 32 | #include 33 | #include "main.h" 34 | #include "pb_config.h" 35 | 36 | /*************************************************************************************************/ 37 | /** Typedef/Struct/Enum **/ 38 | /*************************************************************************************************/ 39 | 40 | /*************************************************************************************************/ 41 | /* Button event type (bitmask + long press flag) */ 42 | typedef struct 43 | { 44 | uint32_t long_press:1; 45 | uint32_t mask:31; 46 | 47 | } pb_evn_t; 48 | 49 | /*************************************************************************************************/ 50 | /* Configuration structure for a single push-button */ 51 | typedef struct __PACKED 52 | { 53 | GPIO_TypeDef *gpio; 54 | uint16_t pin; 55 | 56 | } pb_config_t; 57 | 58 | /*************************************************************************************************/ 59 | /* Main handle for push-button driver */ 60 | typedef struct 61 | { 62 | uint32_t beep; /* Beep counter */ 63 | uint32_t cnt[PB_CONFIG_COUNT]; /* Press duration counters for each button */ 64 | pb_evn_t evn[PB_EVN_QUEUE_SIZE]; /* Circular event buffer */ 65 | __IO uint32_t evn_head; /* Head index of the event queue (written by ISR) */ 66 | __IO uint32_t evn_tail; /* Tail index of the event queue (read by main loop) */ 67 | 68 | } pb_t; 69 | 70 | /*************************************************************************************************/ 71 | /** API Functions **/ 72 | /*************************************************************************************************/ 73 | 74 | /* Initialize the push-button driver */ 75 | void pb_init(void); 76 | 77 | /* Clear pending events */ 78 | void pb_clear(void); 79 | 80 | /* Read pending button events */ 81 | pb_evn_t pb_read(void); 82 | 83 | /* Process pending button events */ 84 | void pb_loop(void); 85 | 86 | /* Callback button events */ 87 | void pb_pressed_cb(pb_evn_t evn); 88 | 89 | /* Callback beep on */ 90 | void pb_beep_on_cb(void); 91 | 92 | /* Callback beep off */ 93 | void pb_beep_off_cb(void); 94 | 95 | /*************************************************************************************************/ 96 | /** End of File **/ 97 | /*************************************************************************************************/ 98 | 99 | #ifdef __cplusplus 100 | } 101 | #endif 102 | #endif /* _PB_H_ */ 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚡ Non-Blocking Push-Button Library for STM32 2 | 3 | A lightweight and efficient **push-button driver** written in C for STM32 (HAL-based). 4 | 5 | Unlike simple polling implementations, this library uses a **non-blocking, timer-driven approach**, allowing the CPU to continue other tasks. 6 | It can run on **any GPIO pins** and supports multiple buttons (up to 31) simultaneously. 7 | 8 | The library is designed for: 9 | 10 | - Projects where CPU blocking must be avoided 11 | - Applications that require short and long press detection 12 | - Easy portability across STM32 families 13 | 14 | --- 15 | 16 | ## ✨ Features 17 | 18 | - Multi-button support (`PB_CONFIG_COUNT`) 19 | - Short and long press detection 20 | - Detect simultaneously pressed push-buttons 21 | - Event queue with configurable size (`PB_EVN_QUEUE_SIZE`) 22 | - Optional callback on button events 23 | - Debouncing for all buttons 24 | - Non-blocking operation via timer interrupts 25 | - Support beep on press event 26 | - Fully STM32 HAL compatible 27 | - Lightweight and modular design 28 | 29 | --- 30 | 31 | ## ⚙️ Installation 32 | 33 | You can install in two ways: 34 | 35 | ### 1. Copy files directly 36 | Add these files to your STM32 project: 37 | - `pb.h` 38 | - `pb.c` 39 | - `pb_config.h` 40 | 41 | ### 2. STM32Cube Pack Installer 42 | Available in the official pack repo: 43 | 👉 [STM32-PACK](https://github.com/nimaltd/STM32-PACK) (Not Ready) 44 | 45 | --- 46 | 47 | ## 🔧 Configuration (`pb_config.h`) 48 | 49 | Defines library parameters and timing values. 50 | `PB_CONFIG` should be fill by your pins 51 | 52 | ```c 53 | /* Pin definitions */ 54 | #define PB_CONFIG {.gpio = KEY_DOWN_GPIO_Port, .pin = KEY_DOWN_Pin}, \ 55 | {.gpio = KEY_UP_GPIO_Port, .pin = KEY_UP_Pin}, \ 56 | {.gpio = KEY_ENTER_GPIO_Port, .pin = KEY_ENTER_Pin} 57 | ``` 58 | --- 59 | 60 | ## 🛠 CubeMX Setup 61 | 62 | 1. **GPIO Pins** 63 | - Configure button pins as **Input with Pull-Up** (idle-high buttons recommended). 64 | 65 | 2. **Timer** 66 | - Use **internal clock source**. 67 | - Set prescaler to get 1us tick. e.g. for 48Mhz bus, select 48-1. 68 | - Enable **Timer NVIC interrupt**. 69 | - In Project Manager → Code Generator, enable Generate Peripheral initialization as a pair ".c/.h" files per peripheral. 70 | - In **Project Manager → Advanced Settings**, enable **Register Callback** for the timer. 71 | 72 | --- 73 | 74 | ## 🚀 Quick Start 75 | 76 | ### Include header 77 | ```c 78 | #include "pb.h" 79 | ``` 80 | 81 | ### 1️⃣ Normal Reading Mode 82 | ```c 83 | int main(void) 84 | { 85 | pb_evn_t pb_evn; 86 | 87 | pb_init(); 88 | 89 | while (1) 90 | { 91 | pb_evn = pb_read(); // Get next event from queue 92 | if (pb_evn.mask) 93 | { 94 | // 0x00000001 for short press, first key 95 | // 0x00000002 for short press, second key 96 | // 0x00000004 for short press, third key 97 | // Handle button event manually 98 | } 99 | } 100 | } 101 | ``` 102 | 103 | --- 104 | 105 | ### 2️⃣ Callback mode 106 | 107 | #### Initialize with callback 108 | ```c 109 | /* Optional in all cases, Can handle beep on/off by a pin or timer */ 110 | void pb_beep_on_cb(void) 111 | { 112 | // turn on buzzer pin 113 | } 114 | 115 | void pb_beep_off_cb(void) 116 | { 117 | // turn off buzzer pin 118 | } 119 | 120 | void pb_pressed_cb(pb_evn_t evn) 121 | { 122 | } 123 | 124 | int main(void) 125 | { 126 | pb_init(); 127 | 128 | while (1) 129 | { 130 | pb_loop(); 131 | } 132 | } 133 | ``` 134 | 135 | --- 136 | 137 | ## 🧰 API Overview 138 | 139 | | Function | Description | 140 | |----------|-------------| 141 | | `pb_init()` | Initialize push-button driver with config and optional callback | 142 | | `pb_clear()` | Clear pending events | 143 | | `pb_read()` | Read pending button events | 144 | | `pb_loop()` | Retrieve event from queue and optionally call callback | 145 | | `pb_pressed_cb()` | Callback button events | 146 | | `pb_beep_on_cb()` | Callback beep on | 147 | | `pb_beep_off_cb()` | Callback beep off | 148 | 149 | --- 150 | 151 | ## 💖 Support 152 | 153 | If you find this project useful, please **⭐ star** the repo and consider supporting! 154 | 155 | - [![GitHub](https://img.shields.io/badge/GitHub-Follow-black?style=for-the-badge&logo=github)](https://github.com/NimaLTD) 156 | - [![YouTube](https://img.shields.io/badge/YouTube-Subscribe-red?style=for-the-badge&logo=youtube)](https://youtube.com/@nimaltd) 157 | - [![Instagram](https://img.shields.io/badge/Instagram-Follow-blue?style=for-the-badge&logo=instagram)](https://instagram.com/github.nimaltd) 158 | - [![LinkedIn](https://img.shields.io/badge/LinkedIn-Connect-blue?style=for-the-badge&logo=linkedin)](https://linkedin.com/in/nimaltd) 159 | - [![Email](https://img.shields.io/badge/Email-Contact-red?style=for-the-badge&logo=gmail)](mailto:nima.askari@gmail.com) 160 | - [![Ko-fi](https://img.shields.io/badge/Ko--fi-Support-orange?style=for-the-badge&logo=ko-fi)](https://ko-fi.com/nimaltd) 161 | 162 | --- 163 | 164 | ## 📜 License 165 | 166 | Licensed under the terms in the [LICENSE](./LICENSE.TXT). 167 | -------------------------------------------------------------------------------- /pb.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * @file pb.c 4 | * @brief Push-Button driver 5 | * @author Nima Askari 6 | * @version 1.0.0 7 | * @license See the LICENSE file in the root folder. 8 | * 9 | * @note All my libraries are dual-licensed. 10 | * Please review the licensing terms before using them. 11 | * For any inquiries, feel free to contact me. 12 | * 13 | * @github https://www.github.com/nimaltd 14 | * @linkedin https://www.linkedin.com/in/nimaltd 15 | * @youtube https://www.youtube.com/@nimaltd 16 | * @instagram https://instagram.com/github.nimaltd 17 | * 18 | * Copyright (C) 2025 Nima Askari - NimaLTD. All rights reserved. 19 | */ 20 | 21 | /*************************************************************************************************/ 22 | /** Includes **/ 23 | /*************************************************************************************************/ 24 | 25 | #include 26 | #include "pb.h" 27 | #include "tim.h" 28 | 29 | /*************************************************************************************************/ 30 | /** Private Function prototype **/ 31 | /*************************************************************************************************/ 32 | 33 | /* Add a new button event to the queue */ 34 | void pb_evn_add(pb_evn_t event); 35 | 36 | /* Periodic timer callback for push-button scan */ 37 | void pb_tim_cb(TIM_HandleTypeDef *htim); 38 | 39 | /*************************************************************************************************/ 40 | /** Global Variable **/ 41 | /*************************************************************************************************/ 42 | 43 | pb_t pb_handle; 44 | 45 | const pb_config_t pb_config[] = { PB_CONFIG }; 46 | 47 | /*************************************************************************************************/ 48 | /** Function Implementations **/ 49 | /*************************************************************************************************/ 50 | 51 | /*************************************************************************************************/ 52 | /** 53 | * @brief Initialize the push-button driver. 54 | * Sets configuration, callback, clears buffers, and starts 55 | * the timer interrupt for periodic button scanning. 56 | */ 57 | void pb_init(void) 58 | { 59 | /* Clear event buffer */ 60 | pb_clear(); 61 | 62 | /* Configure timer for PB scanning */ 63 | __HAL_TIM_SET_AUTORELOAD(&PB_TIM, (PB_INTERVAL_MS * 1000U) - 1U); 64 | __HAL_TIM_SET_COUNTER(&PB_TIM, 0); 65 | 66 | /* Register callback and start timer interrupt */ 67 | HAL_TIM_RegisterCallback(&PB_TIM, HAL_TIM_PERIOD_ELAPSED_CB_ID, pb_tim_cb); 68 | HAL_TIM_Base_Start_IT(&PB_TIM); 69 | } 70 | 71 | /*************************************************************************************************/ 72 | /** 73 | * @brief Clear pending events. 74 | */ 75 | void pb_clear(void) 76 | { 77 | /* Reset head and tail indices */ 78 | pb_handle.evn_head = 0; 79 | pb_handle.evn_tail = 0; 80 | 81 | /* Clear event buffer and press counters */ 82 | memset(pb_handle.evn, 0, sizeof(pb_handle.evn)); 83 | memset(pb_handle.cnt, 0, sizeof(pb_handle.cnt)); 84 | } 85 | 86 | /*************************************************************************************************/ 87 | /** 88 | * @brief Process pending button events. 89 | * Retrieves next event from the queue and calls the user callback 90 | * (if registered). Returns the event for manual polling. 91 | */ 92 | pb_evn_t pb_read(void) 93 | { 94 | pb_evn_t event = {0}; 95 | 96 | if (pb_handle.evn_head != pb_handle.evn_tail) 97 | { 98 | event = pb_handle.evn[pb_handle.evn_tail]; 99 | pb_handle.evn_tail = (pb_handle.evn_tail + 1U) % PB_EVN_QUEUE_SIZE; 100 | } 101 | 102 | return event; 103 | } 104 | 105 | /*************************************************************************************************/ 106 | /** 107 | * @brief Process pending button events. 108 | * Retrieves next event from the queue and calls the user callback 109 | * (if registered). Returns the event for manual polling. 110 | */ 111 | void pb_loop(void) 112 | { 113 | if (pb_handle.evn_head != pb_handle.evn_tail) 114 | { 115 | uint32_t tail = pb_handle.evn_tail; 116 | pb_evn_t event = pb_handle.evn[tail]; 117 | 118 | /* Advance tail before executing callback */ 119 | pb_handle.evn_tail = (tail + 1U) % PB_EVN_QUEUE_SIZE; 120 | 121 | /* Memory barrier for robustness */ 122 | __DMB(); 123 | 124 | /* Call callback */ 125 | pb_pressed_cb(event); 126 | } 127 | } 128 | 129 | /*************************************************************************************************/ 130 | /** Private Implementations **/ 131 | /*************************************************************************************************/ 132 | 133 | /*************************************************************************************************/ 134 | /** 135 | * @brief Add a new button event to the queue. 136 | * Inserts event at the head index if queue not full. 137 | * Head is advanced in a circular manner (single-producer safe). 138 | */ 139 | void pb_evn_add(pb_evn_t event) 140 | { 141 | uint32_t next_head = (pb_handle.evn_head + 1U) % PB_EVN_QUEUE_SIZE; 142 | 143 | /* Check if queue is not full */ 144 | if (next_head != pb_handle.evn_tail) 145 | { 146 | pb_handle.evn[pb_handle.evn_head] = event; 147 | 148 | /* Ensure event is written before publishing head */ 149 | __DMB(); 150 | 151 | /* Update head */ 152 | pb_handle.evn_head = next_head; 153 | } 154 | /* else: queue full */ 155 | } 156 | 157 | /*************************************************************************************************/ 158 | /** 159 | * @brief Periodic timer callback for push-button scan. 160 | * Checks each button state (active-low): 161 | * - Increments counter while pressed. 162 | * - On release, generates short or long press event. 163 | */ 164 | void pb_tim_cb(TIM_HandleTypeDef *htim) 165 | { 166 | pb_evn_t tmp_evn = {0}; 167 | static pb_evn_t last_evn = {0}; 168 | static uint32_t last_time = 0; 169 | 170 | /* Check beep */ 171 | if (pb_handle.beep) 172 | { 173 | pb_handle.beep--; 174 | if (pb_handle.beep == 0) 175 | { 176 | pb_beep_off_cb(); 177 | } 178 | } 179 | 180 | /* Scanning all pins */ 181 | for (uint8_t i = 0; i < PB_CONFIG_COUNT; i++) 182 | { 183 | /* Released (logic high) */ 184 | #if (PB_IDLE_IS_HIGH == 1) 185 | if (pb_config[i].gpio->IDR & pb_config[i].pin) 186 | #else 187 | if (!(pb_config[i].gpio->IDR & pb_config[i].pin)) 188 | #endif 189 | { 190 | if (pb_handle.cnt[i] >= (PB_LONG_TIME_MS / PB_INTERVAL_MS)) 191 | { 192 | tmp_evn.mask |= (1 << i); 193 | tmp_evn.long_press = 1; 194 | } 195 | else if (pb_handle.cnt[i] >= (PB_SHORT_TIME_MS / PB_INTERVAL_MS)) 196 | { 197 | tmp_evn.mask |= (1 << i); 198 | tmp_evn.long_press = 0; 199 | } 200 | 201 | /* Reset after release */ 202 | pb_handle.cnt[i] = 0; 203 | } 204 | /* Pressed (logic low) */ 205 | else 206 | { 207 | /* Count press duration */ 208 | pb_handle.cnt[i]++; 209 | 210 | /* Check beep */ 211 | if (pb_handle.beep == 0) 212 | { 213 | if (pb_handle.cnt[i] == (PB_SHORT_TIME_MS / PB_INTERVAL_MS)) 214 | { 215 | pb_handle.beep = PB_BEEP_TIME_MS / PB_INTERVAL_MS; 216 | pb_beep_on_cb(); 217 | } 218 | } 219 | } 220 | } 221 | 222 | /* Collect all events */ 223 | if (tmp_evn.mask) 224 | { 225 | last_evn.mask |= tmp_evn.mask; 226 | last_evn.long_press |= tmp_evn.long_press; 227 | last_time = HAL_GetTick(); 228 | } 229 | 230 | /* Wait for PB_BEEP_TIME_MS to release all push-buttons and add event */ 231 | if ((last_evn.mask != 0 ) && (HAL_GetTick() - last_time >= PB_BEEP_TIME_MS)) 232 | { 233 | pb_evn_add(last_evn); 234 | last_evn.long_press = 0; 235 | last_evn.mask = 0; 236 | } 237 | } 238 | 239 | /*************************************************************************************************/ 240 | /** 241 | * @brief Callback. 242 | */ 243 | __WEAK void pb_pressed_cb(pb_evn_t evn) 244 | { 245 | UNUSED(evn); 246 | } 247 | 248 | /*************************************************************************************************/ 249 | /** 250 | * @brief Callback. 251 | */ 252 | __WEAK void pb_beep_on_cb(void) 253 | { 254 | 255 | } 256 | 257 | /*************************************************************************************************/ 258 | /** 259 | * @brief Callback. 260 | */ 261 | __WEAK void pb_beep_off_cb(void) 262 | { 263 | 264 | } 265 | 266 | /*************************************************************************************************/ 267 | /** End of File **/ 268 | /*************************************************************************************************/ 269 | --------------------------------------------------------------------------------