button driver按键驱动的学习

按键驱动

1.按键的创建
    Button_Create("Button1",  //按键的名称
                &Button1,  //按键的结构体
                Read_Button1_Level,  //读取按键电平的函数  (需要自己实现)
                0);  // 有效电平(按键按下去时的电平)

参数

按键的名称原则上取任意见名知意的字符串都行

按键的结构体Button_t类型,保存了按键的信息

读取电平的函数,该函数需要用户实现

有效电平,按键按下去时MCU采集的电平

uint8_t Read_Button1_Level(void)//按键读取电平的函数
{
    return rt_pin_read(KEY1_PIN);
}

实现

开一块空间,存放当前按键的信息,空间的大小就是按键结构体的大小。

memset(btn, 0, sizeof(struct button));      //Clear structure information

将形参传递的初始化信息或默认信息保存在结构体中

  StrnCopy(btn->Name, name, BTN_NAME_MAX);    //button name 
  btn->Button_State = NONE_TRIGGER;           //Button status
........................

将新增的按键存放在按键链表中 Add_Button(btn) 从链表头插入

static void Add_Button(Button_t* btn)
{  
  btn->Next = Head_Button;//从表头插入
  Head_Button = btn;
} // note:stdio自动生成的代码可能会多几行代码,那几行无用可删除
2.事件的绑定(单击、双击后的动作)
Button_Attach(&Button1,BUTTON_DOWM,Btn1_Dowm_CallBack);                       //单击

**参数:**哪个按键(&Button1) 什么动作(BUTTON_DOWM) 做什么事(Btn1_Dowm_CallBack)

实现: 将回调函数(具体做什么事的函数),保存在结构体中

 btn->CallBack_Function[btn_event] = btn_callback; 
3.按键扫描

使用:推荐每隔20-50ms扫描**Button_Process()**函数

实现: 遍历存放按键信息的链表,分别扫描每个按键。扫描每个按键并执行具体逻辑的是Button_Cycle_Process函数

void Button_Process(void)
{
  struct button* pass_btn;
  for(pass_btn = Head_Button; pass_btn != RT_NULL; pass_btn = pass_btn->Next)
  {
      Button_Cycle_Process(pass_btn);//从表头开始遍历到最后一个元素
  }
}
4.Button_Cycle_Process

Button_Cycle_Process是具体扫描按键和处理回调函数的函数

实现

1.获取当前按键的电平

rt_uint8_t current_level = (rt_uint8_t)btn->Read_Button_Level();

2.判断按键的状态(按下 or 释放)

当前时刻的电平和上一时刻不一样 且 保持了一定的时间(防抖动)------> 、判断按键按下 或者 按键抬起来

  if((current_level != btn->Button_Last_Level)&&(++(btn->Debounce_Time) >= BUTTON_DEBOUNCE_TIME))//按键状态与上一时刻不同,且保持了一定的时间
  {
      /* Update current button level */
      btn->Button_Last_Level = current_level; //保存当前时刻的电平

      /* button is pressed */
      btn->Debounce_Time = 0; //记录电平维持时间的变量,方便下一次判断是否为双击
      
      /* If the button is not pressed, change the button state to press (first press / double trigger) */
      /*如果上一次的状态是没有触发(第一次按下) 或者 状态是双击 ---->  现在的状态应该是被按下*/
      if((btn->Button_State == NONE_TRIGGER)||(btn->Button_State == BUTTON_DOUBLE))
      {
        btn->Button_State = BUTTON_DOWM;
      }
      //free button 如果 上一次的状态是按下去 -----> 现在的状态是释放按键
      else if(btn->Button_State == BUTTON_DOWM)
      {
        btn->Button_State = BUTTON_UP;
        RT_DEBUG_LOG(RT_DEBUG_THREAD,("button release"));
      }
  }

3. 根据当前按键按下 释放的情况 最终确定是 单击 or 双击 or 长按

  • 如果当前是按键按下的状态----->再进一步判断是否为长按。

实现思路:每次扫描(假设20ms扫描一次)btn->Long_Time增加一次,如果btn->Long_Time超过BUTTON_LONG_TIME(默认为50次)则认为按键长按(即按着超过20*50ms 认为是长按 )。

长按发生时回调对应的事件,调用的时刻有2种,一种是长按时不断的调用;一种是长按时只调用一次(在按键释放时调用)。 默认是长按时不断的调用,如果需要只在长按释放后调用一次,可以在头文件加上**#define LONG_FREE_TRIGGER**这个宏。

如果选择不断的调用可以通过设置BUTTON_LONG_CYCLE 这个宏的大小控制调用的频率。**note:**BUTTON_LONG_CYCLE 大于1时,长按结束之后会再回调一次按下(down)的回调函数,宏的值越大现象越明显。原因:长按的时间(扫描周期数) 整除 长按检测的周期 大概率会出现余数 这个余下的时间不足以认为是长按,所以会被当成 单机按下。BUTTON_LONG_CYCLE 为1时没有这个现象。

  • 如果当前的按键是释放的状态

按键释放—>判断是单机释放 还是 双击释放

实现: 第一次按下按键并释放时,假设后面会在短时间内再按一下(即假设会双击),复位计数次数,开启计数(计算时间)。再第一次按下按键和第二次按下按键之间的时间(间隔时间),每次都会进入case BUTTON_DOUBLE的判断里。在BUTTON_DOUBLE标签下会记录扫描了几次(时间),超过了设定时间会否定之前的双击假设,认为是一次单击(回调单击事件)。如果没有被否定,第二次按下按键并释放时会回调双击事件。

第一次按下按键时执行的部分 (先假设双击的情况)

        else
        {
            btn->Timer_Count=0;
            /* Detection long press failed, clear 0 */
            btn->Long_Time = 0;
          
          #ifndef SINGLE_AND_DOUBLE_TRIGGER

             /* click */
            TRIGGER_CB(BUTTON_DOWM);
          #endif
            btn->Button_State = BUTTON_DOUBLE;
            btn->Button_Last_State = BUTTON_DOUBLE;
          
        }

第一次按键和第二次按下按键之间的间隔时间执行的部分 (计数 如果超过时间就否定双击假设 即认为是单击的情况---->回调单击事件)

    case BUTTON_DOUBLE ://
    {
      /* Update time */
      btn->Timer_Count++;                                      
      if(btn->Timer_Count>=BUTTON_DOUBLE_TIME)  //超时了 假设失败
      {
        btn->Button_State = NONE_TRIGGER;
        btn->Button_Last_State = NONE_TRIGGER;
      }
      #ifdef SINGLE_AND_DOUBLE_TRIGGER
      
        if((btn->Timer_Count>=BUTTON_DOUBLE_TIME)&&(btn->Button_Last_State != BUTTON_DOWM)) 
        {  //超时了 and 上一次的状态是单机按下------>完成了一次单击的过程,回调单击的事件
          btn->Timer_Count=0;
          TRIGGER_CB(BUTTON_DOWM);    
          btn->Button_State = NONE_TRIGGER;
          btn->Button_Last_State = BUTTON_DOWM;
        }
        
      #endif

      break;
    }

第二次按下按键 且假设成功 执行的部分(假设成功 两次按键之间的时间间隔低于阈值 回调双击事件 各种标志位恢复 一个判断周期的结束 如果有第三次按下 代码的判断情况和第一次一样)

        if((btn->Timer_Count <= BUTTON_DOUBLE_TIME)&&(btn->Button_Last_State == BUTTON_DOUBLE)) 
        {
          btn->Button_Trigger_Event = BUTTON_DOUBLE;
          TRIGGER_CB(BUTTON_DOUBLE);    
          RT_DEBUG_LOG(RT_DEBUG_THREAD,("double click"));
          btn->Button_State = NONE_TRIGGER;
          btn->Button_Last_State = NONE_TRIGGER;
        }
5.其他
#define CONTINUOS_TRIGGER    

定义这个宏定义后,按键按下期间会连续回调BUTTON_CONTINUOS绑定的事件,不会回调单击 双击的事件。这个宏定义默认是没有的。

#define SINGLE_AND_DOUBLE_TRIGGER

这个宏默认是有的,屏蔽后,双击之前会触发一次单击。屏蔽后的优点是 单击事件一产生就会立刻执行回调函数,实时性比较高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于使用LVGL库实现多个按钮的按键驱动,可以按照以下步骤进行操作: 1. 创建按钮对象:使用`lv_btn_create(parent, copy)`函数创建按钮对象,其中`parent`为父对象,`copy`为可选参数,表示复制已有的按钮对象。 2. 设置按钮样式:使用`lv_btn_set_style(btn, style, part)`函数设置按钮的样式,其中`btn`为按钮对象,`style`为样式对象,`part`为按钮的不同部分(例如`LV_BTN_PART_MAIN`表示按钮的主要部分)。 3. 设置按钮文本:使用`lv_btn_set_fit(btn, fit_mode)`函数设置按钮文本的适应模式,其中`btn`为按钮对象,`fit_mode`为适应模式(例如`LV_FIT_NONE`表示不适应)。 4. 设置按钮事件回调函数:使用`lv_btn_set_action(btn, type, action)`函数设置按钮的事件回调函数,其中`btn`为按钮对象,`type`为事件类型(例如`LV_EVENT_CLICKED`表示点击事件),`action`为回调函数。 5. 创建按键驱动任务:创建一个任务或线程来处理按键事件。在任务中使用LVGL库提供的函数来获取按键状态,并根据需要处理不同的按键事件。 6. 处理按键事件:在按键驱动任务中使用LVGL库提供的函数来获取按键状态,例如使用`lv_indev_get_key(lv_indev_get_act())`函数获取当前按下的按键。根据按键的不同,执行相应的操作。 以上是使用LVGL库实现多个按钮的按键驱动的基本步骤。您可以根据具体的需求进行适当的调整和扩展。希望对您有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值