HALSTM32通用定时器+EXTI实现单击/双击/长按功能

HALSTM32通用定时器+EXTI实现单击/双击/长按功能


  • ✨在使用USB功率计的时候,发现上面的一个按键实现多画面功能切换,于是探索了一下是如何实现的,将其实现的基本思路以及综合网上收集的相关实现方法,粗陋的整理了一下,将其基本功能实现了一下,具体的功能没有做,只是做了一个简单的框架。
    HALSTM32通用定时器+EXTI实现单击/双击/长按功能_第1张图片
  • 功能实现,并不能保证每次处理的按键结果,都如预期效果,主要的影响因数是单击和双击,之间的间隔时间,每个人的手感或者每次按下的时间差异并不能像计算器那么准确和标准。

HAL STM32CubeMX工程配置

  • 基于STM32F103芯片。

  • 主要配置一个外部中断按键引脚。
    HALSTM32通用定时器+EXTI实现单击/双击/长按功能_第2张图片

  • GPIO引脚按键外部使用电路参考:
    HALSTM32通用定时器+EXTI实现单击/双击/长按功能_第3张图片

  • 配置一个定时器
    HALSTM32通用定时器+EXTI实现单击/双击/长按功能_第4张图片

  • NVIC中断使能以及优先级配置。
    HALSTM32通用定时器+EXTI实现单击/双击/长按功能_第5张图片

  • 其他串口和I2C配置用于显示和调试输出。(这里根据个人需求配置,个人推荐还是使用软件I2C实现比较好,硬件I2C如果程序比较复杂,cpu处理各种中断,容易导致硬件I2C出错,导致显示画面异常的情况。)
    HALSTM32通用定时器+EXTI实现单击/双击/长按功能_第6张图片
    HALSTM32通用定时器+EXTI实现单击/双击/长按功能_第7张图片

  • 其他时钟配置和工程生成就不展示了,根据个人情况配置。

⛳功能实现

  • 完善按键中断回调内容
//重写回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{

    /*判断是中断引脚*/
    if(GPIO_Pin == KEY_Pin)
    {
        Trg++;
        HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5);//状态翻转
    }
}
  • 定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{

    static uint32_t click = 0;
    static char keyStatus = 0;
    static char LongPress = 0;
    if(htim ->Instance == TIM6)
    {
        if(++cnt_1ms >= 1000)
        {
            cnt_1ms = 0;
            HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);//状态翻转
        }
        if(Trg > 0)
        {
            keyStatus = HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin);//读取按键状态
            click++;
            if((click > _debounce_ms) && (keyStatus == 1) && (LongPress == 0)) //1000
            {
                if((Trg == 1) || (Trg > 2)) //单击
                {
                    Trg = 0;
                    funIndex ++;
                    printf("_click_ms,%d\r\n", funIndex);
                    click = 0;//清零
                }
                if(Trg == 2) //双击
                {
                    Trg = 0;
                    funIndex += 2;
                    printf("_doubleClick %d\r\n", funIndex);
                    click = 0;//清零
                }
            }
            if((click > _press_ms) && (keyStatus == 0) && (LongPress == 0)) //1000
            {
                printf("_longPressStart\r\n");
                LongPress = 1;
            }
            if((LongPress == 1) && (keyStatus == 1))
            {
                LongPress = 0;
                Trg = 0;
                funIndex += 3;//松开才赋值
                click = 0;
                printf("_longPressStop %d\r\n", funIndex);
            }
        }
        if(funIndex > 8)funIndex = 0;

    }
}

  • oled驱动显示内容,可以根据个人使用的屏幕规格型号自行完善,个人使用的是SH1106 1.3“寸的OLED屏幕作为显示。
  • 按键菜单显示内容参考网上的内容。
unsigned char funIndex = 0;//9和0->1-1
void menu11(void);
void menu12(void);
void menu21(void);
void menu22(void);
void menu23(void);
void menu31(void);
void menu32(void);
void menu33(void);
void menu34(void);
//定义按键操作数据
KEY_TABLE table[9] =
{
    {0, 0, 1, 0, 2, (*menu11)},
    {1, 0, 1, 1, 4, (*menu12)},
    {2, 2, 3, 0, 5, (*menu21)},
    {3, 2, 3, 0, 7, (*menu22)},
    {4, 4, 4, 1, 4, (*menu23)},
    {5, 5, 6, 2, 5, (*menu31)},
    {6, 5, 6, 2, 6, (*menu32)},
    {7, 7, 8, 3, 7, (*menu33)},
    {8, 7, 8, 3, 8, (*menu34)},
};

void ShowMenu(int16_t x, int16_t y,char *text)
{
    OLED_ShowString(x, y, text, 12);//x,y,字符串,字体大小
}

//一级菜单1
void menu11(void)
{

//    OLED_Clear();
    OLED_ShowString(36, 6, "menu1-1", 16);
}

//一级菜单2
void menu12(void)
{
//    OLED_Clear();
    OLED_ShowString(36, 6, "menu1-2", 16);
}

//二级菜单1
void menu21(void)
{
//    OLED_Clear();
    OLED_ShowString(36, 6, "menu2-1", 16);
}

//二级菜单2
void menu22(void)
{
//    OLED_Clear();
    OLED_ShowString(36, 6, "menu2-2", 16);
}

//二级菜单3
void menu23(void)
{
//    OLED_Clear();
    OLED_ShowString(36, 6, "menu2-3", 16);

}

//三级菜单1
void menu31(void)
{
//    OLED_Clear();
    OLED_ShowString(36, 6, "menu3-1", 16);
}

//三级菜单2
void menu32(void)
{
//    OLED_Clear();
    OLED_ShowString(36, 6, "menu3-2", 16);
}

//三级菜单3
void menu33(void)
{
//    OLED_Clear();
    OLED_ShowString(36, 6, "menu3-3", 16);
}

//三级菜单4
void menu34(void)
{
//    OLED_Clear();
    OLED_ShowString(36, 6, "menu3-4", 16);

}
  • main主函数
int main(void)
{
    /* USER CODE BEGIN 1 */

    /* 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_I2C1_Init();
    MX_USART1_UART_Init();
    MX_I2C2_Init();
    MX_TIM6_Init();
    /* USER CODE BEGIN 2 */
    OLED_Init();
    HAL_TIM_Base_Start_IT(&htim6);
    ShowMenu(2, 0, "OneKey Mul-Menu");
    /* USER CODE END 2 */

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

        /* USER CODE BEGIN 3 */
        current = table[funIndex].operation;//根据需要获取对应需要执行的函数
        (*current)();//执行获取到的函数

    }
    /* USER CODE END 3 */
}

工程源码

链接:https://pan.baidu.com/s/1eR14Lpfjqm7nA0lvwbv5xg 
提取码:vs7f

你可能感兴趣的:(stm32,按键)