【GD32F303红枫派开发板使用手册】第三讲 GPIO-按键查询检测实验
2024-12-03 来源:elecfans
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.
之后按下任意按键,松开后将会打印按键按下的时间范围。
具体现象如下所示。

- GD32F303学习笔记(1)——搭建环境、编译烧写
- 【GD32F303红枫派开发板使用手册】第二十四讲 DHT11温湿度传感器检测实验
- 【GD32F303红枫派开发板使用手册】第十一讲 ADC-电源电压单通道ADC检测实验
- 【GD32F303红枫派开发板使用手册】第二十一讲 I2C-EEPROM读写实验
- 【GD32F303红枫派开发板使用手册】第二十讲八 USB-虚拟串口实验
- 【GD32F303红枫派开发板使用手册】第十七讲 USART-中断串口收发实验
- 【GD32F303红枫派开发板使用手册】第十五讲 USART-printf打印实验
- 【GD32F303红枫派开发板使用手册】第十二讲 ADC-双轴按键摇杆多通道循环采样实验
- 【GD32F303红枫派开发板使用手册】第四讲 GEXTI-按键中断检测实验
- 【GD32F303红枫派开发板使用手册】第十四讲 DAC-输出电压实验
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- 蓝牙信道探测技术原理与开发套件实践
- Microchip 推出生产就绪型全栈边缘 AI 解决方案,赋能MCU和MPU实现 智能实时决策
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析




