按键单按、双按、长按的中断与非中断处理

本文介绍了一款基于GD32E103R-START开发板的按键处理程序,包括非中断及中断处理两种方式。通过定时器和外部中断实现了对按键的长按、短按及双击识别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开发板是GD32E103R-START,2020-6 V1.0
以下是非中断处理,代码比较简陋

#include "gd32e10x.h

int main(void)
{
    volatile static uint8_t a = 0, b = 0, c = 0, d = 0;
    systick_config();
    rcu_periph_clock_enable(RCU_GPIOC);
    gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_6);
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_MAX, GPIO_PIN_0);

    while(1){
        if (gpio_input_bit_get(GPIOA, GPIO_PIN_0)){
            delay_1ms(20);
            if (gpio_input_bit_get(GPIOA, GPIO_PIN_0)){
                while (gpio_input_bit_get(GPIOA, GPIO_PIN_0) && c < 100){
                    c++;
                    delay_1ms(10);
                }
            }
        }
        
        if (c >= 100){
            a = 0;
            b = 0;
            c = 0;
            d = 0;
            gpio_bit_write(GPIOC, GPIO_PIN_6, 1);
        }
        else{
            c = 0;

            if (a == 1){
                gpio_bit_write(GPIOC, GPIO_PIN_6, 1);
                delay_1ms(500);
                gpio_bit_write(GPIOC, GPIO_PIN_6, 0);
                delay_1ms(500);
            }

            if ((a == 1) && (b == 0) && (!(gpio_input_bit_get(GPIOA, GPIO_PIN_0))) && (d == 0)){
                delay_1ms(20);
                if (!gpio_input_bit_get(GPIOA, GPIO_PIN_0)){
                    d = 1;
                }
            }

            if ((d == 1) && gpio_input_bit_get(GPIOA, GPIO_PIN_0)){
                delay_1ms(20);
                if (gpio_input_bit_get(GPIOA, GPIO_PIN_0)){
                    a = 0;
                    b = 0;
                    d = 2;
                }
            }

            if ((d == 2) && (a == 0) && (b == 0)){
                gpio_bit_write(GPIOC, GPIO_PIN_6, 1);
                delay_1ms(100);
                gpio_bit_write(GPIOC, GPIO_PIN_6, 0);
                delay_1ms(100);
            }

            if ((a == 0) && (b == 0) && gpio_input_bit_get(GPIOA, GPIO_PIN_0)){
                d = 0;
                delay_1ms(20);
                if (gpio_input_bit_get(GPIOA, GPIO_PIN_0)){
                    a = 1;
                }
            }
        }
    }
}

以下中断处理

#include "gd32e10x.h"
#include "key_led.h"

int main(void)
{
    systick_config();
    key_init();
    rcu_periph_clock_enable(RCU_GPIOC);
    gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_6);

    while(1){
        if (key_sta.double_flag[0]){
            gpio_bit_write(GPIOC, GPIO_PIN_6, 1);
            delay_1ms(100);
            gpio_bit_write(GPIOC, GPIO_PIN_6, 0);
            delay_1ms(100);
        }
        else if (key_sta.short_flag[0]){
            gpio_bit_write(GPIOC, GPIO_PIN_6, 1);
            delay_1ms(500);
            gpio_bit_write(GPIOC, GPIO_PIN_6, 0);
            delay_1ms(500);
        }
        else if (key_sta.long_flag[0]){
            gpio_bit_write(GPIOC, GPIO_PIN_6, 0);
        }
    }
}
// 按键状态定义
#define KEY_PRESSED             (1U)
#define KEY_UNPRESSED           (0U)
#define SHORT_TIME              (40U)
#define LONG_TIME               (100U)
#define DOUBLE_TIME             (2U)
#define INTERVAL_MAX            (40U)
#define INTERVAL_MIN            (1U)
#define SINGLE_CLICKED			(2U)
#define DOUBLE_CLICKED			(3U)
// 按键数量
#define KEY_PORT_NUM            (1U)
// 按键数据结构
#pragma pack(1)
struct ld_key{
    uint8_t key_status[KEY_PORT_NUM];
    uint8_t short_flag[KEY_PORT_NUM];
    uint8_t long_flag[KEY_PORT_NUM];
    uint8_t double_flag[KEY_PORT_NUM];
};
#pragma pack()
extern volatile struct ld_key key_sta;
#include "key_led.h"
#include "gd32e10x.h"

volatile struct ld_key key_sta = {0};

// 按键扫描间隔10ms
static void init_scan_timer(void)
{
    timer_parameter_struct timer_initpara;

    rcu_periph_clock_enable(RCU_TIMER3);
    nvic_irq_enable(TIMER3_IRQn, 1, 1);
    timer_deinit(TIMER3);
    timer_struct_para_init(&timer_initpara);
    timer_initpara.prescaler = 1199;
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection = TIMER_COUNTER_UP;
    timer_initpara.period = 999;
    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER3, &timer_initpara);
    timer_auto_reload_shadow_enable(TIMER3);
    timer_interrupt_flag_clear(TIMER3, TIMER_INT_FLAG_UP);
    timer_interrupt_enable(TIMER3, TIMER_INT_UP);
    timer_enable(TIMER3);
}

void key_init(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_AF);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_MAX, GPIO_PIN_0);
    nvic_irq_enable(EXTI0_IRQn, 1, 1);
    gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOA, GPIO_PIN_SOURCE_0);
    exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_RISING);    // 这里需要根据原理图确定是上升沿还是下降沿触发
    exti_interrupt_flag_clear(EXTI_0);
    init_scan_timer();
}

以下是gd32e10x_it.c

#include "gd32e10x_it.h"
#include "systick.h"
#include "key_led.h"
// 10ms一次扫描
void TIMER3_IRQHandler(void)
{
    static uint8_t key_holdon_ms[KEY_PORT_NUM] = {0};
    static uint8_t double_interval_ms = 0;
    static uint8_t which_press = 0;
    static uint8_t double_flag = 0;

    if (timer_interrupt_flag_get(TIMER3, TIMER_INT_FLAG_UP) != RESET){
        gpio_input_bit_get(GPIOA, GPIO_PIN_0) ? (key_holdon_ms[0]++) : (0);

        if ((key_holdon_ms[0] >= DOUBLE_TIME) && (key_holdon_ms[0] < SHORT_TIME)){
            double_flag = SET;
        }
        else if ((key_holdon_ms[0] >= SHORT_TIME) && (key_holdon_ms[0] < LONG_TIME)){
            which_press = SINGLE_CLICKED;
        }
        else if ((key_holdon_ms[0] >= LONG_TIME)){
            which_press = RESET;
            key_sta.long_flag[0] = SET;
            key_sta.short_flag[0] = RESET;
            key_sta.double_flag[0] = RESET;
        }
        else {}

        (double_flag && (!gpio_input_bit_get(GPIOA, GPIO_PIN_0))) ? (double_interval_ms++) : (0);

        if ((double_interval_ms > INTERVAL_MIN) && (double_interval_ms < INTERVAL_MAX) && (double_flag == SET)) {
            which_press = DOUBLE_CLICKED;
            double_flag = RESET;
            double_interval_ms = RESET;
        }

        if (double_interval_ms > INTERVAL_MAX) {
            which_press = RESET;
            double_flag = RESET;
            double_interval_ms = RESET;
        }

        if (!gpio_input_bit_get(GPIOA, GPIO_PIN_0) && key_sta.key_status[0] == KEY_PRESSED){
            switch (which_press){
            case SINGLE_CLICKED:
                key_sta.short_flag[0] = SET;
                key_sta.double_flag[0] = RESET;
                key_sta.long_flag[0] = RESET;
                break;
            case DOUBLE_CLICKED:
                key_sta.double_flag[0] = SET;
                key_sta.short_flag[0] = RESET;
                key_sta.long_flag[0] = RESET;
                break;
            default:
                break;
            }
            key_sta.key_status[0] = KEY_UNPRESSED;
            key_holdon_ms[0] = RESET;
            which_press = RESET;
        }
        timer_interrupt_flag_clear(TIMER3, TIMER_INT_FLAG_UP);
    }
}

void EXTI0_IRQHandler(void)
{
    if (RESET != exti_interrupt_flag_get(EXTI_0)){
        key_sta.key_status[0] = KEY_PRESSED;
        exti_interrupt_flag_clear(EXTI_0);
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值