• 智能车菜单编写(2)


    我所采用的菜单是基于一个开源的按键组件,感兴趣的同学可以先去了解一下

    开源按键组件MultiButton支持菜单操作(事件驱动型)

    第1期 | MultiButton,一个小巧简单易用的事件驱动型按键驱动模块

    该组件的优点在于可以无限的扩容按键的使用,且该菜单简洁易懂,看不懂的同学可以直接移植到对应的单片机上,然后一个一个更改参数来慢慢理解。具体的原理实现就不细讲,主要讲如何使用。

    首先将multi_button.c和multi_button.h文件复制到工程目录中

    multi_button.c

    1. /*
    2. * Copyright (c) 2016 Zibin Zheng
    3. * All rights reserved
    4. */
    5. #include "multi_button.h"
    6. #include "headfile.h"
    7. #define EVENT_CB(ev) if(handle->cb[ev])handle->cb[ev]((Button*)handle)
    8. //button handle list head.
    9. static struct Button* head_handle = NULL;
    10. /**
    11. * @brief Initializes the button struct handle.
    12. * @param handle: the button handle strcut.
    13. * @param pin_level: read the HAL GPIO of the connet button level.
    14. * @param active_level: pressed GPIO level.
    15. * @retval None
    16. */
    17. void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level)
    18. {
    19. memset(handle, 0, sizeof(struct Button));
    20. handle->event = (uint8_t)NONE_PRESS;
    21. handle->hal_button_Level = pin_level;
    22. handle->button_level = handle->hal_button_Level();
    23. handle->active_level = active_level;
    24. }
    25. /**
    26. * @brief Attach the button event callback function.
    27. * @param handle: the button handle strcut.
    28. * @param event: trigger event type.
    29. * @param cb: callback function.
    30. * @retval None
    31. */
    32. void button_attach(struct Button* handle, PressEvent event, BtnCallback cb)
    33. {
    34. handle->cb[event] = cb;
    35. }
    36. /**
    37. * @brief Inquire the button event happen.
    38. * @param handle: the button handle strcut.
    39. * @retval button event.
    40. */
    41. PressEvent get_button_event(struct Button* handle)
    42. {
    43. return (PressEvent)(handle->event);
    44. }
    45. /**
    46. * @brief Button driver core function, driver state machine.
    47. * @param handle: the button handle strcut.
    48. * @retval None
    49. */
    50. void button_handler(struct Button* handle)
    51. {
    52. uint8_t read_gpio_level = handle->hal_button_Level();
    53. //ticks counter working..
    54. if((handle->state) > 0) handle->ticks++;
    55. /*------------button debounce handle---------------*/
    56. if(read_gpio_level != handle->button_level) { //not equal to prev one
    57. //continue read 3 times same new level change
    58. if(++(handle->debounce_cnt) >= DEBOUNCE_TICKS) {
    59. handle->button_level = read_gpio_level;
    60. handle->debounce_cnt = 0;
    61. }
    62. } else { //leved not change ,counter reset.
    63. handle->debounce_cnt = 0;
    64. }
    65. /*-----------------State machine-------------------*/
    66. switch (handle->state) {
    67. case 0:
    68. if(handle->button_level == handle->active_level) { //start press down
    69. handle->event = (uint8_t)PRESS_DOWN;
    70. EVENT_CB(PRESS_DOWN);
    71. handle->ticks = 0;
    72. handle->repeat = 1;
    73. handle->state = 1;
    74. } else {
    75. handle->event = (uint8_t)NONE_PRESS;
    76. }
    77. break;
    78. case 1:
    79. if(handle->button_level != handle->active_level) { //released press up
    80. handle->event = (uint8_t)PRESS_UP;
    81. EVENT_CB(PRESS_UP);
    82. handle->ticks = 0;
    83. handle->state = 2;
    84. } else if(handle->ticks > LONG_TICKS) {
    85. handle->event = (uint8_t)LONG_PRESS_START;
    86. EVENT_CB(LONG_PRESS_START);
    87. handle->state = 5;
    88. }
    89. break;
    90. case 2:
    91. if(handle->button_level == handle->active_level) { //press down again
    92. handle->event = (uint8_t)PRESS_DOWN;
    93. EVENT_CB(PRESS_DOWN);
    94. handle->repeat++;
    95. EVENT_CB(PRESS_REPEAT); // repeat hit
    96. handle->ticks = 0;
    97. handle->state = 3;
    98. } else if(handle->ticks > SHORT_TICKS) { //released timeout
    99. if(handle->repeat == 1) {
    100. handle->event = (uint8_t)SINGLE_CLICK;
    101. EVENT_CB(SINGLE_CLICK);
    102. } else if(handle->repeat == 2) {
    103. handle->event = (uint8_t)DOUBLE_CLICK;
    104. EVENT_CB(DOUBLE_CLICK); // repeat hit
    105. }
    106. handle->state = 0;
    107. }
    108. break;
    109. case 3:
    110. if(handle->button_level != handle->active_level) { //released press up
    111. handle->event = (uint8_t)PRESS_UP;
    112. EVENT_CB(PRESS_UP);
    113. if(handle->ticks < SHORT_TICKS) {
    114. handle->ticks = 0;
    115. handle->state = 2; //repeat press
    116. } else {
    117. handle->state = 0;
    118. }
    119. }
    120. break;
    121. case 5:
    122. if(handle->button_level == handle->active_level) {
    123. //continue hold trigger
    124. handle->event = (uint8_t)LONG_PRESS_HOLD;
    125. EVENT_CB(LONG_PRESS_HOLD);
    126. } else { //releasd
    127. handle->event = (uint8_t)PRESS_UP;
    128. EVENT_CB(PRESS_UP);
    129. handle->state = 0; //reset
    130. }
    131. break;
    132. }
    133. }
    134. /**
    135. * @brief Start the button work, add the handle into work list.
    136. * @param handle: target handle strcut.
    137. * @retval 0: succeed. -1: already exist.
    138. */
    139. int button_start(struct Button* handle)
    140. {
    141. struct Button* target = head_handle;
    142. while(target) {
    143. if(target == handle) return -1; //already exist.
    144. target = target->next;
    145. }
    146. handle->next = head_handle;
    147. head_handle = handle;
    148. return 0;
    149. }
    150. /**
    151. * @brief Stop the button work, remove the handle off work list.
    152. * @param handle: target handle strcut.
    153. * @retval None
    154. */
    155. void button_stop(struct Button* handle)
    156. {
    157. struct Button** curr;
    158. for(curr = &head_handle; *curr; ) {
    159. struct Button* entry = *curr;
    160. if (entry == handle) {
    161. *curr = entry->next;
    162. // free(entry);
    163. } else
    164. curr = &entry->next;
    165. }
    166. }
    167. /**
    168. * @brief background ticks, timer repeat invoking interval 5ms.
    169. * @param None.
    170. * @retval None
    171. */
    172. void button_ticks()
    173. {
    174. struct Button* target;
    175. for(target=head_handle; target; target=target->next) {
    176. button_handler(target);
    177. }
    178. }

    multi_button.h:

    1. /*
    2. * Copyright (c) 2016 Zibin Zheng
    3. * All rights reserved
    4. */
    5. #ifndef _MULTI_BUTTON_H_
    6. #define _MULTI_BUTTON_H_
    7. #include
    8. #include
    9. //According to your need to modify the constants.
    10. #define TICKS_INTERVAL 10 //ms
    11. #define DEBOUNCE_TICKS 2 //MAX 8
    12. #define SHORT_TICKS (300 /TICKS_INTERVAL)
    13. #define LONG_TICKS (1000 /TICKS_INTERVAL)
    14. typedef void (*BtnCallback)(void*);
    15. typedef enum {
    16. PRESS_DOWN = 0, //按键按下,每次按下都触发
    17. PRESS_UP, //按键弹起,每次松开都触发
    18. PRESS_REPEAT, //重复按下触发,变量repeat计数连击次数
    19. SINGLE_CLICK, //单击按键事件
    20. DOUBLE_CLICK, //双击按键事件
    21. LONG_PRESS_START, //达到长按时间阈值时触发一次
    22. LONG_PRESS_HOLD, //长按期间一直触发
    23. number_of_event, //事件种类数
    24. NONE_PRESS
    25. }PressEvent;
    26. typedef struct Button {
    27. uint16_t ticks;
    28. uint8_t repeat : 4; // 记录连击次数
    29. uint8_t event : 4; // 记录具体事件
    30. uint8_t state : 3; // 下一个要跳转的状态,用于状态的切换
    31. uint8_t debounce_cnt : 3; // 记录持续次数(每次固定时间,用于去抖)
    32. uint8_t active_level : 1; // 有效电平(按键按下时的电平)
    33. uint8_t button_level : 1; // 记录当前的电平
    34. uint8_t (*hal_button_Level)(void); // 函数指针(指向获取当前按键电平的函数)
    35. BtnCallback cb[number_of_event]; // 函数指针数组:分别指向各个事件的回调函数
    36. struct Button* next;
    37. }Button;
    38. #ifdef __cplusplus
    39. extern "C" {
    40. #endif
    41. void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level);
    42. void button_attach(struct Button* handle, PressEvent event, BtnCallback cb);
    43. PressEvent get_button_event(struct Button* handle);
    44. int button_start(struct Button* handle);
    45. void button_stop(struct Button* handle);
    46. void button_ticks(void);
    47. #ifdef __cplusplus
    48. }
    49. #endif
    50. #endif

    最后将button_ticks(void)函数放入中断中,以用来检测按键状态。也可以放入364的另外一个核中,具体的两个核操作方式以后可能会简单介绍,因为我写的也很烂。

    如上.h文件所示,每个按键都具备用按下触发,弹起触发,单击双击等模式,我之前试过可使用一个按键来实现菜单的功能,就是不停的单击双击长按会混淆每个模式所对应的函数,建议还是4个按键,大体可分两个按键负责页面的上下移动,两个按键负责进入和退出二级菜单。

    移植好按键的固件,下面需要对按键进行每个按键功能的定义。与上一样,可在工程目录中新建button.c和button.h文件。

    button.c:

    1. #include "button.h"
    2. #include "headfile.h"
    3. static const PIN_enum key_pin[4] = {P22_3, P22_2, P22_1, P22_0}, //存放的是对应按键的引脚
    4. dial_pin[4] = {P33_4, P33_5,P33_13,P33_12}; //存放对应拨码开关的引脚,用于之后修改菜单参数的数量级
    5. static Button buttons[4];
    6. IFX_INLINE static void assignments(void) {
    7. button_attach(&buttons[0], SINGLE_CLICK, button1_change_single);
    8. button_attach(&buttons[0], DOUBLE_CLICK, button1_change_double);
    9. button_attach(&buttons[0], LONG_PRESS_START, button1_change_long);
    10. //定义P22_3引脚,单击,双击,长按所对应的功能函数,即第三个参数
    11. button_attach(&buttons[1], SINGLE_CLICK, button2_change_single);
    12. button_attach(&buttons[1], DOUBLE_CLICK, button2_change_double);
    13. button_attach(&buttons[1], LONG_PRESS_START, button2_change_long);
    14. //同上
    15. button_attach(&buttons[2], SINGLE_CLICK, ui_key_yes_click); //同上,单击yes进入二级菜单
    16. button_attach(&buttons[3], SINGLE_CLICK, ui_key_no_click); //同上,单击no退出二级菜单
    17. }
    18. uint8_t key0_read(void) {
    19. return gpio_get(key_pin[0]);
    20. }
    21. uint8_t key1_read(void) {
    22. return gpio_get(key_pin[1]);
    23. }
    24. uint8_t key2_read(void) {
    25. return gpio_get(key_pin[2]);
    26. }
    27. uint8_t key3_read(void) {
    28. return gpio_get(key_pin[3]);
    29. }
    30. uint8_t dial_read(uint8_t id) {
    31. return gpio_get(dial_pin[id]);
    32. }
    33. void buzzer_init(void){
    34. gpio_init(BEEP_PIN, GPO, 1, PUSHPULL);
    35. }
    36. void key_init(void) {
    37. button_init(&buttons[0], key0_read, 0);
    38. button_init(&buttons[1], key1_read, 0);
    39. button_init(&buttons[2], key2_read, 0);
    40. button_init(&buttons[3], key3_read, 0);
    41. assignments();
    42. for (int i = 0; i < 4; ++i) {
    43. gpio_init(key_pin[i], GPI, 0, NO_PULL);
    44. //gpio_init(dial_pin[i], GPI, 0, NO_PULL);
    45. button_start(&buttons[i]);
    46. }
    47. }

    button.h

    1. #ifndef _button_H_
    2. #define _button_H_
    3. #include "StdIf/IfxStdIf_DPipe.h"
    4. #include "PLATFORM_TYPES.H"
    5. #include "common.h"
    6. #include
    7. //#define BEEP_PIN P33_10
    8. #define BEEP_PIN P10_5
    9. #define buzzer_on gpio_set(BEEP_PIN,0)
    10. #define buzzer_off gpio_set(BEEP_PIN,1)
    11. extern uint8 ips200_show_flag;
    12. void key_init(void);
    13. void buzzer_init();
    14. uint8_t dial_read(uint8_t id);
    15. #endif

    具体的按键调用函数如下,下一章就是对菜单页进行编写。

  • 相关阅读:
    C语言之判断与循环语句知识点总结
    Vue3+Ts实现父子组件间传值的两种方式
    这个Python代码为什么会出现报错呢?正确应该怎么写呢
    前端 JS 经典:浏览器中 ESModule 的工作原理
    数字化转型领航者:佑美科技塑造智能健康新生态
    c语言练习45:模拟实现内存函数memcpy
    【Python 实战基础】Pandas如何精确设置表格数据的单元格的值
    数据持久化技术(Python)的使用
    WSL下gcc for arm交叉编译链的系统配置
    Java面试题-JVM
  • 原文地址:https://blog.csdn.net/weixin_50567482/article/details/126574503