按键由于机械特性原因会产生抖动干扰程序的判断,所有要进行消抖,方法有多种,如:消抖电路,软件阻塞式延时消抖,定时器消抖等。

阻塞消抖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define KEY = P1^1;
#define LED = P1^2;

while(1)
{
if(KEY == 0)
{
delay_ms(10);
if(KEY == 0)
{
LED = !LED;
while(!KEY);
}
}
}

GD32 滴答定时器按键消抖例子

首先说下 IO 口的配置,配置IO口为外部中断下降沿触发模式。

消抖过程

GD32 有一下几种外部中断触发模式:

1
2
3
4
5
6
7
8
/* interrupt trigger mode */
typedef enum
{
EXTI_TRIG_RISING = 0, /*!< EXTI rising edge trigger 上升沿触发 */
EXTI_TRIG_FALLING, /*!< EXTI falling edge trigger 下降沿触发 */
EXTI_TRIG_BOTH, /*!< EXTI rising and falling edge trigger 上升下降沿触发 */
EXTI_TRIG_NONE /*!< without rising edge or falling edge trigger 无上升沿下降沿触发 */
}exti_trig_type_enum;

GPIO 模式设置:

1
gpio_mode_set(ENCODER_SW_GPIO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, ENCODER_SW_PIN); // 配置为输入模式,无上拉电阻

使能 Nvic :

1
nvic_irq_enable(ENCODER_SW_EXTI_IRQn, 1U, 1U);

外部中断线配置:

1
syscfg_exti_line_config(ENCODER_SW_EXTI_PORT_SOURCE, ENCODER_SW_EXTI_PIN_SOURCE);

外部中断初始化

1
exti_init(ENCODER_SW_EXTI_LINE, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
EC11 旋转编码器处理函数,在主循环中调用。
*/
void encoder_handle(void)
{
FlagStatus SW_State = gpio_input_bit_get(ENCODER_SW_GPIO_PORT, ENCODER_SW_PIN);
if(ec11_1.sw_down_flag == 1 && ec11_1.sw_down_time > 10)
{
if(SW_State == RESET)
{
test_number++;
ec11_1.sw_down_flag = 0;
ec11_1.sw_down_time = 0;
}
}
}

中断回调函数

1
2
3
4
5
6
7
8
9
10
11
/*******************************************************************************
* @brief 2-3 外部中断
* @brief SW
************************************************************************** ****/
void EXTI2_3_IRQHandler(void)
{
if(SET == exti_interrupt_flag_get(ENCODER_SW_EXTI_LINE)){
ec11_1.sw_down_flag = 1;
exti_interrupt_flag_clear(ENCODER_SW_EXTI_LINE);
}
}

滴答定时器回调

1
2
3
4
5
6
7
8
9
void SysTick_Handler(void)
{
led_spark();
delay_decrement();

if(ec11_1.sw_down_flag == 1){
ec11_1.sw_down_time++;
}
}

滴答定时器回调实例2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void SysTick_Handler(void)
{
led_spark();
delay_decrement();

if(ec11_1.sw_down_flag == 1){
ec11_1.sw_down_time++;
}

// 当 SW 为长按时,让 led_auto_setp++
if(ec11_1.sw_mode_flag == 2)
{
ec11_1.sw_long_press_time++;
}

}

单击&双击&长按的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*******************************************************************************
* @brief 旋转编码器处理函数
******************************************************************************/
void encoder_handle(void)
{
FlagStatus SW_State = gpio_input_bit_get(ENCODER_SW_GPIO_PORT, ENCODER_SW_PIN);
if(ec11_1.sw_down_flag == 1 && ec11_1.sw_down_time > 10 && ec11_1.sw_down_count == 0)
{
if(SW_State == RESET)
{
ec11_1.sw_down_count = 1;
}
}

/* 按键长按 */
if(ec11_1.sw_down_count == 1 && ec11_1.sw_down_time > 500 && SW_State == RESET)
{
ec11_1.sw_mode_flag = 2; // 长按
}
if(ec11_1.sw_down_count == 1 && ec11_1.sw_down_time > 500 && SW_State == SET)
{
ec11_1.sw_down_count = 0; // 长按需要把 sw_down_count 清零
ec11_1.sw_down_time = 0; // 长按需要 sw_down_time 清零
ec11_1.sw_down_flag = 0; // 清除 sw_down_flag 标志
ec11_1.sw_mode_flag = 0; // 模式清除
}

/* 单击双击判断 */
if(ec11_1.sw_down_count == 1 && SW_State == SET && ec11_1.sw_down_time < 500)
{
ec11_1.sw_down_count = 2; // sw_down_time < 500 需要判断双击还是单击
ec11_1.sw_down_time = 0;
}

if(ec11_1.sw_down_flag == 1 && ec11_1.sw_down_count == 2 && ec11_1.sw_down_time > 100)
{
if(SW_State == RESET)
{
ec11_1.sw_mode_flag = 3; // 双击
ec11_1.sw_down_time = 0;
ec11_1.sw_down_flag = 0;
ec11_1.sw_down_count = 0;
} else {
ec11_1.sw_mode_flag = 1; // 单击
ec11_1.sw_down_time = 0;
ec11_1.sw_down_flag = 0;
ec11_1.sw_down_count = 0;
}
}

// 长按
if(ec11_1.sw_mode_flag == 2)
{
// 指定多少毫秒加1
if(ec11_1.sw_long_press_time == LED_AUTO_SETP)
{
test_number++;
ec11_1.sw_long_press_time = 0;
}

FlagStatus sw_state_temp = gpio_input_bit_get(ENCODER_SW_GPIO_PORT, ENCODER_SW_PIN);
if(sw_state_temp == SET)
{
ec11_1.sw_mode_flag = 0;
}

}
// 单击
if(ec11_1.sw_mode_flag == 1)
{
test_number++;
ec11_1.sw_mode_flag = 0;
}

// 双击
if(ec11_1.sw_mode_flag == 3)
{
test_number += 10;
ec11_1.sw_mode_flag = 0;
}
}

/*******************************************************************************
* @brief EC11 结构体初始化
* @brief sw_mode_flag:
******************************************************************************/
inline void ec11_init(EC11_t ec11)
{
ec11.sw_down_time = 0;
ec11.sw_mode_flag = 0;
ec11.sw_down_flag = 0;
ec11.sw_down_count = 0;
ec11.sw_long_press_time = 0;
}