打印
[研电赛技术支持]

【GD32F303红枫派使用手册】第三讲 GPIO-按键查询检测实验

[复制链接]
840|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 聚沃科技 于 2024-6-4 11:00 编辑


3.1 实验内容
通过本实验主要学习以下内容:
• GPIO输入功能原理;
按键查询输入检测原理;
3.2 实验原理
3.2.1 GPIO输入功能原理
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.\r\n");
   
   
        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.\r\n");
                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.\r\n");
                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 .\r\n");
            }            
            else if(KEY0.press_timerms >= PRESS_5000MS)
            {
                KEY0.press_timerms=PRESS_NONE;               
                printf("KEY0 press more than 5000ms.\r\n");
            }            
            else if(KEY0.press_timerms >= PRESS_DOWN)
            {
                KEY0.press_timerms=PRESS_NONE;               
                printf("KEY0 press briefly.\r\n");
            }  

            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 .\r\n");
            }            
            else if(KEY1.press_timerms >= PRESS_5000MS)
            {
                KEY1.press_timerms=PRESS_NONE;                 
                printf("KEY1 press more than 5000ms.\r\n");
            }            
            else if(KEY1.press_timerms >= PRESS_DOWN)
            {
                KEY1.press_timerms=PRESS_NONE;                 
                printf("KEY1 press briefly.\r\n");
            }

            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 .\r\n");
            }            
            else if(KEY2.press_timerms >= PRESS_5000MS)
            {
                KEY2.press_timerms=PRESS_NONE;               
                printf("KEY2 press more than 5000ms.\r\n");
            }            
            else if(KEY2.press_timerms >= PRESS_DOWN)
            {
                KEY2.press_timerms=PRESS_NONE;               
                printf("KEY2 press briefly.\r\n");
            }

            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 .\r\n");
            }            
            else if(WKUP.press_timerms >= PRESS_5000MS)
            {
                WKUP.press_timerms=PRESS_NONE;                                
                printf("WKUP press more than 5000ms.\r\n");
            }            
            else if(WKUP.press_timerms >= PRESS_DOWN)
            {
                WKUP.press_timerms=PRESS_NONE;                                
                printf("WKUP press briefly.\r\n");
            }                                                           
        }

        //按键扫描结果检查:检测任意按键有按下
        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<KEY_INIT_SIZE;i++)
    {
        bsp_key_init(((typdef_bsp_key *)KEY_INIT_GROUP));   
    }
}
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<KEY_INIT_SIZE;i++)
    {
//        ((typdef_bsp_key *)KEY_INIT_GROUP)->press_timerms=press_none;        
        if(bsp_key_state_get((typdef_bsp_key *)KEY_INIT_GROUP)==SET && ((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count<0xffff){
               
            ((typdef_bsp_key *)KEY_INIT_GROUP)->press_timerms =PRESS_DOWN;
            ((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count+=scan_ms_cycle;
        }               
    }   
   
    for(i=0;i<KEY_INIT_SIZE;i++)
    {
      
        if(bsp_key_state_get((typdef_bsp_key *)KEY_INIT_GROUP)==SET  && ((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count < 0xffff) //持续60s被按下按键可能损坏        
        {
            return press_flag;
        }
    }

    for(i=0;i<KEY_INIT_SIZE;i++)
    {   
        if(((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count>PRESS_50MS)
        {
            press_flag=SET;
            if(((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count > PRESS_5000MS){
                ((typdef_bsp_key *)KEY_INIT_GROUP)->press_timerms=PRESS_5000MS;
            }         
            else if(((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count>PRESS_4000MS){
                ((typdef_bsp_key *)KEY_INIT_GROUP)->press_timerms=PRESS_4000MS;
            }        
            else if(((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count>PRESS_3000MS){
                ((typdef_bsp_key *)KEY_INIT_GROUP)->press_timerms=PRESS_3000MS;
            }
            else if(((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count>PRESS_2000MS){
                ((typdef_bsp_key *)KEY_INIT_GROUP)->press_timerms=PRESS_2000MS;
            }
            else if(((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count>PRESS_1000MS){
                ((typdef_bsp_key *)KEY_INIT_GROUP)->press_timerms=PRESS_1000MS;
            }
            else if(((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count>PRESS_500MS){
                ((typdef_bsp_key *)KEY_INIT_GROUP)->press_timerms=PRESS_500MS;
            }
            else if(((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count>PRESS_200MS){
                ((typdef_bsp_key *)KEY_INIT_GROUP)->press_timerms=PRESS_200MS;
            }   
            else{
                ((typdef_bsp_key *)KEY_INIT_GROUP)->press_timerms=PRESS_50MS;
            }
        }        
        if(bsp_key_state_get((typdef_bsp_key *)KEY_INIT_GROUP)==RESET){         
            ((typdef_bsp_key *)KEY_INIT_GROUP)->press_cycle_count=0;   
        }
    }
   
    return press_flag;   
     
}
3.5 实验结果
将本例程烧录到红枫派开发板中,连接USB串口通过Type C接口,上电后打开串口调试助手,先按下复位按键,让系统复位运行。
首先在串口调试助手上打印:Example of key scan detection.
之后按下任意按键,松开后将会打印按键按下的时间范围。
具体现象如下所示。

本教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462



使用特权

评论回复
沙发
tpgf| | 2024-6-4 10:00 | 只看该作者
这个引脚内部的电阻是可以配置的吗

使用特权

评论回复
板凳
八层楼| | 2024-6-4 11:07 | 只看该作者
使用查询方式进行检测的话 是不是就要进行死循环了

使用特权

评论回复
地板
观海| | 2024-6-4 11:43 | 只看该作者
八层楼 发表于 2024-6-4 11:07
使用查询方式进行检测的话 是不是就要进行死循环了

如果是跑系统的话 倒是可以单独建立一个线程

使用特权

评论回复
5
keaibukelian| | 2024-6-4 23:21 | 只看该作者
如果按键速度过快的话 会产生漏检吗

使用特权

评论回复
6
guanjiaer| | 2024-6-4 23:53 | 只看该作者
io口不同的模式 输出的电压能一样高吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

170

主题

190

帖子

9

粉丝