首页 物联网

GD32 RISC-V 按键驱动开发实战:中断、消抖与状态机

分类:物联网
字数: (3657)
阅读: (7858)
内容摘要:GD32 RISC-V 按键驱动开发实战:中断、消抖与状态机,

在嵌入式系统开发中,按键是最常见的人机交互方式之一。本文将基于《嵌入式 – GD32开发实战指南(RISC-V版本)》第6章,深入探讨 GD32 RISC-V 平台上的按键驱动开发,重点分析中断处理、按键消抖以及状态机应用等关键技术点。我们将结合实际案例,分享在 GD32 上进行按键功能开发的实战经验,并提供一些避坑指南。

按键中断:实时响应的关键

中断配置

使用外部中断 (EXTI) 可以实现按键的实时响应。首先,需要配置 GPIO 引脚为中断输入模式,并使能对应的 EXTI 中断线。

GD32 RISC-V 按键驱动开发实战:中断、消抖与状态机
void KEY_EXTI_Configuration(void)
{
    /* Enable GPIOC clock */
    rcu_periph_clock_enable(RCU_GPIOC);
    /* Enable AFIO clock */
    rcu_periph_clock_enable(RCU_AFIO);

    /* Configure PC13 as external interrupt line */
    gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_13);

    /* Connect EXTI line to PC13 pin */
    gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOC, GPIO_PINSOURCE_13);

    /* Enable EXTI line interrupt */
    exti_init(EXTI_13, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
    exti_interrupt_enable(EXTI_13);

    /* Enable the EXTI13 interrupt */
    nvic_irq_enable(EXTI10_15_IRQn, 0, 0);
}

这里,我们将 GPIOC 的 13 号引脚配置为下拉输入,并将其与 EXTI13 中断线关联。当按键按下时,电平由高变低,触发中断。

GD32 RISC-V 按键驱动开发实战:中断、消抖与状态机

中断服务例程 (ISR)

接下来,编写中断服务例程来处理按键事件。注意:ISR 应该尽可能短小精悍,避免执行耗时操作。

GD32 RISC-V 按键驱动开发实战:中断、消抖与状态机
void EXTI10_15_IRQHandler(void)
{
    if(RESET != exti_interrupt_flag_get(EXTI_13)){
        /* Delay 10ms for de-bounce */
        delay_1ms(10);

        if(RESET == gpio_input_bit_get(GPIOC, GPIO_PIN_13)){
            /* Key pressed event */
            // 处理按键事件,例如设置标志位
            key_pressed_flag = 1;
        }

        /* Clear EXTI line flag */
        exti_interrupt_flag_clear(EXTI_13);
    }
}

可以看到,我们在 ISR 中进行了简单的消抖处理(delay_1ms)。更复杂的消抖逻辑可以在主循环中处理。

GD32 RISC-V 按键驱动开发实战:中断、消抖与状态机

按键消抖:确保稳定输入

按键消抖是按键驱动开发中的关键步骤。机械按键在按下和释放时,会产生短暂的抖动,导致 MCU 误判。常见的消抖方法有:

  • 硬件消抖:使用 RC 滤波器等硬件电路滤除抖动。
  • 软件消抖:通过延时和多次采样来判断按键状态。

上面 ISR 中使用的延时是一种简单的软件消抖方法。更健壮的方法是使用定时器中断进行周期性采样,并根据连续多次采样的结果来判断按键状态。 这有点像 Nginx 的健康检查机制,需要多次请求都失败才判定服务不可用,避免网络抖动造成的误判。

基于状态机的消抖实现

enum KeyState {
    KEY_RELEASED,
    KEY_PRESSING,
    KEY_PRESSED,
    KEY_RELEASING
};

enum KeyState key_state = KEY_RELEASED;
uint32_t key_press_time = 0;
#define DEBOUNCE_TIME 20 // ms

void Key_Process(void) {
    switch (key_state) {
        case KEY_RELEASED:
            if (gpio_input_bit_get(GPIOC, GPIO_PIN_13) == RESET) { // Key pressed
                key_state = KEY_PRESSING;
                key_press_time = HAL_GetTick();
            }
            break;
        case KEY_PRESSING:
            if (gpio_input_bit_get(GPIOC, GPIO_PIN_13) == SET) { // Key released during debounce
                key_state = KEY_RELEASED;
            } else if (HAL_GetTick() - key_press_time >= DEBOUNCE_TIME) {
                key_state = KEY_PRESSED;
                // Key pressed event
                HandleKeyPress();
            }
            break;
        case KEY_PRESSED:
            if (gpio_input_bit_get(GPIOC, GPIO_PIN_13) == SET) {
                key_state = KEY_RELEASING;
                key_press_time = HAL_GetTick();
            }
            break;
        case KEY_RELEASING:
            if (gpio_input_bit_get(GPIOC, GPIO_PIN_13) == RESET) {
                key_state = KEY_PRESSED;
            } else if (HAL_GetTick() - key_press_time >= DEBOUNCE_TIME) {
                key_state = KEY_RELEASED;
                // Key released event
                HandleKeyRelease();
            }
            break;
        default:
            key_state = KEY_RELEASED; // Reset to initial state
            break;
    }
}

Key_Process 函数应该周期性地被调用 (例如在 SysTick 中断中)。 状态机通过 KEY_RELEASED, KEY_PRESSING, KEY_PRESSED, 和 KEY_RELEASING 四个状态转换来判断按键的稳定状态。

实战避坑经验

  • GPIO 配置:务必正确配置 GPIO 引脚的模式 (输入/输出、上拉/下拉),否则可能导致按键无法正常工作。
  • 中断优先级:合理分配中断优先级,避免按键中断被其他中断抢占,影响响应速度。 如果系统使用了 FreeRTOS,还要注意任务的优先级设置,避免任务饥饿。
  • 消抖时间:根据实际情况调整消抖时间,过短可能无法有效消抖,过长则会降低响应速度。
  • 长按检测:可以通过记录按键按下的时间来判断是否为长按事件。
  • 功耗优化:如果系统对功耗有要求,可以考虑使用低功耗模式,并在按键按下时唤醒系统。

通过以上实践和经验总结,相信读者能够更好地掌握 GD32 RISC-V 平台上的按键驱动开发,并能够在实际项目中灵活应用。

GD32 RISC-V 按键驱动开发实战:中断、消抖与状态机

转载请注明出处: 键盘上的咸鱼

本文的链接地址: http://m.acea2.store/blog/843841.SHTML

本文最后 发布于2026-04-13 17:10:58,已经过了14天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 豆腐脑 3 天前
    这个代码风格很不错,注释也很清晰,适合新手学习。
  • 番茄炒蛋 2 天前
    讲得很透彻,中断、消抖、状态机都覆盖到了,点赞!
  • 彩虹屁大师 1 天前
    GPIO配置那块确实容易出错,之前就因为上拉/下拉没搞对,折腾了好久。
  • 鸽子王 6 天前
    有没有关于长按检测的更详细的例子?