main.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /**
  2. ******************************************************************************
  3. * @file main.c
  4. * @author MCU Application Team
  5. * @brief 音箱控制面板 - 应用主逻辑
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2023 Puya Semiconductor Co.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by Puya under BSD 3-Clause license,
  13. * the "License"; You may not use this file except in compliance with the
  14. * License. You may obtain a copy of the License at:
  15. * opensource.org/licenses/BSD-3-Clause
  16. *
  17. ******************************************************************************
  18. * @attention
  19. *
  20. * <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
  21. * All rights reserved.</center></h2>
  22. *
  23. * This software component is licensed by ST under BSD 3-Clause license,
  24. * the "License"; You may not use this file except in compliance with the
  25. * License. You may obtain a copy of the License at:
  26. * opensource.org/licenses/BSD-3-Clause
  27. *
  28. ******************************************************************************
  29. */
  30. /* Includes ------------------------------------------------------------------*/
  31. #include "main.h"
  32. #include <stdio.h>
  33. #include "app_state.h"
  34. #include "led_driver.h"
  35. #include "battery_display.h"
  36. #include "input_scan.h"
  37. #include "uart_protocol.h"
  38. /* Private define ------------------------------------------------------------*/
  39. /* ========== TIM3 定时参数 ========== */
  40. /* 系统时钟 48MHz (PLL), 预分频0 => 48MHz, Period=4799 => 10kHz = 100us */
  41. #define TIM3_PRESCALER 0
  42. #define TIM3_PERIOD 4799
  43. /* 中断内时间基准 */
  44. #define TICK_1MS 10u /* 1ms = 10 * 100us */
  45. /* ========== 长按计时 ========== */
  46. #define BOTH_PRESS_MS 10000u /* 两编码器键同时长按10s软复位 */
  47. #define IDLE_QUERY_MS 30000u /* 空闲30s后主动查询 */
  48. /* Private variables ---------------------------------------------------------*/
  49. TIM_HandleTypeDef TimHandle;
  50. /* UART2 句柄由 BSP 库在 py32f030xx_Start_Kit.c 中定义 */
  51. extern UART_HandleTypeDef DebugUartHandle;
  52. /* ========== 共享状态变量定义 (声明在 app_state.h) ========== */
  53. /* 主从同步变量 (来自主板) */
  54. volatile uint8_t g_inputSource = 0u;
  55. volatile uint8_t g_btConnState = 0u;
  56. volatile uint8_t g_audioPlaying = 0u;
  57. volatile uint8_t g_batteryPct = 0u;
  58. volatile uint8_t g_chgFull = 0u;
  59. volatile uint8_t g_chgIng = 0u;
  60. volatile uint8_t g_dacMute = 0u;
  61. /* 音量等级 (本地操作值) */
  62. volatile int16_t g_volLRLevel = 0;
  63. volatile int16_t g_volBassLevel = 0;
  64. /* 异步发送标志 (由中断置位, 主循环处理) */
  65. volatile uint8_t g_flagSendVolLR = 0u;
  66. volatile uint8_t g_flagSendVolBass = 0u;
  67. volatile uint8_t g_flagSendDacUnmute = 0u;
  68. /* 面板本地状态 */
  69. volatile uint8_t g_dataReceived = 0u;
  70. volatile uint8_t g_mutedByBtn = 0u;
  71. /* 各状态接收标志 (用于开机全亮无缝切换) */
  72. volatile uint8_t g_volLRReceived = 0u;
  73. volatile uint8_t g_volBassReceived = 0u;
  74. volatile uint8_t g_batteryReceived = 0u;
  75. volatile uint8_t g_sourceReceived = 0u;
  76. /* 系统毫秒计时 */
  77. volatile uint32_t g_sysMs = 0u;
  78. /* 空闲查询计时 */
  79. volatile uint16_t g_idleTimer = 0u;
  80. volatile uint8_t g_userActive = 0u;
  81. /* Private function prototypes -----------------------------------------------*/
  82. static void APP_SystemClockConfig(void);
  83. static void APP_GPIO_Init(void);
  84. static void APP_UART_Init(void);
  85. static void APP_TIM3_Init(void);
  86. static void SystemReadyIndicate(void);
  87. /* ========== 主函数 ========== */
  88. /**
  89. * @brief Main program - 音箱主板控制面板
  90. */
  91. int main(void)
  92. {
  93. HAL_Init();
  94. APP_SystemClockConfig();
  95. APP_GPIO_Init();
  96. APP_UART_Init();
  97. LED_InitControlBlock();
  98. InputScan_Init();
  99. APP_TIM3_Init();
  100. /* 上电所有灯全亮3秒, 等待主板开机上报 (LED11除外, 等收到数据再显示) */
  101. for (uint8_t i = 0; i < 13u; i++)
  102. {
  103. if (i == 10u)
  104. LED_SetState(i, 1u); /* LED11全亮, 收到主板上报后更新 */
  105. else
  106. LED_SetState(i, 3u); /* 其他反向并联LED双灯同亮 */
  107. }
  108. LED_ApplyAllStates();
  109. /* 等待3秒让主板启动, 期间每秒查询一次 */
  110. for (uint8_t i = 0; i < 3u; i++)
  111. {
  112. HAL_Delay(1000u);
  113. /* 处理延时期间收到的帧 */
  114. while (UART_IsFrameReady())
  115. {
  116. UART_ClearFrameReady();
  117. ProcessReceivedFrame();
  118. }
  119. /* 如果还没收到数据, 主动查询 */
  120. if (!g_dataReceived)
  121. {
  122. SendQueryAll();
  123. HAL_Delay(200u);
  124. while (UART_IsFrameReady())
  125. {
  126. UART_ClearFrameReady();
  127. ProcessReceivedFrame();
  128. }
  129. }
  130. else
  131. {
  132. break; /* 收到数据了, 提前结束等待 */
  133. }
  134. }
  135. /* 系统就绪指示 */
  136. SystemReadyIndicate();
  137. while (1)
  138. {
  139. /* ---- UART 接收看门狗: 检测并恢复卡死的接收 ---- */
  140. {
  141. static uint32_t s_uartWdMs = 0u;
  142. if ((g_sysMs - s_uartWdMs) >= 200u)
  143. {
  144. s_uartWdMs = g_sysMs;
  145. /* 如果 RxState 不是 BUSY_RX, 说明接收已经停止 */
  146. if (DebugUartHandle.RxState != HAL_UART_STATE_BUSY_RX)
  147. {
  148. /* 清除所有错误标志 */
  149. __HAL_UART_CLEAR_OREFLAG(&DebugUartHandle);
  150. __HAL_UART_CLEAR_FEFLAG(&DebugUartHandle);
  151. __HAL_UART_CLEAR_NEFLAG(&DebugUartHandle);
  152. __HAL_UART_CLEAR_PEFLAG(&DebugUartHandle);
  153. /* 强制恢复 RxState 并重启接收 */
  154. DebugUartHandle.RxState = HAL_UART_STATE_READY;
  155. HAL_UART_Receive_IT(&DebugUartHandle, &g_rxByte, 1u);
  156. }
  157. }
  158. }
  159. /* ---- 处理所有待处理协议帧 ---- */
  160. while (UART_IsFrameReady())
  161. {
  162. UART_ClearFrameReady();
  163. ProcessReceivedFrame();
  164. }
  165. /* ---- 异步发送 UART 指令 (脱离中断执行) ---- */
  166. if (g_flagSendVolLR)
  167. {
  168. static int16_t s_dispLRLvl = -1;
  169. if (s_dispLRLvl != g_volLRLevel)
  170. {
  171. s_dispLRLvl = g_volLRLevel;
  172. UpdateVolumeLEDs(); /* 立即更新本地 UI,保证手感无延迟 */
  173. }
  174. /* 限流向主板发送 (50ms) */
  175. static uint32_t s_lastTxVolLRMs = 0u;
  176. if ((g_sysMs - s_lastTxVolLRMs) >= 50u)
  177. {
  178. g_flagSendVolLR = 0u;
  179. s_lastTxVolLRMs = g_sysMs;
  180. SendSetVolLR((uint8_t)g_volLRLevel);
  181. }
  182. }
  183. if (g_flagSendVolBass)
  184. {
  185. static int16_t s_dispBassLvl = -1;
  186. if (s_dispBassLvl != g_volBassLevel)
  187. {
  188. s_dispBassLvl = g_volBassLevel;
  189. UpdateVolumeLEDs();
  190. }
  191. static uint32_t s_lastTxVolBassMs = 0u;
  192. if ((g_sysMs - s_lastTxVolBassMs) >= 50u)
  193. {
  194. g_flagSendVolBass = 0u;
  195. s_lastTxVolBassMs = g_sysMs;
  196. SendSetVolBass((uint8_t)g_volBassLevel);
  197. }
  198. }
  199. if (g_flagSendDacUnmute)
  200. {
  201. g_flagSendDacUnmute = 0u;
  202. SendSetDacMute(0x01u); /* DAC_UNMUTE */
  203. }
  204. /* ---- 处理按键事件 ---- */
  205. if (g_swKeyEdge)
  206. {
  207. g_swKeyEdge = 0u;
  208. /* SW_KEY(PF3): 切换音源 BT <-> AUX (本地切换, 不等主板上报) */
  209. if (g_inputSource == 0x01u) /* BT=0x01 */
  210. g_inputSource = 0x00u; /* AUX=0x00 */
  211. else
  212. g_inputSource = 0x01u;
  213. SendSetInputSrc(g_inputSource);
  214. UpdateSourceLED();
  215. g_userActive = 1u;
  216. g_idleTimer = 0u;
  217. }
  218. if (g_swKeyLongPress == 1u)
  219. {
  220. g_swKeyLongPress = 2u; /* 标记已处理, 防止重复发送 */
  221. SendBTDisconnect();
  222. g_userActive = 1u;
  223. g_idleTimer = 0u;
  224. }
  225. if (g_sw1KeyEdge)
  226. {
  227. g_sw1KeyEdge = 0u;
  228. /* SW1_KEY: 低音静音 */
  229. g_volBassLevel = 0;
  230. UpdateVolumeLEDs();
  231. SendBassMute();
  232. g_userActive = 1u;
  233. g_idleTimer = 0u;
  234. }
  235. if (g_sw2KeyEdge)
  236. {
  237. g_sw2KeyEdge = 0u;
  238. /* SW2_KEY: 快速静音, 仅第一次按下有效 */
  239. if (!g_mutedByBtn)
  240. {
  241. g_mutedByBtn = 1u;
  242. SendSetDacMute(0x00u); /* 0x00 is Mute */
  243. for (uint8_t i = 0; i < 10u; i++)
  244. LED_SetState(i, 0u);
  245. LED_ApplyAllStates();
  246. }
  247. g_userActive = 1u;
  248. g_idleTimer = 0u;
  249. }
  250. /* ---- 双键同按10s软复位 (500ms防误触 + 10s = 10500ms) ---- */
  251. if (g_bothPressFlag && g_bothPressMs >= (BOTH_PRESS_MS + 500u))
  252. {
  253. g_bothPressFlag = 0u;
  254. g_bothPressMs = 0u;
  255. /* 清除可能触发的静音标志 */
  256. g_sw1KeyEdge = 0u;
  257. g_sw2KeyEdge = 0u;
  258. SendSoftReset();
  259. HAL_Delay(100u);
  260. NVIC_SystemReset();
  261. }
  262. /* ---- 空闲30s后主动查询同步 ---- */
  263. if (g_dataReceived && g_idleTimer >= IDLE_QUERY_MS)
  264. {
  265. g_idleTimer = 0u;
  266. SendQueryAll();
  267. }
  268. }
  269. }
  270. /* ========== 系统就绪指示 ========== */
  271. static void SystemReadyIndicate(void)
  272. {
  273. printf("\r\n========================================\r\n");
  274. printf(" Speaker Control Panel\r\n");
  275. printf(" Waiting for mainboard data...\r\n");
  276. printf("========================================\r\n");
  277. }
  278. /* ========== 硬件初始化 ========== */
  279. /**
  280. * @brief 系统时钟配置: HSI 24MHz -> PLL = 48MHz
  281. */
  282. static void APP_SystemClockConfig(void)
  283. {
  284. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  285. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  286. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI
  287. | RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
  288. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  289. #if defined(RCC_HSIDIV_SUPPORT)
  290. RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
  291. #endif
  292. RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_24MHz;
  293. RCC_OscInitStruct.HSEState = RCC_HSE_OFF;
  294. RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
  295. RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
  296. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  297. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  298. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  299. APP_ErrorHandler();
  300. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
  301. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  302. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  303. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  304. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  305. APP_ErrorHandler();
  306. }
  307. /**
  308. * @brief GPIO初始化 (所有引脚初始配置为浮空输入)
  309. */
  310. static void APP_GPIO_Init(void)
  311. {
  312. GPIO_InitTypeDef GPIO_InitStruct = {0};
  313. __HAL_RCC_GPIOA_CLK_ENABLE();
  314. __HAL_RCC_GPIOB_CLK_ENABLE();
  315. RCC->IOPENR |= RCC_IOPENR_GPIOFEN;
  316. /* GPIOA: LED + 编码器 + SW2_KEY */
  317. GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4
  318. | GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12;
  319. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  320. GPIO_InitStruct.Pull = GPIO_NOPULL;
  321. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  322. GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_15;
  323. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  324. GPIO_InitStruct.Pull = GPIO_PULLUP;
  325. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  326. /* GPIOB: LED + 编码器 + SW1_KEY */
  327. GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4
  328. | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
  329. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  330. GPIO_InitStruct.Pull = GPIO_NOPULL;
  331. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  332. GPIO_InitStruct.Pin = GPIO_PIN_8;
  333. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  334. GPIO_InitStruct.Pull = GPIO_NOPULL;
  335. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  336. /* SW1_KEY (PB0) */
  337. GPIO_InitStruct.Pin = GPIO_PIN_0;
  338. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  339. GPIO_InitStruct.Pull = GPIO_PULLUP;
  340. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  341. /* GPIOF: SW_KEY */
  342. GPIO_InitStruct.Pin = GPIO_PIN_3;
  343. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  344. GPIO_InitStruct.Pull = GPIO_PULLUP;
  345. HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
  346. }
  347. /**
  348. * @brief UART2初始化
  349. */
  350. static void APP_UART_Init(void)
  351. {
  352. BSP_USART_Config();
  353. /* 开启UART2中断接收, 缓冲区在 uart_protocol.c 中定义 */
  354. HAL_UART_Receive_IT(&DebugUartHandle, &g_rxByte, 1u);
  355. }
  356. /**
  357. * @brief TIM3初始化: 100us中断 (10kHz)
  358. */
  359. static void APP_TIM3_Init(void)
  360. {
  361. TimHandle.Instance = TIM3;
  362. TimHandle.Init.Period = TIM3_PERIOD;
  363. TimHandle.Init.Prescaler = TIM3_PRESCALER;
  364. TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  365. TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
  366. TimHandle.Init.RepetitionCounter = 0;
  367. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  368. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
  369. APP_ErrorHandler();
  370. if (HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK)
  371. APP_ErrorHandler();
  372. }
  373. /* ========== 中断回调 ========== */
  374. /**
  375. * @brief TIM3 周期中断回调: 每 100us 执行一次
  376. */
  377. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  378. {
  379. static uint32_t s_tick = 0u;
  380. s_tick++;
  381. /* 每 1ms 更新系统毫秒计数 */
  382. if ((s_tick % 10u) == 0u) g_sysMs++;
  383. /* LED 定时翻转 (状态3/4/5) */
  384. LED_Tick100us();
  385. /* 每 1ms 扫描按键/编码器/电池时间槽 */
  386. if ((s_tick % TICK_1MS) == 0u)
  387. {
  388. ScanButtons();
  389. ScanEncoders();
  390. BatterySlotUpdate();
  391. /* 双键同按计时: 前500ms防误触 */
  392. if (g_bothPressFlag)
  393. {
  394. if (g_bothPressMs < (BOTH_PRESS_MS + 500u))
  395. g_bothPressMs++;
  396. }
  397. /* 空闲计时 */
  398. if (g_userActive)
  399. {
  400. if (++g_idleTimer >= 200u) /* 200ms无操作认为活动结束 */
  401. {
  402. g_userActive = 0u;
  403. g_idleTimer = 0u;
  404. }
  405. }
  406. else if (g_dataReceived)
  407. {
  408. if (g_idleTimer < IDLE_QUERY_MS)
  409. g_idleTimer++;
  410. }
  411. }
  412. }
  413. /**
  414. * @brief USART2 接收完成中断回调 (HAL库)
  415. * 每次重新开启接收前清除溢出错误标志, 防止 ORE 卡死
  416. */
  417. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  418. {
  419. if (huart->Instance == USART2)
  420. {
  421. UART_RxByteCallback(g_rxByte);
  422. /* 清除可能的溢出错误标志, 防止 ORE 导致接收停止 */
  423. __HAL_UART_CLEAR_OREFLAG(huart);
  424. HAL_UART_Receive_IT(&DebugUartHandle, &g_rxByte, 1u);
  425. }
  426. }
  427. /**
  428. * @brief UART 错误中断回调 (HAL库)
  429. * 当发生 ORE/FE/NE/PE 错误时, HAL 会调用此函数而非 RxCpltCallback.
  430. * 必须在此处重新启动接收, 否则 UART 接收将永久停止.
  431. */
  432. void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
  433. {
  434. if (huart->Instance == USART2)
  435. {
  436. /* 清除所有错误标志 */
  437. __HAL_UART_CLEAR_OREFLAG(huart);
  438. __HAL_UART_CLEAR_FEFLAG(huart);
  439. __HAL_UART_CLEAR_NEFLAG(huart);
  440. __HAL_UART_CLEAR_PEFLAG(huart);
  441. /* 重新启动中断接收, 恢复通讯 */
  442. HAL_UART_Receive_IT(&DebugUartHandle, &g_rxByte, 1u);
  443. }
  444. }
  445. /* ========== 错误处理 ========== */
  446. void APP_ErrorHandler(void)
  447. {
  448. while (1)
  449. {
  450. }
  451. }
  452. #ifdef USE_FULL_ASSERT
  453. void assert_failed(uint8_t *file, uint32_t line)
  454. {
  455. while (1)
  456. {
  457. }
  458. }
  459. #endif /* USE_FULL_ASSERT */