扫码加入

  • 正文
  • 相关推荐
申请入驻 产业图谱

单片机长短按简单实现

01/17 09:55
382
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

1 原理

按键检测和处理的步骤如下:

1:定时扫描按键(使用定时器定时扫描,也可以用软件延时或者系统心跳之类的方式,总之能保证每次扫描间隔时间固定并且在一个较小的范围即可)。

2:扫描到有按键按下(通常是检测GPIO电平状态来判断按键是否按下,具体情况需要结合实际硬件电路来看)。

3:开始计时,记录按键持续按下的时间。

4:若按下的时间达到了短按的时间(具体多长的时间为短按由自己定义),选择触发按键处理(按下即触发),或者先记录状态,等按键释放时再触发按键处理(弹起时触发)。

5:按键时间超过短按时间,继续计时。

6:按键时间达到长按时间(具体多长的时间为长按由自己定义),选择触发按键处理(按下即触发),或者先记录状态,等按键释放时再触发按键处理(弹起时触发)。

2 示例代码

该示例使用的GD32,共配置了4个按键,特点如下:

1:按键按下时电平为0,释放时为1。

2:短按时间为30ms。

3:长按时间为1s。

4:短按释放时触发按键处理。

5:长按按下时即触发按键处理。

6:按键扫描和按键处理均放在定时器中断服务函数,若按键处理的时间较长,建议分开操作(按键扫描还是放在中断,按键处理放在其他地方,以免长时间占用中断时间)。

7:按键处理我这里都是留空的,只用串口打印了一句话,表明已经触发了按键处理,具体处理什么东西看实际需求。

注:示例代码仅供参考,还需要按具体需求修改。

2.1 按键实现

key.c:

#include "key.h"#include "main.h"key_t key1;key_t key2;key_t key3;key_t key4;void timer_user_init(void);// 按键初始化void key_user_init(void){    /* enable the key clock */    rcu_periph_clock_enable(KEY1_CLOCK);    rcu_periph_clock_enable(KEY2_CLOCK);    rcu_periph_clock_enable(KEY3_CLOCK);    rcu_periph_clock_enable(KEY4_CLOCK);    /* configure key gpio port */ 	gpio_init(KEY1_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, KEY1_PIN);    gpio_init(KEY2_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, KEY2_PIN);	gpio_init(KEY3_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, KEY3_PIN);	gpio_init(KEY4_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, KEY4_PIN);    timer_user_init();  // 启动定时器,定时扫描按键}// 按键扫描int key_scan(void){    if(READ_KEY1_STATE == KEY_PRESSED && (key1.status == 0))    {        if(++key1.debounce > KEY_SHORT_PRESSED)        {// 短按            key1.status = 1;            // LOG("key1 short pressed.n");        }    }    else if(READ_KEY1_STATE == KEY_PRESSED && (key1.status == 1))    {        if(++key1.debounce > KEY_LONG_PRESSED)        {// 长按            key1.status = 2;            key1.debounce = 0;            // LOG("key1 long pressed.n");            return KEY1_LONG_PRESSED;        }    }    else if((READ_KEY1_STATE == KEY_RELEASED) && (key1.status > 0))    {        if(key1.status == 1)        {// 短按释放            key1.status = 0;            key1.debounce = 0;            return KEY1_SHORT_PRESSED;        }        if(key1.status == 2)        {// 长按释放            key1.status = 0;            key1.debounce = 0;        }    }        if(READ_KEY2_STATE == KEY_PRESSED && (key2.status == 0))    {        if(++key2.debounce > KEY_SHORT_PRESSED)        {// 短按            key2.status = 1;        }    }    else if(READ_KEY2_STATE == KEY_PRESSED && (key2.status == 1))    {        if(++key2.debounce > KEY_LONG_PRESSED)        {// 长按            key2.status = 2;            key2.debounce = 0;            return KEY2_LONG_PRESSED;        }    }    else if((READ_KEY2_STATE == KEY_RELEASED) && (key2.status > 0))    {        if(key2.status == 1)        {// 短按释放            key2.status = 0;            key2.debounce = 0;            return KEY2_SHORT_PRESSED;        }        if(key2.status == 2)        {// 长按释放            key2.status = 0;            key2.debounce = 0;        }    }    if(READ_KEY3_STATE == KEY_PRESSED && (key3.status == 0))    {        if(++key3.debounce > KEY_SHORT_PRESSED)        {// 短按            key3.status = 1;        }    }    else if(READ_KEY3_STATE == KEY_PRESSED && (key3.status == 1))    {        if(++key3.debounce > KEY_LONG_PRESSED)        {// 长按            key3.status = 2;            key3.debounce = 0;            return KEY3_LONG_PRESSED;        }    }    else if((READ_KEY3_STATE == KEY_RELEASED) && (key3.status > 0))    {        if(key3.status == 1)        {// 短按释放            key3.status = 0;            key3.debounce = 0;            return KEY3_SHORT_PRESSED;        }        if(key3.status == 2)        {// 长按释放            key3.status = 0;            key3.debounce = 0;        }    }    if(READ_KEY4_STATE == KEY_PRESSED && (key4.status == 0))    {        if(++key4.debounce > KEY_SHORT_PRESSED)        {// 短按            key4.status = 1;        }    }    else if(READ_KEY4_STATE == KEY_PRESSED && (key4.status == 1))    {        if(++key4.debounce > KEY_LONG_PRESSED)        {// 长按            key4.status = 2;            key4.debounce = 0;            return KEY4_LONG_PRESSED;        }    }    else if((READ_KEY4_STATE == KEY_RELEASED) && (key4.status > 0))    {        if(key4.status == 1)        {// 短按释放            key4.status = 0;            key4.debounce = 0;            return KEY4_SHORT_PRESSED;        }        if(key4.status == 2)        {// 长按释放            key4.status = 0;            key4.debounce = 0;        }    }    return -1;}// 按键处理void key_handle(void){    static uint8_t key_state;    uint8_t i;    static uint8_t step = 0;    key_state = key_scan();  // 按键扫描    if(key_state == KEY1_SHORT_PRESSED)    {// 按键1短按        LOG("key1 short pressed.n");    }    else if(key_state == KEY1_LONG_PRESSED)    {// 按键1长按        LOG("key1 long pressed.n");    }    else if(key_state == KEY2_SHORT_PRESSED)    {// 按键2短按        LOG("key2 short pressed.n");    }    else if(key_state == KEY2_LONG_PRESSED)    {// 按键2长按        LOG("key2 long pressed.n");    }    else if(key_state == KEY3_SHORT_PRESSED)    {// 按键3短按        LOG("key3 short pressed.n");    }    else if(key_state == KEY3_LONG_PRESSED)    {// 按键3长按        LOG("key3 long pressed.n");    }    else if(key_state == KEY4_SHORT_PRESSED)    {// 按键4短按        LOG("key4 short pressed.n");    }    else if(key_state == KEY4_LONG_PRESSED)    {// 按键4长按        LOG("key4 long pressed.n");    }}/********************** 定时器配置,用于定时扫描按键 *************************/ void TIMER2_IRQHandler(void){    if(SET == timer_interrupt_flag_get(TIMER2, TIMER_INT_UP))    {        /* clear channel 0 interrupt bit */        timer_interrupt_flag_clear(TIMER2, TIMER_INT_UP);        key_handle();  // 按键扫描并处理    }}void nvic_config(void){    nvic_irq_enable(TIMER2_IRQn, 0, 0);}void timer_config(void){    /* ----------------------------------------------------------------------------    TIMER2 Configuration:     TIMER2CLK = SystemCoreClock/18000 = 10KHz, the period is 1s(10/10000 = 1s).    ---------------------------------------------------------------------------- */    timer_parameter_struct timer_initpara;    /* enable the peripherals clock */    rcu_periph_clock_enable(RCU_TIMER2);    /* deinit a TIMER */    timer_deinit(TIMER2);    /* initialize TIMER init parameter struct */    timer_struct_para_init(&timer_initpara);    /* TIMER2 configuration */    timer_initpara.prescaler         = 18000 - 1;           // 180MHz / 18000 = 10kHz    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;    timer_initpara.counterdirection  = TIMER_COUNTER_UP;    timer_initpara.period            = 10 - 1;             // 10 * 0.01ms = 1ms    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;    timer_init(TIMER2, &timer_initpara);    /* enable the TIMER interrupt */    timer_interrupt_enable(TIMER2, TIMER_INT_UP);    /* enable a TIMER */    timer_enable(TIMER2);}void timer_user_init(void){    /* configure the TIMER peripheral */    timer_config();    /* configure the TIMER2 interrupt */    nvic_config();}

key.h:

#ifndef __KEY_H#define __KEY_H#include "gd32e50x.h"#include "gd32e50x_gpio.h"#define KEY1_SHORT_PRESSED   0#define KEY2_SHORT_PRESSED   1#define KEY3_SHORT_PRESSED   2#define KEY4_SHORT_PRESSED   3#define KEY1_LONG_PRESSED    4#define KEY2_LONG_PRESSED    5#define KEY3_LONG_PRESSED    6#define KEY4_LONG_PRESSED    7#define KEY_PRESSED          0      // 按下时电平为0#define KEY_RELEASED         1      // 按下时电平为1#define KEY_SHORT_PRESSED    30     // 1ms x 30 = 30ms#define KEY_LONG_PRESSED     1000   // 1ms x 1000 = 1s#define KEY1_CLOCK       RCU_GPIOB#define KEY1_PORT        GPIOB#define KEY1_PIN         GPIO_PIN_12#define KEY2_CLOCK       RCU_GPIOB#define KEY2_PORT        GPIOB#define KEY2_PIN         GPIO_PIN_13#define KEY3_CLOCK       RCU_GPIOB#define KEY3_PORT        GPIOB#define KEY3_PIN         GPIO_PIN_14#define KEY4_CLOCK       RCU_GPIOB#define KEY4_PORT        GPIOB#define KEY4_PIN         GPIO_PIN_15#define READ_KEY1_STATE  gpio_input_bit_get(KEY1_PORT, KEY1_PIN)#define READ_KEY2_STATE  gpio_input_bit_get(KEY2_PORT, KEY2_PIN)#define READ_KEY3_STATE  gpio_input_bit_get(KEY3_PORT, KEY3_PIN)#define READ_KEY4_STATE  gpio_input_bit_get(KEY4_PORT, KEY4_PIN)typedef struct{    uint16_t debounce;    uint8_t status;} key_t;void key_user_init(void);int key_scan(void);#endif

main.c:

#include "main.h"#include "uart.h"#include "key.h"int main(void){    // systick_config();    uart_user_init();    key_user_init();    printf("app init success.n");    while(1)    {    }}

mian.h:

#ifndef MAIN_H#define MAIN_H#include "gd32e50x.h"#include "gd32e50x_rcu.h"#include "gd32e50x_gpio.h"#include "systick.h"#include "uart.h"#define UART_DEBUG#ifdef UART_DEBUG    #define DEBUG(format, ...) printf(format, ##__VA_ARGS__)    #define LOG  printf#else    #define DEBUG(format, ...)    #define LOG(format, ...) #endif#endif /* MAIN_H */

3 测试log

在这里插入图片描述

相关推荐