基于STM32的通用按键任务处理方法

程序中需要使用到STM32官方库V3.5.0版本,当然如果使用其他版本可以根据要求自行更改,这里不啰嗦了,直接上程序

首先在头文件中定义按键事件和宏定义,用于表示当前的按键状态:


#define MY_BUTTON_DOWN_MS        50		//按下超过MY_BUTTON_DOWN_MS时间,认为按键为有效按下,过小容易出现抖动误判,过大会导致按键不灵敏
#define MY_BUTTON_HOLD_MS        700	//当超过此数值时认为按键长按保持

#define MY_BUTTON_SCAN_SPACE_MS  5		//按键的扫描周期
#define MY_BUTTON_LIST_MAX       10		//支持的按键数量,可以根据实际要求定义


#define PRESS_LEVEL 		Bit_RESET	//表示按键按下时的电平状态,这里使用的是低电平,Bit_RESET为STM32官方库中的定义
#define DEFAULT_COUNT_TIME  50		

	
enum my_button_event
{
    BUTTON_EVENT_CLICK_DOWN, /* 按键单击按下事件 */
    BUTTON_EVENT_CLICK_UP,   /* 按键单击结束事件 */
    BUTTON_EVENT_HOLD,       /* 按键长按开始事件 */
    BUTTON_EVENT_HOLD_CYC,   /* 按键长按周期性触发事件 */
    BUTTON_EVENT_HOLD_UP,    /* 按键长按结束事件 */
    BUTTON_EVENT_NONE        /* 无按键事件 */
};


//接着,我们定义一下按键逻辑的结构体:
struct my_button
{
    uint8_t  press_logic_level;  /* 按键按下时的电平 */
    uint16_t cnt;                /* 连续扫描到按下状态的次数 */
    uint16_t hold_cyc_period;    /* 长按周期回调的周期 */
    GPIO_TypeDef* GPIOx;			/* 定义按键使用的端口,如GPIOA,基于STM32官方库 */
    uint16_t GPIO_Pin;                /* 按键对应的 pin 引脚 */
    enum my_button_event event;     /* 按键的触发的事件 */

    my_button_callback cb;          /* 按键触发事件回调函数 */
};

接下来编写函数部分:

函数回调宏定义

#define MY_BUTTON_CALL(func, argv) \
    do { if ((func) != RT_NULL) func argv; } while (0)

这里需要定义一个my_button_manage结构体,用于统一管理按键

struct my_button_manage
{
    uint8_t num;                 /* 已注册的按键的数目 */
    rt_timer_t timer;               /* 按键扫描用到的定时器 */
    struct my_button *button_list[MY_BUTTON_LIST_MAX];  /* 存储按键指针的数组 */
};

static struct my_button_manage button_manage;

然后进行STM32的硬件引脚初始化:

void Key_Input_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);	 //使能PA,PD端口时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;				 //LED0-->PA.8 端口配置
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		
    GPIO_Init(GPIOA, &GPIO_InitStructure);					 //根据设定参数初始化GPIOA.8
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14;				 //LED0-->PA.8 端口配置
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		
    GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOA.8
    
    
    Menu_Key_Register();		//这里是完成菜单按键的注册,详细见下面代码

}

再实现按键事件的注册:

//这里可以自己定义按键名称,如下是定义的上下左右OK键和菜单、返回键,并且定义它们使用的引脚
struct my_button UP_Key = {PRESS_LEVEL, 0, 5, GPIOA, GPIO_Pin_7};
struct my_button DOWN_Key = {PRESS_LEVEL, 0, 5, GPIOA, GPIO_Pin_5};
struct my_button LEFT_Key = {PRESS_LEVEL, 0, 5, GPIOA, GPIO_Pin_6};
struct my_button RIGHT_Key = {PRESS_LEVEL, 0, 5, GPIOA, GPIO_Pin_4};
struct my_button OK_Key = {PRESS_LEVEL, 0, 5, GPIOB, GPIO_Pin_12};
struct my_button MENU_Key = {PRESS_LEVEL, 0, 5, GPIOB, GPIO_Pin_13};
struct my_button BACK_Key = {PRESS_LEVEL, 0, 5, GPIOB, GPIO_Pin_14};

int my_button_register(struct my_button *button)
{
    
    button->cnt = 0;
    button->event = BUTTON_EVENT_NONE;
    button_manage.button_list[button_manage.num++] = button;
    
    return 0;
}
//对按键进行初始化注册
void Menu_Key_Register(void)
{
    my_button_register(&UP_Key);
    my_button_register(&DOWN_Key);
    my_button_register(&LEFT_Key);
    my_button_register(&RIGHT_Key);
    my_button_register(&OK_Key);
    my_button_register(&MENU_Key);
    my_button_register(&BACK_Key);

}
//判断按键是否按下
uint8_t Is_Key_Press(struct my_button *btn, enum my_button_event eve)
{
    if(btn->event == eve)
    {
        btn->event = BUTTON_EVENT_NONE;
        return 1;
    }
    
    return 0;
}

接下来是按键的主要处理逻辑了
void My_Button_Scan(void)是按键的处理函数,可以放在定时中断函数中,本文使用的是5MS定时中断

void My_Button_Scan(void)
{
    rt_uint8_t i;
    rt_uint16_t cnt_old;

    for (i = 0; i < button_manage.num; i++)
    {
        cnt_old = button_manage.button_list[i]->cnt;

        if(GPIO_ReadInputDataBit(button_manage.button_list[i]->GPIOx, button_manage.button_list[i]->GPIO_Pin) == PRESS_LEVEL)   
        {
            button_manage.button_list[i]->cnt ++;

            if (button_manage.button_list[i]->cnt == MY_BUTTON_DOWN_MS / MY_BUTTON_SCAN_SPACE_MS) /* BUTTON_DOWN */
            {

                button_manage.button_list[i]->event = BUTTON_EVENT_CLICK_DOWN;
                MY_BUTTON_CALL(button_manage.button_list[i]->cb, (button_manage.button_list[i]));
            }
            else if (button_manage.button_list[i]->cnt == MY_BUTTON_HOLD_MS / MY_BUTTON_SCAN_SPACE_MS) /* BUTTON_HOLD */
            {

                button_manage.button_list[i]->event = BUTTON_EVENT_HOLD;
                MY_BUTTON_CALL(button_manage.button_list[i]->cb, (button_manage.button_list[i]));
            }
            else if (button_manage.button_list[i]->cnt > MY_BUTTON_HOLD_MS / MY_BUTTON_SCAN_SPACE_MS) /* BUTTON_HOLD_CYC */
            {

                button_manage.button_list[i]->event = BUTTON_EVENT_HOLD_CYC;
                if (button_manage.button_list[i]->hold_cyc_period && button_manage.button_list[i]->cnt % (button_manage.button_list[i]->hold_cyc_period / MY_BUTTON_SCAN_SPACE_MS) == 0)
                    MY_BUTTON_CALL(button_manage.button_list[i]->cb, (button_manage.button_list[i]));
            }
        }
        else
        {
            button_manage.button_list[i]->cnt = 0;
            if (cnt_old >= MY_BUTTON_DOWN_MS / MY_BUTTON_SCAN_SPACE_MS && cnt_old < MY_BUTTON_HOLD_MS / MY_BUTTON_SCAN_SPACE_MS) /* BUTTON_CLICK_UP */
            {

                button_manage.button_list[i]->event = BUTTON_EVENT_CLICK_UP;
                MY_BUTTON_CALL(button_manage.button_list[i]->cb, (button_manage.button_list[i]));
            }
            else if (cnt_old >= MY_BUTTON_HOLD_MS / MY_BUTTON_SCAN_SPACE_MS) /* BUTTON_HOLD_UP */
            {

                button_manage.button_list[i]->event = BUTTON_EVENT_HOLD_UP; 
                MY_BUTTON_CALL(button_manage.button_list[i]->cb, (button_manage.button_list[i]));
            }
        }
    }
}

//清除所有按键事件,一般用于初始化或切换系统状态时
void Clear_KeyEvent_All(void)
{
    rt_uint8_t i;

    for (i = 0; i < button_manage.num; i++)
    {
        button_manage.button_list[i]->event = BUTTON_EVENT_NONE;
    }
}
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值