3.1实验内容
通过本实验主要学习以下内容:
GPIO输入功能原理;
按键查询输入检测原理;
3.2实验原理
3.2.1GPIO输入功能原理
GD32F303系列MCU GPIO输入配置结构如下图所示,输入可配置上下拉电阻,通过施密特触发器后可通过备用功能输入或者通过输入状态寄存器进行读取。

输入状态寄存器为GPIOx_ISTAT,其状态位定义如下图所示,每个控制位对应相应引脚的输入电平状态。

GPIO引脚输入电平判断阈值如下图所示,当输入电平小于0.3VDD时,可被内部有效识别为低电平;当输入电平大于0.7VDD时,可被内部有效识别为高电平。

3.3硬件设计
GD32F303红枫派开发板具有四个按键,对应电路图如下图所示,该四个按键均具有上拉限流电阻,对引脚防护电阻以及对地消抖电容。在按键未按下时,对应GPIO引脚的电平为高电平,按下引脚后,对应GPIO引脚的电平为低电平,通过读取按键对应GPIO引脚的电平状态可检测对应按键是否被按下。


注意:机械按键在按下或者松开时具有抖动,建议可增加硬件消抖或者软件消抖,以避免按键检测被多次触发。 |
3.4代码解析
本例程实现通过查询的方式可查询按键按下的时间,进而可实现短时间按下和长时间按下的检测。
主函数代码如下,首先进行延迟初始化/按键初始化/LED初始化/串口初始化,并打印Example of key scan detection.之后进入主循环,通过key_scan函数实现对按键的扫描并检测按键按下时间。
| C int main(void) { //系统延时初始化 driver_init(); //按键组初始化 bsp_key_group_init(); //LED组初始化 bsp_led_group_init(); //板载UART初始化 bsp_uart_init(&BOARD_UART); delay_ms(1000); printf('Example of key scan detection.rn'); while (1) { delay_ms(1); //按键扫描结果检查:检测任意按键和多按键组合按下时间,所有按键弹起后有效 if(SET==key_scan(1)) { //检测按键组合按下时长 if(KEY1.press_timerms >= PRESS_3000MS && KEY2.press_timerms >= PRESS_3000MS && WKUP.press_timerms >= PRESS_3000MS) { printf('KEY0/KEY1/KEY2 pressed together for more than 3000ms.rn'); KEY1.press_timerms=PRESS_NONE;; KEY2.press_timerms=PRESS_NONE; WKUP.press_timerms=PRESS_NONE; } else if(KEY1.press_timerms >= PRESS_50MS && KEY2.press_timerms >= PRESS_50MS && WKUP.press_timerms >= PRESS_50MS) { printf('KEY0/KEY1/KEY2 pressed together for more than 50ms.rn'); KEY1.press_timerms=PRESS_NONE;; KEY2.press_timerms=PRESS_NONE; WKUP.press_timerms=PRESS_NONE; } //检测任意按键按下时长 if(KEY0.press_timerms >= PRESS_200MS && KEY0.press_timerms < PRESS_5000MS) { KEY0.press_timerms=PRESS_NONE; printf('KEY0 press more than 200ms, less than 5000ms .rn'); } else if(KEY0.press_timerms >= PRESS_5000MS) { KEY0.press_timerms=PRESS_NONE; printf('KEY0 press more than 5000ms.rn'); } else if(KEY0.press_timerms >= PRESS_DOWN) { KEY0.press_timerms=PRESS_NONE; printf('KEY0 press briefly.rn'); } if(KEY1.press_timerms >= PRESS_200MS && KEY1.press_timerms < PRESS_5000MS) { KEY1.press_timerms=PRESS_NONE; printf('KEY1 press more than 200ms, less than 5000ms .rn'); } else if(KEY1.press_timerms >= PRESS_5000MS) { KEY1.press_timerms=PRESS_NONE; printf('KEY1 press more than 5000ms.rn'); } else if(KEY1.press_timerms >= PRESS_DOWN) { KEY1.press_timerms=PRESS_NONE; printf('KEY1 press briefly.rn'); } if(KEY2.press_timerms >= PRESS_200MS && KEY2.press_timerms < PRESS_5000MS) { KEY2.press_timerms=PRESS_NONE; printf('KEY2 press more than 200ms, less than 5000ms .rn'); } else if(KEY2.press_timerms >= PRESS_5000MS) { KEY2.press_timerms=PRESS_NONE; printf('KEY2 press more than 5000ms.rn'); } else if(KEY2.press_timerms >= PRESS_DOWN) { KEY2.press_timerms=PRESS_NONE; printf('KEY2 press briefly.rn'); } if(WKUP.press_timerms >= PRESS_200MS && WKUP.press_timerms < PRESS_5000MS) { WKUP.press_timerms=PRESS_NONE; printf('WKUP press more than 200ms, less than 5000ms .rn'); } else if(WKUP.press_timerms >= PRESS_5000MS) { WKUP.press_timerms=PRESS_NONE; printf('WKUP press more than 5000ms.rn'); } else if(WKUP.press_timerms >= PRESS_DOWN) { WKUP.press_timerms=PRESS_NONE; printf('WKUP press briefly.rn'); } } //按键扫描结果检查:检测任意按键有按下 if(KEY0.press_timerms == PRESS_DOWN) { KEY0.press_timerms=PRESS_NONE; bsp_led_toggle(&LED0); } else if(KEY1.press_timerms == PRESS_DOWN) { KEY1.press_timerms=PRESS_NONE; bsp_led_toggle(&LED0); } else if(KEY2.press_timerms == PRESS_DOWN) { KEY2.press_timerms=PRESS_NONE; bsp_led_toggle(&LED0); } else if(WKUP.press_timerms == PRESS_DOWN) { WKUP.press_timerms=PRESS_NONE; bsp_led_toggle(&LED0); } else { bsp_led_off(&LED0); } //直接读取按键有按下 if(bsp_key_state_get(&KEY0)==SET) { bsp_led_toggle(&LED1); } else if(bsp_key_state_get(&KEY1)==SET) { bsp_led_toggle(&LED1); } else if(bsp_key_state_get(&KEY2)==SET) { bsp_led_toggle(&LED1); } else if(bsp_key_state_get(&WKUP)==SET) { bsp_led_toggle(&LED1); } else { bsp_led_off(&LED1); } } } |
按键初始化函数如下,通过KEY_DEF定义相关按键参数,之后调用bsp_key_init对按键进行分别初始化。
| C void bsp_key_group_init(void) { uint8_t i; for(i=0;i { bsp_key_init(((typdef_bsp_key *)KEY_INIT_GROUP[i])); } } KEY_DEF(KEY0,E,2,IN_PU,SET,NULL); // PE2定义为KEY0中断模式,默认状态高 KEY_DEF(KEY1,E,3,IN_PU,SET,NULL); // PE3定义为KEY1非中断模式,默认状态高 KEY_DEF(KEY2,E,4,IN_PU,SET,NULL); // PE4定义为KEY2非中断模式,默认状态高 KEY_DEF(WKUP,A,0,IN_PU,SET,NULL); // PA0定义为KEY2非中断模式,默认状态高 |
通过key_scan进行按键扫描,实现对按键按下时间长度范围的检测。
| C bit_status key_scan(uint16_t scan_ms_cycle) { uint8_t i; bit_status press_flag=RESET; for(i=0;i { // ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=press_none; if(bsp_key_state_get((typdef_bsp_key *)KEY_INIT_GROUP[i])==SET && ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count<0xffff){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms =PRESS_DOWN; ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count+=scan_ms_cycle; } } for(i=0;i { if(bsp_key_state_get((typdef_bsp_key *)KEY_INIT_GROUP[i])==SET && ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count < 0xffff) //持续60s被按下按键可能损坏 { return press_flag; } } for(i=0;i { if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_50MS) { press_flag=SET; if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count > PRESS_5000MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_5000MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_4000MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_4000MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_3000MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_3000MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_2000MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_2000MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_1000MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_1000MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_500MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_500MS; } else if(((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count>PRESS_200MS){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_200MS; } else{ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_timerms=PRESS_50MS; } } if(bsp_key_state_get((typdef_bsp_key *)KEY_INIT_GROUP[i])==RESET){ ((typdef_bsp_key *)KEY_INIT_GROUP[i])->press_cycle_count=0; } } return press_flag; } |
3.5实验结果
将本例程烧录到红枫派开发板中,连接USB串口通过Type C接口,上电后打开串口调试助手,先按下复位按键,让系统复位运行。
首先在串口调试助手上打印:Example of key scan detection.
之后按下任意按键,松开后将会打印按键按下的时间范围。
具体现象如下所示。

上一篇:采用GD32F470高性能MCU的PowerWriter X1多功能调试烧录器
下一篇:关于GD32F207ZE的燃料电池监测系统的介绍和应用分析
推荐阅读最新更新时间:2026-03-25 12:13
- 用于 7VIN 至 16VIN、1.5V 和 1.2V 输出的 LTM4628EV DC/DC 模块稳压器的典型应用电路
- 使用 Analog Devices 的 LTC3728LIGN 的参考设计
- DER-406 - 适用于 A19 灯的 5.76 W 高 PF 非隔离降压-升压型 TRIAC 调光 LED 驱动器
- ADR5045B 5V 输出精密微功率并联模式电压基准的典型应用
- LT3970EDDB-3.42 2.5V 降压转换器的典型应用
- MC78M08BDTG 8V 电流调节器的典型应用
- LT1021DCN8-5 精密电压基准的典型应用
- DER-282 - 100W, 扁平(11 mm), LLC DC-DC转换器
- REF193 低压差开尔文连接电压基准的典型应用电路
- LT3088EM 线性稳压器用于添加软启动的典型应用

【Follow me第三季第4期】英飞凌CY8CPROTO-063-BLE开发板全任务实战源码
ESP32S3串口转websocket源码
非常经典的关于LLC的杨波博士论文
CLC5612IMX
XC6406PP60DL






京公网安备 11010802033920号