mapp_key.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. //==================================================================
  2. //
  3. // Filename: key.c
  4. // Description: key process.
  5. //
  6. //------------------------------------------------------------------
  7. //
  8. // version: v2.0
  9. // data: 10:08am, 07.Mar.2013, written by Sirius
  10. // Description: Change the way to process for CAN & line.
  11. //
  12. //------------------------------------------------------------------
  13. //==================================================================
  14. /*------------------------------------------------------------------------------
  15. * I N C L U D E
  16. *------------------------------------------------------------------------------*/
  17. #include "stm32f0xx.h"
  18. #include "general.h"
  19. #include "main.h"
  20. #include "mapp_msg.h"
  21. #include "mapp_arm.h"
  22. #include "mapp_key.h"
  23. #include "mapp_gpio.h"
  24. #include "mapp_pwr.h"
  25. /*------------------------------------------------------------------------------
  26. * D E F I N E
  27. *------------------------------------------------------------------------------*/
  28. /*--- sampling couter ---*/
  29. #define SCAN_ACK_COUNT (2) //2
  30. #define KEY_COUNT (7)
  31. /*--- Key status timer ---*/
  32. #define K_TIMER_LONG_PRESS (OS_TIMER_1_2S) /* Continious timer since key pressed */
  33. #define K_TIMER_RPT_INTERVAL (OS_TIMER_200MS) /* Interval timer between twice long press */
  34. /*------------------------------------------------------------------------------
  35. * S T R U C T
  36. *------------------------------------------------------------------------------*/
  37. /*----------------------
  38. ** Key struct
  39. -----------------------*/
  40. /*------------------------------------------------------------------------------
  41. * S T A T I C - V A R I A B L E S
  42. *------------------------------------------------------------------------------*/
  43. /*------------------------------------------------------------------------------
  44. * G L O B A L
  45. *------------------------------------------------------------------------------*/
  46. /*------------------------------------------------------------------------------
  47. * P R O T O T Y P E
  48. *------------------------------------------------------------------------------*/
  49. static void s_KeyDealwithTask(void);
  50. static VU16 s_keytime[KEY_COUNT] = {0};
  51. /*----------------------------------------------------------------------
  52. // Function name : ADC_Init
  53. // Input parameter :
  54. // Output parameter :
  55. // Use Function :
  56. // Reserve date : 10:25am, 07.Sep.2013, written by zwj
  57. ----------------------------------------------------------------------*/
  58. void AdcCfgInit(void)
  59. {
  60. }
  61. /*----------------------------------------------------------------------
  62. // Function name : KeyVarInit
  63. // Input parameter :
  64. // Output parameter :
  65. // Use Function : Init key module variables.
  66. // Reserve date : 11:37am, 07.Mar.2013, written by Sirius
  67. ----------------------------------------------------------------------*/
  68. void KeyVarInit(void)
  69. {
  70. }
  71. unsigned char key2_5laycnt = 0;
  72. /**
  73. * @brief 按键扫描与处理任务函数
  74. *
  75. * 该函数负责定期扫描所有按键状态,进行防抖处理,并在状态变化时
  76. * 通过消息队列发送按键事件。同时维护gtArm.KeyState变量以记录所有按键的当前状态。
  77. * 优化版:一次性读取所有GPIO状态,避免引脚读取之间的时间差异。
  78. */
  79. void KeyTask(void)
  80. {
  81. // 静态变量用于记录按键状态的历史信息
  82. static U08 last_KeyVal[KEY_COUNT] = {0}; // 记录每个按键的上一个状态
  83. static U08 trascnt1[KEY_COUNT] = {0}; // 按下状态计数器(用于防抖)
  84. static U08 trascnt2[KEY_COUNT] = {0}; // 释放状态计数器(用于防抖)
  85. U08 index = 0; // 循环索引
  86. U08 u8KeyVal[KEY_COUNT] = {0}; // 当前按键采样值
  87. // 一次性读取所有GPIO端口状态
  88. uint16_t portA_status = GPIOA->IDR; // 读取GPIOA输入数据寄存器
  89. uint16_t portB_status = GPIOB->IDR; // 读取GPIOB输入数据寄存器
  90. // 从端口状态中提取各按键状态 - 使用位操作代替单独的GPIO_ReadInputDataBit调用
  91. u8KeyVal[0] = !((portB_status & GPIO_Pin_5) != 0); // 呼叫按键 (PB5)
  92. u8KeyVal[1] = !gtArm.PA4_Value; // 手柄检测 (PA4) - 特殊处理
  93. u8KeyVal[2] = ((portA_status & GPIO_Pin_7) != 0); // 紧急按钮 (PA7)
  94. u8KeyVal[3] = !((portA_status & GPIO_Pin_15) != 0); // 增援按键 (PA15)
  95. u8KeyVal[4] = !((portB_status & GPIO_Pin_3) != 0); // 护理按键 (PB3)
  96. u8KeyVal[5] = !((portA_status & GPIO_Pin_5) != 0); // 换药按键 (PA5)
  97. u8KeyVal[6] = !((portB_status & GPIO_Pin_4) != 0); // 取消按键 (PB4)
  98. // 拔针功能特殊处理(手柄和换药按键同时按下)
  99. if ((u8KeyVal[1] == 1) && (u8KeyVal[5] == 1)) { // 长按拔针,延时退出
  100. key2_5laycnt = 50; // 设置延时计数
  101. } else {
  102. if (key2_5laycnt == 50) { // 拔针按键刚释放
  103. // 发送拔针释放消息
  104. OSQPost(AmiMsgQueue, ARM_MSG_KEY, TO_WORD(0x0f, KEY_RELEASED));
  105. }
  106. if (key2_5laycnt) {
  107. key2_5laycnt--; // 递减延时计数
  108. u8KeyVal[1] = 0; // 强制清除手柄按键状态
  109. u8KeyVal[5] = 0; // 强制清除换药按键状态
  110. last_KeyVal[1] = 0; // 更新历史状态
  111. last_KeyVal[5] = 0; // 更新历史状态
  112. return; // 在延时期间跳过正常按键处理
  113. }
  114. }
  115. // 增加互斥逻辑,防止PB5和PB4同时触发
  116. // 如果两个按键同时被检测为按下,优先处理PB5(呼叫键)
  117. if (u8KeyVal[0] == 1 && u8KeyVal[6] == 1) {
  118. u8KeyVal[6] = 0; // 忽略PB4按键
  119. }
  120. // 遍历所有按键进行状态检测和处理
  121. for (index = 0; index < KEY_COUNT; index++) {
  122. if (u8KeyVal[index] == 0) { // 按键未按下
  123. gtArm.KeyState &= ~(1 << index); // 清除对应按键状态位
  124. trascnt1[index] = 0; // 重置按下计数器
  125. trascnt2[index]++; // 增加释放计数器
  126. s_keytime[index] = 0; // 重置长按计时
  127. // 按键释放防抖处理
  128. if (trascnt2[index] > SCAN_ACK_COUNT) { // 防抖时间
  129. trascnt2[index] = 0;
  130. // 只有状态确实发生变化时才处理
  131. if (last_KeyVal[index] != u8KeyVal[index]) {
  132. // 区分普通释放和长按后释放
  133. if (last_KeyVal[index] == KEY_CONTINUE) {
  134. // 长按后释放消息
  135. OSQPost(AmiMsgQueue, ARM_MSG_KEY, TO_WORD(index+5, KEY_CONTINUE));
  136. } else {
  137. // 普通释放消息
  138. OSQPost(AmiMsgQueue, ARM_MSG_KEY, TO_WORD(index+5, KEY_RELEASED));
  139. }
  140. // 更新按键历史状态
  141. last_KeyVal[index] = u8KeyVal[index];
  142. }
  143. }
  144. } else { // 按键按下
  145. gtArm.KeyState |= (1 << index); // 设置对应按键状态位
  146. trascnt1[index]++; // 增加按下计数器
  147. trascnt2[index] = 0; // 重置释放计数器
  148. s_keytime[index]++; // 增加长按计时
  149. // 按键按下防抖处理
  150. if (trascnt1[index] > SCAN_ACK_COUNT) { // 防抖
  151. trascnt1[index] = 0;
  152. // 长按检测(超过1.5秒)
  153. if (s_keytime[index] > OS_TIMER_1S5) {
  154. // 首次达到长按时间时触发长按
  155. if (last_KeyVal[index] != KEY_CONTINUE) {
  156. last_KeyVal[index] = KEY_CONTINUE;
  157. // 这里原本有长按消息发送代码(已注释)
  158. }
  159. } else if (last_KeyVal[index] != u8KeyVal[index]) {
  160. // 普通按下消息(状态变化)
  161. OSQPost(AmiMsgQueue, ARM_MSG_KEY, TO_WORD(index+5, KEY_PRESSED));
  162. // 更新按键历史状态
  163. last_KeyVal[index] = u8KeyVal[index];
  164. }
  165. }
  166. }
  167. }
  168. }
  169. /*=============================== END OF FILE ===============================*/