HAL STM32通过multi_button库处理按键事件

HAL STM32通过multi_button库处理按键事件

  • 📍作者:0x1abin的multi_button库:https://github.com/0x1abin/MultiButton

📘MultiButton简介

MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。

  • 🔖 该库驱动代码纯C语言实现,可以移植到任意需要使用的地方。

🔑使用方法

  1. 先申请一个按键结构
struct Button button1;
  1. 初始化按键对象,绑定按键的GPIO电平读取接口read_button_pin() ,后一个参数设置有效触发电平。
button_init(&button1, read_button_pin, 0, 0);//绑定按键,读取按键引脚状态,有效触发电平、按键ID
  1. 注册按键事件
button_attach(&button1, SINGLE_CLICK, Callback_SINGLE_CLICK_Handler);
button_attach(&button1, DOUBLE_CLICK, Callback_DOUBLE_Click_Handler);


4. 启动按键

button_start(&button1);
  1. 设置一个5ms间隔的定时器循环调用后台处理函数
while(1) {
    ...
    if(timer_ticks == 5) {
        timer_ticks = 0;

        button_ticks();
    }
}

🛠按键引脚配置

  • 🌿通过STM32CubeMX,将按键引脚配置成上拉,那么有效触发电平就需要设置为0.
    在这里插入图片描述

📗通过按键事件查询,获取按键状态

  • 🌿在滴答定时器中断函数(SysTick_Handler)中添加button_tick();
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include <stdarg.h>
#include "usbd_cdc_if.h"
#include "multi_button.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
struct Button btn1;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void usb_printf(const char *fmt, ...)
{
    char buf[128];//自定义缓冲区大小
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);
    CDC_Transmit_FS((uint8_t *)buf, strlen(buf));
}



void button_tick(void)
{
    static uint8_t tickstart = 0;
    tickstart++;
    if(tickstart < 5)
        return;
    tickstart = 0;
    button_ticks();
}
//按键状态读取接口  按键输入模式 ReadInputDataBit
uint8_t Read_Button_GPIO(uint8_t button_id)
{
    // you can share the GPIO read function with multiple Buttons
    switch(button_id) {
        case 1:
            return HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin);
				case 2:
            return HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin);
        default:
            return 0;
    }
}


/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    /* USER CODE BEGIN 1 */
    uint32_t TimerUART;
    static PressEvent btn1_event_val;


    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_USB_DEVICE_Init();
    /* USER CODE BEGIN 2 */
    uint32_t Main_Fosc = HAL_RCC_GetSysClockFreq();
    printf("Main_Fosc:%dHz \r\n", Main_Fosc);
    TimerUART = HAL_GetTick();
    usb_printf("STM32F427 SysClockFreq:%d \r\n", Main_Fosc);
    button_init(&btn1, Read_Button_GPIO, 0, 1);
    button_start(&btn1);
  
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while(1) {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        if((HAL_GetTick() - TimerUART) > 1000) {
            HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin | LED2_Pin | LED3_Pin); //翻转电平,LED翻转
            printf("STM32F427 SysClockFreq:%d \r\n", Main_Fosc);
            usb_printf("STM32F427 SysClockFreq:%d \r\n", Main_Fosc);
            TimerUART = HAL_GetTick();
        }
        if(btn1_event_val != get_button_event(&btn1)) {
            btn1_event_val = get_button_event(&btn1);

            if(btn1_event_val == PRESS_DOWN) {
                // printf("STM32F427 KEY1 PRESS_DOWN \r\n");
                usb_printf("STM32F427 KEY1 PRESS_DOWN \r\n");
            } else if(btn1_event_val == PRESS_UP) {
                // printf("STM32F427 KEY1 PRESS_UP \r\n");
                usb_printf("STM32F427 KEY1 PRESS_UP \r\n");
            } else if(btn1_event_val == LONG_PRESS_HOLD) {
                // printf("STM32F427 LONG_PRESS_HOLD\r\n"/);
                usb_printf("STM32F427 LONG_PRESS_HOLD\r\n");
            }
        }
    }
    /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage
    */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

    /** Initializes the RCC Oscillators according to the specified parameters
    * in the RCC_OscInitTypeDef structure.
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 16;
    RCC_OscInitStruct.PLL.PLLN = 384;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
    RCC_OscInitStruct.PLL.PLLQ = 8;
    if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
    */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                  | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

    if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) {
        Error_Handler();
    }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while(1) {
    }
    /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

📓通过注册按键事件,获取按键状态

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include <stdarg.h>
#include "usbd_cdc_if.h"
#include "multi_button.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
struct Button btn1;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void BTN1_PRESS_DOWN_Handler(void* btn);
void BTN1_PRESS_UP_Handler(void* btn);
void BTN1_SINGLE_Click_Handler(void* btn);
void BTN1_DOUBLE_Click_Handler(void* btn);
void BTN1_LONG_RRESS_START_Handler(void* btn);
void BTN1_LONG_PRESS_HOLD_Handler(void* btn);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void usb_printf(const char *fmt, ...)
{
    char buf[128];//自定义缓冲区大小
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);
    CDC_Transmit_FS((uint8_t *)buf, strlen(buf));
}



void button_tick(void)
{
    static uint8_t tickstart = 0;
    tickstart++;
    if(tickstart < 5)
        return;
    tickstart = 0;
    button_ticks();
}
//按键状态读取接口  按键输入模式 ReadInputDataBit
uint8_t Read_Button_GPIO(uint8_t button_id)
{
    // you can share the GPIO read function with multiple Buttons
    switch(button_id) {
        case 1:
            return HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin);
        case 2:
            return HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin);
        default:
            return 0;
    }
}


/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    /* USER CODE BEGIN 1 */
    uint32_t TimerUART;
    // static PressEvent btn1_event_val;


    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_USB_DEVICE_Init();
    /* USER CODE BEGIN 2 */
    uint32_t Main_Fosc = HAL_RCC_GetSysClockFreq();
    printf("Main_Fosc:%dHz \r\n", Main_Fosc);
    TimerUART = HAL_GetTick();
    usb_printf("STM32F427 SysClockFreq:%d \r\n", Main_Fosc);
    button_init(&btn1, Read_Button_GPIO, 0, 1);
    // button_attach(&btn1, PRESS_DOWN, BTN1_PRESS_DOWN_Handler); //按下
    // button_attach(&btn1, PRESS_UP, BTN1_PRESS_UP_Handler);  //按起
    //	button_attach(&btn1, PRESS_REPEAT,     BTN1_PRESS_REPEAT_Handler);
    button_attach(&btn1, SINGLE_CLICK, BTN1_SINGLE_Click_Handler); //单击
    button_attach(&btn1, DOUBLE_CLICK, BTN1_DOUBLE_Click_Handler);  //双击
    button_attach(&btn1, LONG_PRESS_START, BTN1_LONG_RRESS_START_Handler); //长按开始
    // button_attach(&btn1, LONG_PRESS_HOLD, BTN1_LONG_PRESS_HOLD_Handler);//一直长按状态
    button_start(&btn1);
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while(1) {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        if((HAL_GetTick() - TimerUART) > 1000) {
            HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin | LED2_Pin | LED3_Pin); //翻转电平,LED翻转
            printf("STM32F427 SysClockFreq:%d \r\n", Main_Fosc);
            usb_printf("STM32F427 SysClockFreq:%d \r\n", Main_Fosc);
            TimerUART = HAL_GetTick();
        }

    }
    /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage
    */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

    /** Initializes the RCC Oscillators according to the specified parameters
    * in the RCC_OscInitTypeDef structure.
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 16;
    RCC_OscInitStruct.PLL.PLLN = 384;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
    RCC_OscInitStruct.PLL.PLLQ = 8;
    if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
    */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                  | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

    if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) {
        Error_Handler();
    }
}

/* USER CODE BEGIN 4 */
void BTN1_PRESS_DOWN_Handler(void* btn)
{
    // printf("STM32F427 KEY1 PRESS_DOWN \r\n");
    usb_printf("STM32F427 KEY1 PRESS_DOWN \r\n");
}

void BTN1_PRESS_UP_Handler(void* btn)
{
    // printf("STM32F427 KEY1 PRESS_UP \r\n");
    usb_printf("STM32F427 KEY1 PRESS_UP \r\n");
}
void BTN1_SINGLE_Click_Handler(void* btn)
{
    // printf("STM32F427 KEY1 SINGLE_Click \r\n");
    usb_printf("STM32F427 KEY1 SINGLE_Click \r\n");
}
void BTN1_DOUBLE_Click_Handler(void* btn)
{
    // printf("STM32F427 KEY1 DOUBLE_Click \r\n");
    usb_printf("STM32F427 KEY1 DOUBLE_Click \r\n");
}
void BTN1_LONG_RRESS_START_Handler(void* btn)
{
    // printf("STM32F427 KEY1 LONG_RRESS_START \r\n");
    usb_printf("STM32F427 KEY1 LONG_RRESS_START \r\n");
}
void BTN1_LONG_PRESS_HOLD_Handler(void* btn)
{
    // printf("STM32F427 KEY1 LONG_PRESS_HOLD \r\n");
    usb_printf("STM32F427 KEY1 LONG_PRESS_HOLD \r\n");
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while(1) {
    }
    /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

📝通过注册按键事件,统一查询获取按键状态

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include <stdarg.h>
#include "usbd_cdc_if.h"
#include "multi_button.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
struct Button btn1;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
//void BTN1_PRESS_DOWN_Handler(void* btn);
//void BTN1_PRESS_UP_Handler(void* btn);
//void BTN1_SINGLE_Click_Handler(void* btn);
//void BTN1_DOUBLE_Click_Handler(void* btn);
//void BTN1_LONG_RRESS_START_Handler(void* btn);
//void BTN1_LONG_PRESS_HOLD_Handler(void* btn);
void button_callback(void *btn);//
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void usb_printf(const char *fmt, ...)
{
    char buf[128];//自定义缓冲区大小
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);
    CDC_Transmit_FS((uint8_t *)buf, strlen(buf));
}



void button_tick(void)
{
    static uint8_t tickstart = 0;
    tickstart++;
    if(tickstart < 5)
        return;
    tickstart = 0;
    button_ticks();
}
//按键状态读取接口  按键输入模式 ReadInputDataBit
uint8_t Read_Button_GPIO(uint8_t button_id)
{
    // you can share the GPIO read function with multiple Buttons
    switch(button_id) {
        case 1:
            return HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin);
        case 2:
            return HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin);
        default:
            return 0;
    }
}


/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    /* USER CODE BEGIN 1 */
//    uint32_t TimerUART;
    // static PressEvent btn1_event_val;


    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_USB_DEVICE_Init();
    /* USER CODE BEGIN 2 */
    uint32_t Main_Fosc = HAL_RCC_GetSysClockFreq();
    printf("Main_Fosc:%dHz \r\n", Main_Fosc);
//    TimerUART = HAL_GetTick();
    usb_printf("STM32F427 SysClockFreq:%d \r\n", Main_Fosc);
    button_init(&btn1, Read_Button_GPIO, 0, 1);
    // button_attach(&btn1, PRESS_DOWN, button_callback); //按下
    // button_attach(&btn1, PRESS_UP, button_callback);  //按起
    //	button_attach(&btn1, PRESS_REPEAT,button_callback);
    button_attach(&btn1, SINGLE_CLICK, button_callback); //单击
    button_attach(&btn1, DOUBLE_CLICK, button_callback);  //双击
    button_attach(&btn1, LONG_PRESS_START, button_callback); //长按开始
    // button_attach(&btn1, LONG_PRESS_HOLD, button_callback);//一直长按状态
    button_start(&btn1);
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while(1) {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
//        if((HAL_GetTick() - TimerUART) > 1000) {
//            HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin | LED2_Pin | LED3_Pin); //翻转电平,LED翻转
//            printf("STM32F427 SysClockFreq:%d \r\n", Main_Fosc);
//            usb_printf("STM32F427 SysClockFreq:%d \r\n", Main_Fosc);
//            TimerUART = HAL_GetTick();
//        }
        /*
        if(btn1_event_val != get_button_event(&btn1)) {
        btn1_event_val = get_button_event(&btn1);

        if(btn1_event_val == PRESS_DOWN) {
        // printf("STM32F427 KEY1 PRESS_DOWN \r\n");
        usb_printf("STM32F427 KEY1 PRESS_DOWN \r\n");
        } else if(btn1_event_val == PRESS_UP) {
        // printf("STM32F427 KEY1 PRESS_UP \r\n");
        usb_printf("STM32F427 KEY1 PRESS_UP \r\n");
        } else if(btn1_event_val == LONG_PRESS_HOLD) {
        // printf("STM32F427 LONG_PRESS_HOLD\r\n"/);
        usb_printf("STM32F427 LONG_PRESS_HOLD\r\n");
        }

        }
        */
    }
    /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage
    */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

    /** Initializes the RCC Oscillators according to the specified parameters
    * in the RCC_OscInitTypeDef structure.
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 16;
    RCC_OscInitStruct.PLL.PLLN = 384;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
    RCC_OscInitStruct.PLL.PLLQ = 8;
    if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
    */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                  | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

    if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) {
        Error_Handler();
    }
}

/* USER CODE BEGIN 4 */
void BTN1_PRESS_DOWN_Handler(void* btn)
{
    // printf("STM32F427 KEY1 PRESS_DOWN \r\n");
    usb_printf("STM32F427 KEY1 PRESS_DOWN \r\n");
}

void BTN1_PRESS_UP_Handler(void* btn)
{
    // printf("STM32F427 KEY1 PRESS_UP \r\n");
    usb_printf("STM32F427 KEY1 PRESS_UP \r\n");
}
void BTN1_SINGLE_Click_Handler(void* btn)
{
    // printf("STM32F427 KEY1 SINGLE_Click \r\n");
    usb_printf("STM32F427 KEY1 SINGLE_Click \r\n");
}
void BTN1_DOUBLE_Click_Handler(void* btn)
{
    // printf("STM32F427 KEY1 DOUBLE_Click \r\n");
    usb_printf("STM32F427 KEY1 DOUBLE_Click \r\n");
}
void BTN1_LONG_RRESS_START_Handler(void* btn)
{
    // printf("STM32F427 KEY1 LONG_RRESS_START \r\n");
    usb_printf("STM32F427 KEY1 LONG_RRESS_START \r\n");
}
void BTN1_LONG_PRESS_HOLD_Handler(void* btn)
{
    // printf("STM32F427 KEY1 LONG_PRESS_HOLD \r\n");
    usb_printf("STM32F427 KEY1 LONG_PRESS_HOLD \r\n");
}

void button_callback(void *btn)
{
static PressEvent btn1_event_val;
//    uint32_t btn_event_val;    
//    btn_event_val = get_button_event((struct Button *)btn);
//	btn_event_val = get_button_event(&btn1);
if(btn1_event_val != get_button_event(&btn1)) {
			btn1_event_val = get_button_event(&btn1);
    switch(btn1_event_val)
    {
      case PRESS_DOWN:
          printf("---> KEY1 press down! <---\r\n"); 
			usb_printf("---> KEY1 press down! <---\r\n"); 
      break; 

      case PRESS_UP: 
          printf("***> KEY1 press up! <***\r\n");
			usb_printf("---> KEY1 press up! <---\r\n");
      break; 

      case PRESS_REPEAT: 
          printf("---> KEY1 press repeat! <---\r\n");
      break; 

      case SINGLE_CLICK: 
          printf("---> KEY1 single click! <---\r\n");
			usb_printf("---> KEY1 single click! <---\r\n");
      break; 

      case DOUBLE_CLICK: 
          printf("***> KEY1 double click! <***\r\n");
			usb_printf("---> KEY1 double click! <---\r\n");
      break; 

      case LONG_PRESS_START: 
          printf("---> KEY1 long press start! <---\r\n");
					usb_printf("---> KEY1 long press start! <---\r\n");
      break; 

      case LONG_PRESS_HOLD: 
          printf("***> KEY1 long press hold! <***\r\n");
					usb_printf("---> KEY1 press down! <---\r\n");
      break; 
			default:
			break;
	}
}
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while(1) {
    }
    /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

📚相关测试工程

链接:https://pan.baidu.com/s/1DRqSkKnj6Kznh3izOLrlWQ?pwd=awf4 
提取码:awf4
链接:https://pan.baidu.com/s/1rviDB1MHQTQZkIBr590wXQ?pwd=11tu 
提取码:11tu
链接:https://pan.baidu.com/s/1GkQE7OZJnBn8t6gNXMahEw?pwd=vhw5 
提取码:vhw5

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/393376.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分享一个学英语的网站

名字叫&#xff1a;公益大米网​​​​​​​ Freerice 这个网站是以做题的形式来记忆单词&#xff0c;题干是一个单词&#xff0c;给出4个选项&#xff0c;需要选出其中最接近题干单词的选项。 答对可以获得10粒大米&#xff0c;网站的创办者负责捐赠。如图 触发某些条件&a…

解锁Spring Boot中的设计模式—05.策略模式:探索【策略模式】的奥秘与应用实践!

1.策略者工厂模式&#xff08;Map版本&#xff09; 1.需求背景 假设有一个销售系统&#xff0c;需要根据不同的促销活动对商品进行打折或者其他形式的优惠。这些促销活动可以是针对不同商品类别的&#xff0c;比如男装、女装等。 2.需求实现 活动策略接口&#xff1a;定义了…

Docker数据卷容器(容器继承)

Docker数据卷容器&#xff08;容器继承&#xff09; 创建DockerFile构建镜像启动容器修改数据卷创建子容器验证 命名的容器挂载数据卷。其他容器通过挂载这个容器实现数据共享&#xff0c;挂载数据的容器 -> 称之为数据卷容器 创建DockerFile FROM centosVOLUME ["dat…

哪个牌子的洗地机好用?性能超好的洗地机推荐

洗地机已经是家庭中不可或缺的清洁家电之一了&#xff0c;它的出现极大地方便了我们的生活&#xff0c;并为我们解决了一大难题&#xff1a;洗地板的繁琐。无论是家庭主妇还是上班族&#xff0c;对于洗地机的需求都是无可替代的。随着科技的不断进步&#xff0c;洗地机的功能也…

上门回收小程序开发,互联网下发展机遇

在当下生活水平大幅度上升发展下&#xff0c;回收成为了人们日常生活中的一部分。 如今&#xff0c;随着互联网的快速发展&#xff0c;回收行业也进行了升级换代&#xff0c;由传统的线下回收门店到回收箱在到当下的线上互联网回收模式&#xff0c;迈向了“互联网废品回收”的…

安装ts-node有感

起因&#xff1a;想要在vsCode上运行ts脚本 解决方案&#xff1a; 1.安装vsCode插件 code runner 2.全局安装ts-node 这一步遇到三个问题&#xff1a; ①.node版本问题&#xff1a;需安装版本18以上node&#xff0c;可使用nvm去控制不同的node版本 ②.certificate has exp…

【以解决】Pyinstaller打包报错IndexError: tuple index out of range

问题 这个问题主要是在Python3.7以上的版本中遇到&#xff0c;用pyinstaller打包的时候发现报错 (pyinstallerEnv) D:\virtualEnv\pyinstallerEnv\Scripts>auto-py-to-exe pygame 2.5.2 (SDL 2.28.3, Python 3.10.0) Hello from the pygame community. https://www.pygame…

PCIe TX端电容

一、问题&#xff1a;PCIe为什么要加电容 PCIe为什么要加电容&#xff1f;具体的作用是什么&#xff1f; 答&#xff1a;因为PCIe Host和Receiver两端的直流偏置会不一样&#xff0c;所以需要在PCIe的传输路径上加电容&#xff0c;这样传输路径上只有AC信号&#xff0c;不存在…

const--类的常量成员函数

在C中,为了禁止成员函数修改数据成员的值,可以将它设置为常量成员函数。设置常量成员函数的方法是在函数原型的后面加上const,形式如下: class x { …………… T f(t1,t2) const{} ………… }; 常量成员函数的作用&#xff1a; 将成员函数设置为const&#xff0c;表明该成员函…

MySQL跨服务器关联查询

1. 首先确认服务器的Federated引擎是否开启 show engines;修改数据库的配制文件my.ini,(我的my.ini的路径为&#xff1a;D:\ProgramData\MySQL\MySQL Server 5.7/my.ini),将federated添加到my.ini文件中 到MySQL的my.cnf配置文件中修改 在 [mysqld] 下方加入 federated 然后重…

CentOS 7.9如何禁止内核自动更新升级

要在 CentOS 7.9 系统中禁止内核自动更新&#xff0c;你可以通过配置 YUM&#xff08;Yellowdog Updater, Modified&#xff09;来实现。这里有几种方法可以阻止内核自动更新&#xff1a; 方法 1: 使用 exclude 选项在 YUM 配置中 编辑 YUM 的配置文件 /etc/yum.conf&#xff…

[SWPUCTF 2021 新生赛]crypto8

第一眼看见是乱码不确定是什么的编码 看了下感觉是UUencode编码 UUencode编码是一种古老的编码方式&#xff0c;通常用于将二进制数据转换成可打印字符的形式。UUencode编码采用一种基于64个字符的编码表&#xff0c;将每3个字节的数据编码为4个可打印字符&#xff0c;以实现…

C++类和对象——继承详解

目录 1.基本语法 2.继承方式 3.继承中的对象模型 4.构造和构析顺序 5.同名成员处理 6.同名静态成员处理 7.多继承语法 8.菱形继承 图片示例&#xff1a; 虚继承 代码示例&#xff1a; 1.基本语法 #include<bits/stdc.h> using namespace std;//公共页面类 …

心法利器[107] onnx和tensorRT的bert加速方案记录

心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会&#xff0c;与大家一起成长。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。 2023年新一版的文章合集已经发布&#xff0c;获取方式看这里&#xff1a;又添十万字-CS的陋室2…

深度学习基础之《TensorFlow框架(4)—Operation》

一、常见的OP 1、举例 类型实例标量运算add&#xff0c;sub&#xff0c;mul&#xff0c;div&#xff0c;exp&#xff0c;log&#xff0c;greater&#xff0c;less&#xff0c;equal向量运算concat&#xff0c;slice&#xff0c;splot&#xff0c;canstant&#xff0c;rank&am…

Sora OpenAI 101教程(一):从文本生成令人兴奋的视频的 AI 模型

想象一下&#xff0c;您可以通过简单的文本提示创建令人惊叹的视频&#xff0c;例如“一个人带着狗在月球上行走”。听起来不可能&#xff0c;对吧&#xff1f;好吧&#xff0c;现在不再这样了&#xff0c;感谢 OpenAI 的最新人工智能模型 Sora&#xff0c;它可以从文本生成令人…

基于QEMU的vexpress-a9的初始化代码运行(二)

这个part是想详细走读一下用qemu运行kernel的最初始代码&#xff0c;也就是使用qemu运行kernel代码的详细逻辑&#xff0c;从qemu加载根目录下vmlinux镜像的逻辑&#xff0c;也就是运行arch/arm/kernel/head.S的整个过程&#xff0c;直到跳转到start_kernel&#xff0c;使用的k…

GraphPad Prism 10.2.0 for Mac 强大实用的医学绘图分析工具

GraphPad Prism GraphPad Prism是一款非常实用的统计软件&#xff0c;其功能非常强大&#xff0c;能够帮助用户进行各类科研数据的处理和分析&#xff0c;快速绘制出各种专业的图像和数据报告。 GraphPad Prism软件的用户界面非常友好&#xff0c;易于学习和操作&#xff0c;…

通过前序和中序遍历结果构造二叉树

题目 105. 从前序与中序遍历序列构造二叉树 - 力扣&#xff08;LeetCode&#xff09; 思路 首先思考&#xff0c;根节点应该做什么。 肯定要想办法确定根节点的值&#xff0c;把根节点做出来&#xff0c;然后递归构造左右子树即可。 我们先来回顾一下&#xff0c;前序遍历和…

使用MinIO S3存储桶备份Weaviate

Weaviate 是一个开创性的开源向量数据库&#xff0c;旨在通过利用机器学习模型来增强语义搜索。与依赖关键字匹配的传统搜索引擎不同&#xff0c;Weaviate 采用语义相似性原则。这种创新方法将各种形式的数据&#xff08;文本、图像等&#xff09;转换为矢量表示形式&#xff0…