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

描述

单片机

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    {
        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.

之后按下任意按键,松开后将会打印按键按下的时间范围。

具体现象如下所示。

单片机

 

教程GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分