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

开发板是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);
    }
}
好的,以下是一个使用状态机方式运行的,能够识别5个独立按键并且能够识别按键同时按下、按、短按、按键击、按键按的程序。这个程序使用了STM32G030为硬件平台,使用了HAL库进行编程。 ```c #include "stm32g0xx_hal.h" #include <stdbool.h> // 定义按键名称 #define KEY_UP 0x01 #define KEY_DOWN 0x02 #define KEY_LEFT 0x04 #define KEY_RIGHT 0x08 #define KEY_CENTER 0x10 // 定义按键状态 typedef enum { KEY_RELEASED = 0, // 按键释放状态 KEY_PRESSED = 1 // 按键按下状态 } KeyState; // 定义按键信息结构体 typedef struct { GPIO_TypeDef* port; // GPIO端口 uint16_t pin; // GPIO引脚 bool inverted; // 是否反相 KeyState state; // 按键状态 uint32_t time; // 按键按下的时间 uint8_t name; // 按键名称 } KeyInfo; // 初始化按键 void KeyInit(KeyInfo* key, GPIO_TypeDef* port, uint16_t pin, bool inverted, uint8_t name) { key->port = port; key->pin = pin; key->inverted = inverted; key->state = KEY_RELEASED; key->time = 0; key->name = name; GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(port, &GPIO_InitStruct); } // 获取按键状态 KeyState GetKeyState(KeyInfo* key) { bool isPressed = HAL_GPIO_ReadPin(key->port, key->pin) ^ key->inverted; if (isPressed && (key->state == KEY_RELEASED)) { key->state = KEY_PRESSED; key->time = HAL_GetTick(); } else if (!isPressed && (key->state == KEY_PRESSED)) { key->state = KEY_RELEASED; } return key->state; } // 判断是否为按事件 bool IsLongPress(KeyInfo* key) { if (GetKeyState(key) == KEY_PRESSED) { uint32_t timeDiff = HAL_GetTick() - key->time; if (timeDiff >= 1000) { return true; } } return false; } // 判断是否为短按事件 bool IsShortPress(KeyInfo* key) { if (GetKeyState(key) == KEY_RELEASED) { uint32_t timeDiff = HAL_GetTick() - key->time; if (timeDiff < 1000) { return true; } } return false; } // 判断是否为击事件 bool IsDoubleClick(KeyInfo* key) { if (GetKeyState(key) == KEY_RELEASED) { uint32_t timeDiff = HAL_GetTick() - key->time; if ((timeDiff > 100) && (timeDiff < 300)) { return true; } } return false; } // 判断是否为键同时按下事件 bool IsKeyCombination(KeyInfo* key1, KeyInfo* key2) { if ((GetKeyState(key1) == KEY_PRESSED) && (GetKeyState(key2) == KEY_PRESSED)) { return true; } return false; } int main(void) { // 初始化GPIO HAL_Init(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); // 初始化按键 KeyInfo key_up, key_down, key_left, key_right, key_center; KeyInit(&key_up, GPIOA, GPIO_PIN_0, false, KEY_UP); KeyInit(&key_down, GPIOA, GPIO_PIN_1, false, KEY_DOWN); KeyInit(&key_left, GPIOA, GPIO_PIN_2, false, KEY_LEFT); KeyInit(&key_right, GPIOA, GPIO_PIN_3, false, KEY_RIGHT); KeyInit(&key_center, GPIOB, GPIO_PIN_4, false, KEY_CENTER); // 进入状态机 KeyState state = KEY_RELEASED; uint8_t curKey = 0, prevKey = 0; uint32_t curTime = 0, prevTime = 0; while (1) { switch (state) { case KEY_RELEASED: if (IsKeyCombination(&key_up, &key_down)) { state = KEY_UP_DOWN; } else if (IsKeyCombination(&key_left, &key_right)) { state = KEY_LEFT_RIGHT; } else if (IsLongPress(&key_center)) { state = KEY_CENTER_LONG; } else if (IsShortPress(&key_center)) { state = KEY_CENTER_SHORT; } else if (IsDoubleClick(&key_center)) { state = KEY_CENTER_DOUBLE; } else if (GetKeyState(&key_up) == KEY_PRESSED) { state = KEY_UP; } else if (GetKeyState(&key_down) == KEY_PRESSED) { state = KEY_DOWN; } else if (GetKeyState(&key_left) == KEY_PRESSED) { state = KEY_LEFT; } else if (GetKeyState(&key_right) == KEY_PRESSED) { state = KEY_RIGHT; } break; case KEY_UP: curKey = KEY_UP; curTime = HAL_GetTick(); if (IsShortPress(&key_up)) { printf("Key Up Short Pressed\n"); state = KEY_RELEASED; } else if (IsLongPress(&key_up)) { printf("Key Up Long Pressed\n"); state = KEY_RELEASED; } else if (IsDoubleClick(&key_up)) { printf("Key Up Double Clicked\n"); state = KEY_RELEASED; } break; case KEY_DOWN: curKey = KEY_DOWN; curTime = HAL_GetTick(); if (IsShortPress(&key_down)) { printf("Key Down Short Pressed\n"); state = KEY_RELEASED; } else if (IsLongPress(&key_down)) { printf("Key Down Long Pressed\n"); state = KEY_RELEASED; } else if (IsDoubleClick(&key_down)) { printf("Key Down Double Clicked\n"); state = KEY_RELEASED; } break; case KEY_LEFT: curKey = KEY_LEFT; curTime = HAL_GetTick(); if (IsShortPress(&key_left)) { printf("Key Left Short Pressed\n"); state = KEY_RELEASED; } else if (IsLongPress(&key_left)) { printf("Key Left Long Pressed\n"); state = KEY_RELEASED; } else if (IsDoubleClick(&key_left)) { printf("Key Left Double Clicked\n"); state = KEY_RELEASED; } break; case KEY_RIGHT: curKey = KEY_RIGHT; curTime = HAL_GetTick(); if (IsShortPress(&key_right)) { printf("Key Right Short Pressed\n"); state = KEY_RELEASED; } else if (IsLongPress(&key_right)) { printf("Key Right Long Pressed\n"); state = KEY_RELEASED; } else if (IsDoubleClick(&key_right)) { printf("Key Right Double Clicked\n"); state = KEY_RELEASED; } break; case KEY_CENTER_SHORT: printf("Key Center Short Pressed\n"); state = KEY_RELEASED; break; case KEY_CENTER_LONG: printf("Key Center Long Pressed\n"); state = KEY_RELEASED; break; case KEY_CENTER_DOUBLE: printf("Key Center Double Clicked\n"); state = KEY_RELEASED; break; case KEY_UP_DOWN: printf("Key Up and Down Pressed\n"); state = KEY_RELEASED; break; case KEY_LEFT_RIGHT: printf("Key Left and Right Pressed\n"); state = KEY_RELEASED; break; } // 判断按键击 if ((curKey != 0) && (curKey == prevKey)) { uint32_t timeDiff = curTime - prevTime; if ((timeDiff > 100) && (timeDiff < 300)) { printf("Key %d Double Clicked\n", curKey); curKey = 0; } } // 记录上一个按下的按键和时间 if (curKey != 0) { prevKey = curKey; prevTime = curTime; } } } ``` 在这个程序中,我们首先定义了按键名称以及按键状态枚举类型。然后我们定义了包含按键信息的结构体`KeyInfo`,包含GPIO端口、引脚、状态、按下时间以及按键名称等信息。接着我们定义了一些函数,包括初始化按键、获取按键状态、判断是否为按事件、短按事件、击事件以及键同时按下事件等。最后我们通过状态机的方式来处理按键事件,包括按键短按、按、击事件以及键同时按下事件等。同时我们还记录了上一个按下的按键以及时间,以便判断按键击事件。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值