[AT32F423] 【AT-START-F423测评】移植一个优秀的按键程序

[复制链接]
 楼主| lulugl 发表于 2023-10-25 09:32 | 显示全部楼层 |阅读模式
<
本帖最后由 lulugl 于 2023-10-25 09:34 编辑

#申请原创# #有奖活动#@21ic小跑堂
【按键驱动】
单片机在输入设备中,按键是最简单经济可靠的设备之一。单按键可以直接由GPIO来驱动,采集他的高低电平来实现按键状态的功能,但是在实际中,按键的状态获取,要考虑到消抖情况,如果单一按键要通过单击、双击、连击、长按等来实现结合功能,那就实现起来就非常复杂,效果也不是非常好。
在github中我找到了一个开源的按键驱动,Button_drive是一个小巧的按键驱动,支持单击、双击、长按、连续触发等(后续可以在按键控制块中添加触发事件),理论上可无限量扩展Button,Button_drive采用按键触发事件回调方式处理业务逻辑,支持在RTOS中使用,我目前仅在 HYPERLINK "https://github.com/RT-Thread/rt-thread" 上测试过。 写按键驱动的目的是想要将用户按键逻辑与按键处理事件分离,用户无需处理复杂麻烦的逻辑事件。https://github.com/jiejieTop/ButtonDrive
【实现方式】
下载github源码
复制一份示例的printf工程到一个新的文件夹中,重命名为printf_button。
d5106db8e81438ec5fa1ab5d5a768419
解压源码后复制button.c/h到工程文件的middlewares下的button文件夹中。
9842e4bafd50d7189fec0b4e13bfdebf
在工程文件中新增button组,把button.c加入button组中。
a20a24f8a42a16ae616438a379b31c12
添加头文件的引用。
2897d7b07193197dc8be08aab9c867dd
在button.c中添加at32f423_board.h头文件的引用。
3d400889c601b643d75d23e225f01ce3
在button.c中实现按键电平的获取自定义函数,在模版工程中,官方在at32f423_board.c中实现的按键的初始化,我们直接引用就可以实现按键状态的获取:
  1. /* 获取按键电平 */

  2. uint8_t Read_KEY1_Level(void)

  3. {

  4. return at32_button_state();

  5. }

在main.c中,我们实现用户的单击、双击、长按释放的功能回调函数,代码如下:
  1. Button_t Button1;

  2. void Btn1_Dowm_CallBack(void *btn)

  3. {

  4. printf("Button1 单击!\r\n");

  5. }

  6. void Btn1_Double_CallBack(void *btn)

  7. {

  8. printf("Button1 双击!\r\n");

  9. }

  10. void Btn1_Long_CallBack(void *btn)

  11. {

  12. printf("Button1 长按!\r\n");

  13. }

  14. void Btn1_ContinuosFree_CallBack(void *btn)

  15. {

  16. printf("Button1 连按释放!\r\n");

  17. }

在主函中,我们注册需要实现的功能函数,我这里添加单击、双击、长按、长按释放,代码如下:
  1. Button_Attach(&Button1,BUTTON_DOWM,Btn1_Dowm_CallBack); //单击

  2. Button_Attach(&Button1,BUTTON_DOUBLE,Btn1_Double_CallBack); //双击

  3. Button_Attach(&Button1,BUTTON_LONG,Btn1_Long_CallBack); //长按BUTTON_LONG_FREE,

  4. Button_Attach(&Button1,BUTTON_LONG_FREE,Btn1_ContinuosFree_CallBack);

在while中添加按键检测函数:
  1. Button_Process(); //需要周期调用按键处理函数

到此,移植结束,下载到开发板上可以实现相应的功能,按下开发板的按键,就在串口打印出相应的状态:
79ee03a2f36f9b7b8a7ce3677c24a7dd
button.c完整程序如下:
  1. /************************************************************
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]   按键驱动
  3.         * @param   NULL
  4.   * [url=home.php?mod=space&uid=266161]@return[/url]  NULL
  5.   * [url=home.php?mod=space&uid=187600]@author[/url]  jiejie
  6.   * [url=home.php?mod=space&uid=2757600]@Github[/url]  https://github.com/jiejieTop
  7.   * [url=home.php?mod=space&uid=212281]@date[/url]    2018-xx-xx
  8.   * [url=home.php?mod=space&uid=895143]@version[/url] v1.0
  9.   * [url=home.php?mod=space&uid=536309]@NOTE[/url]    button.c
  10.   ***********************************************************/
  11. #include "button.h"
  12. #include "at32f423_board.h"
  13. #include "stdio.h"
  14. #include "string.h"
  15. /*******************************************************************
  16. *                          变量声明                              
  17. *******************************************************************/

  18. static struct button* Head_Button = NULL;


  19. /*******************************************************************
  20. *                         函数声明     
  21. *******************************************************************/
  22. static char *StrnCopy(char *dst, const char *src, uint32_t n);
  23. static void Print_Btn_Info(Button_t* btn);
  24. static void Add_Button(Button_t* btn);


  25. /************************************************************
  26.   * [url=home.php?mod=space&uid=247401]@brief[/url]   按键创建
  27.         * @param   name : 按键名称
  28.         * @param   btn : 按键结构体
  29.   * @param   read_btn_level : 按键电平读取函数,需要用户自己实现返回uint8_t类型的电平
  30.   * @param   btn_trigger_level : 按键触发电平
  31.   * [url=home.php?mod=space&uid=266161]@return[/url]  NULL
  32.   * [url=home.php?mod=space&uid=187600]@author[/url]  jiejie
  33.   * [url=home.php?mod=space&uid=2757600]@Github[/url]  https://github.com/jiejieTop
  34.   * [url=home.php?mod=space&uid=212281]@date[/url]    2018-xx-xx
  35.   * [url=home.php?mod=space&uid=895143]@version[/url] v1.0
  36.   * [url=home.php?mod=space&uid=536309]@NOTE[/url]    NULL
  37.   ***********************************************************/
  38. void Button_Create(const char *name,
  39.                   Button_t *btn,
  40.                   uint8_t(*read_btn_level)(void),
  41.                   uint8_t btn_trigger_level)
  42. {
  43.   if( btn == NULL)
  44.   {
  45.     printf("struct button is null!");
  46.     //ASSERT(ASSERT_ERR);
  47.   }
  48.   
  49.   memset(btn, 0, sizeof(struct button));  //清除结构体信息,建议用户在之前清除

  50.   StrnCopy(btn->Name, name, BTN_NAME_MAX); /* 创建按键名称 */
  51.   
  52.   
  53.   btn->Button_State = NONE_TRIGGER;           //按键状态
  54.   btn->Button_Last_State = NONE_TRIGGER;      //按键上一次状态
  55.   btn->Button_Trigger_Event = NONE_TRIGGER;   //按键触发事件
  56.   btn->Read_Button_Level = read_btn_level;    //按键读电平函数
  57.   btn->Button_Trigger_Level = btn_trigger_level;  //按键触发电平
  58.   btn->Button_Last_Level = btn->Read_Button_Level(); //按键当前电平
  59.   btn->Debounce_Time = 0;
  60.   
  61.   printf("button create success!");
  62.   
  63.   Add_Button(btn);          //创建的时候添加到单链表中
  64.   
  65.   Print_Btn_Info(btn);     //打印信息

  66. }

  67. /************************************************************
  68.   * @brief   按键触发事件与回调函数映射链接起来
  69.         * @param   btn : 按键结构体
  70.         * @param   btn_event : 按键触发事件
  71.   * @param   btn_callback : 按键触发之后的回调处理函数。需要用户实现
  72.   * @return  NULL
  73.   * @author  jiejie
  74.   * @github  https://github.com/jiejieTop
  75.   * @date    2018-xx-xx
  76.   * @version v1.0
  77.   ***********************************************************/
  78. void Button_Attach(Button_t *btn,Button_Event btn_event,Button_CallBack btn_callback)
  79. {
  80.         uint8_t i;
  81.   if( btn == NULL)
  82.   {
  83.     printf("struct button is null!");
  84.     //ASSERT(ASSERT_ERR);       //断言
  85.   }
  86.   
  87.   if(BUTTON_ALL_RIGGER == btn_event)
  88.   {
  89.     for(i = 0 ; i < number_of_event-1 ; i++)
  90.       btn->CallBack_Function[i] = btn_callback; //按键事件触发的回调函数,用于处理按键事件
  91.   }
  92.   else
  93.   {
  94.     btn->CallBack_Function[btn_event] = btn_callback; //按键事件触发的回调函数,用于处理按键事件
  95.   }
  96. }

  97. /************************************************************
  98.   * @brief   删除一个已经创建的按键
  99.         * @param   NULL
  100.   * @return  NULL
  101.   * @author  jiejie
  102.   * @github  https://github.com/jiejieTop
  103.   * @date    2018-xx-xx
  104.   * @version v1.0
  105.   * @note    NULL
  106.   ***********************************************************/
  107. void Button_Delete(Button_t *btn)
  108. {
  109.   struct button** curr;
  110.   for(curr = &Head_Button; *curr;)
  111.   {
  112.     struct button* entry = *curr;
  113.     if (entry == btn)
  114.     {
  115.       *curr = entry->Next;
  116.     }
  117.     else
  118.     {
  119.       curr = &entry->Next;
  120.     }
  121.   }
  122. }

  123. /************************************************************
  124.   * @brief   获取按键触发的事件
  125.         * @param   NULL
  126.   * @return  NULL
  127.   * @author  jiejie
  128.   * @github  https://github.com/jiejieTop
  129.   * @date    2018-xx-xx
  130.   * @version v1.0
  131.   ***********************************************************/
  132. void Get_Button_EventInfo(Button_t *btn)
  133. {
  134.         uint8_t i;
  135.   //按键事件触发的回调函数,用于处理按键事件
  136.   for(i = 0 ; i < number_of_event-1 ; i++)
  137.   {
  138.     if(btn->CallBack_Function[i] != 0)
  139.     {
  140.       printf("Button_Event:%d",i);
  141.     }      
  142.   }
  143. }

  144. uint8_t Get_Button_Event(Button_t *btn)
  145. {
  146.   return (uint8_t)(btn->Button_Trigger_Event);
  147. }

  148. /************************************************************
  149.   * @brief   获取按键触发的事件
  150.         * @param   NULL
  151.   * @return  NULL
  152.   * @author  jiejie
  153.   * @github  https://github.com/jiejieTop
  154.   * @date    2018-xx-xx
  155.   * @version v1.0
  156.   ***********************************************************/
  157. uint8_t Get_Button_State(Button_t *btn)
  158. {
  159.   return (uint8_t)(btn->Button_State);
  160. }

  161. /************************************************************
  162.   * @brief   按键周期处理函数
  163.   * @param   btn:处理的按键
  164.   * @return  NULL
  165.   * @author  jiejie
  166.   * @github  https://github.com/jiejieTop
  167.   * @date    2018-xx-xx
  168.   * @version v1.0
  169.   * @note    必须以一定周期调用此函数,建议周期为20~50ms
  170.   ***********************************************************/
  171. void Button_Cycle_Process(Button_t *btn)
  172. {
  173.   uint8_t current_level = (uint8_t)btn->Read_Button_Level();//获取当前按键电平
  174.   
  175.   if((current_level != btn->Button_Last_Level)&&(++(btn->Debounce_Time) >= BUTTON_DEBOUNCE_TIME)) //按键电平发生变化,消抖
  176.   {
  177.       btn->Button_Last_Level = current_level; //更新当前按键电平
  178.       btn->Debounce_Time = 0;                 //确定了是按下
  179.       
  180.       //如果按键是没被按下的,改变按键状态为按下(首次按下/双击按下)
  181.       if((btn->Button_State == NONE_TRIGGER)||(btn->Button_State == BUTTON_DOUBLE))
  182.       {
  183.         btn->Button_State = BUTTON_DOWM;
  184.       }
  185.       //释放按键
  186.       else if(btn->Button_State == BUTTON_DOWM)
  187.       {
  188.         btn->Button_State = BUTTON_UP;
  189.         TRIGGER_CB(BUTTON_UP);    // 触发释放
  190. //        printf("释放了按键");
  191.       }
  192.   }
  193.   
  194.   switch(btn->Button_State)
  195.   {
  196.     case BUTTON_DOWM :            // 按下状态
  197.     {
  198.       if(btn->Button_Last_Level == btn->Button_Trigger_Level) //按键按下
  199.       {
  200.         #if CONTINUOS_TRIGGER     //支持连续触发

  201.         if(++(btn->Button_Cycle) >= BUTTON_CONTINUOS_CYCLE)
  202.         {
  203.           btn->Button_Cycle = 0;
  204.           btn->Button_Trigger_Event = BUTTON_CONTINUOS;
  205.           TRIGGER_CB(BUTTON_CONTINUOS);    //连按
  206.           printf("连按");
  207.         }
  208.         
  209.         #else
  210.         
  211.         btn->Button_Trigger_Event = BUTTON_DOWM;
  212.       
  213.         if(++(btn->Long_Time) >= BUTTON_LONG_TIME)  //释放按键前更新触发事件为长按
  214.         {
  215.           #if LONG_FREE_TRIGGER
  216.          
  217.           btn->Button_Trigger_Event = BUTTON_LONG;
  218.          
  219.           #else
  220.          
  221.           if(++(btn->Button_Cycle) >= BUTTON_LONG_CYCLE)    //连续触发长按的周期
  222.           {
  223.             btn->Button_Cycle = 0;
  224.             btn->Button_Trigger_Event = BUTTON_LONG;
  225.             TRIGGER_CB(BUTTON_LONG);    //长按
  226.           }
  227.           #endif
  228.          
  229.           if(btn->Long_Time == 0xFF)  //更新时间溢出
  230.           {
  231.             btn->Long_Time = BUTTON_LONG_TIME;
  232.           }
  233. //          printf("长按");
  234.         }
  235.          
  236.         #endif
  237.       }

  238.       break;
  239.     }
  240.    
  241.     case BUTTON_UP :        // 弹起状态
  242.     {
  243.       if(btn->Button_Trigger_Event == BUTTON_DOWM)  //触发单击
  244.       {
  245.         if((btn->Timer_Count <= BUTTON_DOUBLE_TIME)&&(btn->Button_Last_State == BUTTON_DOUBLE)) // 双击
  246.         {
  247.           btn->Button_Trigger_Event = BUTTON_DOUBLE;
  248.           TRIGGER_CB(BUTTON_DOUBLE);   
  249. //          printf("双击");
  250.           btn->Button_State = NONE_TRIGGER;
  251.           btn->Button_Last_State = NONE_TRIGGER;
  252.         }
  253.         else
  254.         {
  255.             btn->Timer_Count=0;
  256.             btn->Long_Time = 0;   //检测长按失败,清0
  257.          
  258.           #if (SINGLE_AND_DOUBLE_TRIGGER == 0)
  259.             TRIGGER_CB(BUTTON_DOWM);    //单击
  260.           #endif
  261.             btn->Button_State = BUTTON_DOUBLE;
  262.             btn->Button_Last_State = BUTTON_DOUBLE;
  263.          
  264.         }
  265.       }
  266.       
  267.       else if(btn->Button_Trigger_Event == BUTTON_LONG)
  268.       {
  269.         #if LONG_FREE_TRIGGER
  270.           TRIGGER_CB(BUTTON_LONG);    //长按
  271.         #else
  272.           TRIGGER_CB(BUTTON_LONG_FREE);    //长按释放
  273.         #endif
  274.         btn->Long_Time = 0;
  275.         btn->Button_State = NONE_TRIGGER;
  276.         btn->Button_Last_State = BUTTON_LONG;
  277.       }
  278.       
  279.       #if CONTINUOS_TRIGGER
  280.         else if(btn->Button_Trigger_Event == BUTTON_CONTINUOS)  //连按
  281.         {
  282.           btn->Long_Time = 0;
  283.           TRIGGER_CB(BUTTON_CONTINUOS_FREE);    //连发释放
  284.           btn->Button_State = NONE_TRIGGER;
  285.           btn->Button_Last_State = BUTTON_CONTINUOS;
  286.         }
  287.       #endif
  288.       
  289.       break;
  290.     }
  291.    
  292.     case BUTTON_DOUBLE :
  293.     {
  294.       btn->Timer_Count++;     //时间记录
  295.       if(btn->Timer_Count>=BUTTON_DOUBLE_TIME)
  296.       {
  297.         btn->Button_State = NONE_TRIGGER;
  298.         btn->Button_Last_State = NONE_TRIGGER;
  299.       }
  300.       #if SINGLE_AND_DOUBLE_TRIGGER
  301.       
  302.         if((btn->Timer_Count>=BUTTON_DOUBLE_TIME)&&(btn->Button_Last_State != BUTTON_DOWM))
  303.         {
  304.           btn->Timer_Count=0;
  305.           TRIGGER_CB(BUTTON_DOWM);    //单击
  306.           btn->Button_State = NONE_TRIGGER;
  307.           btn->Button_Last_State = BUTTON_DOWM;
  308.         }
  309.         
  310.       #endif

  311.       break;
  312.     }

  313.     default :
  314.       break;
  315.   }
  316.   
  317. }

  318. /************************************************************
  319.   * @brief   遍历的方式扫描按键,不会丢失每个按键
  320.         * @param   NULL
  321.   * @return  NULL
  322.   * @author  jiejie
  323.   * @github  https://github.com/jiejieTop
  324.   * @date    2018-xx-xx
  325.   * @version v1.0
  326.   * @note    此函数要周期调用,建议20-50ms调用一次
  327.   ***********************************************************/
  328. void Button_Process(void)
  329. {
  330.   struct button* pass_btn;
  331.   for(pass_btn = Head_Button; pass_btn != NULL; pass_btn = pass_btn->Next)
  332.   {
  333.       Button_Cycle_Process(pass_btn);
  334.   }
  335. }

  336. /************************************************************
  337.   * @brief   遍历按键
  338.         * @param   NULL
  339.   * @return  NULL
  340.   * @author  jiejie
  341.   * @github  https://github.com/jiejieTop
  342.   * @date    2018-xx-xx
  343.   * @version v1.0
  344.   * @note    NULL
  345.   ***********************************************************/
  346. void Search_Button(void)
  347. {
  348.   struct button* pass_btn;
  349.   for(pass_btn = Head_Button; pass_btn != NULL; pass_btn = pass_btn->Next)
  350.   {
  351.     printf("button node have %s",pass_btn->Name);
  352.   }
  353. }

  354. /************************************************************
  355.   * @brief   处理所有按键回调函数
  356.         * @param   NULL
  357.   * @return  NULL
  358.   * @author  jiejie
  359.   * @github  https://github.com/jiejieTop
  360.   * @date    2018-xx-xx
  361.   * @version v1.0
  362.   * @note    暂不实现
  363.   ***********************************************************/
  364. void Button_Process_CallBack(void *btn)
  365. {
  366.   uint8_t btn_event = Get_Button_Event(btn);

  367.   switch(btn_event)
  368.   {
  369.     case BUTTON_DOWM:
  370.     {
  371.       printf("添加你的按下触发的处理逻辑");
  372.       break;
  373.     }
  374.    
  375.     case BUTTON_UP:
  376.     {
  377.       printf("添加你的释放触发的处理逻辑");
  378.       break;
  379.     }
  380.    
  381.     case BUTTON_DOUBLE:
  382.     {
  383.       printf("添加你的双击触发的处理逻辑");
  384.       break;
  385.     }
  386.    
  387.     case BUTTON_LONG:
  388.     {
  389.       printf("添加你的长按触发的处理逻辑");
  390.       break;
  391.     }
  392.    
  393.     case BUTTON_LONG_FREE:
  394.     {
  395.       printf("添加你的长按释放触发的处理逻辑");
  396.       break;
  397.     }
  398.    
  399.     case BUTTON_CONTINUOS:
  400.     {
  401.       printf("添加你的连续触发的处理逻辑");
  402.       break;
  403.     }
  404.    
  405.     case BUTTON_CONTINUOS_FREE:
  406.     {
  407.       printf("添加你的连续触发释放的处理逻辑");
  408.       break;
  409.     }
  410.       
  411.   }
  412. }


  413. /**************************** 以下是内部调用函数 ********************/

  414. /************************************************************
  415.   * @brief   拷贝指定长度字符串
  416.         * @param   NULL
  417.   * @return  NULL
  418.   * @author  jiejie
  419.   * @github  https://github.com/jiejieTop
  420.   * @date    2018-xx-xx
  421.   * @version v1.0
  422.   * @note    NULL
  423.   ***********************************************************/
  424. static char *StrnCopy(char *dst, const char *src, uint32_t n)
  425. {
  426.   if (n != 0)
  427.   {
  428.     char *d = dst;
  429.     const char *s = src;
  430.     do
  431.     {
  432.         if ((*d++ = *s++) == 0)
  433.         {
  434.             while (--n != 0)
  435.                 *d++ = 0;
  436.             break;
  437.         }
  438.     } while (--n != 0);
  439.   }
  440.   return (dst);
  441. }

  442. /************************************************************
  443.   * @brief   打印按键相关信息
  444.         * @param   NULL
  445.   * @return  NULL
  446.   * @author  jiejie
  447.   * @github  https://github.com/jiejieTop
  448.   * @date    2018-xx-xx
  449.   * @version v1.0
  450.   * @note    NULL
  451.   ***********************************************************/
  452. static void Print_Btn_Info(Button_t* btn)
  453. {
  454.   
  455.   printf("button struct information:\n\
  456.               btn->Name:%s \n\
  457.               btn->Button_State:%d \n\
  458.               btn->Button_Trigger_Event:%d \n\
  459.               btn->Button_Trigger_Level:%d \n\
  460.               btn->Button_Last_Level:%d \n\
  461.               ",
  462.               btn->Name,
  463.               btn->Button_State,
  464.               btn->Button_Trigger_Event,
  465.               btn->Button_Trigger_Level,
  466.               btn->Button_Last_Level);
  467.   Search_Button();
  468. }
  469. /************************************************************
  470.   * @brief   使用单链表将按键连接起来
  471.         * @param   NULL
  472.   * @return  NULL
  473.   * @author  jiejie
  474.   * @github  https://github.com/jiejieTop
  475.   * @date    2018-xx-xx
  476.   * @version v1.0
  477.   * @note    NULL
  478.   ***********************************************************/
  479. static void Add_Button(Button_t* btn)
  480. {
  481.   btn->Next = Head_Button;
  482.   Head_Button = btn;
  483. }

  484. /* 获取按键电平 */
  485. uint8_t Read_KEY1_Level(void)
  486. {
  487.         return at32_button_state();
  488. }



button.h完整代码:
  1. #ifndef BUTTON_H
  2. #define BUTTON_H

  3. #include "at32f423_conf.h"

  4. #define NULL          0
  5. #define BTN_NAME_MAX  32     //名字最大为32字节

  6. /* 按键消抖时间40ms, 建议调用周期为20ms
  7. 只有连续检测到40ms状态不变才认为有效,包括弹起和按下两种事件
  8. */

  9. #define CONTINUOS_TRIGGER             0  //是否支持连续触发,连发的话就不要检测单双击与长按了        

  10. /* 是否支持单击&双击同时存在触发,如果选择开启宏定义的话,单双击都回调,只不过单击会延迟响应,
  11.    因为必须判断单击之后是否触发了双击否则,延迟时间是双击间隔时间 BUTTON_DOUBLE_TIME。
  12.    而如果不开启这个宏定义,建议工程中只存在单击/双击中的一个,否则,在双击响应的时候会触发一次单击,
  13.    因为双击必须是有一次按下并且释放之后才产生的 */
  14. #define SINGLE_AND_DOUBLE_TRIGGER     1

  15. /* 是否支持长按释放才触发,如果打开这个宏定义,那么长按释放之后才触发单次长按,
  16.    否则在长按指定时间就一直触发长按,触发周期由 BUTTON_LONG_CYCLE 决定 */
  17. #define LONG_FREE_TRIGGER             0

  18. #define BUTTON_DEBOUNCE_TIME           2   //消抖时间      (n-1)*调用周期
  19. #define BUTTON_CONTINUOS_CYCLE  1          //连按触发周期时间  (n-1)*调用周期  
  20. #define BUTTON_LONG_CYCLE       1          //长按触发周期时间  (n-1)*调用周期
  21. #define BUTTON_DOUBLE_TIME      15         //双击间隔时间  (n-1)*调用周期  建议在200-600ms
  22. #define BUTTON_LONG_TIME               50                /* 持续n秒((n-1)*调用周期 ms),认为长按事件 */

  23. #define TRIGGER_CB(event)   \
  24.         if(btn->CallBack_Function[event]) \
  25.           btn->CallBack_Function[event]((Button_t*)btn)

  26. typedef void (*Button_CallBack)(void*);   /* 按键触发回调函数,需要用户实现 */



  27. typedef enum {
  28.   BUTTON_DOWM = 0,
  29.   BUTTON_UP,
  30.   BUTTON_DOUBLE,
  31.   BUTTON_LONG,
  32.   BUTTON_LONG_FREE,
  33.   BUTTON_CONTINUOS,
  34.   BUTTON_CONTINUOS_FREE,
  35.   BUTTON_ALL_RIGGER,
  36.   number_of_event, /* 触发回调的事件 */
  37.   NONE_TRIGGER
  38. }Button_Event;

  39. /*
  40.         每个按键对应1个全局的结构体变量。
  41.         其成员变量是实现滤波和多种按键状态所必须的
  42. */
  43. typedef struct button
  44. {
  45.         /* 下面是一个函数指针,指向判断按键手否按下的函数 */
  46.         uint8_t (*Read_Button_Level)(void); /* 读取按键电平函数,需要用户实现 */
  47.   
  48.   char Name[BTN_NAME_MAX];
  49.          
  50.   uint8_t Button_State              :   4;          /* 按键当前状态(按下还是弹起) */
  51.   uint8_t Button_Last_State         :   4;          /* 上一次的按键状态,用于判断双击 */
  52.   uint8_t Button_Trigger_Level      :   2;    /* 按键触发电平 */
  53.   uint8_t Button_Last_Level         :   2;    /* 按键当前电平 */
  54.   
  55.   uint8_t Button_Trigger_Event;     /* 按键触发事件,单击,双击,长按等 */
  56.   
  57.   Button_CallBack CallBack_Function[number_of_event];
  58.   
  59.         uint8_t Button_Cycle;                   /* 连续按键周期 */
  60.   
  61.   uint8_t Timer_Count;                        /* 计时 */
  62.         uint8_t Debounce_Time;                /* 消抖时间 */
  63.   
  64.         uint8_t Long_Time;                  /* 按键按下持续时间 */
  65.   
  66.   struct button *Next;
  67.   
  68. }Button_t;




  69. /* 供外部调用的函数声明 */

  70. void Button_Create(const char *name,
  71.                   Button_t *btn,
  72.                   uint8_t(*read_btn_level)(void),
  73.                   uint8_t btn_trigger_level);
  74.                   
  75. void Button_Attach(Button_t *btn,Button_Event btn_event,Button_CallBack btn_callback);   
  76.                   
  77. void Button_Cycle_Process(Button_t *btn);   
  78.                   
  79. void Button_Process(void);
  80.                   
  81. void Button_Delete(Button_t *btn);   
  82.   
  83. void Search_Button(void);     
  84.                   
  85. void Get_Button_EventInfo(Button_t *btn);
  86. uint8_t Get_Button_Event(Button_t *btn);
  87. uint8_t Get_Button_State(Button_t *btn);
  88. void Button_Process_CallBack(void *btn);
  89. uint8_t Read_KEY1_Level(void);                  
  90. #endif
main.c完整代码:
  1. /**
  2.   **************************************************************************
  3.   * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  4.   * @brief    main program
  5.   **************************************************************************
  6.   *                       Copyright notice & Disclaimer
  7.   *
  8.   * The software Board Support Package (BSP) that is made available to
  9.   * download from Artery official website is the copyrighted work of Artery.
  10.   * Artery authorizes customers to use, copy, and distribute the BSP
  11.   * software and its related documentation for the purpose of design and
  12.   * development in conjunction with Artery microcontrollers. Use of the
  13.   * software is governed by this copyright notice and the following disclaimer.
  14.   *
  15.   * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
  16.   * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
  17.   * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
  18.   * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
  19.   * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  20.   * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
  21.   *
  22.   **************************************************************************
  23.   */

  24. #include "at32f423_board.h"
  25. #include "at32f423_clock.h"
  26. #include "button.h"

  27. /** @addtogroup AT32F423_periph_examples
  28.   * @{
  29.   */

  30. /** @addtogroup 423_USART_printf USART_printf
  31.   * @{
  32.   */

  33. __IO uint32_t time_cnt = 0;
  34. Button_t Button1;


  35. void Btn1_Dowm_CallBack(void *btn)
  36. {
  37.   printf("Button1 单击!\r\n");
  38. }

  39. void Btn1_Double_CallBack(void *btn)
  40. {
  41.   printf("Button1 双击!\r\n");
  42. }

  43. void Btn1_Long_CallBack(void *btn)
  44. {
  45.   printf("Button1 长按!\r\n");
  46. }
  47. void Btn1_ContinuosFree_CallBack(void *btn)
  48. {
  49.   printf("Button1 连按释放!\r\n");
  50. }

  51. /**
  52.   * @brief  main function.
  53.   * @param  none
  54.   * @retval none
  55.   */
  56. int main(void)
  57. {
  58.   system_clock_config();
  59.   at32_board_init();
  60.   uart_print_init(115200);
  61.          Button_Create("Button1",
  62.               &Button1,
  63.               Read_KEY1_Level,
  64.               1);
  65.   Button_Attach(&Button1,BUTTON_DOWM,Btn1_Dowm_CallBack);                       //单击
  66.   Button_Attach(&Button1,BUTTON_DOUBLE,Btn1_Double_CallBack);                   //双击  
  67.   Button_Attach(&Button1,BUTTON_LONG,Btn1_Long_CallBack);                       //长按BUTTON_LONG_FREE,
  68.         Button_Attach(&Button1,BUTTON_LONG_FREE,Btn1_ContinuosFree_CallBack);
  69.   /* output a message on hyperterminal using printf function */
  70.   printf("usart printf example: retarget the c library printf function to the usart\r\n");
  71.         Get_Button_Event(&Button1);
  72.   while(1)
  73.   {
  74.                 Button_Process();     //需要周期调用按键处理函数
  75. //    printf("usart printf counter: %u\r\n",time_cnt++);
  76. //    delay_sec(1);
  77.                 delay_ms(20);
  78.   }
  79. }

  80. /**
  81.   * @}
  82.   */

  83. /**
  84.   * @}
  85.   */

【试用心得】
1、此次是我第一次使用按键的驱动代码,实现了很多单按键的功能,这在我们以后面的编程工作中会有很大的帮助。
2、能够顺利的移植,也得益于雅特力的官方示例给了开发板的常规驱动,比如Uart\printf重定向、按键驱动、LED灯驱动都写好了,我们只要调用board.c中的就可以了。
3、在github上有很多优秀的开源软件,能向大佬们学习,也是提高自身技术水平的重要方式之一,这里要感觉这些无私奉献的大佬。

184592967 发表于 2023-10-25 15:32 | 显示全部楼层
谢谢分享,搞来试试
Aeddg 发表于 2023-10-25 16:32 | 显示全部楼层
谢谢分享!
 楼主| lulugl 发表于 2023-10-25 18:23 | 显示全部楼层
184592967 发表于 2023-10-25 15:32
谢谢分享,搞来试试

挺好用的一个开源库,你值得拥有!
trucyw 发表于 2023-10-26 08:23 | 显示全部楼层
谢谢分享,搞来试试
jobszheng 发表于 2023-10-26 09:26 | 显示全部楼层
这个按键代码优秀在哪里了啊?
 楼主| lulugl 发表于 2023-10-26 10:40 | 显示全部楼层
jobszheng 发表于 2023-10-26 09:26
这个按键代码优秀在哪里了啊?

不只是我说他优秀,其他的人也认为他优秀,而且这个驱动,移植方便,只要实现一下IO的驱动,电平状态的获取后就可以实现单击、双击、连击等等的。这样的不优秀,还有什么可以说他优秀?
ssy123321 发表于 2024-12-13 17:42 | 显示全部楼层
呐咯密密 发表于 2024-12-13 20:06 | 显示全部楼层
这些开源的按键驱动真的好用
您需要登录后才可以回帖 登录 | 注册

本版积分规则

180

主题

830

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部

180

主题

830

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部