input_scan.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /**
  2. ******************************************************************************
  3. * @file input_scan.c
  4. * @brief 编码器/按键扫描模块实现
  5. * SW_KEY(PF3): 短按切换音源, 长按5s断开蓝牙
  6. * SW1_KEY(PB8): 短按低音静音
  7. * SW2_KEY(PA15): 短按快速静音
  8. * SW1编码器(PA5/PA6): 低音音量
  9. * SW2编码器(PB0/PA7): 主音量LR
  10. ******************************************************************************
  11. */
  12. /* Includes ------------------------------------------------------------------*/
  13. #include "input_scan.h"
  14. #include "app_state.h"
  15. #include "led_driver.h"
  16. #include "uart_protocol.h"
  17. /* Private define ------------------------------------------------------------*/
  18. /* ========== 按钮 / 编码器引脚定义 (外部上拉, 低电平有效) ========== */
  19. #define SW_KEY_PIN GPIO_PIN_3
  20. #define SW_KEY_PORT GPIOF
  21. #define SW1_A_PIN GPIO_PIN_5
  22. #define SW1_A_PORT GPIOA
  23. #define SW1_B_PIN GPIO_PIN_6
  24. #define SW1_B_PORT GPIOA
  25. #define SW1_KEY_PIN GPIO_PIN_8
  26. #define SW1_KEY_PORT GPIOB
  27. #define SW2_A_PIN GPIO_PIN_0
  28. #define SW2_A_PORT GPIOB
  29. #define SW2_B_PIN GPIO_PIN_7
  30. #define SW2_B_PORT GPIOA
  31. #define SW2_KEY_PIN GPIO_PIN_15
  32. #define SW2_KEY_PORT GPIOA
  33. /* 长按时间 */
  34. #define LONG_PRESS_MS 5000u /* SW_KEY 长按 5s 断开蓝牙 */
  35. /* 编码器变速参数 (按单脉冲间隔计算) */
  36. #define ENC_SLOW_PULSE_MS 200u /* 单脉冲 >200ms: 慢速, 需4脉冲 */
  37. #define ENC_FAST_PULSE_MS 75u /* 单脉冲 <75ms: 快速, 需1脉冲 */
  38. /* Private variables ---------------------------------------------------------*/
  39. /* ========== 按键事件标志 (由 main.c 读取处理) ========== */
  40. volatile uint8_t g_swKeyEdge = 0u;
  41. volatile uint8_t g_sw1KeyEdge = 0u;
  42. volatile uint8_t g_sw2KeyEdge = 0u;
  43. volatile uint8_t g_swKeyLongPress = 0u;
  44. /* ========== 双键同按状态 ========== */
  45. volatile uint8_t g_bothPressFlag = 0u;
  46. volatile uint16_t g_bothPressMs = 0u;
  47. /* ========== 按键内部状态 ========== */
  48. static volatile uint8_t g_swKeyLast = 1u; /* 前一次稳定电平 (0=按下, 1=释放) */
  49. static volatile uint8_t g_sw1KeyLast = 1u;
  50. static volatile uint8_t g_sw2KeyLast = 1u;
  51. static volatile uint8_t g_swKeyHeld = 0u; /* SW_KEY 正在被按住 */
  52. static volatile uint16_t g_swKeyPressMs = 0u; /* SW_KEY 按下持续时间 */
  53. static volatile uint8_t g_swKeyPressed_1 = 0u; /* 见过按下标志 */
  54. static volatile uint8_t g_sw1KeyPressed_1 = 0u;
  55. static volatile uint8_t g_sw2KeyPressed_1 = 0u;
  56. /* ========== 编码器内部状态 ========== */
  57. /* 编码器前一次AB状态 (位1=B, 位0=A) */
  58. static volatile uint8_t g_enc1PrevAB = 0u;
  59. static volatile uint8_t g_enc2PrevAB = 0u;
  60. /* 脉冲计数器 */
  61. static volatile int8_t g_enc1PulseCnt = 0;
  62. static volatile int8_t g_enc2PulseCnt = 0;
  63. /* 上次触发时间 (ms) */
  64. static volatile uint32_t g_enc1LastMs = 0u;
  65. static volatile uint32_t g_enc2LastMs = 0u;
  66. /* ========== 编码器正交解码查找表 ========== */
  67. /* index = (prevAB << 2) | currAB */
  68. /* value: 0=无变化, -1=A方向(顺时针), 1=B方向(逆时针) [AB方向已反转] */
  69. static const int8_t s_encTable[16] = {
  70. 0, 1, -1, 0, /* prev=00 */
  71. -1, 0, 0, 1, /* prev=01 */
  72. 1, 0, 0, -1, /* prev=10 */
  73. 0, -1, 1, 0 /* prev=11 */
  74. };
  75. /* Private function prototypes -----------------------------------------------*/
  76. static uint8_t Encoder_ReadAB(uint8_t encIdx);
  77. static int8_t Encoder_Decode(uint8_t encIdx, uint8_t currAB);
  78. static uint8_t ProcessOneEncoder(int8_t dir,
  79. volatile int8_t *pPulseCnt,
  80. volatile int16_t *pLevel,
  81. volatile uint32_t *pLastMs);
  82. /* ========== 初始化 ========== */
  83. /**
  84. * @brief 读取编码器和按键的初始状态
  85. * 防止 MCU 复位时按着的按键松开后产生误触发
  86. */
  87. void InputScan_Init(void)
  88. {
  89. /* 记录编码器初始 AB 状态 */
  90. g_enc1PrevAB = (uint8_t)(
  91. ((HAL_GPIO_ReadPin(SW1_B_PORT, SW1_B_PIN) == GPIO_PIN_SET) ? 2u : 0u) |
  92. ((HAL_GPIO_ReadPin(SW1_A_PORT, SW1_A_PIN) == GPIO_PIN_SET) ? 1u : 0u));
  93. g_enc2PrevAB = (uint8_t)(
  94. ((HAL_GPIO_ReadPin(SW2_B_PORT, SW2_B_PIN) == GPIO_PIN_SET) ? 2u : 0u) |
  95. ((HAL_GPIO_ReadPin(SW2_A_PORT, SW2_A_PIN) == GPIO_PIN_SET) ? 1u : 0u));
  96. /* 按键初始状态与引脚一致 */
  97. g_swKeyLast = (HAL_GPIO_ReadPin(SW_KEY_PORT, SW_KEY_PIN) == GPIO_PIN_RESET) ? 0u : 1u;
  98. g_sw1KeyLast = (HAL_GPIO_ReadPin(SW1_KEY_PORT, SW1_KEY_PIN) == GPIO_PIN_RESET) ? 0u : 1u;
  99. g_sw2KeyLast = (HAL_GPIO_ReadPin(SW2_KEY_PORT, SW2_KEY_PIN) == GPIO_PIN_RESET) ? 0u : 1u;
  100. /* 清除边缘标志 */
  101. g_swKeyEdge = 0u;
  102. g_sw1KeyEdge = 0u;
  103. g_sw2KeyEdge = 0u;
  104. }
  105. /* ========== 按键扫描 ========== */
  106. /**
  107. * @brief 扫描所有按键 (TIM3 中断中每 1ms 调用)
  108. */
  109. void ScanButtons(void)
  110. {
  111. uint8_t swVal;
  112. /* ----- SW_KEY (PF3): 短按音源切换, 长按5s断开蓝牙 ----- */
  113. swVal = (HAL_GPIO_ReadPin(SW_KEY_PORT, SW_KEY_PIN) == GPIO_PIN_RESET) ? 0u : 1u;
  114. if (swVal == 0u)
  115. {
  116. if (g_swKeyLast == 1u)
  117. {
  118. g_swKeyLast = 0u;
  119. g_swKeyHeld = 1u;
  120. g_swKeyPressMs = 0u;
  121. g_swKeyPressed_1 = 1u;
  122. }
  123. if (g_swKeyHeld)
  124. {
  125. g_swKeyPressMs++;
  126. if (g_swKeyPressMs >= LONG_PRESS_MS && g_swKeyLongPress == 0u)
  127. {
  128. g_swKeyLongPress = 1u;
  129. g_swKeyPressMs = 0u;
  130. }
  131. }
  132. }
  133. else if (g_swKeyLast == 0u)
  134. {
  135. g_swKeyLast = 1u;
  136. g_swKeyHeld = 0u;
  137. /* 必须完整 1→0→1, 且长按已处理则不触发短按 */
  138. if (g_swKeyPressed_1 && g_swKeyLongPress == 0u)
  139. {
  140. g_swKeyEdge = 1u;
  141. }
  142. g_swKeyLongPress = 0u;
  143. g_swKeyPressed_1 = 0u;
  144. g_swKeyPressMs = 0u;
  145. }
  146. /* ----- SW1_KEY (PB8): 静音按键 (完整1→0→1才触发) ----- */
  147. swVal = (HAL_GPIO_ReadPin(SW1_KEY_PORT, SW1_KEY_PIN) == GPIO_PIN_RESET) ? 0u : 1u;
  148. if (swVal == 0u && g_sw1KeyLast == 1u)
  149. {
  150. g_sw1KeyLast = 0u;
  151. g_sw1KeyPressed_1 = 1u;
  152. }
  153. else if (swVal == 1u && g_sw1KeyLast == 0u)
  154. {
  155. g_sw1KeyLast = 1u;
  156. if (g_sw1KeyPressed_1)
  157. {
  158. g_sw1KeyPressed_1 = 0u;
  159. g_sw1KeyEdge = 1u;
  160. }
  161. }
  162. /* ----- SW2_KEY (PA15): 快速静音 (完整1→0→1才触发) ----- */
  163. swVal = (HAL_GPIO_ReadPin(SW2_KEY_PORT, SW2_KEY_PIN) == GPIO_PIN_RESET) ? 0u : 1u;
  164. if (swVal == 0u && g_sw2KeyLast == 1u)
  165. {
  166. g_sw2KeyLast = 0u;
  167. g_sw2KeyPressed_1 = 1u;
  168. }
  169. else if (swVal == 1u && g_sw2KeyLast == 0u)
  170. {
  171. g_sw2KeyLast = 1u;
  172. if (g_sw2KeyPressed_1)
  173. {
  174. g_sw2KeyPressed_1 = 0u;
  175. g_sw2KeyEdge = 1u;
  176. }
  177. }
  178. /* ----- 双键同按检测: 两键均按下持续10s触发软复位 ----- */
  179. if (HAL_GPIO_ReadPin(SW1_KEY_PORT, SW1_KEY_PIN) == GPIO_PIN_RESET
  180. && HAL_GPIO_ReadPin(SW2_KEY_PORT, SW2_KEY_PIN) == GPIO_PIN_RESET)
  181. {
  182. if (!g_bothPressFlag)
  183. {
  184. g_bothPressFlag = 1u;
  185. g_bothPressMs = 0u;
  186. }
  187. }
  188. else
  189. {
  190. if (g_bothPressFlag)
  191. {
  192. g_bothPressFlag = 0u;
  193. g_bothPressMs = 0u;
  194. }
  195. }
  196. }
  197. /* ========== 编码器扫描 ========== */
  198. /**
  199. * @brief 扫描所有编码器 (TIM3 中断中每 1ms 调用)
  200. */
  201. void ScanEncoders(void)
  202. {
  203. int8_t dir;
  204. /* ----- SW1编码器: 低音音量 ----- */
  205. dir = Encoder_Decode(0u, Encoder_ReadAB(0u));
  206. if (ProcessOneEncoder(dir, &g_enc1PulseCnt, &g_volBassLevel, &g_enc1LastMs))
  207. {
  208. g_flagSendVolBass = 1u;
  209. }
  210. /* ----- SW2编码器: 主音量LR ----- */
  211. dir = Encoder_Decode(1u, Encoder_ReadAB(1u));
  212. if (dir != 0 && g_mutedByBtn)
  213. {
  214. g_mutedByBtn = 0u;
  215. g_flagSendDacUnmute = 1u;
  216. }
  217. if (ProcessOneEncoder(dir, &g_enc2PulseCnt, &g_volLRLevel, &g_enc2LastMs))
  218. {
  219. g_flagSendVolLR = 1u;
  220. }
  221. }
  222. /* ========== 私有函数 ========== */
  223. /**
  224. * @brief 读取编码器AB引脚
  225. * @param encIdx 0=编码器1(SW1), 1=编码器2(SW2)
  226. * @retval (B<<1 | A) 值 0-3
  227. */
  228. static uint8_t Encoder_ReadAB(uint8_t encIdx)
  229. {
  230. uint8_t a, b;
  231. if (encIdx == 0u)
  232. {
  233. a = (HAL_GPIO_ReadPin(SW1_A_PORT, SW1_A_PIN) == GPIO_PIN_SET) ? 1u : 0u;
  234. b = (HAL_GPIO_ReadPin(SW1_B_PORT, SW1_B_PIN) == GPIO_PIN_SET) ? 1u : 0u;
  235. }
  236. else
  237. {
  238. a = (HAL_GPIO_ReadPin(SW2_A_PORT, SW2_A_PIN) == GPIO_PIN_SET) ? 1u : 0u;
  239. b = (HAL_GPIO_ReadPin(SW2_B_PORT, SW2_B_PIN) == GPIO_PIN_SET) ? 1u : 0u;
  240. }
  241. return (uint8_t)((b << 1u) | a);
  242. }
  243. /**
  244. * @brief 解码编码器旋转方向
  245. * @param encIdx 0=编码器1, 1=编码器2
  246. * @param currAB 当前AB状态
  247. * @retval 1=A方向, -1=B方向, 0=无变化
  248. */
  249. static int8_t Encoder_Decode(uint8_t encIdx, uint8_t currAB)
  250. {
  251. volatile uint8_t *pPrevAB;
  252. uint8_t prevAB;
  253. uint8_t index;
  254. int8_t result;
  255. pPrevAB = (encIdx == 0u) ? &g_enc1PrevAB : &g_enc2PrevAB;
  256. prevAB = *pPrevAB;
  257. index = (uint8_t)((prevAB << 2u) | currAB);
  258. result = s_encTable[index];
  259. if (result != 0)
  260. {
  261. *pPrevAB = currAB;
  262. }
  263. return result;
  264. }
  265. /**
  266. * @brief 单编码器处理: 累计脉冲, 根据单脉冲速度动态调整阈值
  267. * @retval 1: 触发了音量改变, 0: 未触发
  268. */
  269. static uint8_t ProcessOneEncoder(int8_t dir,
  270. volatile int8_t *pPulseCnt,
  271. volatile int16_t *pLevel,
  272. volatile uint32_t *pLastMs)
  273. {
  274. if (dir == 0) return 0u;
  275. uint32_t now = g_sysMs;
  276. uint32_t interval = now - *pLastMs;
  277. *pLastMs = now;
  278. if (dir > 0)
  279. {
  280. (*pPulseCnt)++;
  281. }
  282. else
  283. {
  284. (*pPulseCnt)--;
  285. }
  286. /* 速度判定基于相邻两次脉冲的间隔 */
  287. uint8_t threshold;
  288. if (interval > ENC_SLOW_PULSE_MS) threshold = 4u; /* 慢速: 需4脉冲 */
  289. else if (interval < ENC_FAST_PULSE_MS) threshold = 1u; /* 快速: 需1脉冲 */
  290. else threshold = 2u; /* 中速: 需2脉冲 */
  291. if (*pPulseCnt >= (int8_t)threshold)
  292. {
  293. *pPulseCnt = 0;
  294. int16_t level = *pLevel;
  295. if (level < 100)
  296. {
  297. *pLevel = level + 1;
  298. g_userActive = 1u;
  299. g_idleTimer = 0u;
  300. return 1u;
  301. }
  302. }
  303. else if (*pPulseCnt <= -(int8_t)threshold)
  304. {
  305. *pPulseCnt = 0;
  306. int16_t level = *pLevel;
  307. if (level > 0)
  308. {
  309. *pLevel = level - 1;
  310. g_userActive = 1u;
  311. g_idleTimer = 0u;
  312. return 1u;
  313. }
  314. }
  315. return 0u;
  316. }